aboutsummaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine/MCJIT/MCJIT.cpp
blob: fee10e1943555cbbc43edcc9702012c361f2afe6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
//===-- MCJIT.cpp - MC-based Just-in-Time Compiler ------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MCJIT.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MutexGuard.h"

using namespace llvm;

namespace {

static struct RegisterJIT {
  RegisterJIT() { MCJIT::Register(); }
} JITRegistrator;

}

extern "C" void LLVMLinkInMCJIT() {
}

ExecutionEngine *MCJIT::createJIT(Module *M,
                                  std::string *ErrorStr,
                                  JITMemoryManager *JMM,
                                  bool GVsWithCode,
                                  TargetMachine *TM) {
  // Try to register the program as a source of symbols to resolve against.
  //
  // FIXME: Don't do this here.
  sys::DynamicLibrary::LoadLibraryPermanently(0, NULL);

  return new MCJIT(M, TM, JMM, GVsWithCode);
}

MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM,
             bool AllocateGVsWithCode)
  : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM),
    isCompiled(false), M(m)  {

  setDataLayout(TM->getDataLayout());
}

MCJIT::~MCJIT() {
  if (LoadedObject)
    NotifyFreeingObject(*LoadedObject.get());
  delete MemMgr;
  delete TM;
}

void MCJIT::emitObject(Module *m) {
  /// Currently, MCJIT only supports a single module and the module passed to
  /// this function call is expected to be the contained module.  The module
  /// is passed as a parameter here to prepare for multiple module support in
  /// the future.
  assert(M == m);

  // Get a thread lock to make sure we aren't trying to compile multiple times
  MutexGuard locked(lock);

  // FIXME: Track compilation state on a per-module basis when multiple modules
  //        are supported.
  // Re-compilation is not supported
  if (isCompiled)
    return;

  PassManager PM;

  PM.add(new DataLayout(*TM->getDataLayout()));

  // The RuntimeDyld will take ownership of this shortly
  OwningPtr<ObjectBufferStream> Buffer(new ObjectBufferStream());

  // Turn the machine code intermediate representation into bytes in memory
  // that may be executed.
  if (TM->addPassesToEmitMC(PM, Ctx, Buffer->getOStream(), false)) {
    report_fatal_error("Target does not support MC emission!");
  }

  // Initialize passes.
  PM.run(*m);
  // Flush the output buffer to get the generated code into memory
  Buffer->flush();

  // Load the object into the dynamic linker.
  // handing off ownership of the buffer
  LoadedObject.reset(Dyld.loadObject(Buffer.take()));
  if (!LoadedObject)
    report_fatal_error(Dyld.getErrorString());

  // Resolve any relocations.
  Dyld.resolveRelocations();

  // FIXME: Make this optional, maybe even move it to a JIT event listener
  LoadedObject->registerWithDebugger();

  NotifyObjectEmitted(*LoadedObject);

  // FIXME: Add support for per-module compilation state
  isCompiled = true;
}

// FIXME: Add a parameter to identify which object is being finalized when
// MCJIT supports multiple modules.
// FIXME: Provide a way to separate code emission, relocations and page 
// protection in the interface.
void MCJIT::finalizeObject() {
  // If the module hasn't been compiled, just do that.
  if (!isCompiled) {
    // If the call to Dyld.resolveRelocations() is removed from emitObject()
    // we'll need to do that here.
    emitObject(M);

    // Set page permissions.
    MemMgr->applyPermissions();

    return;
  }

  // Resolve any relocations.
  Dyld.resolveRelocations();

  // Set page permissions.
  MemMgr->applyPermissions();
}

void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) {
  report_fatal_error("not yet implemented");
}

void *MCJIT::getPointerToFunction(Function *F) {
  // FIXME: This should really return a uint64_t since it's a pointer in the
  // target address space, not our local address space. That's part of the
  // ExecutionEngine interface, though. Fix that when the old JIT finally
  // dies.

  // FIXME: Add support for per-module compilation state
  if (!isCompiled)
    emitObject(M);

  if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
    bool AbortOnFailure = !F->hasExternalWeakLinkage();
    void *Addr = getPointerToNamedFunction(F->getName(), AbortOnFailure);
    addGlobalMapping(F, Addr);
    return Addr;
  }

  // FIXME: Should the Dyld be retaining module information? Probably not.
  // FIXME: Should we be using the mangler for this? Probably.
  //
  // This is the accessor for the target address, so make sure to check the
  // load address of the symbol, not the local address.
  StringRef BaseName = F->getName();
  if (BaseName[0] == '\1')
    return (void*)Dyld.getSymbolLoadAddress(BaseName.substr(1));
  return (void*)Dyld.getSymbolLoadAddress((TM->getMCAsmInfo()->getGlobalPrefix()
                                       + BaseName).str());
}

void *MCJIT::recompileAndRelinkFunction(Function *F) {
  report_fatal_error("not yet implemented");
}

void MCJIT::freeMachineCodeForFunction(Function *F) {
  report_fatal_error("not yet implemented");
}

GenericValue MCJIT::runFunction(Function *F,
                                const std::vector<GenericValue> &ArgValues) {
  assert(F && "Function *F was null at entry to run()");

  void *FPtr = getPointerToFunction(F);
  assert(FPtr && "Pointer to fn's code was null after getPointerToFunction");
  FunctionType *FTy = F->getFunctionType();
  Type *RetTy = FTy->getReturnType();

  assert((FTy->getNumParams() == ArgValues.size() ||
          (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) &&
         "Wrong number of arguments passed into function!");
  assert(FTy->getNumParams() == ArgValues.size() &&
         "This doesn't support passing arguments through varargs (yet)!");

  // Handle some common cases first.  These cases correspond to common `main'
  // prototypes.
  if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) {
    switch (ArgValues.size()) {
    case 3:
      if (FTy->getParamType(0)->isIntegerTy(32) &&
          FTy->getParamType(1)->isPointerTy() &&
          FTy->getParamType(2)->isPointerTy()) {
        int (*PF)(int, char **, const char **) =
          (int(*)(int, char **, const char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(),
                                 (char **)GVTOP(ArgValues[1]),
                                 (const char **)GVTOP(ArgValues[2])));
        return rv;
      }
      break;
    case 2:
      if (FTy->getParamType(0)->isIntegerTy(32) &&
          FTy->getParamType(1)->isPointerTy()) {
        int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr;

        // Call the function.
        GenericValue rv;
        rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(),
                                 (char **)GVTOP(ArgValues[1])));
        return rv;
      }
      break;
    case 1:
      if (FTy->getNumParams() == 1 &&
          FTy->getParamType(0)->isIntegerTy(32)) {
        GenericValue rv;
        int (*PF)(int) = (int(*)(int))(intptr_t)FPtr;
        rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue()));
        return rv;
      }
      break;
    }
  }

  // Handle cases where no arguments are passed first.
  if (ArgValues.empty()) {
    GenericValue rv;
    switch (RetTy->getTypeID()) {
    default: llvm_unreachable("Unknown return type for function call!");
    case Type::IntegerTyID: {
      unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth();
      if (BitWidth == 1)
        rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)());
      else if (BitWidth <= 8)
        rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)());
      else if (BitWidth <= 16)
        rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)());
      else if (BitWidth <= 32)
        rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)());
      else if (BitWidth <= 64)
        rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)());
      else
        llvm_unreachable("Integer types > 64 bits not supported");
      return rv;
    }
    case Type::VoidTyID:
      rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)());
      return rv;
    case Type::FloatTyID:
      rv.FloatVal = ((float(*)())(intptr_t)FPtr)();
      return rv;
    case Type::DoubleTyID:
      rv.DoubleVal = ((double(*)())(intptr_t)FPtr)();
      return rv;
    case Type::X86_FP80TyID:
    case Type::FP128TyID:
    case Type::PPC_FP128TyID:
      llvm_unreachable("long double not supported yet");
    case Type::PointerTyID:
      return PTOGV(((void*(*)())(intptr_t)FPtr)());
    }
  }

  llvm_unreachable("Full-featured argument passing not supported yet!");
}

void *MCJIT::getPointerToNamedFunction(const std::string &Name,
                                       bool AbortOnFailure) {
  // FIXME: Add support for per-module compilation state
  if (!isCompiled)
    emitObject(M);

  if (!isSymbolSearchingDisabled() && MemMgr) {
    void *ptr = MemMgr->getPointerToNamedFunction(Name, false);
    if (ptr)
      return ptr;
  }

  /// If a LazyFunctionCreator is installed, use it to get/create the function.
  if (LazyFunctionCreator)
    if (void *RP = LazyFunctionCreator(Name))
      return RP;

  if (AbortOnFailure) {
    report_fatal_error("Program used external function '"+Name+
                       "' which could not be resolved!");
  }
  return 0;
}

void MCJIT::RegisterJITEventListener(JITEventListener *L) {
  if (L == NULL)
    return;
  MutexGuard locked(lock);
  EventListeners.push_back(L);
}
void MCJIT::UnregisterJITEventListener(JITEventListener *L) {
  if (L == NULL)
    return;
  MutexGuard locked(lock);
  SmallVector<JITEventListener*, 2>::reverse_iterator I=
      std::find(EventListeners.rbegin(), EventListeners.rend(), L);
  if (I != EventListeners.rend()) {
    std::swap(*I, EventListeners.back());
    EventListeners.pop_back();
  }
}
void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) {
  MutexGuard locked(lock);
  for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
    EventListeners[I]->NotifyObjectEmitted(Obj);
  }
}
void MCJIT::NotifyFreeingObject(const ObjectImage& Obj) {
  MutexGuard locked(lock);
  for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {
    EventListeners[I]->NotifyFreeingObject(Obj);
  }
}