summaryrefslogtreecommitdiffstats
path: root/runtime/quick
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-03-21 11:31:51 +0100
committerSebastien Hertz <shertz@google.com>2014-03-21 14:28:09 +0100
commit2c87c4d999bccdff6cc60bf6af4871cca6e2c893 (patch)
tree73e2ed92aac81661708d4c8cfce3d026e7e9614c /runtime/quick
parent0d9c02e661813abdf18b4e7544e204d2da719d20 (diff)
downloadart-2c87c4d999bccdff6cc60bf6af4871cca6e2c893.tar.gz
art-2c87c4d999bccdff6cc60bf6af4871cca6e2c893.tar.bz2
art-2c87c4d999bccdff6cc60bf6af4871cca6e2c893.zip
Support inlining detection from debugger.
In the context of the compiler, every method and field should be resolved. The InlineMethodAnalyser uses that property so we don't inline unresolved methods or methods accessing unresolved fields. In the context of the debugger, this is not true. We may install a breakpoint in a method that's never been resolved yet for instance. This CL weaks that property so we can detect getter/setter methods can be inlined even if they're not resolved yet. To differentiate both contexts, we pass a null inline method pointer to InlineMethodAnalyser::AnalyseIGetMethod. Bug: 12187616 Change-Id: I247f315b9abd6b065d5a7ec4116de15a6cce7649
Diffstat (limited to 'runtime/quick')
-rw-r--r--runtime/quick/inline_method_analyser.cc87
1 files changed, 51 insertions, 36 deletions
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index 4388d31698..a9072d814c 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -80,8 +80,15 @@ COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) ==
COMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) ==
InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), check_iget_iput_short_variant);
+// This is used by compiler and debugger. We look into the dex cache for resolved methods and
+// fields. However, in the context of the debugger, not all methods and fields are resolved. Since
+// we need to be able to detect possibly inlined method, we pass a null inline method to indicate
+// we don't want to take unresolved methods and fields into account during analysis.
bool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier,
InlineMethod* method) {
+ DCHECK(verifier != nullptr);
+ DCHECK_EQ(Runtime::Current()->IsCompiler(), method != nullptr);
+ DCHECK_EQ(verifier->CanLoadClasses(), method != nullptr);
// We currently support only plain return or 2-instruction methods.
const DexFile::CodeItem* code_item = verifier->CodeItem();
@@ -91,9 +98,11 @@ bool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier,
switch (opcode) {
case Instruction::RETURN_VOID:
- method->opcode = kInlineOpNop;
- method->flags = kInlineSpecial;
- method->d.data = 0u;
+ if (method != nullptr) {
+ method->opcode = kInlineOpNop;
+ method->flags = kInlineSpecial;
+ method->d.data = 0u;
+ }
return true;
case Instruction::RETURN:
case Instruction::RETURN_OBJECT:
@@ -136,14 +145,16 @@ bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_ite
DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg,
code_item->registers_size_);
- result->opcode = kInlineOpReturnArg;
- result->flags = kInlineSpecial;
- InlineReturnArgData* data = &result->d.return_data;
- data->arg = reg - arg_start;
- data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u;
- data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
- data->reserved = 0u;
- data->reserved2 = 0u;
+ if (result != nullptr) {
+ result->opcode = kInlineOpReturnArg;
+ result->flags = kInlineSpecial;
+ InlineReturnArgData* data = &result->d.return_data;
+ data->arg = reg - arg_start;
+ data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u;
+ data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
+ data->reserved = 0u;
+ data->reserved2 = 0u;
+ }
return true;
}
@@ -173,9 +184,11 @@ bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item
if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
return false; // Returning non-null reference constant?
}
- result->opcode = kInlineOpNonWideConst;
- result->flags = kInlineSpecial;
- result->d.data = static_cast<uint64_t>(vB);
+ if (result != nullptr) {
+ result->opcode = kInlineOpNonWideConst;
+ result->flags = kInlineSpecial;
+ result->d.data = static_cast<uint64_t>(vB);
+ }
return true;
}
@@ -215,18 +228,19 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
return false;
}
- if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, &result->d.ifield_data)) {
- return false;
+ if (result != nullptr) {
+ InlineIGetIPutData* data = &result->d.ifield_data;
+ if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, data)) {
+ return false;
+ }
+ result->opcode = kInlineOpIGet;
+ result->flags = kInlineSpecial;
+ data->op_variant = IGetVariant(opcode);
+ data->object_arg = object_reg - arg_start; // Allow IGET on any register, not just "this".
+ data->src_arg = 0;
+ data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
+ data->reserved = 0;
}
-
- result->opcode = kInlineOpIGet;
- result->flags = kInlineSpecial;
- InlineIGetIPutData* data = &result->d.ifield_data;
- data->op_variant = IGetVariant(opcode);
- data->object_arg = object_reg - arg_start; // Allow IGET on any register, not just "this".
- data->src_arg = 0;
- data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
- data->reserved = 0;
return true;
}
@@ -262,18 +276,19 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
return false;
}
- if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, &result->d.ifield_data)) {
- return false;
+ if (result != nullptr) {
+ InlineIGetIPutData* data = &result->d.ifield_data;
+ if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, data)) {
+ return false;
+ }
+ result->opcode = kInlineOpIPut;
+ result->flags = kInlineSpecial;
+ data->op_variant = IPutVariant(opcode);
+ data->object_arg = object_reg - arg_start; // Allow IPUT on any register, not just "this".
+ data->src_arg = src_reg - arg_start;
+ data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
+ data->reserved = 0;
}
-
- result->opcode = kInlineOpIPut;
- result->flags = kInlineSpecial;
- InlineIGetIPutData* data = &result->d.ifield_data;
- data->op_variant = IPutVariant(opcode);
- data->object_arg = object_reg - arg_start; // Allow IPUT on any register, not just "this".
- data->src_arg = src_reg - arg_start;
- data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
- data->reserved = 0;
return true;
}