diff options
-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, 173 insertions, 250 deletions
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 22466f08c..661050ffe 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -127,19 +127,15 @@ void ArmMir2Lir::GenPrintLabel(MIR* mir) { } } -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. +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; } - - 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); @@ -152,24 +148,19 @@ MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& spec // 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, 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. +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; } - - 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); @@ -183,7 +174,7 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& spec rl_src = ArmMir2Lir::ArgLoc(rl_src); rl_obj = ArmMir2Lir::ArgLoc(rl_obj); // Reject if source is split across registers & frame - if (rl_src.location == kLocInvalid) { + if (rl_obj.location == kLocInvalid) { ResetRegPool(); return NULL; } @@ -191,7 +182,6 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& spec 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); } @@ -229,6 +219,8 @@ 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; @@ -239,17 +231,30 @@ void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir, break; case kInlineOpConst: ArmMir2Lir::GenPrintLabel(mir); - LoadConstant(rARM_RET0, static_cast<int>(special.d.data)); + LoadConstant(rARM_RET0, special.data); next_mir = GetNextMir(&bb, mir); break; - case kInlineOpIGet: - next_mir = SpecialIGet(&bb, mir, special); + 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); break; - case kInlineOpIPut: - next_mir = SpecialIPut(&bb, mir, special); + } + 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); 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 598da8937..0ed4576e8 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, const InlineMethod& special); - MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special); + 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* 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 0ad8abfcb..0937be323 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -24,27 +24,11 @@ #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 @@ -183,7 +167,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), @@ -264,58 +248,57 @@ DexFileMethodInliner::DexFileMethodInliner() DexFileMethodInliner::~DexFileMethodInliner() { } -bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) { +bool DexFileMethodInliner::AnalyseMethodCode(uint32_t method_idx, + const DexFile::CodeItem* code_item) { // 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: - method.opcode = kInlineOpNop; - method.flags = kInlineSpecial; - method.d.data = 0u; - success = true; - break; + return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0); case Instruction::RETURN: case Instruction::RETURN_OBJECT: + return AnalyseReturnMethod(method_idx, code_item, kWord); case Instruction::RETURN_WIDE: - success = AnalyseReturnMethod(code_item, &method); - break; + return AnalyseReturnMethod(method_idx, code_item, kLong); case Instruction::CONST: case Instruction::CONST_4: case Instruction::CONST_16: case Instruction::CONST_HIGH16: // TODO: Support wide constants (RETURN_WIDE). - success = AnalyseConstMethod(code_item, &method); - break; + return AnalyseConstMethod(method_idx, code_item); 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: - success = AnalyseIGetMethod(verifier, &method); - break; + return AnalyseIGetMethod(method_idx, code_item, kLong, false); 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: - success = AnalyseIPutMethod(verifier, &method); - break; + return AnalyseIPutMethod(method_idx, code_item, kLong, false); default: - success = false; - break; - } - return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method); + return false; + } } bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) { @@ -340,13 +323,13 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { case kIntrinsicFloatCvt: return backend->GenInlinedFloatCvt(info); case kIntrinsicReverseBytes: - return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.d.data)); + return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data)); case kIntrinsicAbsInt: return backend->GenInlinedAbsInt(info); case kIntrinsicAbsLong: return backend->GenInlinedAbsLong(info); case kIntrinsicMinMaxInt: - return backend->GenInlinedMinMaxInt(info, intrinsic.d.data & kIntrinsicFlagMin); + return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin); case kIntrinsicSqrt: return backend->GenInlinedSqrt(info); case kIntrinsicCharAt: @@ -354,27 +337,26 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { case kIntrinsicCompareTo: return backend->GenInlinedStringCompareTo(info); case kIntrinsicIsEmptyOrLength: - return backend->GenInlinedStringIsEmptyOrLength( - info, intrinsic.d.data & kIntrinsicFlagIsEmpty); + return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty); case kIntrinsicIndexOf: - return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0); + return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0); case kIntrinsicCurrentThread: return backend->GenInlinedCurrentThread(info); case kIntrinsicPeek: - return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.d.data)); + return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data)); case kIntrinsicPoke: - return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.d.data)); + return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data)); case kIntrinsicCas: - return backend->GenInlinedCas(info, intrinsic.d.data & kIntrinsicFlagIsLong, - intrinsic.d.data & kIntrinsicFlagIsObject); + return backend->GenInlinedCas(info, intrinsic.data & kIntrinsicFlagIsLong, + intrinsic.data & kIntrinsicFlagIsObject); case kIntrinsicUnsafeGet: - return backend->GenInlinedUnsafeGet(info, intrinsic.d.data & kIntrinsicFlagIsLong, - intrinsic.d.data & kIntrinsicFlagIsVolatile); + return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong, + intrinsic.data & kIntrinsicFlagIsVolatile); case kIntrinsicUnsafePut: - return backend->GenInlinedUnsafePut(info, intrinsic.d.data & kIntrinsicFlagIsLong, - intrinsic.d.data & kIntrinsicFlagIsObject, - intrinsic.d.data & kIntrinsicFlagIsVolatile, - intrinsic.d.data & kIntrinsicFlagIsOrdered); + return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong, + intrinsic.data & kIntrinsicFlagIsObject, + intrinsic.data & kIntrinsicFlagIsVolatile, + intrinsic.data & kIntrinsicFlagIsOrdered); default: LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode; return false; // avoid warning "control reaches end of non-void function" @@ -523,10 +505,12 @@ void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { dex_file_ = dex_file; } -bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) { +bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, InlineMethodOpcode opcode, + InlineMethodFlags flags, uint32_t data) { WriterMutexLock mu(Thread::Current(), lock_); if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) { - inline_methods_.Put(method_idx, method); + InlineMethod im = {opcode, flags, data}; + inline_methods_.Put(method_idx, im); return true; } else { if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") { @@ -538,30 +522,26 @@ bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMetho } } -bool DexFileMethodInliner::AnalyseReturnMethod(const DexFile::CodeItem* code_item, - InlineMethod* result) { +bool DexFileMethodInliner::AnalyseReturnMethod(int32_t method_idx, + const DexFile::CodeItem* code_item, OpSize size) { const Instruction* return_instruction = Instruction::At(code_item->insns_); - 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; + if (return_instruction->Opcode() == Instruction::RETURN_VOID) { + return AddInlineMethod(method_idx, kInlineOpNop, kInlineSpecial, 0); + } 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_); - 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; + 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); } -bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item, - InlineMethod* result) { +bool DexFileMethodInliner::AnalyseConstMethod(int32_t method_idx, + const DexFile::CodeItem* code_item) { const Instruction* instruction = Instruction::At(code_item->insns_); const Instruction* return_instruction = instruction->Next(); Instruction::Code return_opcode = return_instruction->Opcode(); @@ -586,20 +566,13 @@ bool DexFileMethodInliner::AnalyseConstMethod(const DexFile::CodeItem* code_item if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) { return false; // Returning non-null reference constant? } - result->opcode = kInlineOpConst; - result->flags = kInlineSpecial; - result->d.data = static_cast<uint64_t>(vB); - return true; + return AddInlineMethod(method_idx, kInlineOpConst, kInlineSpecial, vB); } -bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier, - InlineMethod* result) { - const DexFile::CodeItem* code_item = verifier->CodeItem(); +bool DexFileMethodInliner::AnalyseIGetMethod(int32_t method_idx, const DexFile::CodeItem* code_item, + OpSize size, bool is_object) { 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) && @@ -612,74 +585,61 @@ bool DexFileMethodInliner::AnalyseIGetMethod(verifier::MethodVerifier* verifier, DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, code_item->registers_size_); - uint32_t dst_reg = instruction->VRegA_22c(); - uint32_t object_reg = instruction->VRegB_22c(); - uint32_t field_idx = instruction->VRegC_22c(); + uint32_t vA, vB, vC; + uint64_t dummy_wide; + instruction->Decode(vA, vB, dummy_wide, vC, nullptr); 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_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? + 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? } - if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier, - &result->d.ifield_data)) { - return false; - } + // TODO: Check that the field is FastInstance(). - 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; + 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); } -bool DexFileMethodInliner::AnalyseIPutMethod(verifier::MethodVerifier* verifier, - InlineMethod* result) { - const DexFile::CodeItem* code_item = verifier->CodeItem(); +bool DexFileMethodInliner::AnalyseIPutMethod(int32_t method_idx, const DexFile::CodeItem* code_item, + OpSize size, bool is_object) { 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::reserved to hold the information. + // Use InlineIGetIPutData::d::reserved to hold the information. return false; } - uint32_t src_reg = instruction->VRegA_22c(); - uint32_t object_reg = instruction->VRegB_22c(); - uint32_t field_idx = instruction->VRegC_22c(); + uint32_t vA, vB, vC; + uint64_t dummy_wide; + instruction->Decode(vA, vB, dummy_wide, vC, nullptr); 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(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; + 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); } } // namespace art diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index fe0824cea..6e81303f9 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -27,10 +27,6 @@ namespace art { -namespace verifier { -class MethodVerifier; -} // namespace verifier - class CallInfo; class Mir2Lir; @@ -66,7 +62,13 @@ enum InlineMethodFlags : uint16_t { kInlineSpecial = 0x0002, }; -// IntrinsicFlags are stored in InlineMethod::d::raw_data +struct InlineMethod { + InlineMethodOpcode opcode; + InlineMethodFlags flags; + uint32_t data; +}; + +// IntrinsicFlags are stored in InlineMethod::data enum IntrinsicFlags { kIntrinsicFlagNone = 0, @@ -95,37 +97,28 @@ 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); -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(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; +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; }; -COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint64_t), InvalidSizeOfInlineReturnArgData); - -struct InlineMethod { - InlineMethodOpcode opcode; - InlineMethodFlags flags; - union { - uint64_t data; - InlineIGetIPutData ifield_data; - InlineReturnArgData return_data; +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; } d; }; +COMPILE_ASSERT(sizeof(InlineReturnArgData) == sizeof(uint32_t), InvalidSizeOfInlineReturnArgData); /** * Handles inlining of methods from a particular DexFile. @@ -151,8 +144,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(verifier::MethodVerifier* verifier) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_); + bool AnalyseMethodCode(uint32_t method_idx, + const DexFile::CodeItem* code_item) LOCKS_EXCLUDED(lock_); /** * Check whether a particular method index corresponds to an intrinsic function. @@ -376,14 +369,17 @@ class DexFileMethodInliner { friend class DexFileToMethodInlinerMap; - 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_); + 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_); ReaderWriterMutex lock_; /* diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 5b9d66c21..9f4835164 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -29,7 +29,6 @@ #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" @@ -50,7 +49,6 @@ #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" @@ -997,30 +995,6 @@ 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 ea43e4f49..430721225 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -38,15 +38,10 @@ namespace art { -namespace verifier { -class MethodVerifier; -} // namespace verifier - class AOTCompilationStats; class ParallelCompilationManager; class DexCompilationUnit; class DexFileToMethodInlinerMap; -class InlineIGetIPutData; class OatWriter; class TimingLogger; class VerificationResults; @@ -199,13 +194,6 @@ 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 90eea5e97..5ac01f290 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(verifier); + ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem()); } return result; } diff --git a/runtime/common_test.h b/runtime/common_test.h index daa2ff152..ddaf52a04 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(verifier); + ->AnalyseMethodCode(ref.dex_method_index, verifier->CodeItem()); } return result; } |