diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index 8709d00..b7c2e29 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -26,9 +26,10 @@ endif() #set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) #set(CMAKE_CXX_FLAGS "-Wall -Wextra") -set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fstandalone-debug") -set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -fno-omit-frame-pointer") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fstandalone-debug") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -fno-omit-frame-pointer -g") set(CMAKE_CXX_STANDARD 20) + add_compile_definitions(BUILD_TYPE="${CMAKE_BUILD_TYPE}") @@ -207,6 +208,7 @@ include_directories(${GMP_INCLUDE_DIRS}) add_library(backend_lib STATIC ${BACKEND_SOURCES} ${PROTO_SRCS} ${PROTO_HDRS}) +set_target_properties(backend_lib PROPERTIES ENABLE_EXPORTS TRUE) # Use target-based linking for Protobuf to handle Abseil dependencies automatically if(TARGET protobuf::libprotobuf) set(PROTOBUF_LINK_TARGET protobuf::libprotobuf) diff --git a/backend/bridge/Exceptions.cpp b/backend/bridge/Exceptions.cpp index ff76309..2cf47cb 100644 --- a/backend/bridge/Exceptions.cpp +++ b/backend/bridge/Exceptions.cpp @@ -184,7 +184,27 @@ void symbolizeStackChain(std::stringstream &ss, auto objOrErr = llvm::object::ObjectFile::createObjectFile( buffer->getMemBufferRef()); if (objOrErr) { - uword_t offset = addr - entryStart; + uword_t symbolOffsetInObj = 0; + uint64_t sectionIndex = llvm::object::SectionedAddress::UndefSection; + for (auto const &Sym : objOrErr.get()->symbols()) { + auto nameOrErr = Sym.getName(); + if (nameOrErr) { + std::string symName = nameOrErr.get().str(); + if (symName == entry.name || (symName.starts_with("_") && symName.substr(1) == entry.name)) { + auto valOrErr = Sym.getValue(); + if (valOrErr) { + symbolOffsetInObj = valOrErr.get(); + auto secOrErr = Sym.getSection(); + if (secOrErr && secOrErr.get() != objOrErr.get()->section_end()) { + sectionIndex = secOrErr.get()->getIndex(); + } + break; + } + } + } + } + + uword_t offset = symbolOffsetInObj + (addr - entryStart); if (offset >= 4) offset -= 4; @@ -193,17 +213,20 @@ void symbolizeStackChain(std::stringstream &ss, llvm::symbolize::LLVMSymbolizer localSymbolizer; auto resOrErr = localSymbolizer.symbolizeInlinedCode( *objOrErr.get(), - {offset, llvm::object::SectionedAddress::UndefSection}); + {offset, sectionIndex}); if (resOrErr) { auto &inlinedInfo = resOrErr.get(); for (uint32_t i = 0; i < inlinedInfo.getNumberOfFrames(); ++i) { auto &info = inlinedInfo.getFrame(i); - std::string fnName = - (info.FunctionName != "") - ? llvm::demangle(info.FunctionName) - : demangled; + std::string funcName = info.FunctionName; + if (funcName == "" || + funcName.find("asan.module_ctor") != std::string::npos || + funcName.find("asan.module_dtor") != std::string::npos) { + funcName = entry.name; + } + std::string fnName = llvm::demangle(funcName); std::stringstream frameSs; frameSs << " " << Colors::INFRA(useColor) << "at " @@ -447,14 +470,34 @@ LanguageException::LanguageException(const std::string &name, RTValue message, auto objOrErr = llvm::object::ObjectFile::createObjectFile( buffer->getMemBufferRef()); if (objOrErr) { - uword_t offset = addr - entryStart; + uword_t symbolOffsetInObj = 0; + uint64_t sectionIndex = llvm::object::SectionedAddress::UndefSection; + for (auto const &Sym : objOrErr.get()->symbols()) { + auto nameOrErr = Sym.getName(); + if (nameOrErr) { + std::string symName = nameOrErr.get().str(); + if (symName == entry.name || (symName.starts_with("_") && symName.substr(1) == entry.name)) { + auto valOrErr = Sym.getValue(); + if (valOrErr) { + symbolOffsetInObj = valOrErr.get(); + auto secOrErr = Sym.getSection(); + if (secOrErr && secOrErr.get() != objOrErr.get()->section_end()) { + sectionIndex = secOrErr.get()->getIndex(); + } + break; + } + } + } + } + + uword_t offset = symbolOffsetInObj + (addr - entryStart); if (offset >= 4) offset -= 4; llvm::symbolize::LLVMSymbolizer localSymbolizer; auto resOrErr = localSymbolizer.symbolizeInlinedCode( *objOrErr.get(), - {offset, llvm::object::SectionedAddress::UndefSection}); + {offset, sectionIndex}); if (resOrErr) { auto &inlinedInfo = resOrErr.get(); diff --git a/backend/codegen/CodeGen.h b/backend/codegen/CodeGen.h index 993a1f3..8c59263 100644 --- a/backend/codegen/CodeGen.h +++ b/backend/codegen/CodeGen.h @@ -55,11 +55,13 @@ struct RecurTarget { class CodeGen { std::unique_ptr TSContext; - llvm::LLVMContext &TheContext; + +public: std::unique_ptr TheModule; - llvm::IRBuilder<> Builder; +private: + llvm::IRBuilder<> Builder; VariableBindings variableBindingStack; VariableBindings variableTypesBindingsStack; @@ -70,7 +72,9 @@ class CodeGen { DynamicConstructor dynamicConstructor; MemoryManagement memoryManagement; std::vector executionContextStack; - void pushExecutionContext(llvm::Value *ctx) { executionContextStack.push_back(ctx); } + void pushExecutionContext(llvm::Value *ctx) { + executionContextStack.push_back(ctx); + } void popExecutionContext() { executionContextStack.pop_back(); } ThreadsafeCompilerState &compilerState; diff --git a/backend/codegen/invoke/InvokeManager.h b/backend/codegen/invoke/InvokeManager.h index 5283e90..8942d02 100644 --- a/backend/codegen/invoke/InvokeManager.h +++ b/backend/codegen/invoke/InvokeManager.h @@ -63,6 +63,7 @@ class InvokeManager { ObjectTypeSet createQ(mpq_ptr val); bool canThrow(const std::string &fname) const; bool hasSwiftSelf(const std::vector &args); + public: explicit InvokeManager(llvm::IRBuilder<> &b, llvm::Module &m, ValueEncoder &v, LLVMTypes &t, ThreadsafeCompilerState &s, CodeGen &cg); @@ -126,11 +127,11 @@ class InvokeManager { const clojure::rt::protobuf::bytecode::Node *node = nullptr, const std::vector &extraCleanup = {}); - - TypedValue generateVarInvoke( - TypedValue varObj, const std::vector &args, - CleanupChainGuard *guard = nullptr, - const clojure::rt::protobuf::bytecode::Node *node = nullptr); + TypedValue + generateVarInvoke(TypedValue varObj, const std::vector &args, + CleanupChainGuard *guard = nullptr, + const clojure::rt::protobuf::bytecode::Node *node = nullptr, + bool forceStaticVar = false); TypedValue generateStaticKeywordInvoke( TypedValue keyword, const std::vector &args, @@ -153,8 +154,8 @@ class InvokeManager { const clojure::rt::protobuf::bytecode::Node *node = nullptr, const std::vector &extraCleanup = {}); - llvm::Value *generateICLookup( - llvm::Value *currentVal, size_t argCount, CleanupChainGuard *guard); + llvm::Value *generateICLookup(llvm::Value *currentVal, size_t argCount, + CleanupChainGuard *guard); const std::vector &getICSlotNames() const { return icSlotNames; } }; diff --git a/backend/codegen/invoke/InvokeManager_InstanceCall.cpp b/backend/codegen/invoke/InvokeManager_InstanceCall.cpp index 2aecca6..d967ff3 100644 --- a/backend/codegen/invoke/InvokeManager_InstanceCall.cpp +++ b/backend/codegen/invoke/InvokeManager_InstanceCall.cpp @@ -91,11 +91,11 @@ TypedValue InvokeManager::generateDynamicInstanceCall( // 1. Get current instance type TypedValue boxedInstance = valueEncoder.box(instance); FunctionType *getTypeSig = - FunctionType::get(types.wordTy, {types.RT_valueTy}, false); + FunctionType::get(types.i32Ty, {types.RT_valueTy}, false); FunctionCallee getTypeFunc = theModule.getOrInsertFunction("getType", getTypeSig); - Value *currentTypeIdent = - builder.CreateCall(getTypeFunc, {boxedInstance.value}); + Value *currentTypeIdent = builder.CreateZExt( + builder.CreateCall(getTypeFunc, {boxedInstance.value}), types.wordTy); // 2. Check IC hit (Atomic load for consistency) unsigned int pairSizeBits = wordSizeBits * 2; diff --git a/backend/codegen/invoke/InvokeManager_VarCall.cpp b/backend/codegen/invoke/InvokeManager_VarCall.cpp index 7ef830c..1d45443 100644 --- a/backend/codegen/invoke/InvokeManager_VarCall.cpp +++ b/backend/codegen/invoke/InvokeManager_VarCall.cpp @@ -12,8 +12,8 @@ namespace rt { TypedValue InvokeManager::generateVarInvoke( TypedValue varObj, const std::vector &args, - CleanupChainGuard *guard, - const clojure::rt::protobuf::bytecode::Node *node) { + CleanupChainGuard *guard, const clojure::rt::protobuf::bytecode::Node *node, + bool forceStaticVar) { size_t argCount = args.size(); @@ -23,10 +23,9 @@ TypedValue InvokeManager::generateVarInvoke( // 2. Load current value FROM VAR (borrowed call - Var_peek) FunctionType *peekSig = FunctionType::get( types.RT_valueTy, {types.ExecutionContextPtrTy, types.ptrTy}, false); - Value *currentVal = - invokeRaw("Var_peek", peekSig, {codeGen.getExecutionContext(), varPtr}, - guard, false, {}, true); - + Value *currentVal = invokeRaw( + forceStaticVar ? "Var_peekStatic" : "Var_peek", peekSig, + {codeGen.getExecutionContext(), varPtr}, guard, false, {}, true); // 3. Unified IC resolution (Handles Functions, Keywords, Maps, Vectors) Value *methodToCall = generateICLookup(currentVal, argCount, guard); diff --git a/backend/codegen/ops/InvokeNode.cpp b/backend/codegen/ops/InvokeNode.cpp index caa9773..1c37824 100644 --- a/backend/codegen/ops/InvokeNode.cpp +++ b/backend/codegen/ops/InvokeNode.cpp @@ -39,8 +39,8 @@ TypedValue CodeGen::codegen(const Node &node, const InvokeNode &subnode, } // 3. Generate the VarInvoke call - TypedValue result = - invokeManager.generateVarInvoke(varObj, args, &guard, &node); + TypedValue result = invokeManager.generateVarInvoke(varObj, args, &guard, + &node, !v->dynamic); return TypedValue(result.type.restriction(typeRestrictions), result.value); } diff --git a/backend/codegen/ops/NewNode.cpp b/backend/codegen/ops/NewNode.cpp index 681b053..22d4c1c 100644 --- a/backend/codegen/ops/NewNode.cpp +++ b/backend/codegen/ops/NewNode.cpp @@ -127,7 +127,7 @@ TypedValue CodeGen::codegen(const Node &node, const NewNode &subnode, if (!argRuntimeTypes[i]) { TypedValue boxed = this->valueEncoder.box(args[i]); FunctionType *getTypeSig = FunctionType::get( - this->types.wordTy, {this->types.RT_valueTy}, false); + this->types.i32Ty, {this->types.RT_valueTy}, false); argRuntimeTypes[i] = this->invokeManager.invokeRaw( "getType", getTypeSig, {boxed.value}, &guard, true); } @@ -136,7 +136,7 @@ TypedValue CodeGen::codegen(const Node &node, const NewNode &subnode, Value *targetVal = ConstantInt::get(this->types.i32Ty, (uint32_t)targetTypeID); Value *isType = this->Builder.CreateICmpEQ( - this->Builder.CreateTrunc(argRuntimeTypes[i], this->types.i32Ty), + argRuntimeTypes[i], targetVal); if (match) diff --git a/backend/codegen/ops/StaticCallNode.cpp b/backend/codegen/ops/StaticCallNode.cpp index 6c05897..0ee6d21 100644 --- a/backend/codegen/ops/StaticCallNode.cpp +++ b/backend/codegen/ops/StaticCallNode.cpp @@ -168,7 +168,7 @@ TypedValue CodeGen::codegen(const Node &node, const StaticCallNode &subnode, if (!argRuntimeTypes[i]) { TypedValue boxed = this->valueEncoder.box(args[i]); FunctionType *getTypeSig = FunctionType::get( - this->types.wordTy, {this->types.RT_valueTy}, false); + this->types.i32Ty, {this->types.RT_valueTy}, false); argRuntimeTypes[i] = this->invokeManager.invokeRaw( "getType", getTypeSig, {boxed.value}, &guard, true); } @@ -177,7 +177,7 @@ TypedValue CodeGen::codegen(const Node &node, const StaticCallNode &subnode, Value *targetVal = ConstantInt::get(this->types.i32Ty, (uint32_t)targetID); Value *isType = this->Builder.CreateICmpEQ( - this->Builder.CreateTrunc(argRuntimeTypes[i], this->types.i32Ty), + argRuntimeTypes[i], targetVal); if (match) { diff --git a/backend/jit/JITEngine.cpp b/backend/jit/JITEngine.cpp index ab41431..77ccd89 100644 --- a/backend/jit/JITEngine.cpp +++ b/backend/jit/JITEngine.cpp @@ -24,8 +24,19 @@ #include #include #include +#include #include +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((weak)) void __asan_version_mismatch_check_v8(void) {} + +#ifdef __cplusplus +} +#endif + namespace rt { JITEngine::Finaliser::~Finaliser() { @@ -185,8 +196,13 @@ JITEngine::compileGeneric(std::function codegenFunc, compilationPool .enqueue([this, codegenFunc, moduleName]() -> JITResult { try { + static std::atomic moduleCounter{0}; + std::string uniqueModuleId = moduleName + "_" + std::to_string(moduleCounter.fetch_add(1)); auto codeGenerator = - CodeGen(moduleName, threadsafeState, (void *)this); + CodeGen(uniqueModuleId, threadsafeState, (void *)this); + codeGenerator.TheModule->setTargetTriple( + TM->getTargetTriple().str()); + codeGenerator.TheModule->setDataLayout(TM->createDataLayout()); std::string fName; try { @@ -501,6 +517,9 @@ void JITEngine::registerRuntimeSymbols() { runtimeSymbols.insert( absoluteSymbol("deleteException_C", (void *)deleteException_C)); + runtimeSymbols.insert( + absoluteSymbol("__asan_version_mismatch_check_v8", + (void *)__asan_version_mismatch_check_v8)); cantFail(jit->getMainJITDylib().define( absoluteSymbols(std::move(runtimeSymbols)))); } @@ -672,6 +691,15 @@ void JITEngine::optimize(llvm::Module &M, const std::string &entryPoint) { MPM.addPass(PB.buildPerModuleDefaultPipeline(optLevel)); MPM.addPass(llvm::GlobalDCEPass()); + + if (optLevel == llvm::OptimizationLevel::O0) { + llvm::AddressSanitizerOptions opts; + MPM.addPass(llvm::AddressSanitizerPass(opts, + /*UseGlobalGC=*/true, + /*UseOdrIndicator=*/false, + llvm::AsanDtorKind::Global, + llvm::AsanCtorKind::Global)); + } MPM.run(M, MAM); } diff --git a/backend/runtime/CMakeLists.txt b/backend/runtime/CMakeLists.txt index 21cef73..d561ead 100644 --- a/backend/runtime/CMakeLists.txt +++ b/backend/runtime/CMakeLists.txt @@ -6,11 +6,11 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -set(CMAKE_CXX_FLAGS_DEBUG "-g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fexceptions") -set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -fexceptions") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fexceptions") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Ofast -fexceptions -g") -set(CMAKE_C_FLAGS_DEBUG "-g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fexceptions") -set(CMAKE_C_FLAGS_RELEASE "-Ofast -fexceptions") +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -fexceptions") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Ofast -fexceptions -g") add_compile_definitions(BUILD_TYPE="${CMAKE_BUILD_TYPE}") @@ -135,6 +135,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(EMULATED_TLS_FLAG "-femulated-tls") endif() +set(NDEBUG_FLAG "") +if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo|MinSizeRel)$") + set(NDEBUG_FLAG "-DNDEBUG") +endif() + # 2. Compile each source file to an individual .bc file foreach(src ${SOURCES}) get_filename_component(basename ${src} NAME_WE) @@ -145,9 +150,11 @@ foreach(src ${SOURCES}) COMMAND ${CLANG_EXECUTABLE} -emit-llvm -c ${CMAKE_CURRENT_SOURCE_DIR}/${src} -iquote ${CMAKE_CURRENT_SOURCE_DIR} -I${GMP_INCLUDE_DIRS} - -O3 -gline-tables-only -fPIC -fexceptions -funwind-tables ${EMULATED_TLS_FLAG} ${MCX16_FLAG} + -O3 -gline-tables-only -fPIC -fexceptions -funwind-tables ${EMULATED_TLS_FLAG} ${MCX16_FLAG} ${NDEBUG_FLAG} + -MD -MF ${bc_output}.d -o ${bc_output} - DEPENDS ${src} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${src} + DEPFILE ${bc_output}.d COMMENT "Generating LLVM Bitcode for ${src}" ) list(APPEND BITCODE_OUTPUTS ${bc_output}) @@ -163,6 +170,7 @@ add_custom_command( # 4. Create a target to trigger the build add_custom_target(runtime_ir ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/runtime_uber.bc) +add_dependencies(runtime runtime_ir) ######################################################################## diff --git a/backend/runtime/Object.h b/backend/runtime/Object.h index d15f2f7..8260358 100644 --- a/backend/runtime/Object.h +++ b/backend/runtime/Object.h @@ -5,8 +5,6 @@ struct ExecutionContext; #define RT_OBJECT - - #include "Hash.h" #include "word.h" #ifdef __cplusplus @@ -106,24 +104,50 @@ inline void Object_promoteToSharedShallow(Object *self, uword_t current); inline uword_t Object_getRawRefCount(Object *self); inline void Object_create(Object *restrict self, objectType type) { +#ifdef REFCOUNT_NONATOMIC + self->refCount = COUNT_INC; +#else atomic_store_explicit(&(self->atomicRefCount), COUNT_INC, memory_order_relaxed); +#endif self->type = type; +#ifdef REFCOUNT_TRACING if (self->type > 0 && (int)self->type <= TRACING_LIMIT) { atomic_fetch_add_explicit(&(allocationCount[self->type - 1]), 1, memory_order_relaxed); atomic_fetch_add_explicit(&(objectCount[self->type - 1]), 1, memory_order_relaxed); } +#endif + // printf("--> Allocating type %d addres %p\n", self->type, ); } inline void Object_retain(Object *restrict self) { +// printf("RETAIN!!! %d\n", self->type); +#ifdef REFCOUNT_TRACING if (self->type > 0 && (int)self->type <= TRACING_LIMIT) { atomic_fetch_add_explicit(&(allocationCount[self->type - 1]), 1, memory_order_relaxed); } - atomic_fetch_add_explicit(&(self->atomicRefCount), COUNT_INC, +#endif +#ifdef REFCOUNT_NONATOMIC + self->refCount += COUNT_INC; +#else + uword_t current = + atomic_load_explicit(&(self->atomicRefCount), memory_order_relaxed); + + if (__builtin_expect(!(current & SHARED_BIT), 1)) { + // FAST PATH: It's local. Use a plain non-atomic write. + // We can do this because only THIS thread owns it. + uword_t new_val = current + COUNT_INC; + atomic_store_explicit(&(self->atomicRefCount), new_val, + memory_order_relaxed); + } else { + // SLOW PATH: It's shared. Must use atomic fetch_add. + atomic_fetch_add_explicit(&(self->atomicRefCount), COUNT_INC, memory_order_relaxed); + } +#endif } inline void Ptr_retain(void *ptr); @@ -140,31 +164,30 @@ RTValue RT_withMeta(RTValue v, RTValue meta); #include "BigInteger.h" #include "Boolean.h" #include "BridgedObject.h" -#include "PersistentVectorChunkedSeq.h" -#include "PersistentVectorReverseSeq.h" -#include "ArrayChunk.h" #include "Class.h" #include "ConcurrentHashMap.h" #include "Double.h" #include "Exception.h" +#include "ExecutionContext.h" #include "Function.h" #include "Integer.h" #include "Keyword.h" +#include "Namespace.h" #include "Nil.h" #include "PersistentArrayMap.h" #include "PersistentList.h" #include "PersistentVector.h" +#include "PersistentVectorChunkedSeq.h" #include "PersistentVectorIterator.h" #include "PersistentVectorNode.h" +#include "PersistentVectorReverseSeq.h" #include "Ratio.h" #include "String.h" #include "StringBuilder.h" #include "Symbol.h" #include "Var.h" -#include "ExecutionContext.h" -#include "Namespace.h" -extern void ExecutionContext_destroy(ExecutionContext* self); +extern void ExecutionContext_destroy(ExecutionContext *self); inline void *allocate(size_t size) { #ifndef USE_MEMORY_BANKS @@ -321,13 +344,15 @@ inline void Object_destroy(Object *restrict self, bool deallocateChildren) { StringBuilder_destroy((StringBuilder *)self); break; case persistentVectorChunkedSeqType: - PersistentVectorChunkedSeq_destroy((PersistentVectorChunkedSeq *)self, deallocateChildren); + PersistentVectorChunkedSeq_destroy((PersistentVectorChunkedSeq *)self, + deallocateChildren); break; case arrayChunkType: ArrayChunk_destroy((ArrayChunk *)self, deallocateChildren); break; case persistentVectorReverseSeqType: - PersistentVectorReverseSeq_destroy((PersistentVectorReverseSeq *)self, deallocateChildren); + PersistentVectorReverseSeq_destroy((PersistentVectorReverseSeq *)self, + deallocateChildren); break; case symbolType: Symbol_destroy((Symbol *)self); @@ -370,10 +395,12 @@ inline bool isReusable(RTValue self) { inline bool Object_release_internal(Object *restrict self, bool deallocateChildren) { +#ifdef REFCOUNT_TRACING if (self->type > 0 && (int)self->type <= TRACING_LIMIT) { atomic_fetch_sub_explicit(&(allocationCount[self->type - 1]), 1, memory_order_relaxed); } +#endif #ifdef REFCOUNT_NONATOMIC self->refCount -= COUNT_INC; if ((self->refCount >> 1) == 0) { @@ -482,7 +509,8 @@ inline void Object_promoteToShared(Object *restrict self) { break; case persistentVectorChunkedSeqType: - Object_promoteToShared((Object *)((PersistentVectorChunkedSeq *)self)->it.parent); + Object_promoteToShared( + (Object *)((PersistentVectorChunkedSeq *)self)->it.parent); Object_promoteToSharedShallow(self, count); break; case arrayChunkType: @@ -627,7 +655,9 @@ inline bool Object_equals(Object *self, Object *other) { case stringBuilderType: return StringBuilder_equals((StringBuilder *)self, (StringBuilder *)other); case persistentVectorChunkedSeqType: - return PersistentVectorChunkedSeq_equals((PersistentVectorChunkedSeq *)self, (PersistentVectorChunkedSeq *)other); + return PersistentVectorChunkedSeq_equals( + (PersistentVectorChunkedSeq *)self, + (PersistentVectorChunkedSeq *)other); case symbolType: return Symbol_equals((Symbol *)self, (Symbol *)other); case namespaceType: @@ -696,7 +726,8 @@ inline String *Object_toString(Object *restrict self) { case stringBuilderType: return StringBuilder_toString((StringBuilder *)self); case persistentVectorChunkedSeqType: - return PersistentVectorChunkedSeq_toString((PersistentVectorChunkedSeq *)self); + return PersistentVectorChunkedSeq_toString( + (PersistentVectorChunkedSeq *)self); case symbolType: return Symbol_toString(RT_boxSymbol(self)); case namespaceType: diff --git a/backend/runtime/PersistentArrayMap.c b/backend/runtime/PersistentArrayMap.c index 13225d4..965e364 100644 --- a/backend/runtime/PersistentArrayMap.c +++ b/backend/runtime/PersistentArrayMap.c @@ -5,24 +5,24 @@ #include "defines.h" #include -static PersistentArrayMap *EMPTY = NULL; +PersistentArrayMap * volatile EMPTY_ARRAY_MAP = NULL; /* mem done */ PersistentArrayMap *PersistentArrayMap_empty() { - Ptr_retain(EMPTY); - return EMPTY; + Ptr_retain(EMPTY_ARRAY_MAP); + return EMPTY_ARRAY_MAP; } void PersistentArrayMap_initialise() { - if (EMPTY) + if (EMPTY_ARRAY_MAP) return; - EMPTY = PersistentArrayMap_create(); + EMPTY_ARRAY_MAP = PersistentArrayMap_create(); } void PersistentArrayMap_cleanup() { - if (EMPTY) { - Ptr_release(EMPTY); - EMPTY = NULL; + if (EMPTY_ARRAY_MAP) { + Ptr_release(EMPTY_ARRAY_MAP); + EMPTY_ARRAY_MAP = NULL; } } diff --git a/backend/runtime/PersistentList.c b/backend/runtime/PersistentList.c index 38a1e88..e12481c 100644 --- a/backend/runtime/PersistentList.c +++ b/backend/runtime/PersistentList.c @@ -4,23 +4,23 @@ #include "RTValue.h" #include -static PersistentList *EMPTY = NULL; +PersistentList * volatile EMPTY_LIST = NULL; // How to mark /* mem done */ void PersistentList_initialise() { - if (EMPTY == NULL) - EMPTY = PersistentList_create(RT_boxNull(), NULL); + if (EMPTY_LIST == NULL) + EMPTY_LIST = PersistentList_create(RT_boxNull(), NULL); } PersistentList *PersistentList_empty() { - Ptr_retain(EMPTY); - return EMPTY; + Ptr_retain(EMPTY_LIST); + return EMPTY_LIST; } void PersistentList_cleanup() { - if (EMPTY) { - Ptr_release(EMPTY); - EMPTY = NULL; + if (EMPTY_LIST) { + Ptr_release(EMPTY_LIST); + EMPTY_LIST = NULL; } } diff --git a/backend/runtime/PersistentVector.c b/backend/runtime/PersistentVector.c index 6cae8a8..1441ca3 100644 --- a/backend/runtime/PersistentVector.c +++ b/backend/runtime/PersistentVector.c @@ -9,7 +9,7 @@ #include "Transient.h" #include -PersistentVector *EMPTY_VECTOR = NULL; +PersistentVector * volatile EMPTY_VECTOR = NULL; /* mem done */ PersistentVector *PersistentVector_create() { diff --git a/backend/runtime/Var.c b/backend/runtime/Var.c index 906dc86..75956e9 100644 --- a/backend/runtime/Var.c +++ b/backend/runtime/Var.c @@ -200,7 +200,13 @@ RTValue Var_peek(__attribute__((swift_context)) struct ExecutionContext *ctx, } } } - return atomic_load_explicit(&self->root, memory_order_acquire); + return atomic_load_explicit(&self->root, memory_order_relaxed); +} + +RTValue +Var_peekStatic(__attribute__((swift_context)) struct ExecutionContext *ctx, + Var *self) __attribute__((swiftcall)) { + return atomic_load_explicit(&self->root, memory_order_relaxed); } RTValue Var_set(__attribute__((swift_context)) struct ExecutionContext *ctx, diff --git a/backend/runtime/Var.h b/backend/runtime/Var.h index f7ad726..d75afd4 100644 --- a/backend/runtime/Var.h +++ b/backend/runtime/Var.h @@ -44,11 +44,18 @@ void Var_destroy(Var *self); Var *Var_setDynamic(Var *self, bool dynamic); // modifies and returns self bool Var_isDynamic(Var *self); bool Var_hasRoot(Var *self); -RTValue Var_deref(__attribute__((swift_context)) struct ExecutionContext *ctx, Var *self) __attribute__((swiftcall)); +RTValue Var_deref(__attribute__((swift_context)) struct ExecutionContext *ctx, + Var *self) __attribute__((swiftcall)); /* the returned reference is not retained and is not guaranteed to even be valid after the call returns. */ -RTValue Var_peek(__attribute__((swift_context)) struct ExecutionContext *ctx, Var *self) __attribute__((swiftcall)); -RTValue Var_set(__attribute__((swift_context)) struct ExecutionContext *ctx, Var *self, RTValue value) __attribute__((swiftcall)); +RTValue Var_peek(__attribute__((swift_context)) struct ExecutionContext *ctx, + Var *self) __attribute__((swiftcall)); +RTValue +Var_peekStatic(__attribute__((swift_context)) struct ExecutionContext *ctx, + Var *self) __attribute__((swiftcall)); + +RTValue Var_set(__attribute__((swift_context)) struct ExecutionContext *ctx, + Var *self, RTValue value) __attribute__((swiftcall)); RTValue Var_bindRoot(Var *self, RTValue object); RTValue Var_unbindRoot(Var *self); diff --git a/tests/fib.clj b/tests/fib.clj index 5cc9363..f45ddbb 100644 --- a/tests/fib.clj +++ b/tests/fib.clj @@ -1,3 +1,7 @@ +(in-ns 'clojure.core) +(def list clojure.lang.PersistentList/creator) +(in-ns 'user) + (defn fib [x] (if (= x 1) 1 (if (= x 2) 1 (+ (fib (- x 1)) (fib (- x 2)))))) (fib 42) diff --git a/tests/fibjank.clj b/tests/fibjank.clj new file mode 100644 index 0000000..03ea0ca --- /dev/null +++ b/tests/fibjank.clj @@ -0,0 +1,12 @@ +(in-ns 'clojure.core) +(def list clojure.lang.PersistentList/creator) +(in-ns 'user) + +(defn fibonacci [n] + (if (<= n 1) + n + (+ (fibonacci (- n 1)) + (fibonacci (- n 2))))) + + +(fibonacci 42) \ No newline at end of file