brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 6962c69 Raw
277 lines · c
1//=== OrcV2CBindingsMemoryManager.c - OrcV2 Memory Manager C Bindings Demo ===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This demo illustrates the C-API bindings for custom memory managers in10// ORCv2. They are used here to place generated code into manually allocated11// buffers that are subsequently marked as executable.12//13//===----------------------------------------------------------------------===//14 15#include "llvm-c/Core.h"16#include "llvm-c/Error.h"17#include "llvm-c/LLJIT.h"18#include "llvm-c/OrcEE.h"19#include "llvm-c/Support.h"20#include "llvm-c/Target.h"21 22#include <assert.h>23#include <stdio.h>24#include <stdlib.h>25 26#if defined(_WIN32)27#include <windows.h>28#else29#include <dlfcn.h>30#include <sys/mman.h>31#endif32 33struct Section {34  void *Ptr;35  size_t Size;36  LLVMBool IsCode;37};38 39char CtxCtxPlaceholder;40char CtxPlaceholder;41 42#define MaxSections 1643static size_t SectionCount = 0;44static struct Section Sections[MaxSections];45 46void *addSection(size_t Size, LLVMBool IsCode) {47  if (SectionCount >= MaxSections) {48    fprintf(stderr, "addSection(): Too many sections!\n");49    abort();50  }51 52#if defined(_WIN32)53  void *Ptr =54      VirtualAlloc(NULL, Size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);55  if (!Ptr) {56    fprintf(stderr, "addSection(): Memory allocation failed!\n");57    abort();58  }59#else60  void *Ptr = mmap(NULL, Size, PROT_READ | PROT_WRITE,61                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);62  if (Ptr == MAP_FAILED) {63    fprintf(stderr, "addSection(): Memory allocation failed!\n");64    abort();65  }66#endif67 68  Sections[SectionCount].Ptr = Ptr;69  Sections[SectionCount].Size = Size;70  Sections[SectionCount].IsCode = IsCode;71  SectionCount++;72  return Ptr;73}74 75// Callbacks to create the context for the subsequent functions (not used in76// this example)77void *memCreateContext(void *CtxCtx) {78  assert(CtxCtx == &CtxCtxPlaceholder && "Unexpected CtxCtx value");79  return &CtxPlaceholder;80}81 82void memNotifyTerminating(void *CtxCtx) {83  assert(CtxCtx == &CtxCtxPlaceholder && "Unexpected CtxCtx value");84}85 86uint8_t *memAllocate(void *Opaque, uintptr_t Size, unsigned Align, unsigned Id,87                     const char *Name) {88  printf("Allocated code section \"%s\"\n", Name);89  return addSection(Size, 1);90}91 92uint8_t *memAllocateData(void *Opaque, uintptr_t Size, unsigned Align,93                         unsigned Id, const char *Name, LLVMBool ReadOnly) {94  printf("Allocated data section \"%s\"\n", Name);95  return addSection(Size, 0);96}97 98LLVMBool memFinalize(void *Opaque, char **Err) {99  printf("Marking code sections as executable ..\n");100  for (size_t i = 0; i < SectionCount; ++i) {101    if (Sections[i].IsCode) {102      LLVMBool fail;103#if defined(_WIN32)104      DWORD unused;105      fail = VirtualProtect(Sections[i].Ptr, Sections[i].Size,106                            PAGE_EXECUTE_READ, &unused) == 0;107#else108      fail = mprotect(Sections[i].Ptr, Sections[i].Size,109                      PROT_READ | PROT_EXEC) == -1;110#endif111      if (fail) {112        fprintf(stderr, "Could not mark code section as executable!\n");113        abort();114      }115    }116  }117  return 0;118}119 120void memDestroy(void *Opaque) {121  assert(Opaque == &CtxPlaceholder && "Unexpected Ctx value");122  printf("Releasing section memory ..\n");123  for (size_t i = 0; i < SectionCount; ++i) {124    LLVMBool fail;125#if defined(_WIN32)126    fail = VirtualFree(Sections[i].Ptr, 0, MEM_RELEASE) == 0;127#else128    fail = munmap(Sections[i].Ptr, Sections[i].Size) == -1;129#endif130    if (fail) {131      fprintf(stderr, "Could not release memory for section!");132      abort();133    }134  }135}136 137LLVMOrcObjectLayerRef objectLinkingLayerCreator(void *Opaque,138                                                LLVMOrcExecutionSessionRef ES,139                                                const char *Triple) {140  return LLVMOrcCreateRTDyldObjectLinkingLayerWithMCJITMemoryManagerLikeCallbacks(141      ES, &CtxCtxPlaceholder, memCreateContext, memNotifyTerminating,142      memAllocate, memAllocateData, memFinalize, memDestroy);143}144 145int handleError(LLVMErrorRef Err) {146  char *ErrMsg = LLVMGetErrorMessage(Err);147  fprintf(stderr, "Error: %s\n", ErrMsg);148  LLVMDisposeErrorMessage(ErrMsg);149  return 1;150}151 152LLVMOrcThreadSafeModuleRef createDemoModule(void) {153  // Create an LLVMContext.154  LLVMContextRef Ctx = LLVMContextCreate();155 156  // Create a new LLVM module.157  LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx);158 159  // Add a "sum" function":160  //  - Create the function type and function instance.161  LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()};162  LLVMTypeRef SumFunctionType =163      LLVMFunctionType(LLVMInt32Type(), ParamTypes, 2, 0);164  LLVMValueRef SumFunction = LLVMAddFunction(M, "sum", SumFunctionType);165 166  //  - Add a basic block to the function.167  LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(SumFunction, "entry");168 169  //  - Add an IR builder and point it at the end of the basic block.170  LLVMBuilderRef Builder = LLVMCreateBuilder();171  LLVMPositionBuilderAtEnd(Builder, EntryBB);172 173  //  - Get the two function arguments and use them co construct an "add"174  //    instruction.175  LLVMValueRef SumArg0 = LLVMGetParam(SumFunction, 0);176  LLVMValueRef SumArg1 = LLVMGetParam(SumFunction, 1);177  LLVMValueRef Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, "result");178 179  //  - Build the return instruction.180  LLVMBuildRet(Builder, Result);181 182  // Create a new ThreadSafeContext to hold the context.183  LLVMOrcThreadSafeContextRef TSCtx =184      LLVMOrcCreateNewThreadSafeContextFromLLVMContext(Ctx);185 186  // Our demo module is now complete. Wrap it and our ThreadSafeContext in a187  // ThreadSafeModule.188  LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);189 190  // Dispose of our local ThreadSafeContext value. The underlying LLVMContext191  // will be kept alive by our ThreadSafeModule, TSM.192  LLVMOrcDisposeThreadSafeContext(TSCtx);193 194  // Return the result.195  return TSM;196}197 198int main(int argc, const char *argv[]) {199 200  int MainResult = 0;201 202  // Parse command line arguments and initialize LLVM Core.203  LLVMParseCommandLineOptions(argc, argv, "");204 205  // Initialize native target codegen and asm printer.206  LLVMInitializeNativeTarget();207  LLVMInitializeNativeAsmPrinter();208 209  // Create the JIT instance.210  LLVMOrcLLJITRef J;211  {212    LLVMErrorRef Err;213 214    LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();215    LLVMOrcLLJITBuilderSetObjectLinkingLayerCreator(216        Builder, objectLinkingLayerCreator, NULL);217 218    if ((Err = LLVMOrcCreateLLJIT(&J, Builder))) {219      MainResult = handleError(Err);220      goto llvm_shutdown;221    }222  }223 224  // Create our demo module.225  LLVMOrcThreadSafeModuleRef TSM = createDemoModule();226 227  // Add our demo module to the JIT.228  {229    LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);230    LLVMErrorRef Err;231    if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM))) {232      // If adding the ThreadSafeModule fails then we need to clean it up233      // ourselves. If adding it succeeds the JIT will manage the memory.234      LLVMOrcDisposeThreadSafeModule(TSM);235      MainResult = handleError(Err);236      goto jit_cleanup;237    }238  }239 240  // Look up the address of our demo entry point.241  LLVMOrcJITTargetAddress SumAddr;242  {243    LLVMErrorRef Err;244    if ((Err = LLVMOrcLLJITLookup(J, &SumAddr, "sum"))) {245      MainResult = handleError(Err);246      goto jit_cleanup;247    }248  }249 250  // If we made it here then everything succeeded. Execute our JIT'd code.251  int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr;252  int32_t Result = Sum(1, 2);253 254  // Print the result.255  printf("1 + 2 = %i\n", Result);256 257jit_cleanup:258  // Destroy our JIT instance. This will clean up any memory that the JIT has259  // taken ownership of. This operation is non-trivial (e.g. it may need to260  // JIT static destructors) and may also fail. In that case we want to render261  // the error to stderr, but not overwrite any existing return value.262  {263    LLVMErrorRef Err;264    if ((Err = LLVMOrcDisposeLLJIT(J))) {265      int NewFailureResult = handleError(Err);266      if (MainResult == 0)267        MainResult = NewFailureResult;268    }269  }270 271llvm_shutdown:272  // Shut down LLVM.273  LLVMShutdown();274 275  return MainResult;276}277