diff options
45 files changed, 468 insertions, 107 deletions
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 6ea21fc586..56facfd889 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -44,6 +44,8 @@ enum SpecialTargetRegister { kRet0, kRet1, kInvokeTgt, + kHiddenArg, + kHiddenFpArg, kCount }; diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 3395ae7a44..52aba9b4df 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -74,6 +74,8 @@ int ArmMir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rARM_RET0; break; case kRet1: res = rARM_RET1; break; case kInvokeTgt: res = rARM_INVOKE_TGT; break; + case kHiddenArg: res = r12; break; + case kHiddenFpArg: res = INVALID_REG; break; case kCount: res = rARM_COUNT; break; } return res; diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 62feadedcc..0a5fbb1f17 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -491,69 +491,56 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, } /* - * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline, - * which will locate the target and continue on via a tail call. + * Emit the next instruction in an invoke interface sequence. This will do a lookup in the + * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if + * more than one interface method map to the same index. Note also that we'll load the first + * argument ("this") into kArg1 here rather than the standard LoadArgRegs. */ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, - uint32_t unused, uintptr_t unused2, - uintptr_t direct_method, InvokeType unused4) { + uint32_t method_idx, uintptr_t unused, + uintptr_t direct_method, InvokeType unused2) { Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); - ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); - if (direct_method != 0) { - switch (state) { - case 0: // Load the trampoline target [sets kInvokeTgt]. - if (cu->instruction_set != kX86) { - cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), - cg->TargetReg(kInvokeTgt)); - } - // Get the interface Method* [sets kArg0] - if (direct_method != static_cast<unsigned int>(-1)) { - cg->LoadConstant(cg->TargetReg(kArg0), direct_method); - } else { - CHECK_EQ(cu->dex_file, target_method.dex_file); - LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, - target_method.dex_method_index, 0); - if (data_target == NULL) { - data_target = cg->AddWordData(&cg->method_literal_list_, - target_method.dex_method_index); - data_target->operands[1] = kInterface; - } - LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target); - cg->AppendLIR(load_pc_rel); - DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast<void*>(data_target); - } - break; - default: - return -1; + switch (state) { + case 0: // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)] + CHECK_EQ(cu->dex_file, target_method.dex_file); + CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); + cg->LoadConstant(cg->TargetReg(kHiddenArg), target_method.dex_method_index); + if (cu->instruction_set == kX86) { + cg->OpRegCopy(cg->TargetReg(kHiddenFpArg), cg->TargetReg(kHiddenArg)); + } + break; + case 1: { // Get "this" [set kArg1] + RegLocation rl_arg = info->args[0]; + cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1)); + break; } - } else { - switch (state) { - case 0: - // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted. - cg->LoadCurrMethodDirect(cg->TargetReg(kArg0)); - // Load the trampoline target [sets kInvokeTgt]. - if (cu->instruction_set != kX86) { - cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), - cg->TargetReg(kInvokeTgt)); - } - break; - case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0] - cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), - cg->TargetReg(kArg0)); + case 2: // Is "this" null? [use kArg1] + cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags); + // Get this->klass_ [use kArg1, set kInvokeTgt] + cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); break; - case 2: // Grab target method* [set/use kArg0] - CHECK_EQ(cu->dex_file, target_method.dex_file); - cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + - (target_method.dex_method_index * 4), + case 3: // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt] + cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); + break; + case 4: // Get target method [use kInvokeTgt, set kArg0] + cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) + + mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(), cg->TargetReg(kArg0)); break; + case 5: // Get the compiled code address [use kArg0, set kInvokeTgt] + if (cu->instruction_set != kX86) { + cg->LoadWordDisp(cg->TargetReg(kArg0), + mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); + break; + } + // Intentional fallthrough for X86 default: return -1; - } } return state + 1; } @@ -1390,11 +1377,8 @@ void Mir2Lir::GenInvoke(CallInfo* info) { &vtable_idx, &direct_code, &direct_method) && !SLOW_INVOKE_PATH; if (info->type == kInterface) { - if (fast_path) { - p_null_ck = &null_ck; - } next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck; - skip_this = false; + skip_this = fast_path; } else if (info->type == kDirect) { if (fast_path) { p_null_ck = &null_ck; @@ -1434,15 +1418,14 @@ void Mir2Lir::GenInvoke(CallInfo* info) { if (cu_->instruction_set != kX86) { call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt)); } else { - if (fast_path && info->type != kInterface) { + if (fast_path) { call_inst = OpMem(kOpBlx, TargetReg(kArg0), mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value()); } else { ThreadOffset trampoline(-1); switch (info->type) { case kInterface: - trampoline = fast_path ? QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline) - : QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); break; case kDirect: trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 0ee32d4d21..9c598e6bee 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -76,6 +76,8 @@ int MipsMir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rMIPS_RET0; break; case kRet1: res = rMIPS_RET1; break; case kInvokeTgt: res = rMIPS_INVOKE_TGT; break; + case kHiddenArg: res = r_T0; break; + case kHiddenFpArg: res = INVALID_REG; break; case kCount: res = rMIPS_COUNT; break; } return res; diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 901ac9e69d..878fa769b6 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -85,6 +85,8 @@ int X86Mir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rX86_RET0; break; case kRet1: res = rX86_RET1; break; case kInvokeTgt: res = rX86_INVOKE_TGT; break; + case kHiddenArg: res = rAX; break; + case kHiddenFpArg: res = fr0; break; case kCount: res = rX86_COUNT; break; } return res; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 91b0188b7b..053ea16fe8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -469,6 +469,11 @@ const std::vector<uint8_t>* CompilerDriver::CreateJniDlsymLookup() const { return CreateTrampoline(instruction_set_, kJniAbi, JNI_ENTRYPOINT_OFFSET(pDlsymLookup)); } +const std::vector<uint8_t>* CompilerDriver::CreatePortableImtConflictTrampoline() const { + return CreateTrampoline(instruction_set_, kPortableAbi, + PORTABLE_ENTRYPOINT_OFFSET(pPortableImtConflictTrampoline)); +} + const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const { return CreateTrampoline(instruction_set_, kPortableAbi, PORTABLE_ENTRYPOINT_OFFSET(pPortableResolutionTrampoline)); @@ -479,6 +484,11 @@ const std::vector<uint8_t>* CompilerDriver::CreatePortableToInterpreterBridge() PORTABLE_ENTRYPOINT_OFFSET(pPortableToInterpreterBridge)); } +const std::vector<uint8_t>* CompilerDriver::CreateQuickImtConflictTrampoline() const { + return CreateTrampoline(instruction_set_, kQuickAbi, + QUICK_ENTRYPOINT_OFFSET(pQuickImtConflictTrampoline)); +} + const std::vector<uint8_t>* CompilerDriver::CreateQuickResolutionTrampoline() const { return CreateTrampoline(instruction_set_, kQuickAbi, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampoline)); @@ -1080,7 +1090,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } use_dex_cache = true; } else { - if (sharp_type != kStatic && sharp_type != kDirect && sharp_type != kInterface) { + if (sharp_type != kStatic && sharp_type != kDirect) { return; } // TODO: support patching on all architectures. @@ -1101,9 +1111,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } } if (update_stats && method_code_in_boot) { - if (sharp_type != kInterface) { // Interfaces always go via a trampoline until we get IMTs. - stats_->DirectCallsToBoot(*type); - } + stats_->DirectCallsToBoot(*type); stats_->DirectMethodsToBoot(*type); } if (!use_dex_cache && compiling_boot) { @@ -1145,19 +1153,15 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType if (compiling_boot) { *type = sharp_type; *direct_method = -1; - if (sharp_type != kInterface) { - *direct_code = -1; - } + *direct_code = -1; } else { bool method_in_image = Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); if (method_in_image) { - CHECK_EQ(method->IsAbstract(), sharp_type == kInterface); + CHECK(!method->IsAbstract()); *type = sharp_type; *direct_method = reinterpret_cast<uintptr_t>(method); - if (*type != kInterface) { - *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); - } + *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromCompiledCode()); target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); target_method->dex_method_index = method->GetDexMethodIndex(); } else if (!must_use_direct_pointers) { @@ -1187,6 +1191,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui if (resolved_method != NULL) { if (*invoke_type == kVirtual || *invoke_type == kSuper) { *vtable_idx = resolved_method->GetMethodIndex(); + } else if (*invoke_type == kInterface) { + *vtable_idx = resolved_method->GetDexMethodIndex(); } // 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. diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 971021f903..c79175394a 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -130,10 +130,14 @@ class CompilerDriver { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector<uint8_t>* CreateJniDlsymLookup() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<uint8_t>* CreatePortableImtConflictTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector<uint8_t>* CreatePortableToInterpreterBridge() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<uint8_t>* CreateQuickImtConflictTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector<uint8_t>* CreateQuickToInterpreterBridge() const diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 871cfd5c41..af61bcc79a 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -98,11 +98,15 @@ bool ImageWriter::Write(const std::string& image_filename, jni_dlsym_lookup_offset_ = oat_file_->GetOatHeader().GetJniDlsymLookupOffset(); + portable_imt_conflict_trampoline_offset_ = + oat_file_->GetOatHeader().GetPortableImtConflictTrampolineOffset(); portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset(); portable_to_interpreter_bridge_offset_ = oat_file_->GetOatHeader().GetPortableToInterpreterBridgeOffset(); + quick_imt_conflict_trampoline_offset_ = + oat_file_->GetOatHeader().GetQuickImtConflictTrampolineOffset(); quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset(); quick_to_interpreter_bridge_offset_ = @@ -390,6 +394,8 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots() const { ObjectArray<Object>::Alloc(self, object_array_class, ImageHeader::kImageRootsMax)); image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod()); + image_roots->Set(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod()); + image_roots->Set(ImageHeader::kDefaultImt, runtime->GetDefaultImt()); image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod(Runtime::kSaveAll)); image_roots->Set(ImageHeader::kRefsOnlySaveMethod, @@ -527,6 +533,12 @@ void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { #else copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); #endif + } else if (UNLIKELY(orig == Runtime::Current()->GetImtConflictMethod())) { +#if defined(ART_USE_PORTABLE_COMPILER) + copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_imt_conflict_trampoline_offset_)); +#else + copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_imt_conflict_trampoline_offset_)); +#endif } else { // We assume all methods have code. If they don't currently then we set them to the use the // resolution trampoline. Abstract methods never have code and so we need to make sure their diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 0d85f36a5b..0b408e85cc 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -40,7 +40,8 @@ class ImageWriter { explicit ImageWriter(const CompilerDriver& compiler_driver) : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL), oat_data_begin_(NULL), interpreter_to_interpreter_bridge_offset_(0), - interpreter_to_compiled_code_bridge_offset_(0), portable_resolution_trampoline_offset_(0), + interpreter_to_compiled_code_bridge_offset_(0), portable_imt_conflict_trampoline_offset_(0), + portable_resolution_trampoline_offset_(0), quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0) {} ~ImageWriter() {} @@ -204,8 +205,10 @@ class ImageWriter { uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; + uint32_t portable_imt_conflict_trampoline_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index af86743014..815bca5c5a 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -149,7 +149,7 @@ TEST_F(OatTest, WriteRead) { TEST_F(OatTest, OatHeaderSizeCheck) { // If this test is failing and you have to update these constants, // it is time to update OatHeader::kOatVersion - EXPECT_EQ(64U, sizeof(OatHeader)); + EXPECT_EQ(72U, sizeof(OatHeader)); EXPECT_EQ(28U, sizeof(OatMethodOffsets)); } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index f681d7da6f..28355bfc74 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -55,8 +55,10 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, size_interpreter_to_interpreter_bridge_(0), size_interpreter_to_compiled_code_bridge_(0), size_jni_dlsym_lookup_(0), + size_portable_imt_conflict_trampoline_(0), size_portable_resolution_trampoline_(0), size_portable_to_interpreter_bridge_(0), + size_quick_imt_conflict_trampoline_(0), size_quick_resolution_trampoline_(0), size_quick_to_interpreter_bridge_(0), size_trampoline_alignment_(0), @@ -229,8 +231,10 @@ size_t OatWriter::InitOatCode(size_t offset) { DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge); DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge); DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup); + DO_TRAMPOLINE(portable_imt_conflict_trampoline_, PortableImtConflictTrampoline); DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline); DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge); + DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline); DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline); DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge); @@ -239,8 +243,10 @@ size_t OatWriter::InitOatCode(size_t offset) { oat_header_->SetInterpreterToInterpreterBridgeOffset(0); oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); oat_header_->SetJniDlsymLookupOffset(0); + oat_header_->SetPortableImtConflictTrampolineOffset(0); oat_header_->SetPortableResolutionTrampolineOffset(0); oat_header_->SetPortableToInterpreterBridgeOffset(0); + oat_header_->SetQuickImtConflictTrampolineOffset(0); oat_header_->SetQuickResolutionTrampolineOffset(0); oat_header_->SetQuickToInterpreterBridgeOffset(0); } @@ -519,8 +525,10 @@ bool OatWriter::Write(OutputStream& out) { DO_STAT(size_interpreter_to_interpreter_bridge_); DO_STAT(size_interpreter_to_compiled_code_bridge_); DO_STAT(size_jni_dlsym_lookup_); + DO_STAT(size_portable_imt_conflict_trampoline_); DO_STAT(size_portable_resolution_trampoline_); DO_STAT(size_portable_to_interpreter_bridge_); + DO_STAT(size_quick_imt_conflict_trampoline_); DO_STAT(size_quick_resolution_trampoline_); DO_STAT(size_quick_to_interpreter_bridge_); DO_STAT(size_trampoline_alignment_); @@ -616,8 +624,10 @@ size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) { DO_TRAMPOLINE(interpreter_to_interpreter_bridge_); DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_); DO_TRAMPOLINE(jni_dlsym_lookup_); + DO_TRAMPOLINE(portable_imt_conflict_trampoline_); DO_TRAMPOLINE(portable_resolution_trampoline_); DO_TRAMPOLINE(portable_to_interpreter_bridge_); + DO_TRAMPOLINE(quick_imt_conflict_trampoline_); DO_TRAMPOLINE(quick_resolution_trampoline_); DO_TRAMPOLINE(quick_to_interpreter_bridge_); #undef DO_TRAMPOLINE diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index e3cb0a86ed..5d947cfaea 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -226,8 +226,10 @@ class OatWriter { UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_bridge_; UniquePtr<const std::vector<uint8_t> > interpreter_to_compiled_code_bridge_; UniquePtr<const std::vector<uint8_t> > jni_dlsym_lookup_; + UniquePtr<const std::vector<uint8_t> > portable_imt_conflict_trampoline_; UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_; UniquePtr<const std::vector<uint8_t> > portable_to_interpreter_bridge_; + UniquePtr<const std::vector<uint8_t> > quick_imt_conflict_trampoline_; UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_; UniquePtr<const std::vector<uint8_t> > quick_to_interpreter_bridge_; @@ -240,8 +242,10 @@ class OatWriter { uint32_t size_interpreter_to_interpreter_bridge_; uint32_t size_interpreter_to_compiled_code_bridge_; uint32_t size_jni_dlsym_lookup_; + uint32_t size_portable_imt_conflict_trampoline_; uint32_t size_portable_resolution_trampoline_; uint32_t size_portable_to_interpreter_bridge_; + uint32_t size_quick_imt_conflict_trampoline_; uint32_t size_quick_resolution_trampoline_; uint32_t size_quick_to_interpreter_bridge_; uint32_t size_trampoline_alignment_; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index d8112ea708..1beb862267 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -345,10 +345,6 @@ class Dex2Oat { return false; } Runtime* runtime = Runtime::Current(); - // if we loaded an existing image, we will reuse values from the image roots. - if (!runtime->HasResolutionMethod()) { - runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); - } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); if (!runtime->HasCalleeSaveMethod(type)) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index fdeeaecd93..3a32ff14bd 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -86,6 +86,8 @@ static void usage() { const char* image_roots_descriptions_[] = { "kResolutionMethod", + "kImtConflictMethod", + "kDefaultImt", "kCalleeSaveMethod", "kRefsOnlySaveMethod", "kRefsAndArgsSaveMethod", @@ -1005,7 +1007,8 @@ class ImageDumper { indent_os << StringPrintf("OAT CODE: %p\n", oat_code); } } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || - method->IsResolutionMethod() || MethodHelper(method).IsClassInitializer()) { + method->IsResolutionMethod() || method->IsImtConflictMethod() || + MethodHelper(method).IsClassInitializer()) { DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); } else { diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 352982fc3a..3dac636df9 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -121,10 +121,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 736ce2fb24..808ff5b34f 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1040,6 +1040,18 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + ldr r0, [sp, #0] @ load caller Method* + ldr r0, [r0, #METHOD_DEX_CACHE_METHODS_OFFSET] @ load dex_cache_resolved_methods + add r0, #OBJECT_ARRAY_DATA_OFFSET @ get starting address of data + ldr r0, [r0, r12, lsl 2] @ load the target method + b art_quick_invoke_interface_trampoline +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index cc975d75a3..331a461354 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -122,10 +122,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 031d13a6b0..451b1bb30f 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -1060,6 +1060,21 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + GENERATE_GLOBAL_POINTER + lw $a0, 0($sp) # load caller Method* + lw $a0, METHOD_DEX_CACHE_METHODS_OFFSET($a0) # load dex_cache_resolved_methods + sll $t0, 2 # convert target method offset to bytes + add $a0, $t0 # get address of target method + lw $a0, OBJECT_ARRAY_DATA_OFFSET($a0) # load the target method + la $t9, art_quick_invoke_interface_trampoline + jr $t9 +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline GENERATE_GLOBAL_POINTER diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index 89dd1b8f8c..99b0dd548c 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -104,10 +104,10 @@ extern "C" int32_t art_quick_string_compareto(void*, void*); extern "C" void* art_quick_memcpy(void*, const void*, size_t); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -235,10 +235,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = art_quick_memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 805f6f4bd1..6a6891b331 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -997,6 +997,20 @@ DEFINE_FUNCTION art_quick_proxy_invoke_handler RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception END_FUNCTION art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. xmm0 is a hidden argument that holds the target method's + * dex method index. + */ +DEFINE_FUNCTION art_quick_imt_conflict_trampoline + PUSH ecx + movl 8(%esp), %eax // load caller Method* + movl METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax // load dex_cache_resolved_methods + movd %xmm0, %ecx // get target method index stored in xmm0 + movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax // load the target method + POP ecx + jmp art_quick_invoke_interface_trampoline +END_FUNCTION art_quick_imt_conflict_trampoline + DEFINE_FUNCTION art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME PUSH esp // pass SP diff --git a/runtime/asm_support.h b/runtime/asm_support.h index a6700bc2e4..e9bbf91761 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -38,7 +38,8 @@ #define STRING_OFFSET_OFFSET 20 #define STRING_DATA_OFFSET 12 -// Offset of field Method::entry_point_from_compiled_code_ +// Offsets within java.lang.Method. +#define METHOD_DEX_CACHE_METHODS_OFFSET 16 #define METHOD_CODE_OFFSET 40 #endif // ART_RUNTIME_ASM_SUPPORT_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 03f2c9df42..2fc564fbd5 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -196,7 +196,9 @@ ClassLinker::ClassLinker(InternTable* intern_table) class_table_dirty_(false), intern_table_(intern_table), portable_resolution_trampoline_(NULL), - quick_resolution_trampoline_(NULL) { + quick_resolution_trampoline_(NULL), + portable_imt_conflict_trampoline_(NULL), + quick_imt_conflict_trampoline_(NULL) { CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); } @@ -336,6 +338,12 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor + // Create runtime resolution and imt conflict methods. Also setup the default imt. + Runtime* runtime = Runtime::Current(); + runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); + runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod()); + runtime->SetDefaultImt(runtime->CreateDefaultImt(this)); + // Object, String and DexCache need to be rerun through FindSystemClass to finish init java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self); mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;"); @@ -1045,6 +1053,8 @@ void ClassLinker::InitFromImage() { CHECK(oat_file.GetOatHeader().GetImageFileLocation().empty()); portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline(); quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline(); + portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline(); + quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline(); mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); mirror::ObjectArray<mirror::DexCache>* dex_caches = dex_caches_object->AsObjectArray<mirror::DexCache>(); @@ -3518,6 +3528,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces) { + // Set the imt table to be all conflicts by default. + klass->SetImTable(Runtime::Current()->GetDefaultImt()); size_t super_ifcount; if (klass->HasSuperClass()) { super_ifcount = klass->GetSuperClass()->GetIfTableCount(); @@ -3625,6 +3637,13 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, if (klass->IsInterface()) { return true; } + // Allocate imtable + bool imtable_changed = false; + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, AllocArtMethodArray(self, kImtSize)); + if (UNLIKELY(imtable.get() == NULL)) { + CHECK(self->IsExceptionPending()); // OOME. + return false; + } std::vector<mirror::ArtMethod*> miranda_list; MethodHelper vtable_mh(NULL, this); MethodHelper interface_mh(NULL, this); @@ -3664,6 +3683,14 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, return false; } method_array->Set(j, vtable_method); + // Place method in imt if entry is empty, place conflict otherwise. + uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize; + if (imtable->Get(imt_index) == NULL) { + imtable->Set(imt_index, vtable_method); + imtable_changed = true; + } else { + imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod()); + } break; } } @@ -3695,6 +3722,16 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, } } } + if (imtable_changed) { + // Fill in empty entries in interface method table with conflict. + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < kImtSize; i++) { + if (imtable->Get(i) == NULL) { + imtable->Set(i, imt_conflict_method); + } + } + klass->SetImTable(imtable.get()); + } if (!miranda_list.empty()) { int old_method_count = klass->NumVirtualMethods(); int new_method_count = old_method_count + miranda_list.size(); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 0bc1b5f444..473370d90f 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -51,6 +51,11 @@ typedef bool (ClassVisitor)(mirror::Class* c, void* arg); class ClassLinker { public: + // Interface method table size. Increasing this value reduces the chance of two interface methods + // colliding in the interface method table but increases the size of classes that implement + // (non-marker) interfaces. + static constexpr size_t kImtSize = 64; + // Creates the class linker by bootstrapping from dex files. static ClassLinker* CreateFromCompiler(const std::vector<const DexFile*>& boot_class_path, InternTable* intern_table) @@ -340,6 +345,18 @@ class ClassLinker { return quick_resolution_trampoline_; } + const void* GetPortableImtConflictTrampoline() const { + return portable_imt_conflict_trampoline_; + } + + const void* GetQuickImtConflictTrampoline() const { + return quick_imt_conflict_trampoline_; + } + + InternTable* GetInternTable() const { + return intern_table_; + } + // Attempts to insert a class into a class table. Returns NULL if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. @@ -608,6 +625,8 @@ class ClassLinker { const void* portable_resolution_trampoline_; const void* quick_resolution_trampoline_; + const void* portable_imt_conflict_trampoline_; + const void* quick_imt_conflict_trampoline_; friend class ImageWriter; // for GetClassRoots FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 029b73e35f..a52b680260 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -497,6 +497,7 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, imtable_), "imTable")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass")); @@ -582,11 +583,11 @@ struct StringClassOffsets : public CheckOffsets<mirror::StringClass> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // alphabetical 64-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); - // alphabetical 32-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); + + // alphabetical 64-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); }; }; diff --git a/runtime/common_test.h b/runtime/common_test.h index 899eab1f63..673a03b355 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -329,9 +329,6 @@ class CommonTest : public testing::Test { CompilerBackend compiler_backend = kQuick; #endif - if (!runtime_->HasResolutionMethod()) { - runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod()); - } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); if (!runtime_->HasCalleeSaveMethod(type)) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 200860470d..7ce50c5dfb 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -372,14 +372,21 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror: return vtable->GetWithoutChecks(vtable_index); } case kInterface: { - mirror::ArtMethod* interface_method = - this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); - if (UNLIKELY(interface_method == nullptr)) { - ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, - referrer); - return nullptr; // Failure. + uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize; + mirror::ObjectArray<mirror::ArtMethod>* imt_table = this_object->GetClass()->GetImTable(); + mirror::ArtMethod* imt_method = imt_table->Get(imt_index); + if (!imt_method->IsImtConflictMethod()) { + return imt_method; } else { - return interface_method; + mirror::ArtMethod* interface_method = + this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); + if (UNLIKELY(interface_method == nullptr)) { + ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, + referrer); + return nullptr; // Failure. + } else { + return interface_method; + } } } default: @@ -665,6 +672,23 @@ static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { #endif } +static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetPortableImtConflictTrampoline(); +} + +static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetQuickImtConflictTrampoline(); +} + +// Return address of imt conflict trampoline stub for defined compiler. +static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) { +#if defined(ART_USE_PORTABLE_COMPILER) + return GetPortableImtConflictTrampoline(class_linker); +#else + return GetQuickImtConflictTrampoline(class_linker); +#endif +} + extern "C" void art_portable_proxy_invoke_handler(); static inline const void* GetPortableProxyInvokeHandler() { return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h index d4564471ac..dbea70735f 100644 --- a/runtime/entrypoints/portable/portable_entrypoints.h +++ b/runtime/entrypoints/portable/portable_entrypoints.h @@ -35,6 +35,7 @@ class Thread; // compiler ABI. struct PACKED(4) PortableEntryPoints { // Invocation + void (*pPortableImtConflictTrampoline)(mirror::ArtMethod*); void (*pPortableResolutionTrampoline)(mirror::ArtMethod*); void (*pPortableToInterpreterBridge)(mirror::ArtMethod*); }; diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index c8a85a0fe3..1ba206629e 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -118,10 +118,10 @@ struct PACKED(4) QuickEntryPoints { void* (*pMemcpy)(void*, const void*, size_t); // Invocation + void (*pQuickImtConflictTrampoline)(mirror::ArtMethod*); void (*pQuickResolutionTrampoline)(mirror::ArtMethod*); void (*pQuickToInterpreterBridge)(mirror::ArtMethod*); void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*); - void (*pInvokeInterfaceTrampoline)(uint32_t, void*); void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index fa28642c3e..e12ee063c0 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -241,6 +241,10 @@ ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file Runtime* runtime = Runtime::Current(); mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod); runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method)); + mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod); + runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method)); + mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt); + runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt)); mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod); runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll); diff --git a/runtime/image.h b/runtime/image.h index 2cb468fed1..246f106382 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -90,6 +90,8 @@ class PACKED(4) ImageHeader { enum ImageRoot { kResolutionMethod, + kImtConflictMethod, + kDefaultImt, kCalleeSaveMethod, kRefsOnlySaveMethod, kRefsAndArgsSaveMethod, diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index ccf3e59f18..c9bf1609a0 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -202,6 +202,13 @@ inline bool ArtMethod::IsResolutionMethod() const { DCHECK(!result || IsRuntimeMethod()); return result; } + +inline bool ArtMethod::IsImtConflictMethod() const { + bool result = this == Runtime::Current()->GetImtConflictMethod(); + // Check that if we do think it is phony it looks like the imt conflict method. + DCHECK(!result || IsRuntimeMethod()); + return result; +} } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 052089373d..f396fbe436 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -357,6 +357,8 @@ class MANAGED ArtMethod : public Object { bool IsResolutionMethod() const; + bool IsImtConflictMethod() const; + uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a native PC to a dex PC. diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index cd5e865c7c..7f3a302768 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -139,6 +139,14 @@ inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false); } +inline ObjectArray<ArtMethod>* Class::GetImTable() const { + return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false); +} + +inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) { + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false); +} + inline bool Class::Implements(const Class* klass) const { DCHECK(klass != NULL); DCHECK(klass->IsInterface()) << PrettyClass(this); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index d15f3375fd..ed1aad39d2 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -555,6 +555,15 @@ class MANAGED Class : public StaticStorageBase { return OFFSET_OF_OBJECT_MEMBER(Class, vtable_); } + ObjectArray<ArtMethod>* GetImTable() const; + + void SetImTable(ObjectArray<ArtMethod>* new_imtable) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static MemberOffset ImTableOffset() { + return OFFSET_OF_OBJECT_MEMBER(Class, imtable_); + } + // Given a method implemented by this class but potentially from a super class, return the // specific implementation method for this class. ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) const @@ -830,6 +839,9 @@ class MANAGED Class : public StaticStorageBase { // methods for the methods in the interface. IfTable* iftable_; + // Interface method table (imt), for quick "invoke-interface". + ObjectArray<ArtMethod>* imtable_; + // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName String* name_; @@ -912,6 +924,7 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: + int32_t pad_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 6c6d488f4a..d0d1ee4a46 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -84,6 +84,7 @@ TEST_F(ObjectTest, AsmConstants) { EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value()); EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value()); + EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value()); } diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 1879f04bef..01d8f318ff 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - int64_t serialVersionUID_; uint32_t REPLACEMENT_CHAR_; + int64_t serialVersionUID_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/oat.cc b/runtime/oat.cc index 6fe5d1097b..defda6bb1a 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -22,7 +22,7 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '8', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); @@ -60,8 +60,10 @@ OatHeader::OatHeader(InstructionSet instruction_set, interpreter_to_interpreter_bridge_offset_ = 0; interpreter_to_compiled_code_bridge_offset_ = 0; jni_dlsym_lookup_offset_ = 0; + portable_imt_conflict_trampoline_offset_ = 0; portable_resolution_trampoline_offset_ = 0; portable_to_interpreter_bridge_offset_ = 0; + quick_imt_conflict_trampoline_offset_ = 0; quick_resolution_trampoline_offset_ = 0; quick_to_interpreter_bridge_offset_ = 0; } @@ -171,18 +173,37 @@ void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) { UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset)); } +const void* OatHeader::GetPortableImtConflictTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_); + return portable_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + DCHECK(IsValid()); + DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset; + + portable_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset)); +} + const void* OatHeader::GetPortableResolutionTrampoline() const { return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset(); } uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const { DCHECK(IsValid()); - CHECK_GE(portable_resolution_trampoline_offset_, jni_dlsym_lookup_offset_); + CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_); return portable_resolution_trampoline_offset_; } void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset; @@ -209,18 +230,37 @@ void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) { UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset)); } +const void* OatHeader::GetQuickImtConflictTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_); + return quick_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + DCHECK(IsValid()); + DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset; + + quick_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset)); +} + const void* OatHeader::GetQuickResolutionTrampoline() const { return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset(); } uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const { DCHECK(IsValid()); - CHECK_GE(quick_resolution_trampoline_offset_, portable_to_interpreter_bridge_offset_); + CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_); return quick_resolution_trampoline_offset_; } void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset; diff --git a/runtime/oat.h b/runtime/oat.h index a9dc540c03..c864c2cc52 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -62,6 +62,9 @@ class PACKED(4) OatHeader { const void* GetPortableResolutionTrampoline() const; uint32_t GetPortableResolutionTrampolineOffset() const; void SetPortableResolutionTrampolineOffset(uint32_t offset); + const void* GetPortableImtConflictTrampoline() const; + uint32_t GetPortableImtConflictTrampolineOffset() const; + void SetPortableImtConflictTrampolineOffset(uint32_t offset); const void* GetPortableToInterpreterBridge() const; uint32_t GetPortableToInterpreterBridgeOffset() const; void SetPortableToInterpreterBridgeOffset(uint32_t offset); @@ -69,6 +72,9 @@ class PACKED(4) OatHeader { const void* GetQuickResolutionTrampoline() const; uint32_t GetQuickResolutionTrampolineOffset() const; void SetQuickResolutionTrampolineOffset(uint32_t offset); + const void* GetQuickImtConflictTrampoline() const; + uint32_t GetQuickImtConflictTrampolineOffset() const; + void SetQuickImtConflictTrampolineOffset(uint32_t offset); const void* GetQuickToInterpreterBridge() const; uint32_t GetQuickToInterpreterBridgeOffset() const; void SetQuickToInterpreterBridgeOffset(uint32_t offset); @@ -91,8 +97,10 @@ class PACKED(4) OatHeader { uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; + uint32_t portable_imt_conflict_trampoline_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 3ca3c0bcf3..bf25b810a9 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -458,6 +458,8 @@ class MethodHelper { Runtime* runtime = Runtime::Current(); if (method_ == runtime->GetResolutionMethod()) { return "<runtime internal resolution method>"; + } else if (method_ == runtime->GetImtConflictMethod()) { + return "<runtime internal imt conflict method>"; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) { return "<runtime internal callee-save all registers method>"; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f46b794387..34cf45b4c7 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -84,6 +84,8 @@ Runtime::Runtime() java_vm_(NULL), pre_allocated_OutOfMemoryError_(NULL), resolution_method_(NULL), + imt_conflict_method_(NULL), + default_imt_(NULL), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), shutting_down_(false), @@ -1175,6 +1177,10 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) { } resolution_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(resolution_method_, arg)); DCHECK(resolution_method_ != nullptr); + imt_conflict_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(imt_conflict_method_, arg)); + DCHECK(imt_conflict_method_ != nullptr); + default_imt_ = reinterpret_cast<mirror::ObjectArray<mirror::ArtMethod>*>(visitor(default_imt_, arg)); + DCHECK(default_imt_ != nullptr); for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { callee_save_methods_[i] = reinterpret_cast<mirror::ArtMethod*>( visitor(callee_save_methods_[i], arg)); @@ -1192,6 +1198,31 @@ void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool VisitNonConcurrentRoots(visitor, arg); } +mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* cl) { + Thread* self = Thread::Current(); + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64)); + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < 64; i++) { + imtable->Set(i, imt_conflict_method); + } + return imtable.get(); +} + +mirror::ArtMethod* Runtime::CreateImtConflictMethod() { + mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); + Thread* self = Thread::Current(); + SirtRef<mirror::ArtMethod> + method(self, down_cast<mirror::ArtMethod*>(method_class->AllocObject(self))); + method->SetDeclaringClass(method_class); + // TODO: use a special method for imt conflict method saves + method->SetDexMethodIndex(DexFile::kDexNoIndex); + // When compiling, the code pointer will get set later when the image is loaded. + Runtime* r = Runtime::Current(); + ClassLinker* cl = r->GetClassLinker(); + method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetImtConflictTrampoline(cl)); + return method.get(); +} + mirror::ArtMethod* Runtime::CreateResolutionMethod() { mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); Thread* self = Thread::Current(); diff --git a/runtime/runtime.h b/runtime/runtime.h index b6429b646d..51d9074d03 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -45,6 +45,7 @@ namespace gc { namespace mirror { class ArtMethod; class ClassLoader; + template<class T> class ObjectArray; template<class T> class PrimitiveArray; typedef PrimitiveArray<int8_t> ByteArray; class String; @@ -349,6 +350,39 @@ class Runtime { mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that calls into a trampoline for runtime imt conflicts + mirror::ArtMethod* GetImtConflictMethod() const { + CHECK(HasImtConflictMethod()); + return imt_conflict_method_; + } + + bool HasImtConflictMethod() const { + return imt_conflict_method_ != NULL; + } + + void SetImtConflictMethod(mirror::ArtMethod* method) { + imt_conflict_method_ = method; + } + + mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Returns an imt with every entry set to conflict, used as default imt for all classes. + mirror::ObjectArray<mirror::ArtMethod>* GetDefaultImt() const { + CHECK(HasDefaultImt()); + return default_imt_; + } + + bool HasDefaultImt() const { + return default_imt_ != NULL; + } + + void SetDefaultImt(mirror::ObjectArray<mirror::ArtMethod>* imt) { + default_imt_ = imt; + } + + mirror::ObjectArray<mirror::ArtMethod>* CreateDefaultImt(ClassLinker* cl) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that describes all callee saves being spilled to the stack. enum CalleeSaveType { kSaveAll, @@ -485,6 +519,10 @@ class Runtime { mirror::ArtMethod* resolution_method_; + mirror::ArtMethod* imt_conflict_method_; + + mirror::ObjectArray<mirror::ArtMethod>* default_imt_; + // A non-zero value indicates that a thread has been created but not yet initialized. Guarded by // the shutdown lock so that threads aren't born while we're shutting down. size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_); diff --git a/runtime/thread.cc b/runtime/thread.cc index 30636589cd..9751076235 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1555,6 +1555,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { INTERPRETER_ENTRY_POINT_INFO(pInterpreterToInterpreterBridge), INTERPRETER_ENTRY_POINT_INFO(pInterpreterToCompiledCodeBridge), JNI_ENTRY_POINT_INFO(pDlsymLookup), + PORTABLE_ENTRY_POINT_INFO(pPortableImtConflictTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pAllocArray), @@ -1617,10 +1618,10 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { QUICK_ENTRY_POINT_INFO(pMemcmp16), QUICK_ENTRY_POINT_INFO(pStringCompareTo), QUICK_ENTRY_POINT_INFO(pMemcpy), + QUICK_ENTRY_POINT_INFO(pQuickImtConflictTrampoline), QUICK_ENTRY_POINT_INFO(pQuickResolutionTrampoline), QUICK_ENTRY_POINT_INFO(pQuickToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), - QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck), diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 967f167f37..3d87ebc559 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -35,7 +35,7 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR] +[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] diff --git a/test/Android.mk b/test/Android.mk index cdd61f0eef..6d3a84a25f 100644 --- a/test/Android.mk +++ b/test/Android.mk @@ -44,6 +44,7 @@ TEST_OAT_DIRECTORIES := \ Main \ HelloWorld \ \ + InterfaceTest \ JniTest \ NativeAllocations \ ParallelGC \ diff --git a/test/InterfaceTest/InterfaceTest.java b/test/InterfaceTest/InterfaceTest.java new file mode 100644 index 0000000000..ed18eb3dc7 --- /dev/null +++ b/test/InterfaceTest/InterfaceTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Map; +import java.util.HashMap; + +class InterfaceTest { + + public static long test_virtual(HashMap map) { + Integer intobj = new Integer(0); + String s = "asdf"; + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + map.put(intobj, s); + } + long end = System.currentTimeMillis(); + return (end - start); + } + + public static long test_interface(Map map) { + Integer intobj = new Integer(0); + String s = "asdf"; + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + map.put(intobj, s); + } + long end = System.currentTimeMillis(); + return (end - start); + } + + public static void main(String[] args) { + HashMap hashmap = new HashMap(); + long elapsed = test_virtual(hashmap); + System.logI("virtual map put: " + elapsed); + hashmap.clear(); + + elapsed = test_interface(hashmap); + System.logI("interface map put: " + elapsed); + } +} |
