Enhance the support for removing global values from the module with JIT lock.

When the machine code was generated the JIT retains a lock to the global values
so they don't go out of sync. In the cases of circular references like:
int g();
int f() {g();}
int g() {f();}
we cannot count on the removal order to get rid of the uses. We need to use the
replaceAllUsesWith. This is however tricky because the JIT already generated the
code for f and g and it doesn't make sense to replace anything with anything else.

Thus in order to support that we need to hack one of the JIT callbacks which
prevents the replace of values of already emitted code.
This commit is contained in:
Vassil Vassilev 2013-10-28 21:00:27 -05:00 committed by sftnight
parent bf03ba5040
commit a08152d576
2 changed files with 44 additions and 9 deletions

View File

@ -451,6 +451,7 @@ namespace cling {
}
void DeclReverter::RemoveDeclFromModule(GlobalDecl& GD) const {
using namespace llvm;
// if it was successfully removed from the AST we have to check whether
// code was generated and remove it.
@ -481,26 +482,46 @@ namespace cling {
std::string mangledName;
utils::Analyze::maybeMangleDeclName(GD, mangledName);
llvm::GlobalValue* GV
GlobalValue* GV
= m_CurTransaction->getModule()->getNamedValue(mangledName);
if (GV) { // May be deferred decl and thus 0
if (GV && !GV->use_empty()) {
GV->removeDeadConstantUsers();
if (!GV->use_empty()) {
// Assert that if there was a use it is not coming from the explicit
// AST node, but from the implicitly generated functions, which ensure
// the initialization order semantics. Such functions are:
// _GLOBAL__I* and __cxx_global_var_init*
//
assert(GV->hasOneUse()
&& "Must have only one use coming from the static inits");
// We can 'afford' to drop all the references because we know that the
// static init functions must be called only once, and that was
// already done.
SmallVector<User*, 4> uses;
for(llvm::Value::use_iterator I = GV->use_begin(), E = GV->use_end();
I != E; ++I) {
uses.push_back(*I);
}
for(SmallVector<User*, 4>::iterator I = uses.begin(), E = uses.end();
I != E; ++I)
if (llvm::Instruction* instr = dyn_cast<llvm::Instruction>(*I)) {
llvm::Function* F = instr->getParent()->getParent();
if (F->getName().startswith("__cxx_global_var_init"))
RemoveStaticInit(*F);
}
//m_EEngine->updateGlobalMapping(GV, 0);
//GV->replaceAllUsesWith(llvm::UndefValue::get(GV->getType()));
llvm::BasicBlock* BB
= cast<llvm::Instruction>(GV->use_back())->getParent();
RemoveStaticInit(*BB->getParent());
}
// Cleanup the jit mapping of GV->addr.
m_EEngine->updateGlobalMapping(GV, 0);
GV->dropAllReferences();
if (!GV->use_empty()) {
if (Function* F = dyn_cast<Function>(GV)) {
Function* dummy = Function::Create(F->getFunctionType(), F->getLinkage());
F->replaceAllUsesWith(dummy);
}
else
GV->replaceAllUsesWith(UndefValue::get(GV->getType()));
}
GV->eraseFromParent();
}

View File

@ -0,0 +1,14 @@
// RUN: cat %s | %cling 2>&1 | FileCheck %s
.storeState "preUnload"
.rawInput 1
int g(); int f(int i) { if (i != 1) return g(); return 0; } int g() { return f(1); } int x = f(0);
.rawInput 0
.U
.compareState "preUnload"
//CHECK-NOT: Differences
float f = 1.1
//CHECK: (float) 1.1
int g = 42
//CHECK: (int) 42
.q