evanphx (owner)

Revisions

gist: 179392 Download_button fork
public
Public Clone URL: git://gist.github.com/179392.git
Embed All Files: show embed
Text #
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
Index: include/llvm/Target/TargetJITInfo.h
===================================================================
--- include/llvm/Target/TargetJITInfo.h (revision 80590)
+++ include/llvm/Target/TargetJITInfo.h (working copy)
@@ -127,6 +127,16 @@
     /// separately allocated heap memory rather than in the same
     /// code memory allocated by JITCodeEmitter.
     virtual bool allocateSeparateGVMemory() const { return false; }
+
+ /// This is used by the JITEmitter to decide whether or not to
+ /// generate a stub for an external function. By default,
+ /// we indicate false so all platforms where the CodeGen
+ /// has advise that stub might be needed have stubs. This
+ /// is the conservative approach.
+ virtual bool fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR) {
+ return false;
+ }
   protected:
     bool useGOT;
   };
Index: unittests/ExecutionEngine/JIT/JITTest.cpp
===================================================================
--- unittests/ExecutionEngine/JIT/JITTest.cpp (revision 80590)
+++ unittests/ExecutionEngine/JIT/JITTest.cpp (working copy)
@@ -24,9 +24,14 @@
 #include "llvm/Support/IRBuilder.h"
 #include "llvm/Target/TargetSelect.h"
 #include "llvm/Type.h"
+#include "llvm/CodeGen/MachineCodeInfo.h"
 
 using namespace llvm;
 
+extern "C" int test_function() {
+ return 47;
+}
+
 namespace {
 
 Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
@@ -44,6 +49,79 @@
   return F;
 }
 
+void stop() {
+ std::cout << "stop now\n";
+}
+
+#ifdef __LP64__
+
+TEST(JIT, NoStubOnConcreteExternal) {
+ LLVMContext context;
+ Module *M = new Module("<main>", context);
+ ExistingModuleProvider *MP = new ExistingModuleProvider(M);
+
+ JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
+ // Tell the memory manager to poison freed memory so that accessing freed
+ // memory is more easily tested.
+ MemMgr->setPoisonMemory(true);
+ std::string Error;
+ OwningPtr<ExecutionEngine> JIT(EngineBuilder(MP)
+ .setEngineKind(EngineKind::JIT)
+ .setErrorStr(&Error)
+ .setJITMemoryManager(MemMgr)
+ .create());
+ ASSERT_EQ(Error, "");
+
+ intptr_t addr = (intptr_t)test_function;
+
+ std::vector<const Type*> params;
+ const FunctionType *ft = FunctionType::get(Type::getInt32Ty(context), params, false);
+ Function *func = cast<Function>(M->getOrInsertFunction("test_function", ft));
+
+ void *ptr = JIT->getPointerToFunction(func);
+
+ // Make sure that we can read it properly.
+ ASSERT_EQ(ptr, (void*)addr);
+
+ // Ok, make a function that calls test_function
+
+ Function *callee = cast<Function>(M->getOrInsertFunction("test_function_callee", ft));
+
+ BasicBlock *Entry = BasicBlock::Create(M->getContext(), "entry", callee);
+ IRBuilder<> builder(Entry);
+ builder.CreateRet(builder.CreateCall(func));
+
+ llvm::MachineCodeInfo mci;
+ JIT->runJITOnFunction(callee, &mci);
+
+ // Ok, this is crazy. But unless i've got a disassembler, there is no
+ // other way to do it.
+
+ uint8_t* buffer = (uint8_t*)mci.address();
+ uint8_t* end = buffer + (mci.size() - sizeof(intptr_t));
+
+ // std::cout << ptr << "\n";
+
+ bool found_in_buffer = false;
+ while(buffer <= end) {
+ if(buffer[0] == 232) { // this might be the call
+ int32_t pc_rel = addr - (((intptr_t)buffer) + 5);
+ int32_t* cur = (int32_t*)(buffer + 1);
+ // std::cout << (void*)buffer << ": " << (*cur) << " vs " << pc_rel << "\n";
+ if(*cur == pc_rel) {
+ found_in_buffer = true;
+ break;
+ }
+ }
+
+ buffer++;
+ }
+
+ ASSERT_EQ(found_in_buffer, true);
+}
+
+#endif
+
 // Regression test for a bug. The JIT used to allocate globals inside the same
 // memory block used for the function, and when the function code was freed,
 // the global was left in the same place. This test allocates a function
Index: lib/Target/X86/X86JITInfo.h
===================================================================
--- lib/Target/X86/X86JITInfo.h (revision 80590)
+++ lib/Target/X86/X86JITInfo.h (working copy)
@@ -78,6 +78,9 @@
     /// PIC jumptable entry.
     void setPICBase(uintptr_t Base) { PICBase = Base; }
     uintptr_t getPICBase() const { return PICBase; }
+
+ virtual bool fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR);
   };
 }
 
Index: lib/Target/X86/X86JITInfo.cpp
===================================================================
--- lib/Target/X86/X86JITInfo.cpp (revision 80590)
+++ lib/Target/X86/X86JITInfo.cpp (working copy)
@@ -560,3 +560,19 @@
   return 0;
 #endif
 }
+
+/// Indicates if, for a pc-relative relocation, code located at Reference
+/// call ResultPtr directly. In other words, does the offset between
+/// these two address fit into a word.
+/// This code is conservative and only supports pc-relative relocations.
+/// All other relocations return false.
+bool X86JITInfo::fitsInCallInstruction(void *Reference, void *ResultPtr,
+ MachineRelocation &MR) {
+ if (MR.getRelocationType() != X86::reloc_pcrel_word) return false;
+ intptr_t difference = (intptr_t)Reference - (intptr_t)ResultPtr;
+
+ // Give the difference some tolerance. The tolerance could be eliminated
+ // so that fewer stubs would have to be used, but that requires more
+ // boundary calculations. If you're reading this, you're welcome to fix it!
+ return difference > -0x1fffffff && difference < 0x1fffffff;
+}
Index: lib/ExecutionEngine/JIT/JITEmitter.cpp
===================================================================
--- lib/ExecutionEngine/JIT/JITEmitter.cpp (revision 80590)
+++ lib/ExecutionEngine/JIT/JITEmitter.cpp (working copy)
@@ -614,9 +614,10 @@
     JITMemoryManager *getMemMgr() const { return MemMgr; }
 
   private:
- void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
+ void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub,
+ MachineRelocation &MR);
     void *getPointerToGVIndirectSym(GlobalValue *V, void *Reference,
- bool NoNeedStub);
+ bool NoNeedStub, MachineRelocation &MR);
     unsigned addSizeOfGlobal(const GlobalVariable *GV, unsigned Size);
     unsigned addSizeOfGlobalsInConstantVal(const Constant *C, unsigned Size);
     unsigned addSizeOfGlobalsInInitializer(const Constant *Init, unsigned Size);
@@ -625,7 +626,7 @@
 }
 
 void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
- bool DoesntNeedStub) {
+ bool DoesntNeedStub, MachineRelocation &MR) {
   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(V))
     return TheJIT->getOrEmitGlobalVariable(GV);
 
@@ -646,12 +647,32 @@
   if (ResultPtr) return ResultPtr;
 
   // If this is an external function pointer, we can force the JIT to
- // 'compile' it, which really just adds it to the map. In dlsym mode,
+ // 'compile' it, which really just adds it to the map. In dlsym mode,
   // external functions are forced through a stub, regardless of reloc type.
   if (F->isDeclaration() && !F->hasNotBeenReadFromBitcode() &&
- DoesntNeedStub && !TheJIT->areDlsymStubsEnabled())
- return TheJIT->getPointerToFunction(F);
+ !TheJIT->areDlsymStubsEnabled()) {
+ ResultPtr = TheJIT->getPointerToFunction(F);
+ if (DoesntNeedStub) {
+ // The CodeGen has indicates that the code model is small enough that
+ // all possible pointer values fit in the call, so we can return
+ // the true address of the callee.
+ return ResultPtr;
+ }
 
+ // Otherwise, the CodeGen is indicating that not all pointers fit. It's
+ // being conservative and indicating that a stub is needed. We verify
+ // this by checking if ResultPtr would in fact fit. If it does, return
+ // it directly. Otherwise, keep going and create a stub and return
+ // the address of the stub (which is assumed to fit).
+ //
+ // FIXME the address of the stub is not asserted to fit though!
+ if (TheJIT->getJITInfo().fitsInCallInstruction(Reference, ResultPtr, MR)) {
+ return ResultPtr;
+ }
+
+ // Otherwise, go ahead and emit a stub.
+ }
+
   // Okay, the function has not been compiled yet, if the target callback
   // mechanism is capable of rewriting the instruction directly, prefer to do
   // that instead of emitting a stub. This uses the lazy resolver, so is not
@@ -673,10 +694,10 @@
 }
 
 void *JITEmitter::getPointerToGVIndirectSym(GlobalValue *V, void *Reference,
- bool NoNeedStub) {
+ bool NoNeedStub, MachineRelocation &MR) {
   // Make sure GV is emitted first, and create a stub containing the fully
   // resolved address.
- void *GVAddress = getPointerToGlobal(V, Reference, true);
+ void *GVAddress = getPointerToGlobal(V, Reference, true, MR);
   void *StubAddr = Resolver.getGlobalValueIndirectSym(V, GVAddress);
   
   // Add the stub to the current function's list of referenced stubs, so we can
@@ -1014,11 +1035,11 @@
         } else if (MR.isGlobalValue()) {
           ResultPtr = getPointerToGlobal(MR.getGlobalValue(),
                                          BufferBegin+MR.getMachineCodeOffset(),
- MR.doesntNeedStub());
+ MR.doesntNeedStub(), MR);
         } else if (MR.isIndirectSymbol()) {
           ResultPtr = getPointerToGVIndirectSym(MR.getGlobalValue(),
                                           BufferBegin+MR.getMachineCodeOffset(),
- MR.doesntNeedStub());
+ MR.doesntNeedStub(), MR);
         } else if (MR.isBasicBlock()) {
           ResultPtr = (void*)getMachineBasicBlockAddress(MR.getBasicBlock());
         } else if (MR.isConstantPoolIndex()) {
Index: autoconf/config.guess
===================================================================
--- autoconf/config.guess (revision 80590)
+++ autoconf/config.guess (working copy)
@@ -1181,6 +1181,15 @@
  *86) UNAME_PROCESSOR=i686 ;;
  unknown) UNAME_PROCESSOR=powerpc ;;
  esac
+ case $UNAME_RELEASE in
+ 10.*)
+ test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -dM -) | grep __LP64__ >/dev/null
+ then
+ echo x86_64-apple-darwin${UNAME_RELEASE}
+ exit 0
+ fi
+ esac
  echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
  exit 0 ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)