forked from OSchip/llvm-project
Use stubs when we have them, otherwise use code we already have,
otherwise create a stub. Add a test to make sure we don't create extraneous stubs. llvm-svn: 86941
This commit is contained in:
parent
2940303363
commit
cb5e227373
|
@ -736,15 +736,18 @@ void *JITEmitter::getPointerToGlobal(GlobalValue *V, void *Reference,
|
|||
|
||||
// If we have already compiled the function, return a pointer to its body.
|
||||
Function *F = cast<Function>(V);
|
||||
void *ResultPtr;
|
||||
if (MayNeedFarStub) {
|
||||
// Return the function stub if it's already created.
|
||||
ResultPtr = Resolver.getFunctionStubIfAvailable(F);
|
||||
if (ResultPtr)
|
||||
AddStubToCurrentFunction(ResultPtr);
|
||||
} else {
|
||||
ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
|
||||
|
||||
void *FnStub = Resolver.getFunctionStubIfAvailable(F);
|
||||
if (FnStub) {
|
||||
// Return the function stub if it's already created. We do this first
|
||||
// so that we're returning the same address for the function as any
|
||||
// previous call.
|
||||
AddStubToCurrentFunction(FnStub);
|
||||
return FnStub;
|
||||
}
|
||||
|
||||
// Otherwise if we have code, go ahead and return that.
|
||||
void *ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
|
||||
if (ResultPtr) return ResultPtr;
|
||||
|
||||
// If this is an external function pointer, we can force the JIT to
|
||||
|
|
|
@ -61,6 +61,7 @@ class RecordingJITMemoryManager : public JITMemoryManager {
|
|||
public:
|
||||
RecordingJITMemoryManager()
|
||||
: Base(JITMemoryManager::CreateDefaultMemManager()) {
|
||||
stubsAllocated = 0;
|
||||
}
|
||||
|
||||
virtual void setMemoryWritable() { Base->setMemoryWritable(); }
|
||||
|
@ -88,8 +89,10 @@ public:
|
|||
StartFunctionBodyCall(Result, F, InitialActualSize, ActualSize));
|
||||
return Result;
|
||||
}
|
||||
int stubsAllocated;
|
||||
virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
|
||||
unsigned Alignment) {
|
||||
stubsAllocated++;
|
||||
return Base->allocateStub(F, StubSize, Alignment);
|
||||
}
|
||||
struct EndFunctionBodyCall {
|
||||
|
@ -455,6 +458,44 @@ TEST_F(JITTest, ModuleDeletion) {
|
|||
NumTablesDeallocated);
|
||||
}
|
||||
|
||||
typedef int (*FooPtr) ();
|
||||
|
||||
TEST_F(JITTest, NoStubs) {
|
||||
LoadAssembly("define void @bar() {"
|
||||
"entry: "
|
||||
"ret void"
|
||||
"}"
|
||||
" "
|
||||
"define i32 @foo() {"
|
||||
"entry:"
|
||||
"call void @bar()"
|
||||
"ret i32 undef"
|
||||
"}"
|
||||
" "
|
||||
"define i32 @main() {"
|
||||
"entry:"
|
||||
"%0 = call i32 @foo()"
|
||||
"call void @bar()"
|
||||
"ret i32 undef"
|
||||
"}");
|
||||
Function *foo = M->getFunction("foo");
|
||||
uintptr_t tmp = (uintptr_t)(TheJIT->getPointerToFunction(foo));
|
||||
FooPtr ptr = (FooPtr)(tmp);
|
||||
|
||||
(ptr)();
|
||||
|
||||
// We should now allocate no more stubs, we have the code to foo
|
||||
// and the existing stub for bar.
|
||||
int stubsBefore = RJMM->stubsAllocated;
|
||||
Function *func = M->getFunction("main");
|
||||
TheJIT->getPointerToFunction(func);
|
||||
|
||||
Function *bar = M->getFunction("bar");
|
||||
TheJIT->getPointerToFunction(bar);
|
||||
|
||||
ASSERT_EQ(stubsBefore, RJMM->stubsAllocated);
|
||||
}
|
||||
|
||||
// This code is copied from JITEventListenerTest, but it only runs once for all
|
||||
// the tests in this directory. Everything seems fine, but that's strange
|
||||
// behavior.
|
||||
|
|
Loading…
Reference in New Issue