summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Marko <vmarko@google.com>2014-02-07 14:52:18 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-02-07 14:52:18 +0000
commit92ef04ca2309971b8d013f63c85925209f075a3a (patch)
treeef722d79fb041864aca76a0243271c6edc7a9bd6
parenta52214230ad091359956ed7566670963aedf2045 (diff)
parent5dc5727261e87ba8a418e2d0e970c75f67e4ab79 (diff)
downloadart-92ef04ca2309971b8d013f63c85925209f075a3a.zip
art-92ef04ca2309971b8d013f63c85925209f075a3a.tar.gz
art-92ef04ca2309971b8d013f63c85925209f075a3a.tar.bz2
Merge "Check FastInstance() early for special getters and setters."
-rw-r--r--compiler/dex/quick/arm/call_arm.cc71
-rw-r--r--compiler/dex/quick/arm/codegen_arm.h4
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.cc224
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.h82
-rw-r--r--compiler/driver/compiler_driver.cc26
-rw-r--r--compiler/driver/compiler_driver.h12
-rw-r--r--dex2oat/dex2oat.cc2
-rw-r--r--runtime/common_test.h2
8 files changed, 250 insertions, 173 deletions
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 661050f..22466f0 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -127,15 +127,19 @@ void ArmMir2Lir::GenPrintLabel(MIR* mir) {
}
}
-MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir,
- OpSize size, bool long_or_double, bool is_object) {
- int32_t field_offset;
- bool is_volatile;
- uint32_t field_idx = mir->dalvikInsn.vC;
- bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile);
- if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) {
- return NULL;
+MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
+ // FastInstance() already checked by DexFileMethodInliner.
+ const InlineIGetIPutData& data = special.d.ifield_data;
+ if (!data.method_is_static || data.object_arg != 0) {
+ return NULL; // The object is not "this" and has to be null-checked.
}
+
+ OpSize size = static_cast<OpSize>(data.op_size);
+ DCHECK_NE(data.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
+ bool long_or_double = (data.op_size == kLong);
+ bool is_object = data.is_object;
+
+ // TODO: Generate the method using only the data in special.
RegLocation rl_obj = mir_graph_->GetSrc(mir, 0);
LockLiveArgs(mir);
rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
@@ -148,19 +152,24 @@ MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir,
// Point of no return - no aborts after this
ArmMir2Lir::GenPrintLabel(mir);
rl_obj = LoadArg(rl_obj);
+ uint32_t field_idx = mir->dalvikInsn.vC;
GenIGet(field_idx, mir->optimization_flags, size, rl_dest, rl_obj, long_or_double, is_object);
return GetNextMir(bb, mir);
}
-MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir,
- OpSize size, bool long_or_double, bool is_object) {
- int32_t field_offset;
- bool is_volatile;
- uint32_t field_idx = mir->dalvikInsn.vC;
- bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile);
- if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) {
- return NULL;
+MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
+ // FastInstance() already checked by DexFileMethodInliner.
+ const InlineIGetIPutData& data = special.d.ifield_data;
+ if (!data.method_is_static || data.object_arg != 0) {
+ return NULL; // The object is not "this" and has to be null-checked.
}
+
+ OpSize size = static_cast<OpSize>(data.op_size);
+ DCHECK_NE(data.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
+ bool long_or_double = (data.op_size == kLong);
+ bool is_object = data.is_object;
+
+ // TODO: Generate the method using only the data in special.
RegLocation rl_src;
RegLocation rl_obj;
LockLiveArgs(mir);
@@ -174,7 +183,7 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir,
rl_src = ArmMir2Lir::ArgLoc(rl_src);
rl_obj = ArmMir2Lir::ArgLoc(rl_obj);
// Reject if source is split across registers & frame
- if (rl_obj.location == kLocInvalid) {
+ if (rl_src.location == kLocInvalid) {
ResetRegPool();
return NULL;
}
@@ -182,6 +191,7 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir,
ArmMir2Lir::GenPrintLabel(mir);
rl_obj = LoadArg(rl_obj);
rl_src = LoadArg(rl_src);
+ uint32_t field_idx = mir->dalvikInsn.vC;
GenIPut(field_idx, mir->optimization_flags, size, rl_src, rl_obj, long_or_double, is_object);
return GetNextMir(bb, mir);
}
@@ -219,8 +229,6 @@ MIR* ArmMir2Lir::SpecialIdentity(MIR* mir) {
*/
void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
const InlineMethod& special) {
- // TODO: Generate the method using only the data in special. (Requires FastInstance() field
- // validation in DexFileMethodInliner::AnalyseIGetMethod()/AnalyseIPutMethod().)
DCHECK(special.flags & kInlineSpecial);
current_dalvik_offset_ = mir->offset;
MIR* next_mir = NULL;
@@ -231,30 +239,17 @@ void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
break;
case kInlineOpConst:
ArmMir2Lir::GenPrintLabel(mir);
- LoadConstant(rARM_RET0, special.data);
+ LoadConstant(rARM_RET0, static_cast<int>(special.d.data));
next_mir = GetNextMir(&bb, mir);
break;
- case kInlineOpIGet: {
- InlineIGetIPutData data;
- data.data = special.data;
- OpSize op_size = static_cast<OpSize>(data.d.op_size);
- DCHECK_NE(data.d.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
- bool long_or_double = (data.d.op_size == kLong);
- bool is_object = data.d.is_object;
- next_mir = SpecialIGet(&bb, mir, op_size, long_or_double, is_object);
+ case kInlineOpIGet:
+ next_mir = SpecialIGet(&bb, mir, special);
break;
- }
- case kInlineOpIPut: {
- InlineIGetIPutData data;
- data.data = special.data;
- OpSize op_size = static_cast<OpSize>(data.d.op_size);
- DCHECK_NE(data.d.op_size, kDouble); // The inliner doesn't distinguish kDouble, uses kLong.
- bool long_or_double = (data.d.op_size == kLong);
- bool is_object = data.d.is_object;
- next_mir = SpecialIPut(&bb, mir, op_size, long_or_double, is_object);
+ case kInlineOpIPut:
+ next_mir = SpecialIPut(&bb, mir, special);
break;
- }
case kInlineOpReturnArg:
+ // TODO: Generate the method using only the data in special.
next_mir = SpecialIdentity(mir);
break;
default:
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 0ed4576..598da89 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -190,8 +190,8 @@ class ArmMir2Lir : public Mir2Lir {
RegLocation LoadArg(RegLocation loc);
void LockLiveArgs(MIR* mir);
MIR* GetNextMir(BasicBlock** p_bb, MIR* mir);
- MIR* SpecialIGet(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object);
- MIR* SpecialIPut(BasicBlock** bb, MIR* mir, OpSize size, bool long_or_double, bool is_object);
+ MIR* SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special);
+ MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
MIR* SpecialIdentity(MIR* mir);
LIR* LoadFPConstantValue(int r_dest, int value);
void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 0937be3..0ad8abf 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -24,11 +24,27 @@
#include "dex/mir_graph.h"
#include "dex_instruction.h"
#include "dex_instruction-inl.h"
+#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
#include "dex_file_method_inliner.h"
namespace art {
+namespace { // anonymous namespace
+
+constexpr uint8_t kIGetIPutOpSizes[] = {
+ kWord, // IGET, IPUT
+ kLong, // IGET_WIDE, IPUT_WIDE
+ kWord, // IGET_OBJECT, IPUT_OBJECT
+ kSignedByte, // IGET_BOOLEAN, IPUT_BOOLEAN
+ kSignedByte, // IGET_BYTE, IPUT_BYTE
+ kUnsignedHalf, // IGET_CHAR, IPUT_CHAR
+ kSignedHalf, // IGET_SHORT, IPUT_SHORT
+};
+
+} // anonymous namespace
+
const uint32_t DexFileMethodInliner::kIndexUnresolved;
const char* const DexFileMethodInliner::kClassCacheNames[] = {
"Z", // kClassCacheBoolean
@@ -167,7 +183,7 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
#define INTRINSIC(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, d } }
+ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
@@ -248,57 +264,58 @@ DexFileMethodInliner::DexFileMethodInliner()
DexFileMethodInliner::~DexFileMethodInliner() {
}
-bool DexFileMethodInliner::AnalyseMethodCode(uint32_t method_idx,
- const DexFile::CodeItem* code_item) {
+bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
// We currently support only plain return or 2-instruction methods.
+ const DexFile::CodeItem* code_item = verifier->CodeItem();
DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
const Instruction* instruction = Instruction::At(code_item->insns_);
Instruction::Code opcode = instruction->Opcode();
+ InlineMethod method;
+ bool success;
switch (opcode) {
case Instruction::RETURN_VOID:
- return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
+ method.opcode = kInlineOpNop;
+ method.flags = kInlineSpecial;
+ method.d.data = 0u;
+ success = true;
+ break;
case Instruction::RETURN:
case Instruction::RETURN_OBJECT:
- return AnalyseReturnMethod(method_idx, code_item, kWord);
case Instruction::RETURN_WIDE:
- return AnalyseReturnMethod(method_idx, code_item, kLong);
+ success = AnalyseReturnMethod(code_item, &method);
+ break;
case Instruction::CONST:
case Instruction::CONST_4:
case Instruction::CONST_16:
case Instruction::CONST_HIGH16:
// TODO: Support wide constants (RETURN_WIDE).
- return AnalyseConstMethod(method_idx, code_item);
+ success = AnalyseConstMethod(code_item, &method);
+ break;
case Instruction::IGET:
- return AnalyseIGetMethod(method_idx, code_item, kWord, false);
case Instruction::IGET_OBJECT:
- return AnalyseIGetMethod(method_idx, code_item, kWord, true);
case Instruction::IGET_BOOLEAN:
case Instruction::IGET_BYTE:
- return AnalyseIGetMethod(method_idx, code_item, kSignedByte, false);
case Instruction::IGET_CHAR:
- return AnalyseIGetMethod(method_idx, code_item, kUnsignedHalf, false);
case Instruction::IGET_SHORT:
- return AnalyseIGetMethod(method_idx, code_item, kSignedHalf, false);
case Instruction::IGET_WIDE:
- return AnalyseIGetMethod(method_idx, code_item, kLong, false);
+ success = AnalyseIGetMethod(verifier, &method);
+ break;
case Instruction::IPUT:
- return AnalyseIPutMethod(method_idx, code_item, kWord, false);
case Instruction::IPUT_OBJECT:
- return AnalyseIPutMethod(method_idx, code_item, kWord, true);
case Instruction::IPUT_BOOLEAN:
case Instruction::IPUT_BYTE:
- return AnalyseIPutMethod(method_idx, code_item, kSignedByte, false);
case Instruction::IPUT_CHAR:
- return AnalyseIPutMethod(method_idx, code_item, kUnsignedHalf, false);
case Instruction::IPUT_SHORT:
- return AnalyseIPutMethod(method_idx, code_item, kSignedHalf, false);
case Instruction::IPUT_WIDE:
- return AnalyseIPutMethod(method_idx, code_item, kLong, false);
+ success = AnalyseIPutMethod(verifier, &method);
+ break;
default:
- return false;
- }
+ success = false;
+ break;
+ }
+ return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
}
bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
@@ -323,13 +340,13 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
case kIntrinsicFloatCvt:
return backend->GenInlinedFloatCvt(info);
case kIntrinsicReverseBytes:
- return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
+ return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data));
case kIntrinsicAbsInt:
return backend->GenInlinedAbsInt(info);
case kIntrinsicAbsLong:
return backend->GenInlinedAbsLong(info);
case kIntrinsicMinMaxInt:
- return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
+ return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin);
case kIntrinsicSqrt:
return backend->GenInlinedSqrt(info);
case kIntrinsicCharAt:
@@ -337,26 +354,27 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) {
case kIntrinsicCompareTo:
return backend->GenInlinedStringCompareTo(info);
case kIntrinsicIsEmptyOrLength:
- return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
+ return backend->GenInlinedStringIsEmptyOrLength(
+ info, intrinsic.d.data & kIntrinsicFlagIsEmpty);
case kIntrinsicIndexOf:
- return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
+ return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0);
case kIntrinsicCurrentThread:
return backend->GenInlinedCurrentThread(info);
case kIntrinsicPeek:
- return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
+ return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data));
case kIntrinsicPoke:
- return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
+ return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data));
case kIntrinsicCas:
- return backend->GenInlinedCas(info, intrinsic.data & kIntrinsicFlagIsLong,
- intrinsic.data & kIntrinsicFlagIsObject);
+ return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+ intrinsic.d.data & kIntrinsicFlagIsObject);
case kIntrinsicUnsafeGet:
- return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
- intrinsic.data & kIntrinsicFlagIsVolatile);
+ return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+ intrinsic.d.data & kIntrinsicFlagIsVolatile);
case kIntrinsicUnsafePut:
- return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
- intrinsic.data & kIntrinsicFlagIsObject,
- intrinsic.data & kIntrinsicFlagIsVolatile,
- intrinsic.data & kIntrinsicFlagIsOrdered);
+ return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong,
+ intrinsic.d.data & kIntrinsicFlagIsObject,
+ intrinsic.d.data & kIntrinsicFlagIsVolatile,
+ intrinsic.d.data & kIntrinsicFlagIsOrdered);
default:
LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
return false; // avoid warning "control reaches end of non-void function"
@@ -505,12 +523,10 @@ void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
dex_file_ = dex_file;
}
-bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
- InlineMethodFlags flags, uint32_t data) {
+bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
WriterMutexLock mu(Thread::Current(), lock_);
if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
- InlineMethod im = {opcode, flags, data};
- inline_methods_.Put(method_idx, im);
+ inline_methods_.Put(method_idx, method);
return true;
} else {
if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
@@ -522,26 +538,30 @@ bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, InlineMethodOpcod
}
}
-bool DexFileMethodInliner::AnalyseReturnMethod(int32_t method_idx,
- const DexFile::CodeItem* code_item, OpSize size) {
+bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
+ InlineMethod* result) {
const Instruction* return_instruction = Instruction::At(code_item->insns_);
- if (return_instruction->Opcode() == Instruction::RETURN_VOID) {
- return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0);
- }
+ Instruction::Code return_opcode = return_instruction->Opcode();
+ uint16_t size = (return_opcode == Instruction::RETURN_WIDE) ? kLong : kWord;
+ uint16_t is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u;
uint32_t reg = return_instruction->VRegA_11x();
uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
DCHECK_GE(reg, arg_start);
DCHECK_LT(size == kLong ? reg + 1 : reg, code_item->registers_size_);
- InlineReturnArgData data;
- data.d.arg = reg - arg_start;
- data.d.op_size = size;
- data.d.reserved = 0;
- return AddInlineMethod(method_idx, kInlineOpReturnArg, kInlineSpecial, data.data);
+ result->opcode = kInlineOpReturnArg;
+ result->flags = kInlineSpecial;
+ InlineReturnArgData* data = &result->d.return_data;
+ data->arg = reg - arg_start;
+ data->op_size = size;
+ data->is_object = is_object;
+ data->reserved = 0u;
+ data->reserved2 = 0u;
+ return true;
}
-bool DexFileMethodInliner::AnalyseConstMethod(int32_t method_idx,
- const DexFile::CodeItem* code_item) {
+bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item,
+ InlineMethod* result) {
const Instruction* instruction = Instruction::At(code_item->insns_);
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
@@ -566,13 +586,20 @@ bool DexFileMethodInliner::AnalyseConstMethod(int32_t method_idx,
if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
return false; // Returning non-null reference constant?
}
- return AddInlineMethod(method_idx, kInlineOpConst, kInlineSpecial, vB);
+ result->opcode = kInlineOpConst;
+ result->flags = kInlineSpecial;
+ result->d.data = static_cast<uint64_t>(vB);
+ return true;
}
-bool DexFileMethodInliner::AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
- OpSize size, bool is_object) {
+bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier,
+ InlineMethod* result) {
+ const DexFile::CodeItem* code_item = verifier->CodeItem();
const Instruction* instruction = Instruction::At(code_item->insns_);
Instruction::Code opcode = instruction->Opcode();
+ DCHECK_LT(static_cast<size_t>(opcode - Instruction::IGET), arraysize(kIGetIPutOpSizes));
+ uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IGET];
+
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
if (!(return_opcode == Instruction::RETURN && size != kLong) &&
@@ -585,61 +612,74 @@ bool DexFileMethodInliner::AnalyseIGetMethod(int32_t method_idx, const DexFile::
DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg,
code_item->registers_size_);
- uint32_t vA, vB, vC;
- uint64_t dummy_wide;
- instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
+ uint32_t dst_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(vB, arg_start);
- DCHECK_LT(vB, code_item->registers_size_);
- DCHECK_LT(size == kLong ? vA + 1 : vA, code_item->registers_size_);
- if (vA != return_reg) {
- return false; // Not returning the value retrieved by iget?
+ DCHECK_GE(object_reg, arg_start);
+ DCHECK_LT(object_reg, code_item->registers_size_);
+ DCHECK_LT(size == kLong ? dst_reg + 1 : dst_reg, code_item->registers_size_);
+ if (dst_reg != return_reg) {
+ return false; // Not returning the value retrieved by IGET?
}
- // TODO: Check that the field is FastInstance().
+ if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
+ &result->d.ifield_data)) {
+ return false;
+ }
- InlineIGetIPutData data;
- data.d.field = vC;
- data.d.op_size = size;
- data.d.is_object = is_object;
- data.d.object_arg = vB - arg_start; // Allow iget on any register, not just "this"
- data.d.src_arg = 0;
- data.d.reserved = 0;
- return AddInlineMethod(method_idx, kInlineOpIGet, kInlineSpecial, data.data);
+ result->opcode = kInlineOpIGet;
+ result->flags = kInlineSpecial;
+ InlineIGetIPutData* data = &result->d.ifield_data;
+ data->op_size = size;
+ data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u;
+ data->object_arg = object_reg - arg_start; // Allow IGET on any register, not just "this".
+ data->src_arg = 0;
+ data->reserved = 0;
+ return true;
}
-bool DexFileMethodInliner::AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
- OpSize size, bool is_object) {
+bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier,
+ InlineMethod* result) {
+ const DexFile::CodeItem* code_item = verifier->CodeItem();
const Instruction* instruction = Instruction::At(code_item->insns_);
+ Instruction::Code opcode = instruction->Opcode();
+ DCHECK_LT(static_cast<size_t>(opcode - Instruction::IPUT), arraysize(kIGetIPutOpSizes));
+ uint16_t size = kIGetIPutOpSizes[opcode - Instruction::IPUT];
+
const Instruction* return_instruction = instruction->Next();
if (return_instruction->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::d::reserved to hold the information.
+ // Use InlineIGetIPutData::reserved to hold the information.
return false;
}
- uint32_t vA, vB, vC;
- uint64_t dummy_wide;
- instruction->Decode(vA, vB, dummy_wide, vC, nullptr);
+ 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(vB, arg_start);
- DCHECK_GE(vA, arg_start);
- DCHECK_LT(vB, code_item->registers_size_);
- DCHECK_LT(size == kLong ? vA + 1 : vA, code_item->registers_size_);
-
- // TODO: Check that the field (vC) is FastInstance().
-
- InlineIGetIPutData data;
- data.d.field = vC;
- data.d.op_size = size;
- data.d.is_object = is_object;
- data.d.object_arg = vB - arg_start; // Allow iput on any register, not just "this"
- data.d.src_arg = vA - arg_start;
- data.d.reserved = 0;
- return AddInlineMethod(method_idx, kInlineOpIPut, kInlineSpecial, data.data);
+ DCHECK_GE(object_reg, arg_start);
+ DCHECK_LT(object_reg, code_item->registers_size_);
+ DCHECK_GE(src_reg, arg_start);
+ DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_);
+
+ if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
+ &result->d.ifield_data)) {
+ return false;
+ }
+
+ result->opcode = kInlineOpIPut;
+ result->flags = kInlineSpecial;
+ InlineIGetIPutData* data = &result->d.ifield_data;
+ data->op_size = size;
+ data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u;
+ data->object_arg = object_reg - arg_start; // Allow IPUT on any register, not just "this".
+ data->src_arg = src_reg - arg_start;
+ data->reserved = 0;
+ return true;
}
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 6e81303..fe0824c 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -27,6 +27,10 @@
namespace art {
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
class CallInfo;
class Mir2Lir;
@@ -62,13 +66,7 @@ enum InlineMethodFlags : uint16_t {
kInlineSpecial = 0x0002,
};
-struct InlineMethod {
- InlineMethodOpcode opcode;
- InlineMethodFlags flags;
- uint32_t data;
-};
-
-// IntrinsicFlags are stored in InlineMethod::data
+// IntrinsicFlags are stored in InlineMethod::d::raw_data
enum IntrinsicFlags {
kIntrinsicFlagNone = 0,
@@ -97,28 +95,37 @@ enum IntrinsicFlags {
COMPILE_ASSERT(kWord < 8 && kLong < 8 && kSingle < 8 && kDouble < 8 && kUnsignedHalf < 8 &&
kSignedHalf < 8 && kUnsignedByte < 8 && kSignedByte < 8, op_size_field_too_narrow);
-union InlineIGetIPutData {
- uint32_t data;
- struct {
- uint16_t field;
- uint32_t op_size : 3; // OpSize
- uint32_t is_object : 1;
- uint32_t object_arg : 4;
- uint32_t src_arg : 4; // iput only
- uint32_t reserved : 4;
- } d;
+struct InlineIGetIPutData {
+ uint16_t op_size : 3; // OpSize
+ uint16_t is_object : 1;
+ uint16_t object_arg : 4;
+ uint16_t src_arg : 4; // iput only
+ uint16_t method_is_static : 1;
+ uint16_t reserved : 3;
+ uint16_t field_idx;
+ uint32_t is_volatile : 1;
+ uint32_t field_offset : 31;
};
-COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint32_t), InvalidSizeOfInlineIGetIPutData);
-
-union InlineReturnArgData {
- uint32_t data;
- struct {
- uint16_t arg;
- uint32_t op_size : 3; // OpSize
- uint32_t reserved : 13;
+COMPILE_ASSERT(sizeof(InlineIGetIPutData) == sizeof(uint64_t), InvalidSizeOfInlineIGetIPutData);
+
+struct InlineReturnArgData {
+ uint16_t arg;
+ uint16_t op_size : 3; // OpSize
+ uint16_t is_object : 1;
+ uint16_t reserved : 12;
+ uint32_t reserved2;
+};
+COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData);
+
+struct InlineMethod {
+ InlineMethodOpcode opcode;
+ InlineMethodFlags flags;
+ union {
+ uint64_t data;
+ InlineIGetIPutData ifield_data;
+ InlineReturnArgData return_data;
} d;
};
-COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint32_t), InvalidSizeOfInlineReturnArgData);
/**
* Handles inlining of methods from a particular DexFile.
@@ -144,8 +151,8 @@ class DexFileMethodInliner {
* @param method_idx the index of the inlining candidate.
* @param code_item a previously verified code item of the method.
*/
- bool AnalyseMethodCode(uint32_t method_idx,
- const DexFile::CodeItem* code_item) LOCKS_EXCLUDED(lock_);
+ bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
/**
* Check whether a particular method index corresponds to an intrinsic function.
@@ -369,17 +376,14 @@ class DexFileMethodInliner {
friend class DexFileToMethodInlinerMap;
- bool AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode,
- InlineMethodFlags flags, uint32_t data) LOCKS_EXCLUDED(lock_);
-
- bool AnalyseReturnMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
- OpSize size) LOCKS_EXCLUDED(lock_);
- bool AnalyseConstMethod(int32_t method_idx, const DexFile::CodeItem* code_item)
- LOCKS_EXCLUDED(lock_);
- bool AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
- OpSize size, bool is_object) LOCKS_EXCLUDED(lock_);
- bool AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item,
- OpSize size, bool is_object) LOCKS_EXCLUDED(lock_);
+ bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) LOCKS_EXCLUDED(lock_);
+
+ static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+ static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result);
+ static bool AnalyseIGetMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ static bool AnalyseIPutMethod(verifier::MethodVerifier* verifier, InlineMethod* result)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
ReaderWriterMutex lock_;
/*
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 9f48351..5b9d66c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -29,6 +29,7 @@
#include "dex_file-inl.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
+#include "dex/quick/dex_file_method_inliner.h"
#include "jni_internal.h"
#include "object_utils.h"
#include "runtime.h"
@@ -49,6 +50,7 @@
#include "thread_pool.h"
#include "trampolines/trampoline_compiler.h"
#include "verifier/method_verifier.h"
+#include "verifier/method_verifier-inl.h"
#if defined(ART_USE_PORTABLE_COMPILER)
#include "elf_writer_mclinker.h"
@@ -995,6 +997,30 @@ static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjec
class_loader, NULL, type);
}
+bool CompilerDriver::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+ verifier::MethodVerifier* verifier,
+ InlineIGetIPutData* result) {
+ mirror::DexCache* dex_cache = verifier->GetDexCache();
+ uint32_t method_idx = verifier->GetMethodReference().dex_method_index;
+ mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx);
+ mirror::ArtField* field = dex_cache->GetResolvedField(field_idx);
+ if (method == nullptr || field == nullptr) {
+ return false;
+ }
+ mirror::Class* method_class = method->GetDeclaringClass();
+ mirror::Class* field_class = field->GetDeclaringClass();
+ if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) ||
+ (is_put && field->IsFinal() && method_class != field_class)) {
+ return false;
+ }
+ DCHECK_GE(field->GetOffset().Int32Value(), 0);
+ result->method_is_static = method->IsStatic();
+ result->field_idx = field_idx;
+ result->field_offset = field->GetOffset().Int32Value();
+ result->is_volatile = field->IsVolatile();
+ return true;
+}
+
bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit,
bool is_put, int* field_offset, bool* is_volatile) {
ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 4307212..ea43e4f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -38,10 +38,15 @@
namespace art {
+namespace verifier {
+class MethodVerifier;
+} // namespace verifier
+
class AOTCompilationStats;
class ParallelCompilationManager;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
+class InlineIGetIPutData;
class OatWriter;
class TimingLogger;
class VerificationResults;
@@ -194,6 +199,13 @@ class CompilerDriver {
bool* is_type_initialized, bool* use_direct_type_ptr,
uintptr_t* direct_type_ptr);
+ // Can we fast path instance field access in a verified accessor?
+ // If yes, computes field's offset and volatility and whether the method is static or not.
+ static bool ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put,
+ verifier::MethodVerifier* verifier,
+ InlineIGetIPutData* result)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Can we fast path instance field access? Computes field's offset and volatility.
bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put,
int* field_offset, bool* is_volatile)
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 5ac01f2..90eea5e 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -364,7 +364,7 @@ class Dex2Oat {
if (result && method_inliner_map_ != nullptr) {
MethodReference ref = verifier->GetMethodReference();
method_inliner_map_->GetMethodInliner(ref.dex_file)
- ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
+ ->AnalyseMethodCode(verifier);
}
return result;
}
diff --git a/runtime/common_test.h b/runtime/common_test.h
index ddaf52a..daa2ff1 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -677,7 +677,7 @@ class CommonTest : public testing::Test {
if (result && method_inliner_map_ != nullptr) {
MethodReference ref = verifier->GetMethodReference();
method_inliner_map_->GetMethodInliner(ref.dex_file)
- ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem());
+ ->AnalyseMethodCode(verifier);
}
return result;
}