diff options
| author | 2015-04-24 16:43:49 +0100 | |
|---|---|---|
| committer | 2015-04-24 16:43:49 +0100 | |
| commit | 4c0eb42259d790fddcd9978b66328dbb3ab65615 (patch) | |
| tree | 9d1ac505dfd4d0225f479d860b72a58747c8f6ce /compiler/optimizing/graph_checker.cc | |
| parent | 223f2f5b2a20ca8246da1523494900a2424d5956 (diff) | |
Ensure inlined static calls perform clinit checks in Optimizing.
Calls to static methods have implicit class initialization
(clinit) checks of the method's declaring class in
Optimizing. However, when such a static call is inlined,
the implicit clinit check vanishes, possibly leading to an
incorrect behavior.
To ensure that inlining static methods does not change the
behavior of a program, add explicit class initialization
checks (art::HClinitCheck) as well as load class
instructions (art::HLoadClass) as last input of static
calls (art::HInvokeStaticOrDirect) in Optimizing' control
flow graphs, when the declaring class is reachable and not
known to be already initialized. Then when considering the
inlining of a static method call, proceed only if the method
has no implicit clinit check requirement.
The added explicit clinit checks are already removed by the
art::PrepareForRegisterAllocation visitor. This CL also
extends this visitor to turn explicit clinit checks from
static invokes into implicit ones after the inlining step,
by removing the added art::HLoadClass nodes mentioned
hereinbefore.
Change-Id: I9ba452b8bd09ae1fdd9a3797ef556e3e7e19c651
Diffstat (limited to 'compiler/optimizing/graph_checker.cc')
| -rw-r--r-- | compiler/optimizing/graph_checker.cc | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc index 2216cecc2b..7c3c379795 100644 --- a/compiler/optimizing/graph_checker.cc +++ b/compiler/optimizing/graph_checker.cc @@ -178,6 +178,30 @@ void GraphChecker::VisitInstruction(HInstruction* instruction) { } } +void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { + VisitInstruction(invoke); + + if (invoke->IsStaticWithExplicitClinitCheck()) { + size_t last_input_index = invoke->InputCount() - 1; + HInstruction* last_input = invoke->InputAt(last_input_index); + if (last_input == nullptr) { + AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check " + "has a null pointer as last input.", + invoke->DebugName(), + invoke->GetId())); + } + if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) { + AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check " + "has a last instruction (%s:%d) which is neither a clinit check " + "nor a load class instruction.", + invoke->DebugName(), + invoke->GetId(), + last_input->DebugName(), + last_input->GetId())); + } + } +} + void SSAChecker::VisitBasicBlock(HBasicBlock* block) { super_type::VisitBasicBlock(block); @@ -459,7 +483,7 @@ void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { Primitive::PrettyDescriptor(op->InputAt(1)->GetType()))); } } else { - if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) { + if (PrimitiveKind(op->InputAt(0)->GetType()) != PrimitiveKind(op->InputAt(1)->GetType())) { AddError(StringPrintf( "Binary operation %s %d has inputs of different types: " "%s, and %s.", @@ -484,7 +508,7 @@ void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { "from its input type: %s vs %s.", op->DebugName(), op->GetId(), Primitive::PrettyDescriptor(op->GetType()), - Primitive::PrettyDescriptor(op->InputAt(1)->GetType()))); + Primitive::PrettyDescriptor(op->InputAt(0)->GetType()))); } } } |