Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")


Expand Down Expand Up @@ -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)
Expand Down
59 changes: 51 additions & 8 deletions backend/bridge/Exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 != "<invalid>")
? llvm::demangle(info.FunctionName)
: demangled;
std::string funcName = info.FunctionName;
if (funcName == "<invalid>" ||
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 "
Expand Down Expand Up @@ -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();
Expand Down
10 changes: 7 additions & 3 deletions backend/codegen/CodeGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ struct RecurTarget {

class CodeGen {
std::unique_ptr<llvm::orc::ThreadSafeContext> TSContext;

llvm::LLVMContext &TheContext;

public:
std::unique_ptr<llvm::Module> TheModule;
llvm::IRBuilder<> Builder;

private:
llvm::IRBuilder<> Builder;
VariableBindings<TypedValue> variableBindingStack;
VariableBindings<ObjectTypeSet> variableTypesBindingsStack;

Expand All @@ -70,7 +72,9 @@ class CodeGen {
DynamicConstructor dynamicConstructor;
MemoryManagement memoryManagement;
std::vector<llvm::Value *> 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;
Expand Down
15 changes: 8 additions & 7 deletions backend/codegen/invoke/InvokeManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class InvokeManager {
ObjectTypeSet createQ(mpq_ptr val);
bool canThrow(const std::string &fname) const;
bool hasSwiftSelf(const std::vector<llvm::Value *> &args);

public:
explicit InvokeManager(llvm::IRBuilder<> &b, llvm::Module &m, ValueEncoder &v,
LLVMTypes &t, ThreadsafeCompilerState &s, CodeGen &cg);
Expand Down Expand Up @@ -126,11 +127,11 @@ class InvokeManager {
const clojure::rt::protobuf::bytecode::Node *node = nullptr,
const std::vector<TypedValue> &extraCleanup = {});


TypedValue generateVarInvoke(
TypedValue varObj, const std::vector<TypedValue> &args,
CleanupChainGuard *guard = nullptr,
const clojure::rt::protobuf::bytecode::Node *node = nullptr);
TypedValue
generateVarInvoke(TypedValue varObj, const std::vector<TypedValue> &args,
CleanupChainGuard *guard = nullptr,
const clojure::rt::protobuf::bytecode::Node *node = nullptr,
bool forceStaticVar = false);

TypedValue generateStaticKeywordInvoke(
TypedValue keyword, const std::vector<TypedValue> &args,
Expand All @@ -153,8 +154,8 @@ class InvokeManager {
const clojure::rt::protobuf::bytecode::Node *node = nullptr,
const std::vector<TypedValue> &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<std::string> &getICSlotNames() const { return icSlotNames; }
};
Expand Down
6 changes: 3 additions & 3 deletions backend/codegen/invoke/InvokeManager_InstanceCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions backend/codegen/invoke/InvokeManager_VarCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace rt {

TypedValue InvokeManager::generateVarInvoke(
TypedValue varObj, const std::vector<TypedValue> &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();

Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions backend/codegen/ops/InvokeNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions backend/codegen/ops/NewNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions backend/codegen/ops/StaticCallNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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) {
Expand Down
30 changes: 29 additions & 1 deletion backend/jit/JITEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,19 @@
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Transforms/IPO/Inliner.h>
#include <llvm/Transforms/IPO/ModuleInliner.h>
#include <llvm/Transforms/Instrumentation/AddressSanitizer.h>
#include <string>

#ifdef __cplusplus
extern "C" {
#endif

__attribute__((weak)) void __asan_version_mismatch_check_v8(void) {}

#ifdef __cplusplus
}
#endif

namespace rt {

JITEngine::Finaliser::~Finaliser() {
Expand Down Expand Up @@ -185,8 +196,13 @@ JITEngine::compileGeneric(std::function<std::string(CodeGen &)> codegenFunc,
compilationPool
.enqueue([this, codegenFunc, moduleName]() -> JITResult {
try {
static std::atomic<uint64_t> 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 {
Expand Down Expand Up @@ -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))));
}
Expand Down Expand Up @@ -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);
}

Expand Down
20 changes: 14 additions & 6 deletions backend/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}")

Expand Down Expand Up @@ -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)
Expand All @@ -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})
Expand All @@ -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)

########################################################################

Expand Down
Loading
Loading