diff options
author | Jeff Hao <jeffhao@google.com> | 2014-01-15 13:49:50 -0800 |
---|---|---|
committer | Jeff Hao <jeffhao@google.com> | 2015-04-27 18:54:52 -0700 |
commit | 848f70a3d73833fc1bf3032a9ff6812e429661d9 (patch) | |
tree | b0349b3a40aab5a915af491b100659a5ca9fbbf6 /compiler/dex | |
parent | d14438f0c5071962be7fab572b54687d32d9d087 (diff) | |
download | android_art-848f70a3d73833fc1bf3032a9ff6812e429661d9.tar.gz android_art-848f70a3d73833fc1bf3032a9ff6812e429661d9.tar.bz2 android_art-848f70a3d73833fc1bf3032a9ff6812e429661d9.zip |
Replace String CharArray with internal uint16_t array.
Summary of high level changes:
- Adds compiler inliner support to identify string init methods
- Adds compiler support (quick & optimizing) with new invoke code path
that calls method off the thread pointer
- Adds thread entrypoints for all string init methods
- Adds map to verifier to log when receiver of string init has been
copied to other registers. used by compiler and interpreter
Change-Id: I797b992a8feb566f9ad73060011ab6f51eb7ce01
Diffstat (limited to 'compiler/dex')
-rw-r--r-- | compiler/dex/bb_optimizations.h | 24 | ||||
-rw-r--r-- | compiler/dex/mir_graph.h | 3 | ||||
-rw-r--r-- | compiler/dex/mir_method_info.cc | 11 | ||||
-rw-r--r-- | compiler/dex/mir_optimization.cc | 75 | ||||
-rw-r--r-- | compiler/dex/pass_driver_me_opts.cc | 1 | ||||
-rw-r--r-- | compiler/dex/quick/arm/call_arm.cc | 23 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/call_arm64.cc | 21 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 125 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 44 | ||||
-rwxr-xr-x | compiler/dex/quick/gen_invoke.cc | 164 | ||||
-rw-r--r-- | compiler/dex/quick/mips/call_mips.cc | 23 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 8 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 16 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/target_x86.cc | 44 | ||||
-rw-r--r-- | compiler/dex/verified_method.cc | 3 | ||||
-rw-r--r-- | compiler/dex/verified_method.h | 11 |
16 files changed, 518 insertions, 78 deletions
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index b948afd605..72919b6a9d 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -26,6 +26,30 @@ namespace art { /** + * @class String Change + * @brief Converts calls to String.<init> to StringFactory instead. + */ +class StringChange : public PassME { + public: + StringChange() : PassME("StringChange", kNoNodes) { + } + + void Start(PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* c_unit = down_cast<PassMEDataHolder*>(data)->c_unit; + DCHECK(c_unit != nullptr); + c_unit->mir_graph->StringChange(); + } + + bool Gate(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* c_unit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(c_unit != nullptr); + return c_unit->mir_graph->HasInvokes(); + } +}; + +/** * @class CacheFieldLoweringInfo * @brief Cache the lowering info for fields used by IGET/IPUT/SGET/SPUT insns. */ diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 7bfbb34ae9..7385a8bd53 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -519,6 +519,7 @@ struct CallInfo { bool is_range; DexOffset offset; // Offset in code units. MIR* mir; + int32_t string_init_offset; }; @@ -723,6 +724,8 @@ class MIRGraph { void BasicBlockOptimization(); void BasicBlockOptimizationEnd(); + void StringChange(); + const ArenaVector<BasicBlockId>& GetTopologicalSortOrder() { DCHECK(!topological_order_.empty()); return topological_order_; diff --git a/compiler/dex/mir_method_info.cc b/compiler/dex/mir_method_info.cc index 0c84b82edd..5654604797 100644 --- a/compiler/dex/mir_method_info.cc +++ b/compiler/dex/mir_method_info.cc @@ -16,6 +16,7 @@ # include "mir_method_info.h" +#include "dex/compiler_ir.h" #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/verified_method.h" @@ -83,6 +84,13 @@ void MirMethodLoweringInfo::Resolve(CompilerDriver* compiler_driver, MethodReference* devirt_target = (it->target_dex_file_ != nullptr) ? &devirt_ref : nullptr; InvokeType invoke_type = it->GetInvokeType(); mirror::ArtMethod* resolved_method = nullptr; + + bool string_init = false; + if (default_inliner->IsStringInitMethodIndex(it->MethodIndex())) { + string_init = true; + invoke_type = kDirect; + } + if (!it->IsQuickened()) { it->target_dex_file_ = dex_file; it->target_method_idx_ = it->MethodIndex(); @@ -170,6 +178,9 @@ void MirMethodLoweringInfo::Resolve(CompilerDriver* compiler_driver, it->target_dex_file_ = target_method.dex_file; it->target_method_idx_ = target_method.dex_method_index; it->stats_flags_ = fast_path_flags; + if (string_init) { + it->direct_code_ = 0; + } } } diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 3482602704..25c159f2a1 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -18,6 +18,7 @@ #include "base/logging.h" #include "base/scoped_arena_containers.h" #include "dataflow_iterator-inl.h" +#include "dex/verified_method.h" #include "dex_flags.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" @@ -25,10 +26,11 @@ #include "gvn_dead_code_elimination.h" #include "local_value_numbering.h" #include "mir_field_info.h" -#include "type_inference.h" +#include "mirror/string.h" #include "quick/dex_file_method_inliner.h" #include "quick/dex_file_to_method_inliner_map.h" #include "stack.h" +#include "type_inference.h" namespace art { @@ -1660,6 +1662,77 @@ void MIRGraph::BasicBlockOptimizationEnd() { temp_scoped_alloc_.reset(); } +void MIRGraph::StringChange() { + AllNodesIterator iter(this); + for (BasicBlock* bb = iter.Next(); bb != nullptr; bb = iter.Next()) { + for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { + // Look for new instance opcodes, skip otherwise + Instruction::Code opcode = mir->dalvikInsn.opcode; + if (opcode == Instruction::NEW_INSTANCE) { + uint32_t type_idx = mir->dalvikInsn.vB; + if (cu_->compiler_driver->IsStringTypeIndex(type_idx, cu_->dex_file)) { + // Change NEW_INSTANCE and throwing half of the insn (if it exists) into CONST_4 of 0 + mir->dalvikInsn.opcode = Instruction::CONST_4; + mir->dalvikInsn.vB = 0; + MIR* check_mir = GetBasicBlock(bb->predecessors[0])->last_mir_insn; + if (check_mir != nullptr && + static_cast<int>(check_mir->dalvikInsn.opcode) == kMirOpCheck) { + check_mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); + check_mir->dalvikInsn.vB = 0; + } + } + } else if ((opcode == Instruction::INVOKE_DIRECT) || + (opcode == Instruction::INVOKE_DIRECT_RANGE)) { + uint32_t method_idx = mir->dalvikInsn.vB; + DexFileMethodInliner* inliner = + cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file); + if (inliner->IsStringInitMethodIndex(method_idx)) { + bool is_range = (opcode == Instruction::INVOKE_DIRECT_RANGE); + uint32_t orig_this_reg = is_range ? mir->dalvikInsn.vC : mir->dalvikInsn.arg[0]; + // Remove this pointer from string init and change to static call. + mir->dalvikInsn.vA--; + if (!is_range) { + mir->dalvikInsn.opcode = Instruction::INVOKE_STATIC; + for (uint32_t i = 0; i < mir->dalvikInsn.vA; i++) { + mir->dalvikInsn.arg[i] = mir->dalvikInsn.arg[i + 1]; + } + } else { + mir->dalvikInsn.opcode = Instruction::INVOKE_STATIC_RANGE; + mir->dalvikInsn.vC++; + } + // Insert a move-result instruction to the original this pointer reg. + MIR* move_result_mir = static_cast<MIR *>(arena_->Alloc(sizeof(MIR), kArenaAllocMIR)); + move_result_mir->dalvikInsn.opcode = Instruction::MOVE_RESULT_OBJECT; + move_result_mir->dalvikInsn.vA = orig_this_reg; + move_result_mir->offset = mir->offset; + move_result_mir->m_unit_index = mir->m_unit_index; + bb->InsertMIRAfter(mir, move_result_mir); + // Add additional moves if this pointer was copied to other registers. + const VerifiedMethod* verified_method = + cu_->compiler_driver->GetVerifiedMethod(cu_->dex_file, cu_->method_idx); + DCHECK(verified_method != nullptr); + const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map = + verified_method->GetStringInitPcRegMap(); + auto map_it = string_init_map.find(mir->offset); + if (map_it != string_init_map.end()) { + const std::set<uint32_t>& reg_set = map_it->second; + for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) { + MIR* move_mir = static_cast<MIR *>(arena_->Alloc(sizeof(MIR), kArenaAllocMIR)); + move_mir->dalvikInsn.opcode = Instruction::MOVE_OBJECT; + move_mir->dalvikInsn.vA = *set_it; + move_mir->dalvikInsn.vB = orig_this_reg; + move_mir->offset = mir->offset; + move_mir->m_unit_index = mir->m_unit_index; + bb->InsertMIRAfter(move_result_mir, move_mir); + } + } + } + } + } + } +} + + bool MIRGraph::EliminateSuspendChecksGate() { if ((cu_->disable_opt & (1 << kSuspendCheckElimination)) != 0 || // Disabled. GetMaxNestedLoops() == 0u || // Nothing to do. diff --git a/compiler/dex/pass_driver_me_opts.cc b/compiler/dex/pass_driver_me_opts.cc index 3e193b471b..375003bf1f 100644 --- a/compiler/dex/pass_driver_me_opts.cc +++ b/compiler/dex/pass_driver_me_opts.cc @@ -35,6 +35,7 @@ void PassDriverMEOpts::SetupPasses(PassManager* pass_manager) { * Disadvantage is the passes can't change their internal states depending on CompilationUnit: * - This is not yet an issue: no current pass would require it. */ + pass_manager->AddPass(new StringChange); pass_manager->AddPass(new CacheFieldLoweringInfo); pass_manager->AddPass(new CacheMethodLoweringInfo); pass_manager->AddPass(new CalculatePredecessors); diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 6ba4016260..2b2d6af326 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -21,6 +21,7 @@ #include "arm_lir.h" #include "base/logging.h" #include "dex/mir_graph.h" +#include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" @@ -619,13 +620,31 @@ static bool ArmUseRelativeCall(CompilationUnit* cu, const MethodReference& targe * Bit of a hack here - in the absence of a real scheduling pass, * emit the next instruction in static & direct invoke sequences. */ -int ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED, +int ArmMir2Lir::ArmNextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t unused_idx ATTRIBUTE_UNUSED, uintptr_t direct_code, uintptr_t direct_method, InvokeType type) { ArmMir2Lir* cg = static_cast<ArmMir2Lir*>(cu->cg.get()); - if (direct_code != 0 && direct_method != 0) { + if (info->string_init_offset != 0) { + RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); + switch (state) { + case 0: { // Grab target method* from thread pointer + cg->LoadRefDisp(rs_rARM_SELF, info->string_init_offset, arg0_ref, kNotVolatile); + break; + } + case 1: // Grab the code from the method* + if (direct_code == 0) { + // kInvokeTgt := arg0_ref->entrypoint + cg->LoadWordDisp(arg0_ref, + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArmPointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt)); + } + break; + default: + return -1; + } + } else if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_code != static_cast<uintptr_t>(-1)) { diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc index 9a7c2ade18..e49e40d868 100644 --- a/compiler/dex/quick/arm64/call_arm64.cc +++ b/compiler/dex/quick/arm64/call_arm64.cc @@ -21,6 +21,7 @@ #include "arm64_lir.h" #include "base/logging.h" #include "dex/mir_graph.h" +#include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" @@ -460,7 +461,25 @@ int Arm64Mir2Lir::Arm64NextSDCallInsn(CompilationUnit* cu, CallInfo* info, InvokeType type) { UNUSED(info, unused_idx); Arm64Mir2Lir* cg = static_cast<Arm64Mir2Lir*>(cu->cg.get()); - if (direct_code != 0 && direct_method != 0) { + if (info->string_init_offset != 0) { + RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); + switch (state) { + case 0: { // Grab target method* from thread pointer + cg->LoadRefDisp(rs_xSELF, info->string_init_offset, arg0_ref, kNotVolatile); + break; + } + case 1: // Grab the code from the method* + if (direct_code == 0) { + // kInvokeTgt := arg0_ref->entrypoint + cg->LoadWordDisp(arg0_ref, + mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArm64PointerSize).Int32Value(), cg->TargetPtrReg(kInvokeTgt)); + } + break; + default: + return -1; + } + } else if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_code != static_cast<uintptr_t>(-1)) { diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index f5e6c09dba..2568ee3064 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -55,8 +55,12 @@ static constexpr bool kIntrinsicIsStatic[] = { false, // kIntrinsicReferenceGetReferent false, // kIntrinsicCharAt false, // kIntrinsicCompareTo + false, // kIntrinsicGetCharsNoCheck false, // kIntrinsicIsEmptyOrLength false, // kIntrinsicIndexOf + true, // kIntrinsicNewStringFromBytes + true, // kIntrinsicNewStringFromChars + true, // kIntrinsicNewStringFromString true, // kIntrinsicCurrentThread true, // kIntrinsicPeek true, // kIntrinsicPoke @@ -88,8 +92,15 @@ static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be st static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static"); +static_assert(!kIntrinsicIsStatic[kIntrinsicGetCharsNoCheck], "GetCharsNoCheck must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static"); static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromBytes], + "NewStringFromBytes must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromChars], + "NewStringFromChars must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromString], + "NewStringFromString must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static"); @@ -137,9 +148,15 @@ const char* const DexFileMethodInliner::kClassCacheNames[] = { "F", // kClassCacheFloat "D", // kClassCacheDouble "V", // kClassCacheVoid + "[B", // kClassCacheJavaLangByteArray + "[C", // kClassCacheJavaLangCharArray + "[I", // kClassCacheJavaLangIntArray "Ljava/lang/Object;", // kClassCacheJavaLangObject - "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference + "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference "Ljava/lang/String;", // kClassCacheJavaLangString + "Ljava/lang/StringBuffer;", // kClassCacheJavaLangStringBuffer + "Ljava/lang/StringBuilder;", // kClassCacheJavaLangStringBuilder + "Ljava/lang/StringFactory;", // kClassCacheJavaLangStringFactory "Ljava/lang/Double;", // kClassCacheJavaLangDouble "Ljava/lang/Float;", // kClassCacheJavaLangFloat "Ljava/lang/Integer;", // kClassCacheJavaLangInteger @@ -148,10 +165,10 @@ const char* const DexFileMethodInliner::kClassCacheNames[] = { "Ljava/lang/Math;", // kClassCacheJavaLangMath "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath "Ljava/lang/Thread;", // kClassCacheJavaLangThread + "Ljava/nio/charset/Charset;", // kClassCacheJavaNioCharsetCharset "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe "Ljava/lang/System;", // kClassCacheJavaLangSystem - "[C" // kClassCacheJavaLangCharArray }; const char* const DexFileMethodInliner::kNameCacheNames[] = { @@ -172,9 +189,14 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "getReferent", // kNameCacheReferenceGet "charAt", // kNameCacheCharAt "compareTo", // kNameCacheCompareTo + "getCharsNoCheck", // kNameCacheGetCharsNoCheck "isEmpty", // kNameCacheIsEmpty "indexOf", // kNameCacheIndexOf "length", // kNameCacheLength + "<init>", // kNameCacheInit + "newStringFromBytes", // kNameCacheNewStringFromBytes + "newStringFromChars", // kNameCacheNewStringFromChars + "newStringFromString", // kNameCacheNewStringFromString "currentThread", // kNameCacheCurrentThread "peekByte", // kNameCachePeekByte "peekIntNative", // kNameCachePeekIntNative @@ -282,7 +304,53 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { kClassCacheJavaLangObject } }, // kProtoCacheCharArrayICharArrayII_V { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt, - kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt}} + kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} }, + // kProtoCacheIICharArrayI_V + { kClassCacheVoid, 4, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray, + kClassCacheInt } }, + // kProtoCacheByteArrayIII_String + { kClassCacheJavaLangString, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, + kClassCacheInt } }, + // kProtoCacheIICharArray_String + { kClassCacheJavaLangString, 3, { kClassCacheInt, kClassCacheInt, + kClassCacheJavaLangCharArray } }, + // kProtoCacheString_String + { kClassCacheJavaLangString, 1, { kClassCacheJavaLangString } }, + // kProtoCache_V + { kClassCacheVoid, 0, { } }, + // kProtoCacheByteArray_V + { kClassCacheVoid, 1, { kClassCacheJavaLangByteArray } }, + // kProtoCacheByteArrayI_V + { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheInt } }, + // kProtoCacheByteArrayII_V + { kClassCacheVoid, 3, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt } }, + // kProtoCacheByteArrayIII_V + { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, + kClassCacheInt } }, + // kProtoCacheByteArrayIIString_V + { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, + kClassCacheJavaLangString } }, + // kProtoCacheByteArrayString_V + { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaLangString } }, + // kProtoCacheByteArrayIICharset_V + { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt, + kClassCacheJavaNioCharsetCharset } }, + // kProtoCacheByteArrayCharset_V + { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaNioCharsetCharset } }, + // kProtoCacheCharArray_V + { kClassCacheVoid, 1, { kClassCacheJavaLangCharArray } }, + // kProtoCacheCharArrayII_V + { kClassCacheVoid, 3, { kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt } }, + // kProtoCacheIICharArray_V + { kClassCacheVoid, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } }, + // kProtoCacheIntArrayII_V + { kClassCacheVoid, 3, { kClassCacheJavaLangIntArray, kClassCacheInt, kClassCacheInt } }, + // kProtoCacheString_V + { kClassCacheVoid, 1, { kClassCacheJavaLangString } }, + // kProtoCacheStringBuffer_V + { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuffer } }, + // kProtoCacheStringBuilder_V + { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuilder } }, }; const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = { @@ -343,6 +411,7 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), + INTRINSIC(JavaLangString, GetCharsNoCheck, IICharArrayI_V, kIntrinsicGetCharsNoCheck, 0), INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), @@ -386,8 +455,29 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray, 0), - #undef INTRINSIC + +#define SPECIAL(c, n, p, o, d) \ + { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineSpecial, { d } } } + + SPECIAL(JavaLangString, Init, _V, kInlineStringInit, 0), + SPECIAL(JavaLangString, Init, ByteArray_V, kInlineStringInit, 1), + SPECIAL(JavaLangString, Init, ByteArrayI_V, kInlineStringInit, 2), + SPECIAL(JavaLangString, Init, ByteArrayII_V, kInlineStringInit, 3), + SPECIAL(JavaLangString, Init, ByteArrayIII_V, kInlineStringInit, 4), + SPECIAL(JavaLangString, Init, ByteArrayIIString_V, kInlineStringInit, 5), + SPECIAL(JavaLangString, Init, ByteArrayString_V, kInlineStringInit, 6), + SPECIAL(JavaLangString, Init, ByteArrayIICharset_V, kInlineStringInit, 7), + SPECIAL(JavaLangString, Init, ByteArrayCharset_V, kInlineStringInit, 8), + SPECIAL(JavaLangString, Init, CharArray_V, kInlineStringInit, 9), + SPECIAL(JavaLangString, Init, CharArrayII_V, kInlineStringInit, 10), + SPECIAL(JavaLangString, Init, IICharArray_V, kInlineStringInit, 11), + SPECIAL(JavaLangString, Init, IntArrayII_V, kInlineStringInit, 12), + SPECIAL(JavaLangString, Init, String_V, kInlineStringInit, 13), + SPECIAL(JavaLangString, Init, StringBuffer_V, kInlineStringInit, 14), + SPECIAL(JavaLangString, Init, StringBuilder_V, kInlineStringInit, 15), + +#undef SPECIAL }; DexFileMethodInliner::DexFileMethodInliner() @@ -491,11 +581,19 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { return backend->GenInlinedCharAt(info); case kIntrinsicCompareTo: return backend->GenInlinedStringCompareTo(info); + case kIntrinsicGetCharsNoCheck: + return backend->GenInlinedStringGetCharsNoCheck(info); case kIntrinsicIsEmptyOrLength: return backend->GenInlinedStringIsEmptyOrLength( info, intrinsic.d.data & kIntrinsicFlagIsEmpty); case kIntrinsicIndexOf: return backend->GenInlinedIndexOf(info, intrinsic.d.data & kIntrinsicFlagBase0); + case kIntrinsicNewStringFromBytes: + return backend->GenInlinedStringFactoryNewStringFromBytes(info); + case kIntrinsicNewStringFromChars: + return backend->GenInlinedStringFactoryNewStringFromChars(info); + case kIntrinsicNewStringFromString: + return backend->GenInlinedStringFactoryNewStringFromString(info); case kIntrinsicCurrentThread: return backend->GenInlinedCurrentThread(info); case kIntrinsicPeek: @@ -574,6 +672,8 @@ bool DexFileMethodInliner::GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* i move_result = mir_graph->FindMoveResult(bb, invoke); result = GenInlineIPut(mir_graph, bb, invoke, move_result, method); break; + case kInlineStringInit: + return false; default: LOG(FATAL) << "Unexpected inline op: " << method.opcode; break; @@ -921,4 +1021,21 @@ bool DexFileMethodInliner::GenInlineIPut(MIRGraph* mir_graph, BasicBlock* bb, MI return true; } +uint32_t DexFileMethodInliner::GetOffsetForStringInit(uint32_t method_index, size_t pointer_size) { + ReaderMutexLock mu(Thread::Current(), lock_); + auto it = inline_methods_.find(method_index); + if (it != inline_methods_.end() && (it->second.opcode == kInlineStringInit)) { + uint32_t string_init_base_offset = Thread::QuickEntryPointOffsetWithSize( + OFFSETOF_MEMBER(QuickEntryPoints, pNewEmptyString), pointer_size); + return string_init_base_offset + it->second.d.data * pointer_size; + } + return 0; +} + +bool DexFileMethodInliner::IsStringInitMethodIndex(uint32_t method_index) { + ReaderMutexLock mu(Thread::Current(), lock_); + auto it = inline_methods_.find(method_index); + return (it != inline_methods_.end()) && (it->second.opcode == kInlineStringInit); +} + } // namespace art diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index d1e562119c..26b41bf54d 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -96,6 +96,17 @@ class DexFileMethodInliner { LOCKS_EXCLUDED(lock_); /** + * Gets the thread pointer entrypoint offset for a string init method index and pointer size. + */ + uint32_t GetOffsetForStringInit(uint32_t method_index, size_t pointer_size) + LOCKS_EXCLUDED(lock_); + + /** + * Check whether a particular method index is a string init. + */ + bool IsStringInitMethodIndex(uint32_t method_index) LOCKS_EXCLUDED(lock_); + + /** * To avoid multiple lookups of a class by its descriptor, we cache its * type index in the IndexCache. These are the indexes into the IndexCache * class_indexes array. @@ -111,9 +122,15 @@ class DexFileMethodInliner { kClassCacheFloat, kClassCacheDouble, kClassCacheVoid, + kClassCacheJavaLangByteArray, + kClassCacheJavaLangCharArray, + kClassCacheJavaLangIntArray, kClassCacheJavaLangObject, kClassCacheJavaLangRefReference, kClassCacheJavaLangString, + kClassCacheJavaLangStringBuffer, + kClassCacheJavaLangStringBuilder, + kClassCacheJavaLangStringFactory, kClassCacheJavaLangDouble, kClassCacheJavaLangFloat, kClassCacheJavaLangInteger, @@ -122,10 +139,10 @@ class DexFileMethodInliner { kClassCacheJavaLangMath, kClassCacheJavaLangStrictMath, kClassCacheJavaLangThread, + kClassCacheJavaNioCharsetCharset, kClassCacheLibcoreIoMemory, kClassCacheSunMiscUnsafe, kClassCacheJavaLangSystem, - kClassCacheJavaLangCharArray, kClassCacheLast }; @@ -153,9 +170,14 @@ class DexFileMethodInliner { kNameCacheReferenceGetReferent, kNameCacheCharAt, kNameCacheCompareTo, + kNameCacheGetCharsNoCheck, kNameCacheIsEmpty, kNameCacheIndexOf, kNameCacheLength, + kNameCacheInit, + kNameCacheNewStringFromBytes, + kNameCacheNewStringFromChars, + kNameCacheNewStringFromString, kNameCacheCurrentThread, kNameCachePeekByte, kNameCachePeekIntNative, @@ -230,6 +252,26 @@ class DexFileMethodInliner { kProtoCacheObjectJ_Object, kProtoCacheObjectJObject_V, kProtoCacheCharArrayICharArrayII_V, + kProtoCacheIICharArrayI_V, + kProtoCacheByteArrayIII_String, + kProtoCacheIICharArray_String, + kProtoCacheString_String, + kProtoCache_V, + kProtoCacheByteArray_V, + kProtoCacheByteArrayI_V, + kProtoCacheByteArrayII_V, + kProtoCacheByteArrayIII_V, + kProtoCacheByteArrayIIString_V, + kProtoCacheByteArrayString_V, + kProtoCacheByteArrayIICharset_V, + kProtoCacheByteArrayCharset_V, + kProtoCacheCharArray_V, + kProtoCacheCharArrayII_V, + kProtoCacheIICharArray_V, + kProtoCacheIntArrayII_V, + kProtoCacheString_V, + kProtoCacheStringBuffer_V, + kProtoCacheStringBuilder_V, kProtoCacheLast }; diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 1eb3a5f1b5..ab011fc0b2 100755 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -375,6 +375,18 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation( CallHelper(r_tgt, trampoline, safepoint_pc); } +void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocationRegLocation( + QuickEntrypointEnum trampoline, RegLocation arg0, RegLocation arg1, RegLocation arg2, + RegLocation arg3, bool safepoint_pc) { + RegStorage r_tgt = CallHelperSetup(trampoline); + LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0)); + LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1)); + LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); + LoadValueDirectFixed(arg3, TargetReg(kArg3, arg3)); + ClobberCallerSave(); + CallHelper(r_tgt, trampoline, safepoint_pc); +} + /* * If there are any ins passed in registers that have not been promoted * to a callee-save register, flush them to the frame. Perform initial @@ -966,14 +978,10 @@ bool Mir2Lir::GenInlinedReferenceGetReferent(CallInfo* info) { } bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { - // Location of reference to data array + // Location of char array data int value_offset = mirror::String::ValueOffset().Int32Value(); // Location of count int count_offset = mirror::String::CountOffset().Int32Value(); - // Starting offset within data array - int offset_offset = mirror::String::OffsetOffset().Int32Value(); - // Start of char data with array_ - int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value(); RegLocation rl_obj = info->args[0]; RegLocation rl_idx = info->args[1]; @@ -983,38 +991,21 @@ bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { GenNullCheck(rl_obj.reg, info->opt_flags); bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK)); LIR* range_check_branch = nullptr; - RegStorage reg_off; - RegStorage reg_ptr; - reg_off = AllocTemp(); - reg_ptr = AllocTempRef(); if (range_check) { reg_max = AllocTemp(); Load32Disp(rl_obj.reg, count_offset, reg_max); MarkPossibleNullPointerException(info->opt_flags); - } - Load32Disp(rl_obj.reg, offset_offset, reg_off); - MarkPossibleNullPointerException(info->opt_flags); - LoadRefDisp(rl_obj.reg, value_offset, reg_ptr, kNotVolatile); - if (range_check) { - // Set up a slow path to allow retry in case of bounds violation */ + // Set up a slow path to allow retry in case of bounds violation OpRegReg(kOpCmp, rl_idx.reg, reg_max); FreeTemp(reg_max); range_check_branch = OpCondBranch(kCondUge, nullptr); } - OpRegImm(kOpAdd, reg_ptr, data_offset); - if (rl_idx.is_const) { - OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg)); - } else { - OpRegReg(kOpAdd, reg_off, rl_idx.reg); - } + RegStorage reg_ptr = AllocTempRef(); + OpRegRegImm(kOpAdd, reg_ptr, rl_obj.reg, value_offset); FreeTemp(rl_obj.reg); - if (rl_idx.location == kLocPhysReg) { - FreeTemp(rl_idx.reg); - } RegLocation rl_dest = InlineTarget(info); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - LoadBaseIndexed(reg_ptr, reg_off, rl_result.reg, 1, kUnsignedHalf); - FreeTemp(reg_off); + LoadBaseIndexed(reg_ptr, rl_idx.reg, rl_result.reg, 1, kUnsignedHalf); FreeTemp(reg_ptr); StoreValue(rl_dest, rl_result); if (range_check) { @@ -1025,6 +1016,59 @@ bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { return true; } +bool Mir2Lir::GenInlinedStringGetCharsNoCheck(CallInfo* info) { + if (cu_->instruction_set == kMips) { + // TODO - add Mips implementation + return false; + } + size_t char_component_size = Primitive::ComponentSize(Primitive::kPrimChar); + // Location of data in char array buffer + int data_offset = mirror::Array::DataOffset(char_component_size).Int32Value(); + // Location of char array data in string + int value_offset = mirror::String::ValueOffset().Int32Value(); + + RegLocation rl_obj = info->args[0]; + RegLocation rl_start = info->args[1]; + RegLocation rl_end = info->args[2]; + RegLocation rl_buffer = info->args[3]; + RegLocation rl_index = info->args[4]; + + ClobberCallerSave(); + LockCallTemps(); // Using fixed registers + RegStorage reg_dst_ptr = TargetReg(kArg0, kRef); + RegStorage reg_src_ptr = TargetReg(kArg1, kRef); + RegStorage reg_length = TargetReg(kArg2, kNotWide); + RegStorage reg_tmp = TargetReg(kArg3, kNotWide); + RegStorage reg_tmp_ptr = RegStorage(RegStorage::k64BitSolo, reg_tmp.GetRawBits() & RegStorage::kRegTypeMask); + + LoadValueDirectFixed(rl_buffer, reg_dst_ptr); + OpRegImm(kOpAdd, reg_dst_ptr, data_offset); + LoadValueDirectFixed(rl_index, reg_tmp); + OpRegRegImm(kOpLsl, reg_tmp, reg_tmp, 1); + OpRegReg(kOpAdd, reg_dst_ptr, cu_->instruction_set == kArm64 ? reg_tmp_ptr : reg_tmp); + + LoadValueDirectFixed(rl_start, reg_tmp); + LoadValueDirectFixed(rl_end, reg_length); + OpRegReg(kOpSub, reg_length, reg_tmp); + OpRegRegImm(kOpLsl, reg_length, reg_length, 1); + LoadValueDirectFixed(rl_obj, reg_src_ptr); + + OpRegImm(kOpAdd, reg_src_ptr, value_offset); + OpRegRegImm(kOpLsl, reg_tmp, reg_tmp, 1); + OpRegReg(kOpAdd, reg_src_ptr, cu_->instruction_set == kArm64 ? reg_tmp_ptr : reg_tmp); + + RegStorage r_tgt; + if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) { + r_tgt = LoadHelper(kQuickMemcpy); + } else { + r_tgt = RegStorage::InvalidReg(); + } + // NOTE: not a safepoint + CallHelper(r_tgt, kQuickMemcpy, false, true); + + return true; +} + // Generates an inlined String.is_empty or String.length. bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) { if (cu_->instruction_set == kMips || cu_->instruction_set == kMips64) { @@ -1058,6 +1102,58 @@ bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) { return true; } +bool Mir2Lir::GenInlinedStringFactoryNewStringFromBytes(CallInfo* info) { + if (cu_->instruction_set == kMips) { + // TODO - add Mips implementation + return false; + } + RegLocation rl_data = info->args[0]; + RegLocation rl_high = info->args[1]; + RegLocation rl_offset = info->args[2]; + RegLocation rl_count = info->args[3]; + rl_data = LoadValue(rl_data, kRefReg); + LIR* data_null_check_branch = OpCmpImmBranch(kCondEq, rl_data.reg, 0, nullptr); + AddIntrinsicSlowPath(info, data_null_check_branch); + CallRuntimeHelperRegLocationRegLocationRegLocationRegLocation( + kQuickAllocStringFromBytes, rl_data, rl_high, rl_offset, rl_count, true); + RegLocation rl_return = GetReturn(kRefReg); + RegLocation rl_dest = InlineTarget(info); + StoreValue(rl_dest, rl_return); + return true; +} + +bool Mir2Lir::GenInlinedStringFactoryNewStringFromChars(CallInfo* info) { + if (cu_->instruction_set == kMips) { + // TODO - add Mips implementation + return false; + } + RegLocation rl_offset = info->args[0]; + RegLocation rl_count = info->args[1]; + RegLocation rl_data = info->args[2]; + CallRuntimeHelperRegLocationRegLocationRegLocation( + kQuickAllocStringFromChars, rl_offset, rl_count, rl_data, true); + RegLocation rl_return = GetReturn(kRefReg); + RegLocation rl_dest = InlineTarget(info); + StoreValue(rl_dest, rl_return); + return true; +} + +bool Mir2Lir::GenInlinedStringFactoryNewStringFromString(CallInfo* info) { + if (cu_->instruction_set == kMips) { + // TODO - add Mips implementation + return false; + } + RegLocation rl_string = info->args[0]; + rl_string = LoadValue(rl_string, kRefReg); + LIR* string_null_check_branch = OpCmpImmBranch(kCondEq, rl_string.reg, 0, nullptr); + AddIntrinsicSlowPath(info, string_null_check_branch); + CallRuntimeHelperRegLocation(kQuickAllocStringFromString, rl_string, true); + RegLocation rl_return = GetReturn(kRefReg); + RegLocation rl_dest = InlineTarget(info); + StoreValue(rl_dest, rl_return); + return true; +} + bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) { if (cu_->instruction_set == kMips || cu_->instruction_set == kMips64) { // TODO: add Mips and Mips64 implementations. @@ -1451,9 +1547,22 @@ void Mir2Lir::GenInvokeNoInline(CallInfo* info) { LockCallTemps(); const MirMethodLoweringInfo& method_info = mir_graph_->GetMethodLoweringInfo(info->mir); + MethodReference target_method = method_info.GetTargetMethod(); cu_->compiler_driver->ProcessedInvoke(method_info.GetInvokeType(), method_info.StatsFlags()); InvokeType original_type = static_cast<InvokeType>(method_info.GetInvokeType()); info->type = method_info.GetSharpType(); + bool is_string_init = false; + if (method_info.IsSpecial()) { + DexFileMethodInliner* inliner = cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner( + target_method.dex_file); + if (inliner->IsStringInitMethodIndex(target_method.dex_method_index)) { + is_string_init = true; + size_t pointer_size = GetInstructionSetPointerSize(cu_->instruction_set); + info->string_init_offset = inliner->GetOffsetForStringInit(target_method.dex_method_index, + pointer_size); + info->type = kStatic; + } + } bool fast_path = method_info.FastPath(); bool skip_this; @@ -1478,7 +1587,6 @@ void Mir2Lir::GenInvokeNoInline(CallInfo* info) { next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP; skip_this = fast_path; } - MethodReference target_method = method_info.GetTargetMethod(); call_state = GenDalvikArgs(info, call_state, p_null_ck, next_call_insn, target_method, method_info.VTableIndex(), method_info.DirectCode(), method_info.DirectMethod(), @@ -1495,7 +1603,7 @@ void Mir2Lir::GenInvokeNoInline(CallInfo* info) { FreeCallTemps(); if (info->result.location != kLocInvalid) { // We have a following MOVE_RESULT - do it now. - RegisterClass reg_class = + RegisterClass reg_class = is_string_init ? kRefReg : ShortyToRegClass(mir_graph_->GetShortyFromMethodReference(info->method_ref)[0]); if (info->result.wide) { RegLocation ret_loc = GetReturnWide(reg_class); diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index 39b9cc7056..3d253842c9 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -20,7 +20,9 @@ #include "base/logging.h" #include "dex/mir_graph.h" +#include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/quick/mir_to_lir-inl.h" +#include "driver/compiler_driver.h" #include "entrypoints/quick/quick_entrypoints.h" #include "gc/accounting/card_table.h" #include "mips_lir.h" @@ -397,11 +399,28 @@ void MipsMir2Lir::GenSpecialExitForSuspend() { * Bit of a hack here - in the absence of a real scheduling pass, * emit the next instruction in static & direct invoke sequences. */ -static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info ATTRIBUTE_UNUSED, int state, +static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t, uintptr_t direct_code, uintptr_t direct_method, InvokeType type) { Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); - if (direct_code != 0 && direct_method != 0) { + if (info->string_init_offset != 0) { + RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); + switch (state) { + case 0: { // Grab target method* from thread pointer + cg->LoadRefDisp(cg->TargetPtrReg(kSelf), info->string_init_offset, arg0_ref, kNotVolatile); + break; + } + case 1: // Grab the code from the method* + if (direct_code == 0) { + int32_t offset = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( + InstructionSetPointerSize(cu->instruction_set)).Int32Value(); + cg->LoadWordDisp(arg0_ref, offset, cg->TargetPtrReg(kInvokeTgt)); + } + break; + default: + return -1; + } + } else if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_code != static_cast<uintptr_t>(-1)) { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 6f227fcee3..a07274f17e 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -897,6 +897,10 @@ class Mir2Lir { RegLocation arg0, RegLocation arg1, RegLocation arg2, bool safepoint_pc); + void CallRuntimeHelperRegLocationRegLocationRegLocationRegLocation( + QuickEntrypointEnum trampoline, RegLocation arg0, RegLocation arg1, + RegLocation arg2, RegLocation arg3, bool safepoint_pc); + void GenInvoke(CallInfo* info); void GenInvokeNoInline(CallInfo* info); virtual NextCallInsn GetNextSDCallInsn() = 0; @@ -937,7 +941,11 @@ class Mir2Lir { bool GenInlinedReferenceGetReferent(CallInfo* info); virtual bool GenInlinedCharAt(CallInfo* info); + bool GenInlinedStringGetCharsNoCheck(CallInfo* info); bool GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty); + bool GenInlinedStringFactoryNewStringFromBytes(CallInfo* info); + bool GenInlinedStringFactoryNewStringFromChars(CallInfo* info); + bool GenInlinedStringFactoryNewStringFromString(CallInfo* info); virtual bool GenInlinedReverseBits(CallInfo* info, OpSize size); bool GenInlinedReverseBytes(CallInfo* info, OpSize size); virtual bool GenInlinedAbsInt(CallInfo* info); diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index e2364d8548..249575761e 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -19,6 +19,7 @@ #include "codegen_x86.h" #include "base/logging.h" +#include "dex/quick/dex_file_to_method_inliner_map.h" #include "dex/quick/mir_to_lir-inl.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" @@ -343,11 +344,20 @@ void X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) { int X86Mir2Lir::X86NextSDCallInsn(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, uint32_t, - uintptr_t direct_code, uintptr_t direct_method, + uintptr_t direct_code ATTRIBUTE_UNUSED, uintptr_t direct_method, InvokeType type) { - UNUSED(info, direct_code); X86Mir2Lir* cg = static_cast<X86Mir2Lir*>(cu->cg.get()); - if (direct_method != 0) { + if (info->string_init_offset != 0) { + RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); + switch (state) { + case 0: { // Grab target method* from thread pointer + cg->NewLIR2(kX86Mov32RT, arg0_ref.GetReg(), info->string_init_offset); + break; + } + default: + return -1; + } + } else if (direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_method != static_cast<uintptr_t>(-1)) { diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index b4603793b4..2f211da264 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -1302,10 +1302,6 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { int value_offset = mirror::String::ValueOffset().Int32Value(); // Location of count within the String object. int count_offset = mirror::String::CountOffset().Int32Value(); - // Starting offset within data array. - int offset_offset = mirror::String::OffsetOffset().Int32Value(); - // Start of char data with array_. - int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value(); // Compute the number of words to search in to rCX. Load32Disp(rs_rDX, count_offset, rs_rCX); @@ -1388,15 +1384,13 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { // Load the address of the string into EDI. // In case of start index we have to add the address to existing value in EDI. - // The string starts at VALUE(String) + 2 * OFFSET(String) + DATA_OFFSET. if (zero_based || (!zero_based && rl_start.is_const && start_value == 0)) { - Load32Disp(rs_rDX, offset_offset, rs_rDI); + OpRegRegImm(kOpAdd, rs_rDI, rs_rDX, value_offset); } else { - OpRegMem(kOpAdd, rs_rDI, rs_rDX, offset_offset); + OpRegImm(kOpLsl, rs_rDI, 1); + OpRegReg(kOpAdd, rs_rDI, rs_rDX); + OpRegImm(kOpAdd, rs_rDI, value_offset); } - OpRegImm(kOpLsl, rs_rDI, 1); - OpRegMem(kOpAdd, rs_rDI, rs_rDX, value_offset); - OpRegImm(kOpAdd, rs_rDI, data_offset); // EDI now contains the start of the string to be searched. // We are all prepared to do the search for the character. @@ -2423,24 +2417,15 @@ bool X86Mir2Lir::GenInlinedCharAt(CallInfo* info) { int value_offset = mirror::String::ValueOffset().Int32Value(); // Location of count int count_offset = mirror::String::CountOffset().Int32Value(); - // Starting offset within data array - int offset_offset = mirror::String::OffsetOffset().Int32Value(); - // Start of char data with array_ - int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value(); RegLocation rl_obj = info->args[0]; RegLocation rl_idx = info->args[1]; rl_obj = LoadValue(rl_obj, kRefReg); - // X86 wants to avoid putting a constant index into a register. - if (!rl_idx.is_const) { - rl_idx = LoadValue(rl_idx, kCoreReg); - } + rl_idx = LoadValue(rl_idx, kCoreReg); RegStorage reg_max; GenNullCheck(rl_obj.reg, info->opt_flags); bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK)); LIR* range_check_branch = nullptr; - RegStorage reg_off; - RegStorage reg_ptr; if (range_check) { // On x86, we can compare to memory directly // Set up a launch pad to allow retry in case of bounds violation */ @@ -2456,24 +2441,11 @@ bool X86Mir2Lir::GenInlinedCharAt(CallInfo* info) { range_check_branch = OpCondBranch(kCondUge, nullptr); } } - reg_off = AllocTemp(); - reg_ptr = AllocTempRef(); - Load32Disp(rl_obj.reg, offset_offset, reg_off); - LoadRefDisp(rl_obj.reg, value_offset, reg_ptr, kNotVolatile); - if (rl_idx.is_const) { - OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg)); - } else { - OpRegReg(kOpAdd, reg_off, rl_idx.reg); - } - FreeTemp(rl_obj.reg); - if (rl_idx.location == kLocPhysReg) { - FreeTemp(rl_idx.reg); - } RegLocation rl_dest = InlineTarget(info); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); - LoadBaseIndexedDisp(reg_ptr, reg_off, 1, data_offset, rl_result.reg, kUnsignedHalf); - FreeTemp(reg_off); - FreeTemp(reg_ptr); + LoadBaseIndexedDisp(rl_obj.reg, rl_idx.reg, 1, value_offset, rl_result.reg, kUnsignedHalf); + FreeTemp(rl_idx.reg); + FreeTemp(rl_obj.reg); StoreValue(rl_dest, rl_result); if (range_check) { DCHECK(range_check_branch != nullptr); diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc index 7eba515200..e788261ad0 100644 --- a/compiler/dex/verified_method.cc +++ b/compiler/dex/verified_method.cc @@ -64,6 +64,9 @@ const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_ve if (method_verifier->HasCheckCasts()) { verified_method->GenerateSafeCastSet(method_verifier); } + + verified_method->SetStringInitPcRegMap(method_verifier->GetStringInitPcRegMap()); + return verified_method.release(); } diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h index ad07639b1c..242e3dfe6e 100644 --- a/compiler/dex/verified_method.h +++ b/compiler/dex/verified_method.h @@ -75,6 +75,13 @@ class VerifiedMethod { return has_verification_failures_; } + void SetStringInitPcRegMap(SafeMap<uint32_t, std::set<uint32_t>>& string_init_pc_reg_map) { + string_init_pc_reg_map_ = string_init_pc_reg_map; + } + const SafeMap<uint32_t, std::set<uint32_t>>& GetStringInitPcRegMap() const { + return string_init_pc_reg_map_; + } + private: VerifiedMethod() = default; @@ -114,6 +121,10 @@ class VerifiedMethod { SafeCastSet safe_cast_set_; bool has_verification_failures_; + + // Copy of mapping generated by verifier of dex PCs of string init invocations + // to the set of other registers that the receiver has been copied into. + SafeMap<uint32_t, std::set<uint32_t>> string_init_pc_reg_map_; }; } // namespace art |