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:
Eric Christopher 2009-11-12 03:12:18 +00:00
parent 2940303363
commit cb5e227373
2 changed files with 109 additions and 65 deletions

View File

@ -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

View File

@ -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.