Right now the functions createNewCall, createFreeCall in src\codegen\llvm\LLVMIRBuilder.cpp has hard coded references to malloc, free, abort and exit. This can be made more flexible by utilizing the linker support for weak symbols.
I replaced malloc with OberonRuntime_Allocate:
Value *
LLVMIRBuilder::createNewCall(TypeNode *type, llvm::Value *param) {
auto fun = module_->getFunction("OberonRuntime_Allocate");
if (!fun) {
auto funTy = FunctionType::get(builder_.getPtrTy(), { builder_.getInt64Ty() }, false);
fun = Function::Create(funTy, GlobalValue::ExternalLinkage, "OberonRuntime_Allocate", module_);
fun->addFnAttr(Attribute::getWithAllocSizeArgs(builder_.getContext(), 0, {}));
fun->addParamAttr(0, Attribute::NoUndef);
}
...
and free with OberonRuntime_Deallocate:
Value *
LLVMIRBuilder::createFreeCall([[maybe_unused]] TypeNode *type, Value *param) {
auto fun = module_->getFunction("OberonRuntime_Deallocate");
#ifdef _LLVM_LEGACY
auto voidTy = PointerType::get(builder_.getVoidTy(), 0);
#else
auto voidTy = builder_.getPtrTy();
#endif
if (!fun) {
auto funTy = FunctionType::get(builder_.getVoidTy(), {voidTy}, false);
fun = Function::Create(funTy, GlobalValue::ExternalLinkage, "OberonRuntime_Deallocate", module_);
fun->addParamAttr(0, Attribute::NoUndef);
}
...
Then creates a default implementation OberonRuntimeDefault.c:
#include <stdlib.h>
#include <stdio.h>
__attribute__((weak)) void *OberonRuntime_Allocate( size_t size ) {
printf("OberonRuntimeDefault.Allocate\n");
return malloc(size);
}
__attribute__((weak)) void OberonRuntime_Deallocate( void *ptr ) {
printf("OberonRuntimeDefault.Deallocate\n");
free(ptr);
}
Functions here are decorated with the weak attribute.
This is then just compiled to a static library and works as expected when linked.
This can then exploited to replace the functionality with for example a Garbage Collector (Boehm):
#include <stdlib.h>
#include <stdio.h>
#include <gc.h>
void *OberonRuntime_Allocate( size_t size ) {
printf("OberonRuntimeGC.Allocate\n");
return GC_malloc(size);
}
void OberonRuntime_Deallocate( void *ptr ) {
printf("OberonRuntimeGC.Deallocate\n");
// Skip
}
By linking this as a static library, these definitions take precedence over the weak version.
(This could also be done with an Oberon module.)
In order for this to work as expected with the JIT implementation, default functions need to be injected.
Perhaps default functions can just be defined in the main module.
Also this can be expanded to cover putchar etc., so that the Out module can be redirected.
Right now the functions
createNewCall,createFreeCallinsrc\codegen\llvm\LLVMIRBuilder.cpphas hard coded references tomalloc,free,abortandexit. This can be made more flexible by utilizing the linker support for weak symbols.I replaced
mallocwithOberonRuntime_Allocate:and
freewithOberonRuntime_Deallocate:Then creates a default implementation OberonRuntimeDefault.c:
Functions here are decorated with the weak attribute.
This is then just compiled to a static library and works as expected when linked.
This can then exploited to replace the functionality with for example a Garbage Collector (Boehm):
By linking this as a static library, these definitions take precedence over the weak version.
(This could also be done with an Oberon module.)
In order for this to work as expected with the JIT implementation, default functions need to be injected.
Perhaps default functions can just be defined in the
mainmodule.Also this can be expanded to cover
putcharetc., so that theOutmodule can be redirected.