diff options
author | Vladimir Marko <vmarko@google.com> | 2014-02-07 14:52:18 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-02-07 14:52:18 +0000 |
commit | 92ef04ca2309971b8d013f63c85925209f075a3a (patch) | |
tree | ef722d79fb041864aca76a0243271c6edc7a9bd6 | |
parent | a52214230ad091359956ed7566670963aedf2045 (diff) | |
parent | 5dc5727261e87ba8a418e2d0e970c75f67e4ab79 (diff) | |
download | art-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.cc | 71 | ||||
-rw-r--r-- | compiler/dex/quick/arm/codegen_arm.h | 4 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 224 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 82 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 26 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.h | 12 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 2 | ||||
-rw-r--r-- | runtime/common_test.h | 2 |
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; } |