summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/quick/inline_method_analyser.cc56
-rw-r--r--runtime/quick/inline_method_analyser.h4
2 files changed, 42 insertions, 18 deletions
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index a9072d814c..0a1b72e6b4 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -218,16 +218,24 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
DCHECK_GE(object_reg, arg_start);
DCHECK_LT(object_reg, code_item->registers_size_);
+ uint32_t object_arg = object_reg - arg_start;
+
DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_);
if (dst_reg != return_reg) {
return false; // Not returning the value retrieved by IGET?
}
- if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+ if ((verifier->GetAccessFlags() & kAccStatic) != 0u || object_arg != 0u) {
// TODO: Support inlining IGET on other register than "this".
return false;
}
+ // InlineIGetIPutData::object_arg is only 4 bits wide.
+ static constexpr uint16_t kMaxObjectArg = 15u;
+ if (object_arg > kMaxObjectArg) {
+ return false;
+ }
+
if (result != nullptr) {
InlineIGetIPutData* data = &result->d.ifield_data;
if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, data)) {
@@ -236,10 +244,10 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
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->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0 ? 1u : 0u;
+ data->object_arg = object_arg; // Allow IGET on any register, not just "this".
data->src_arg = 0;
- data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
- data->reserved = 0;
+ data->return_arg_plus1 = 0u;
}
return true;
}
@@ -253,29 +261,45 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
+ uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t return_arg_plus1 = 0u;
if (return_opcode != Instruction::RETURN_VOID) {
- // TODO: Support returning an argument.
- // This is needed by builder classes and generated accessor setters.
- // builder.setX(value): iput value, this, fieldX; return-object this;
- // object.access$nnn(value): iput value, this, fieldX; return value;
- // Use InlineIGetIPutData::reserved to hold the information.
- return false;
+ if (return_opcode != Instruction::RETURN &&
+ return_opcode != Instruction::RETURN_OBJECT &&
+ return_opcode != Instruction::RETURN_WIDE) {
+ return false;
+ }
+ // Returning an argument.
+ uint32_t return_reg = return_instruction->VRegA_11x();
+ DCHECK_GE(return_reg, arg_start);
+ DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg,
+ code_item->registers_size_);
+ return_arg_plus1 = return_reg - arg_start + 1u;
}
uint32_t src_reg = instruction->VRegA_22c();
uint32_t object_reg = instruction->VRegB_22c();
uint32_t field_idx = instruction->VRegC_22c();
- uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
DCHECK_GE(object_reg, arg_start);
DCHECK_LT(object_reg, code_item->registers_size_);
DCHECK_GE(src_reg, arg_start);
DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_);
+ uint32_t object_arg = object_reg - arg_start;
+ uint32_t src_arg = src_reg - arg_start;
- if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+ if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_arg != 0) {
// TODO: Support inlining IPUT on other register than "this".
return false;
}
+ // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide.
+ static constexpr uint16_t kMaxObjectArg = 15u;
+ static constexpr uint16_t kMaxSrcArg = 15u;
+ static constexpr uint16_t kMaxReturnArgPlus1 = 15u;
+ if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) {
+ return false;
+ }
+
if (result != nullptr) {
InlineIGetIPutData* data = &result->d.ifield_data;
if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, data)) {
@@ -284,10 +308,10 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
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;
+ data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0 ? 1u : 0u;
+ data->object_arg = object_arg; // Allow IPUT on any register, not just "this".
+ data->src_arg = src_arg;
+ data->return_arg_plus1 = return_arg_plus1;
}
return true;
}
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index 8e1a4083cd..277a01e502 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -98,10 +98,10 @@ struct InlineIGetIPutData {
// opcode-Instruction::IPUT for IPUTs. This is because the runtime
// doesn't know the OpSize enumeration.
uint16_t op_variant : 3;
+ uint16_t method_is_static : 1;
uint16_t object_arg : 4;
uint16_t src_arg : 4; // iput only
- uint16_t method_is_static : 1;
- uint16_t reserved : 4;
+ uint16_t return_arg_plus1 : 4; // iput only, method argument to return + 1, 0 = return void.
uint16_t field_idx;
uint32_t is_volatile : 1;
uint32_t field_offset : 31;