diff options
25 files changed, 348 insertions, 267 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index a392f829f6..4a724b109a 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -216,8 +216,8 @@ void DexCompiler::CompileInstanceFieldAccess(Instruction* inst, uint32_t field_idx = inst->VRegC_22c(); int field_offset; bool is_volatile; - bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, field_offset, - is_volatile, is_put); + bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put, + &field_offset, &is_volatile); if (fast_path && !is_volatile && IsUint(16, field_offset)) { VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) << " to " << Instruction::Name(new_opcode) @@ -246,11 +246,13 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, int vtable_idx; uintptr_t direct_code; uintptr_t direct_method; - bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, invoke_type, - target_method, vtable_idx, - direct_code, direct_method, - false); // TODO: support devirtualization. + const bool kEnableDevirtualization = false; + bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, + false, kEnableDevirtualization, + &invoke_type, + &target_method, &vtable_idx, + &direct_code, &direct_method); if (fast_path && original_invoke_type == invoke_type) { if (vtable_idx >= 0 && IsUint(16, vtable_idx)) { VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 3a73717a7b..be622762b4 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1221,10 +1221,10 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir) { uint32_t current_offset = static_cast<uint32_t>(current_offset_); bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset, - type, target_method, - vtable_idx, - direct_code, direct_method, - false) && + false, true, + &type, &target_method, + &vtable_idx, + &direct_code, &direct_method) && !(cu_->enable_debug & (1 << kDebugSlowInvokePath)); return (((type == kDirect) || (type == kStatic)) && fast_path && ((direct_code == 0) || (direct_method == 0))); diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index 90cec75039..7831cf6f7a 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -1972,7 +1972,7 @@ void MirConverter::MethodMIR2Bitcode() { ::llvm::OwningPtr< ::llvm::tool_output_file> out_file( new ::llvm::tool_output_file(fname.c_str(), errmsg, - ::llvm::sys::fs::F_Binary)); + ::llvm::raw_fd_ostream::F_Binary)); if (!errmsg.empty()) { LOG(ERROR) << "Failed to create bitcode output file: " << errmsg; diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 2dbe5f5c36..e0e198a50d 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -130,7 +130,7 @@ MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, int field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { return NULL; } @@ -155,7 +155,7 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, int field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { return NULL; } diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index e081c16bb5..dcb0a99d08 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -50,9 +50,9 @@ void Mir2Lir::MarkSafepointPC(LIR* inst) { DCHECK_EQ(safepoint_pc->def_mask, ENCODE_ALL); } -bool Mir2Lir::FastInstance(uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put) { +bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile) { return cu_->compiler_driver->ComputeInstanceFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, is_volatile, is_put); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), is_put, field_offset, is_volatile); } /* Convert an instruction to a NOP */ diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index f018c61819..aa45d98cf6 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -337,8 +337,8 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do bool is_volatile; bool is_referrers_class; bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, - is_referrers_class, is_volatile, true); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), true, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { DCHECK_GE(field_offset, 0); int rBase; @@ -423,8 +423,8 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, bool is_volatile; bool is_referrers_class; bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, - is_referrers_class, is_volatile, false); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), false, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { DCHECK_GE(field_offset, 0); int rBase; @@ -626,7 +626,7 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size, int field_offset; bool is_volatile; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { RegLocation rl_result; @@ -687,8 +687,7 @@ void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size, int field_offset; bool is_volatile; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, - true); + bool fast_path = FastInstance(field_idx, true, &field_offset, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { RegisterClass reg_class = oat_reg_class_by_size(size); DCHECK_GE(field_offset, 0); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 073b550d78..fa608183be 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1356,10 +1356,10 @@ void Mir2Lir::GenInvoke(CallInfo* info) { bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(), current_dalvik_offset_, - info->type, target_method, - vtable_idx, - direct_code, direct_method, - true) && !SLOW_INVOKE_PATH; + true, true, + &info->type, &target_method, + &vtable_idx, + &direct_code, &direct_method) && !SLOW_INVOKE_PATH; if (info->type == kInterface) { if (fast_path) { p_null_ck = &null_ck; diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index a37ebd173f..85d90c8657 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -250,7 +250,7 @@ class Mir2Lir : public Backend { virtual void Materialize(); virtual CompiledMethod* GetCompiledMethod(); void MarkSafepointPC(LIR* inst); - bool FastInstance(uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put); + bool FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile); void SetupResourceMasks(LIR* lir); void AssembleLIR(); void SetMemRefType(LIR* lir, bool is_load, int mem_type); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index cbd9020df4..8d521de72f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -355,7 +355,11 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet jni_compiler_(NULL), compiler_enable_auto_elf_loading_(NULL), compiler_get_method_code_addr_(NULL), - support_boot_image_fixup_(true) { + support_boot_image_fixup_(true), + dedupe_code_("dedupe code"), + dedupe_mapping_table_("dedupe mapping table"), + dedupe_vmap_table_("dedupe vmap table"), + dedupe_gc_map_("dedupe gc map") { CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key"); @@ -912,9 +916,9 @@ static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod(ScopedObjectA } static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit, - uint32_t method_idx, - InvokeType type) + const DexCompilationUnit* mUnit, + uint32_t method_idx, + InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()); @@ -923,11 +927,11 @@ static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjec } bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, bool& is_volatile, bool is_put) { + bool is_put, int* field_offset, bool* is_volatile) { ScopedObjectAccess soa(Thread::Current()); // Conservative defaults. - field_offset = -1; - is_volatile = true; + *field_offset = -1; + *is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && !resolved_field->IsStatic()) { @@ -954,8 +958,8 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() && fields_class != referrer_class; if (access_ok && !is_write_to_final_from_wrong_class) { - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedInstanceField(); return true; // Fast path. } @@ -970,15 +974,14 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi } bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, int& ssb_index, - bool& is_referrers_class, bool& is_volatile, - bool is_put) { + bool is_put, int* field_offset, int* ssb_index, + bool* is_referrers_class, bool* is_volatile) { ScopedObjectAccess soa(Thread::Current()); // Conservative defaults. - field_offset = -1; - ssb_index = -1; - is_referrers_class = false; - is_volatile = true; + *field_offset = -1; + *ssb_index = -1; + *is_referrers_class = false; + *is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && resolved_field->IsStatic()) { @@ -988,9 +991,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); if (fields_class == referrer_class) { - is_referrers_class = true; // implies no worrying about class initialization - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *is_referrers_class = true; // implies no worrying about class initialization + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedLocalStaticField(); return true; // fast path } else { @@ -1021,9 +1024,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila if (fields_class->GetDexCache() == dex_cache) { // common case where the dex cache of both the referrer and the field are the same, // no need to search the dex file - ssb_index = fields_class->GetDexTypeIndex(); - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *ssb_index = fields_class->GetDexTypeIndex(); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedStaticField(); return true; } @@ -1036,9 +1039,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id)); if (type_id != NULL) { // medium path, needs check of static storage base being initialized - ssb_index = mUnit->GetDexFile()->GetIndexForTypeId(*type_id); - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *ssb_index = mUnit->GetDexFile()->GetIndexForTypeId(*type_id); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedStaticField(); return true; } @@ -1058,15 +1061,15 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, mirror::ArtMethod* method, - uintptr_t& direct_code, - uintptr_t& direct_method, - bool update_stats) { + bool update_stats, + uintptr_t* direct_code, + uintptr_t* direct_method) { // For direct and static methods compute possible direct_code and direct_method values, ie // an address for the Method* being invoked and an address of the code for that Method*. // For interface calls compute a value for direct_method that is the interface method being // invoked, so this can be passed to the out-of-line runtime support code. - direct_code = 0; - direct_method = 0; + *direct_code = 0; + *direct_method = 0; if (compiler_backend_ == kPortable) { if (sharp_type != kStatic && sharp_type != kDirect) { return; @@ -1098,38 +1101,37 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s if (IsImageClass(mh.GetDeclaringClassDescriptor())) { // We can only branch directly to Methods that are resolved in the DexCache. // Otherwise we won't invoke the resolution trampoline. - direct_method = -1; - direct_code = -1; + *direct_method = -1; + *direct_code = -1; } } } else { if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) { - direct_method = reinterpret_cast<uintptr_t>(method); + *direct_method = reinterpret_cast<uintptr_t>(method); } - direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); } } bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - InvokeType& invoke_type, - MethodReference& target_method, - int& vtable_idx, - uintptr_t& direct_code, uintptr_t& direct_method, - bool update_stats) { + bool update_stats, bool enable_devirtualization, + InvokeType* invoke_type, MethodReference* target_method, + int* vtable_idx, uintptr_t* direct_code, + uintptr_t* direct_method) { ScopedObjectAccess soa(Thread::Current()); - vtable_idx = -1; - direct_code = 0; - direct_method = 0; + *vtable_idx = -1; + *direct_code = 0; + *direct_method = 0; mirror::ArtMethod* resolved_method = - ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index, - invoke_type); + ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method->dex_method_index, + *invoke_type); if (resolved_method != NULL) { // Don't try to fast-path if we don't understand the caller's class or this appears to be an // Incompatible Class Change Error. mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(), mUnit); - bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type); + bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); if (!referrer_class->CanAccess(methods_class) || @@ -1140,42 +1142,42 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // method public. Resort to the dex file to determine the correct class for the access // check. uint16_t class_idx = - target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_; - methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file, + target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_; + methods_class = mUnit->GetClassLinker()->ResolveType(*target_method->dex_file, class_idx, referrer_class); } if (referrer_class->CanAccess(methods_class) && referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) { - const bool kEnableFinalBasedSharpening = true; + const bool enableFinalBasedSharpening = enable_devirtualization; // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). bool can_sharpen_virtual_based_on_type = - (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); + (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of // the super class. - bool can_sharpen_super_based_on_type = (invoke_type == kSuper) && + bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) && (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() && (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method); - if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type || + if (enableFinalBasedSharpening && (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type)) { // Sharpen a virtual call into a direct call. The method_idx is into referrer's // dex cache, check that this resolved method is where we expect it. - CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) == + CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) == resolved_method) << PrettyMethod(resolved_method); if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); } - GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method, - direct_code, direct_method, update_stats); - invoke_type = kDirect; + GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, resolved_method, + update_stats, direct_code, direct_method); + *invoke_type = kDirect; return true; } - const bool kEnableVerifierBasedSharpening = true; - if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual || - invoke_type == kInterface)) { + const bool enableVerifierBasedSharpening = enable_devirtualization; + if (enableVerifierBasedSharpening && (*invoke_type == kVirtual || + *invoke_type == kInterface)) { // Did the verifier record a more precise invoke target based on its type information? const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex()); const MethodReference* devirt_map_target = @@ -1192,14 +1194,14 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui kVirtual); CHECK(called_method != NULL); CHECK(!called_method->IsAbstract()); - GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method, - direct_code, direct_method, update_stats); + GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, called_method, + update_stats, direct_code, direct_method); bool compiler_needs_dex_cache = (GetCompilerBackend() == kPortable) || (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || - (direct_code == 0) || (direct_code == static_cast<unsigned int>(-1)) || - (direct_method == 0) || (direct_method == static_cast<unsigned int>(-1)); - if ((devirt_map_target->dex_file != target_method.dex_file) && + (*direct_code == 0) || (*direct_code == static_cast<unsigned int>(-1)) || + (*direct_method == 0) || (*direct_method == static_cast<unsigned int>(-1)); + if ((devirt_map_target->dex_file != target_method->dex_file) && compiler_needs_dex_cache) { // We need to use the dex cache to find either the method or code, and the dex file // containing the method isn't the one expected for the target method. Try to find @@ -1209,7 +1211,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // TODO: quick only supports direct pointers with Thumb2. // TODO: the following should be factored into a common helper routine to find // one dex file's method within another. - const DexFile* dexfile = target_method.dex_file; + const DexFile* dexfile = target_method->dex_file; const DexFile* cm_dexfile = called_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); const DexFile::MethodId& cm_method_id = @@ -1235,12 +1237,13 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui *name, *sig); if (method_id != NULL) { if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); stats_->PreciseTypeDevirtualization(); } - target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id); - invoke_type = kDirect; + target_method->dex_method_index = + dexfile->GetIndexForMethodId(*method_id); + *invoke_type = kDirect; return true; } } @@ -1252,28 +1255,28 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // method in the referring method's dex cache/file. } else { if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); stats_->PreciseTypeDevirtualization(); } - target_method = *devirt_map_target; - invoke_type = kDirect; + *target_method = *devirt_map_target; + *invoke_type = kDirect; return true; } } } - if (invoke_type == kSuper) { + if (*invoke_type == kSuper) { // Unsharpened super calls are suspicious so go slow-path. } else { // Sharpening failed so generate a regular resolved method dispatch. if (update_stats) { - stats_->ResolvedMethod(invoke_type); + stats_->ResolvedMethod(*invoke_type); } - if (invoke_type == kVirtual || invoke_type == kSuper) { - vtable_idx = resolved_method->GetMethodIndex(); + if (*invoke_type == kVirtual || *invoke_type == kSuper) { + *vtable_idx = resolved_method->GetMethodIndex(); } - GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method, - direct_code, direct_method, update_stats); + GetCodeAndMethodForDirectCall(*invoke_type, *invoke_type, referrer_class, resolved_method, + update_stats, direct_code, direct_method); return true; } } @@ -1284,7 +1287,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui soa.Self()->ClearException(); } if (update_stats) { - stats_->UnresolvedMethod(invoke_type); + stats_->UnresolvedMethod(*invoke_type); } return false; // Incomplete knowledge needs slow path. } @@ -1585,13 +1588,11 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil if (IsImage()) { // For images we resolve all types, such as array, whereas for applications just those with // classdefs are resolved by ResolveClassFieldsAndMethods. - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str())); + timings.NewSplit("Resolve Types"); context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_); } - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str())); + timings.NewSplit("Resolve MethodsAndFields"); context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_); } @@ -1652,8 +1653,7 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str())); + timings.NewSplit("Verify Dex File"); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_); @@ -2150,8 +2150,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str())); + timings.NewSplit("InitializeNoClinit"); #ifndef NDEBUG // Sanity check blacklist descriptors. if (IsImage()) { @@ -2258,8 +2257,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str())); + timings.NewSplit("Compile Dex File"); ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index cd6b5fab02..b4ec0c134b 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -169,22 +169,23 @@ class CompilerDriver { LOCKS_EXCLUDED(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, - int& field_offset, bool& is_volatile, bool is_put) + bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, + int* field_offset, bool* is_volatile) LOCKS_EXCLUDED(Locks::mutator_lock_); // Can we fastpath static field access? Computes field's offset, volatility and whether the // field is within the referrer (which can avoid checking class initialization). - bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, int& ssb_index, - bool& is_referrers_class, bool& is_volatile, bool is_put) + bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, + int* field_offset, int* ssb_index, + bool* is_referrers_class, bool* is_volatile) LOCKS_EXCLUDED(Locks::mutator_lock_); // Can we fastpath a interface, super class or virtual method call? Computes method's vtable // index. bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - InvokeType& type, MethodReference& target_method, int& vtable_idx, - uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats) + bool update_stats, bool enable_devirtualization, + InvokeType* type, MethodReference* target_method, int* vtable_idx, + uintptr_t* direct_code, uintptr_t* direct_method) LOCKS_EXCLUDED(Locks::mutator_lock_); bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc); @@ -314,8 +315,8 @@ class CompilerDriver { void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, mirror::ArtMethod* method, - uintptr_t& direct_code, uintptr_t& direct_method, - bool update_stats) + bool update_stats, + uintptr_t* direct_code, uintptr_t* direct_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void PreCompile(jobject class_loader, const std::vector<const DexFile*>& dex_files, @@ -449,27 +450,40 @@ class CompilerDriver { class DedupeHashFunc { public: size_t operator()(const std::vector<uint8_t>& array) const { - // Take a random sample of bytes. + // For small arrays compute a hash using every byte. static const size_t kSmallArrayThreshold = 16; - static const size_t kRandomHashCount = 16; - size_t hash = 0; - if (array.size() < kSmallArrayThreshold) { - for (auto c : array) { - hash = hash * 54 + c; + size_t hash = 0x811c9dc5; + if (array.size() <= kSmallArrayThreshold) { + for (uint8_t b : array) { + hash = (hash * 16777619) ^ b; } } else { - for (size_t i = 0; i < kRandomHashCount; ++i) { + // For larger arrays use the 2 bytes at 6 bytes (the location of a push registers + // instruction field for quick generated code on ARM) and then select a number of other + // values at random. + static const size_t kRandomHashCount = 16; + for (size_t i = 0; i < 2; ++i) { + uint8_t b = array[i + 6]; + hash = (hash * 16777619) ^ b; + } + for (size_t i = 2; i < kRandomHashCount; ++i) { size_t r = i * 1103515245 + 12345; - hash = hash * 54 + array[r % array.size()]; + uint8_t b = array[r % array.size()]; + hash = (hash * 16777619) ^ b; } } + hash += hash << 13; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; return hash; } }; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc> dedupe_code_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc> dedupe_mapping_table_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc> dedupe_vmap_table_; - DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc> dedupe_gc_map_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_code_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_; + DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_; DISALLOW_COPY_AND_ASSIGN(CompilerDriver); }; diff --git a/compiler/jni/portable/jni_compiler.cc b/compiler/jni/portable/jni_compiler.cc index 43408a7d64..0c14346ad8 100644 --- a/compiler/jni/portable/jni_compiler.cc +++ b/compiler/jni/portable/jni_compiler.cc @@ -50,9 +50,9 @@ using ::art::llvm::runtime_support::JniMethodStartSynchronized; using ::art::llvm::runtime_support::RuntimeId; JniCompiler::JniCompiler(LlvmCompilationUnit* cunit, - CompilerDriver& driver, + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) - : cunit_(cunit), driver_(&driver), module_(cunit_->GetModule()), + : cunit_(cunit), driver_(driver), module_(cunit_->GetModule()), context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()), dex_compilation_unit_(dex_compilation_unit), func_(NULL), elf_func_idx_(0) { diff --git a/compiler/jni/portable/jni_compiler.h b/compiler/jni/portable/jni_compiler.h index d20c63bc1e..ffabfe61c2 100644 --- a/compiler/jni/portable/jni_compiler.h +++ b/compiler/jni/portable/jni_compiler.h @@ -54,7 +54,7 @@ class IRBuilder; class JniCompiler { public: JniCompiler(LlvmCompilationUnit* cunit, - CompilerDriver& driver, + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit); CompiledMethod* Compile(); @@ -67,7 +67,7 @@ class JniCompiler { private: LlvmCompilationUnit* cunit_; - CompilerDriver* driver_; + CompilerDriver* const driver_; ::llvm::Module* module_; ::llvm::LLVMContext* context_; diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index fd440d5bf0..83b0c75e04 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -164,7 +164,7 @@ CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) { UniquePtr<LlvmCompilationUnit> cunit(AllocateCompilationUnit()); UniquePtr<JniCompiler> jni_compiler( - new JniCompiler(cunit.get(), *compiler_driver_, dex_compilation_unit)); + new JniCompiler(cunit.get(), compiler_driver_, dex_compilation_unit)); return jni_compiler->Compile(); } diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index 4f6fa0a2df..b206a25f25 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -846,10 +846,10 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { uintptr_t direct_code = 0; uintptr_t direct_method = 0; bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, - invoke_type, target_method, - vtable_idx, - direct_code, direct_method, - true); + true, true, + &invoke_type, &target_method, + &vtable_idx, + &direct_code, &direct_method); // Load the method object llvm::Value* callee_method_object_addr = NULL; @@ -1630,7 +1630,7 @@ llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst, int field_offset; bool is_volatile; bool is_fast_path = driver_->ComputeInstanceFieldInfo( - field_idx, dex_compilation_unit_, field_offset, is_volatile, false); + field_idx, dex_compilation_unit_, false, &field_offset, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; @@ -1692,7 +1692,7 @@ void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst, int field_offset; bool is_volatile; bool is_fast_path = driver_->ComputeInstanceFieldInfo( - field_idx, dex_compilation_unit_, field_offset, is_volatile, true); + field_idx, dex_compilation_unit_, true, &field_offset, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; @@ -1897,8 +1897,8 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst, bool is_volatile; bool is_fast_path = driver_->ComputeStaticFieldInfo( - field_idx, dex_compilation_unit_, field_offset, ssb_index, - is_referrers_class, is_volatile, false); + field_idx, dex_compilation_unit_, false, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); llvm::Value* static_field_value; @@ -1981,8 +1981,8 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst, bool is_volatile; bool is_fast_path = driver_->ComputeStaticFieldInfo( - field_idx, dex_compilation_unit_, field_offset, ssb_index, - is_referrers_class, is_volatile, true); + field_idx, dex_compilation_unit_, true, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc index 139100bee9..aa439ccbae 100644 --- a/compiler/llvm/llvm_compilation_unit.cc +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -214,6 +214,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::llvm::TargetOptions target_options; target_options.FloatABIType = ::llvm::FloatABI::Soft; target_options.NoFramePointerElim = true; + target_options.NoFramePointerElimNonLeaf = true; target_options.UseSoftFloat = false; target_options.EnableFastISel = false; @@ -257,7 +258,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::llvm::OwningPtr< ::llvm::tool_output_file> out_file( new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg, - ::llvm::sys::fs::F_Binary)); + ::llvm::raw_fd_ostream::F_Binary)); if (!errmsg.empty()) { @@ -277,6 +278,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea // pm_builder.Inliner = ::llvm::createAlwaysInlinerPass(); // pm_builder.Inliner = ::llvm::createPartialInliningPass(); pm_builder.OptLevel = 3; + pm_builder.DisableSimplifyLibCalls = 1; pm_builder.DisableUnitAtATime = 1; pm_builder.populateFunctionPassManager(fpm); pm_builder.populateModulePassManager(pm); diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 74b5da9eff..9ed264288b 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -104,7 +104,7 @@ TEST_F(OatTest, WriteRead) { ASSERT_TRUE(oat_file.get() != NULL); const OatHeader& oat_header = oat_file->GetOatHeader(); ASSERT_TRUE(oat_header.IsValid()); - ASSERT_EQ(2U, oat_header.GetDexFileCount()); // core and conscrypt + ASSERT_EQ(1U, oat_header.GetDexFileCount()); // core ASSERT_EQ(42U, oat_header.GetImageFileLocationOatChecksum()); ASSERT_EQ(4096U, oat_header.GetImageFileLocationOatDataBegin()); ASSERT_EQ("lue.art", oat_header.GetImageFileLocation()); diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index f3d35d728c..53c1afa698 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -18,62 +18,65 @@ #define ART_COMPILER_UTILS_DEDUPE_SET_H_ #include <set> +#include <string> #include "base/mutex.h" #include "base/stl_util.h" namespace art { -// A simple data structure to handle hashed deduplication. Add is thread safe. -template <typename Key, typename HashType, typename HashFunc> +// A set of Keys that support a HashFunc returning HashType. Used to find duplicates of Key in the +// Add method. The data-structure is thread-safe through the use of internal locks, it also +// supports the lock being sharded. +template <typename Key, typename HashType, typename HashFunc, HashType kShard = 1> class DedupeSet { typedef std::pair<HashType, Key*> HashedKey; class Comparator { public: bool operator()(const HashedKey& a, const HashedKey& b) const { - if (a.first < b.first) return true; - if (a.first > b.first) return true; - return *a.second < *b.second; + if (a.first != b.first) { + return a.first < b.first; + } else { + return *a.second < *b.second; + } } }; - typedef std::set<HashedKey, Comparator> Keys; - public: - typedef typename Keys::iterator iterator; - typedef typename Keys::const_iterator const_iterator; - typedef typename Keys::size_type size_type; - typedef typename Keys::value_type value_type; - - iterator begin() { return keys_.begin(); } - const_iterator begin() const { return keys_.begin(); } - iterator end() { return keys_.end(); } - const_iterator end() const { return keys_.end(); } - Key* Add(Thread* self, const Key& key) { - HashType hash = HashFunc()(key); - HashedKey hashed_key(hash, const_cast<Key*>(&key)); - MutexLock lock(self, lock_); - auto it = keys_.find(hashed_key); - if (it != keys_.end()) { + HashType raw_hash = HashFunc()(key); + HashType shard_hash = raw_hash / kShard; + HashType shard_bin = raw_hash % kShard; + HashedKey hashed_key(shard_hash, const_cast<Key*>(&key)); + MutexLock lock(self, *lock_[shard_bin]); + auto it = keys_[shard_bin].find(hashed_key); + if (it != keys_[shard_bin].end()) { return it->second; } hashed_key.second = new Key(key); - keys_.insert(hashed_key); + keys_[shard_bin].insert(hashed_key); return hashed_key.second; } - DedupeSet() : lock_("dedupe lock") { + explicit DedupeSet(const char* set_name) { + for (HashType i = 0; i < kShard; ++i) { + lock_name_[i] = StringPrintf("%s lock %d", set_name, i); + lock_[i].reset(new Mutex(lock_name_[i].c_str())); + } } ~DedupeSet() { - STLDeleteValues(&keys_); + for (HashType i = 0; i < kShard; ++i) { + STLDeleteValues(&keys_[i]); + } } private: - Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - Keys keys_; + std::string lock_name_[kShard]; + UniquePtr<Mutex> lock_[kShard]; + std::set<HashedKey, Comparator> keys_[kShard]; + DISALLOW_COPY_AND_ASSIGN(DedupeSet); }; diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc index 9f5e292f53..03d8b961fa 100644 --- a/compiler/utils/dedupe_set_test.cc +++ b/compiler/utils/dedupe_set_test.cc @@ -38,7 +38,7 @@ class DedupeHashFunc { TEST_F(DedupeSetTest, Test) { Thread* self = Thread::Current(); typedef std::vector<uint8_t> ByteArray; - DedupeSet<ByteArray, size_t, DedupeHashFunc> deduplicator; + DedupeSet<ByteArray, size_t, DedupeHashFunc> deduplicator("test"); ByteArray* array1; { ByteArray test1; diff --git a/runtime/common_test.h b/runtime/common_test.h index dc1f5922d9..fe54d0341d 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -286,12 +286,7 @@ class CommonTest : public testing::Test { if (java_lang_dex_file_ == NULL) { LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "'\n"; } - conscrypt_file_ = DexFile::Open(GetConscryptFileName(), GetConscryptFileName()); - if (conscrypt_file_ == NULL) { - LOG(FATAL) << "Could not open .dex file '" << GetConscryptFileName() << "'\n"; - } boot_class_path_.push_back(java_lang_dex_file_); - boot_class_path_.push_back(conscrypt_file_); std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB)); std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB)); @@ -398,10 +393,6 @@ class CommonTest : public testing::Test { return GetDexFileName("core-libart"); } - std::string GetConscryptFileName() { - return GetDexFileName("conscrypt"); - } - std::string GetDexFileName(const std::string& jar_prefix) { if (IsHost()) { const char* host_dir = getenv("ANDROID_HOST_OUT"); @@ -520,7 +511,6 @@ class CommonTest : public testing::Test { std::string android_data_; std::string dalvik_cache_; const DexFile* java_lang_dex_file_; // owned by runtime_ - const DexFile* conscrypt_file_; // owned by runtime_ std::vector<const DexFile*> boot_class_path_; UniquePtr<Runtime> runtime_; // Owned by the runtime diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index 30b4dc7ef5..100f5a9b18 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -316,6 +316,28 @@ static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, } } +static void System_arraycopyCharUnchecked(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) { + ScopedObjectAccess soa(env); + DCHECK(javaSrc != NULL); + DCHECK(javaDst != NULL); + mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc); + mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst); + DCHECK(srcObject->IsArrayInstance()); + DCHECK(dstObject->IsArrayInstance()); + mirror::Array* srcArray = srcObject->AsArray(); + mirror::Array* dstArray = dstObject->AsArray(); + DCHECK(srcPos >= 0 && dstPos >= 0 && length >= 0 && + srcPos + length <= srcArray->GetLength() && dstPos + length <= dstArray->GetLength()); + DCHECK_EQ(srcArray->GetClass()->GetComponentType(), dstArray->GetClass()->GetComponentType()); + DCHECK(srcArray->GetClass()->GetComponentType()->IsPrimitive()); + DCHECK(dstArray->GetClass()->GetComponentType()->IsPrimitive()); + DCHECK_EQ(srcArray->GetClass()->GetComponentSize(), static_cast<size_t>(2)); + DCHECK_EQ(dstArray->GetClass()->GetComponentSize(), static_cast<size_t>(2)); + uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(2)); + const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(2)); + move16(dstBytes + dstPos * 2, srcBytes + srcPos * 2, length * 2); +} + static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) { ScopedObjectAccess soa(env); mirror::Object* o = soa.Decode<mirror::Object*>(javaObject); @@ -324,6 +346,7 @@ static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) { static JNINativeMethod gMethods[] = { NATIVE_METHOD(System, arraycopy, "(Ljava/lang/Object;ILjava/lang/Object;II)V"), + NATIVE_METHOD(System, arraycopyCharUnchecked, "([CI[CII)V"), NATIVE_METHOD(System, identityHashCode, "(Ljava/lang/Object;)I"), }; diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 34a0f73fdf..fa00c61017 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -1921,9 +1921,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { (instance_of_inst->VRegA_22c() != instance_of_inst->VRegB_22c())) { // Check that the we are not attempting conversion to interface types, // which is not done because of the multiple inheritance implications. + // Also don't change the type if it would result in an upcast. + const RegType& orig_type = work_line_->GetRegisterType(instance_of_inst->VRegB_22c()); const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c()); - if (!cast_type.IsUnresolvedTypes() && !cast_type.GetClass()->IsInterface()) { + if (!cast_type.IsUnresolvedTypes() && !cast_type.GetClass()->IsInterface() && + !cast_type.IsAssignableFrom(orig_type)) { RegisterLine* update_line = new RegisterLine(code_item_->registers_size_, this); if (inst->Opcode() == Instruction::IF_EQZ) { fallthrough_line.reset(update_line); diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index 25f840cc56..857acb8743 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -99,7 +99,7 @@ std::string PreciseConstType::Dump() const { } std::string BooleanType::Dump() const { - return "boolean"; + return "Boolean"; } std::string ConflictType::Dump() const { @@ -111,7 +111,7 @@ std::string ByteType::Dump() const { } std::string ShortType::Dump() const { - return "short"; + return "Short"; } std::string CharType::Dump() const { @@ -119,15 +119,15 @@ std::string CharType::Dump() const { } std::string FloatType::Dump() const { - return "float"; + return "Float"; } std::string LongLoType::Dump() const { - return "long (Low Half)"; + return "Long (Low Half)"; } std::string LongHiType::Dump() const { - return "long (High Half)"; + return "Long (High Half)"; } std::string DoubleLoType::Dump() const { @@ -461,7 +461,6 @@ std::string ImpreciseConstType::Dump() const { std::stringstream result; uint32_t val = ConstantValue(); if (val == 0) { - CHECK(IsPreciseConstant()); result << "Zero/null"; } else { result << "Imprecise "; diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h index 295e27198d..fc9e5c98f7 100644 --- a/runtime/verifier/reg_type_cache-inl.h +++ b/runtime/verifier/reg_type_cache-inl.h @@ -23,17 +23,6 @@ namespace art { namespace verifier { -template <class Type> -Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) { - mirror::Class* klass = NULL; - // Try loading the class from linker. - if (!descriptor.empty()) { - klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor.c_str()); - } - Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_); - RegTypeCache::primitive_count_++; - return entry; -} inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const { DCHECK_LT(id, entries_.size()); @@ -41,6 +30,16 @@ inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const DCHECK(result != NULL); return *result; } + +inline const ConstantType& RegTypeCache::FromCat1Const(int32_t value, bool precise) { + // We only expect 0 to be a precise constant. + DCHECK(value != 0 || precise); + if (precise && (value >= kMinSmallConstant) && (value <= kMaxSmallConstant)) { + return *small_precise_constants_[value - kMinSmallConstant]; + } + return FromCat1NonSmallConstant(value, precise); +} + } // namespace verifier } // namespace art #endif // ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_INL_H_ diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 2c18132c0b..ce465a415d 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -26,8 +26,8 @@ namespace art { namespace verifier { bool RegTypeCache::primitive_initialized_ = false; -uint16_t RegTypeCache::primitive_start_ = 0; uint16_t RegTypeCache::primitive_count_ = 0; +PreciseConstType* RegTypeCache::small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1]; static bool MatchingPrecisionForClass(RegType* entry, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -44,7 +44,7 @@ static bool MatchingPrecisionForClass(RegType* entry, bool precise) } } -void RegTypeCache::FillPrimitiveTypes() { +void RegTypeCache::FillPrimitiveAndSmallConstantTypes() { entries_.push_back(UndefinedType::GetInstance()); entries_.push_back(ConflictType::GetInstance()); entries_.push_back(BooleanType::GetInstance()); @@ -57,6 +57,11 @@ void RegTypeCache::FillPrimitiveTypes() { entries_.push_back(FloatType::GetInstance()); entries_.push_back(DoubleLoType::GetInstance()); entries_.push_back(DoubleHiType::GetInstance()); + for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { + int32_t i = value - kMinSmallConstant; + DCHECK_EQ(entries_.size(), small_precise_constants_[i]->GetId()); + entries_.push_back(small_precise_constants_[i]); + } DCHECK_EQ(entries_.size(), primitive_count_); } @@ -232,12 +237,12 @@ const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* kl RegTypeCache::~RegTypeCache() { CHECK_LE(primitive_count_, entries_.size()); // Delete only the non primitive types. - if (entries_.size() == kNumPrimitives) { - // All entries are primitive, nothing to delete. + if (entries_.size() == kNumPrimitivesAndSmallConstants) { + // All entries are from the global pool, nothing to delete. return; } std::vector<RegType*>::iterator non_primitive_begin = entries_.begin(); - std::advance(non_primitive_begin, kNumPrimitives); + std::advance(non_primitive_begin, kNumPrimitivesAndSmallConstants); STLDeleteContainerPointers(non_primitive_begin, entries_.end()); } @@ -255,12 +260,29 @@ void RegTypeCache::ShutDown() { FloatType::Destroy(); DoubleLoType::Destroy(); DoubleHiType::Destroy(); + for (uint16_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { + PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant]; + delete type; + } + RegTypeCache::primitive_initialized_ = false; RegTypeCache::primitive_count_ = 0; } } -void RegTypeCache::CreatePrimitiveTypes() { +template <class Type> +Type* RegTypeCache::CreatePrimitiveTypeInstance(const std::string& descriptor) { + mirror::Class* klass = NULL; + // Try loading the class from linker. + if (!descriptor.empty()) { + klass = art::Runtime::Current()->GetClassLinker()->FindSystemClass(descriptor.c_str()); + } + Type* entry = Type::CreateInstance(klass, descriptor, RegTypeCache::primitive_count_); + RegTypeCache::primitive_count_++; + return entry; +} + +void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() { CreatePrimitiveTypeInstance<UndefinedType>(""); CreatePrimitiveTypeInstance<ConflictType>(""); CreatePrimitiveTypeInstance<BooleanType>("Z"); @@ -273,6 +295,11 @@ void RegTypeCache::CreatePrimitiveTypes() { CreatePrimitiveTypeInstance<FloatType>("F"); CreatePrimitiveTypeInstance<DoubleLoType>("D"); CreatePrimitiveTypeInstance<DoubleHiType>("D"); + for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) { + PreciseConstType* type = new PreciseConstType(value, primitive_count_); + small_precise_constants_[value - kMinSmallConstant] = type; + primitive_count_++; + } } const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left, const RegType& right) { @@ -331,29 +358,28 @@ const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) { return *entry; } -const RegType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) { - RegType* entry = NULL; - RegType* cur_entry = NULL; +const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) { + UninitializedType* entry = NULL; const std::string& descriptor(type.GetDescriptor()); if (type.IsUnresolvedTypes()) { for (size_t i = primitive_count_; i < entries_.size(); i++) { - cur_entry = entries_[i]; + RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedAndUninitializedReference() && down_cast<UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc() == allocation_pc && (cur_entry->GetDescriptor() == descriptor)) { - return *cur_entry; + return *down_cast<UnresolvedUninitializedRefType*>(cur_entry); } } entry = new UnresolvedUninitializedRefType(descriptor, allocation_pc, entries_.size()); } else { mirror::Class* klass = type.GetClass(); for (size_t i = primitive_count_; i < entries_.size(); i++) { - cur_entry = entries_[i]; + RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedReference() && down_cast<UninitializedReferenceType*>(cur_entry) ->GetAllocationPc() == allocation_pc && cur_entry->GetClass() == klass) { - return *cur_entry; + return *down_cast<UninitializedReferenceType*>(cur_entry); } } entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size()); @@ -404,27 +430,33 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { return *entry; } -const RegType& RegTypeCache::ByteConstant() { - return FromCat1Const(std::numeric_limits<jbyte>::min(), false); +const ImpreciseConstType& RegTypeCache::ByteConstant() { + const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false); + DCHECK(result.IsImpreciseConstant()); + return *down_cast<const ImpreciseConstType*>(&result); } -const RegType& RegTypeCache::ShortConstant() { - return FromCat1Const(std::numeric_limits<jshort>::min(), false); +const ImpreciseConstType& RegTypeCache::ShortConstant() { + const ConstantType& result = FromCat1Const(std::numeric_limits<jshort>::min(), false); + DCHECK(result.IsImpreciseConstant()); + return *down_cast<const ImpreciseConstType*>(&result); } -const RegType& RegTypeCache::IntConstant() { - return FromCat1Const(std::numeric_limits<jint>::max(), false); +const ImpreciseConstType& RegTypeCache::IntConstant() { + const ConstantType& result = FromCat1Const(std::numeric_limits<jint>::max(), false); + DCHECK(result.IsImpreciseConstant()); + return *down_cast<const ImpreciseConstType*>(&result); } -const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) { - RegType* entry; +const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& type) { + UninitializedType* entry; const std::string& descriptor(type.GetDescriptor()); if (type.IsUnresolvedTypes()) { for (size_t i = primitive_count_; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsUnresolvedAndUninitializedThisReference() && cur_entry->GetDescriptor() == descriptor) { - return *cur_entry; + return *down_cast<UninitializedType*>(cur_entry); } } entry = new UnresolvedUninitializedThisRefType(descriptor, entries_.size()); @@ -433,7 +465,7 @@ const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) { for (size_t i = primitive_count_; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) { - return *cur_entry; + return *down_cast<UninitializedType*>(cur_entry); } } entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size()); @@ -442,16 +474,16 @@ const RegType& RegTypeCache::UninitializedThisArgument(const RegType& type) { return *entry; } -const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) { +const ConstantType& RegTypeCache::FromCat1NonSmallConstant(int32_t value, bool precise) { for (size_t i = primitive_count_; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->klass_ == NULL && cur_entry->IsConstant() && cur_entry->IsPreciseConstant() == precise && (down_cast<ConstantType*>(cur_entry))->ConstantValue() == value) { - return *cur_entry; + return *down_cast<ConstantType*>(cur_entry); } } - RegType* entry; + ConstantType* entry; if (precise) { entry = new PreciseConstType(value, entries_.size()); } else { @@ -461,15 +493,15 @@ const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) { return *entry; } -const RegType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) { +const ConstantType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) { for (size_t i = primitive_count_; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsConstantLo() && (cur_entry->IsPrecise() == precise) && (down_cast<ConstantType*>(cur_entry))->ConstantValueLo() == value) { - return *cur_entry; + return *down_cast<ConstantType*>(cur_entry); } } - RegType* entry; + ConstantType* entry; if (precise) { entry = new PreciseConstLoType(value, entries_.size()); } else { @@ -479,15 +511,15 @@ const RegType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) { return *entry; } -const RegType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { +const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { for (size_t i = primitive_count_; i < entries_.size(); i++) { RegType* cur_entry = entries_[i]; if (cur_entry->IsConstantHi() && (cur_entry->IsPrecise() == precise) && (down_cast<ConstantType*>(cur_entry))->ConstantValueHi() == value) { - return *cur_entry; + return *down_cast<ConstantType*>(cur_entry); } } - RegType* entry; + ConstantType* entry; if (precise) { entry = new PreciseConstHiType(value, entries_.size()); } else { diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index 77f58934da..a9f8bff784 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -35,19 +35,18 @@ namespace verifier { class RegType; -const size_t kNumPrimitives = 12; class RegTypeCache { public: explicit RegTypeCache(bool can_load_classes) : can_load_classes_(can_load_classes) { entries_.reserve(64); - FillPrimitiveTypes(); + FillPrimitiveAndSmallConstantTypes(); } ~RegTypeCache(); static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (!RegTypeCache::primitive_initialized_) { CHECK_EQ(RegTypeCache::primitive_count_, 0); - CreatePrimitiveTypes(); - CHECK_EQ(RegTypeCache::primitive_count_, kNumPrimitives); + CreatePrimitiveAndSmallConstantTypes(); + CHECK_EQ(RegTypeCache::primitive_count_, kNumPrimitivesAndSmallConstants); RegTypeCache::primitive_initialized_ = true; } } @@ -55,17 +54,13 @@ class RegTypeCache { const art::verifier::RegType& GetFromId(uint16_t id) const; const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - template <class Type> - static Type* CreatePrimitiveTypeInstance(const std::string& descriptor) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FillPrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& FromCat1Const(int32_t value, bool precise) + const ConstantType& FromCat1Const(int32_t value, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& FromCat2ConstLo(int32_t value, bool precise) + const ConstantType& FromCat2ConstLo(int32_t value, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& FromCat2ConstHi(int32_t value, bool precise) + const ConstantType& FromCat2ConstHi(int32_t value, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -129,34 +124,56 @@ class RegTypeCache { const RegType& JavaLangObject(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return From(NULL, "Ljava/lang/Object;", precise); } - const RegType& Uninitialized(const RegType& type, uint32_t allocation_pc) + const UninitializedType& Uninitialized(const RegType& type, uint32_t allocation_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Create an uninitialized 'this' argument for the given type. - const RegType& UninitializedThisArgument(const RegType& type) + const UninitializedType& UninitializedThisArgument(const RegType& type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& FromUninitialized(const RegType& uninit_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - const RegType& IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const ImpreciseConstType& ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const ImpreciseConstType& ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const ImpreciseConstType& IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& GetComponentType(const RegType& array, mirror::ClassLoader* loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& RegTypeFromPrimitiveType(Primitive::Type) const; private: - std::vector<RegType*> entries_; - static bool primitive_initialized_; - static uint16_t primitive_start_; - static uint16_t primitive_count_; - static void CreatePrimitiveTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Whether or not we're allowed to load classes. - const bool can_load_classes_; + void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ClearException(); bool MatchDescriptor(size_t idx, const char* descriptor, bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + template <class Type> + static Type* CreatePrimitiveTypeInstance(const std::string& descriptor) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static void CreatePrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // The actual storage for the RegTypes. + std::vector<RegType*> entries_; + + // A quick look up for popular small constants. + static constexpr int32_t kMinSmallConstant = -1; + static constexpr int32_t kMaxSmallConstant = 4; + static PreciseConstType* small_precise_constants_[kMaxSmallConstant - kMinSmallConstant + 1]; + + static constexpr size_t kNumPrimitivesAndSmallConstants = + 12 + (kMaxSmallConstant - kMinSmallConstant + 1); + + // Have the well known global primitives been created? + static bool primitive_initialized_; + + // Number of well known primitives that will be copied into a RegTypeCache upon construction. + static uint16_t primitive_count_; + + // Whether or not we're allowed to load classes. + const bool can_load_classes_; + DISALLOW_COPY_AND_ASSIGN(RegTypeCache); }; |