diff options
130 files changed, 2146 insertions, 2498 deletions
@@ -93,9 +93,9 @@ include $(art_path)/jdwpspy/Android.mk include $(art_build_path)/Android.oat.mk # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES -ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-hostdex.jar +ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) -ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so +ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so ######################################################################## # test targets diff --git a/compiler/Android.mk b/compiler/Android.mk index b7dc9f6..a2419d5 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -23,7 +23,6 @@ LIBART_COMPILER_SRC_FILES := \ dex/local_value_numbering.cc \ dex/arena_allocator.cc \ dex/arena_bit_vector.cc \ - dex/quick/arm/arm_dex_file_method_inliner.cc \ dex/quick/arm/assemble_arm.cc \ dex/quick/arm/call_arm.cc \ dex/quick/arm/fp_arm.cc \ @@ -41,7 +40,6 @@ LIBART_COMPILER_SRC_FILES := \ dex/quick/mips/call_mips.cc \ dex/quick/mips/fp_mips.cc \ dex/quick/mips/int_mips.cc \ - dex/quick/mips/mips_dex_file_method_inliner.cc \ dex/quick/mips/target_mips.cc \ dex/quick/mips/utility_mips.cc \ dex/quick/mir_to_lir.cc \ @@ -52,7 +50,6 @@ LIBART_COMPILER_SRC_FILES := \ dex/quick/x86/int_x86.cc \ dex/quick/x86/target_x86.cc \ dex/quick/x86/utility_x86.cc \ - dex/quick/x86/x86_dex_file_method_inliner.cc \ dex/portable/mir_to_gbc.cc \ dex/dex_to_dex_compiler.cc \ dex/mir_dataflow.cc \ diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc index 95e44b3..132831c 100644 --- a/compiler/dex/arena_allocator.cc +++ b/compiler/dex/arena_allocator.cc @@ -28,6 +28,7 @@ namespace art { static constexpr bool kUseMemMap = false; static constexpr bool kUseMemSet = true && kUseMemMap; static constexpr size_t kValgrindRedZoneBytes = 8; +constexpr size_t Arena::kDefaultSize; static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = { "Misc ", diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 56facfd..d73f148 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -374,6 +374,7 @@ enum OpFeatureFlags { kRegUseA, kRegUseC, kRegUseD, + kRegUseB, kRegUseFPCSList0, kRegUseFPCSList2, kRegUseList0, diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index abafbc5..3368132 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -52,12 +52,6 @@ class DexCompiler { return *unit_.GetDexFile(); } - // TODO: since the whole compilation pipeline uses a "const DexFile", we need - // to "unconst" here. The DEX-to-DEX compiler should work on a non-const DexFile. - DexFile& GetModifiableDexFile() { - return *const_cast<DexFile*>(unit_.GetDexFile()); - } - bool PerformOptimizations() const { return dex_to_dex_compilation_level_ >= kOptimize; } diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 197bba5..6aabb2a 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -63,21 +63,21 @@ LLVMInfo::LLVMInfo() { LLVMInfo::~LLVMInfo() { } -QuickCompilerContext::QuickCompilerContext(CompilerDriver& compiler) - : inliner_map_(new DexFileToMethodInlinerMap(&compiler)) { +QuickCompilerContext::QuickCompilerContext() + : inliner_map_(new DexFileToMethodInlinerMap()) { } QuickCompilerContext::~QuickCompilerContext() { } -extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) { - CHECK(compiler.GetCompilerContext() == NULL); - compiler.SetCompilerContext(new QuickCompilerContext(compiler)); +extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) { + CHECK(driver.GetCompilerContext() == NULL); + driver.SetCompilerContext(new QuickCompilerContext()); } -extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) { - delete reinterpret_cast<QuickCompilerContext*>(compiler.GetCompilerContext()); - compiler.SetCompilerContext(NULL); +extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver) { + delete reinterpret_cast<QuickCompilerContext*>(driver.GetCompilerContext()); + driver.SetCompilerContext(NULL); } /* Default optimizer/debug setting for the compiler. */ diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index 4a863f5..bcb8bf0 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -115,7 +115,7 @@ class LLVMInfo { class QuickCompilerContext { public: - explicit QuickCompilerContext(CompilerDriver& compiler); + QuickCompilerContext(); ~QuickCompilerContext(); DexFileToMethodInlinerMap* GetInlinerMap() { diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 6353937..5d83991 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -923,11 +923,11 @@ void MIRGraph::BasicBlockOptimization() { for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) { BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i])); } - } - } else { - PreOrderDfsIterator iter(this); - for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { - BasicBlockOpt(bb); + } else { + PreOrderDfsIterator iter(this); + for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) { + BasicBlockOpt(bb); + } } } if (cu_->enable_debug & (1 << kDebugDumpCFG)) { diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc b/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc deleted file mode 100644 index 59f7202..0000000 --- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "base/logging.h" -#include "base/macros.h" -#include "dex/compiler_enums.h" - -#include "arm_dex_file_method_inliner.h" - -namespace art { - -const DexFileMethodInliner::IntrinsicDef ArmDexFileMethodInliner::kIntrinsicMethods[] = { -#define INTRINSIC(c, n, p, o, d) \ - { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } } - - INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), - INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), - INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), - INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), - - INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord), - INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong), - INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), - - INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), - INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), - INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), - INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), - INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), - INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), - - INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), - INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), - INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), - INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), - INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), - INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), - - INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), - - INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), - INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord), - INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong), - INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), - INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), - INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord), - INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong), - INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), - - INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, - kIntrinsicFlagNone), - INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, - kIntrinsicFlagIsLong), - INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, - kIntrinsicFlagIsObject), - -#define UNSAFE_GET_PUT(type, code, type_flags) \ - INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - type_flags & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags), \ - INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsVolatile), \ - INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsOrdered) - - UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), - UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), - UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), -#undef UNSAFE_GET_PUT - -#undef INTRINSIC -}; - -ArmDexFileMethodInliner::ArmDexFileMethodInliner() { -} - -ArmDexFileMethodInliner::~ArmDexFileMethodInliner() { -} - -void ArmDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { - IndexCache cache; - DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods)); -} - -} // namespace art diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h b/compiler/dex/quick/arm/arm_dex_file_method_inliner.h deleted file mode 100644 index 3428391..0000000 --- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_ -#define ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_ - -#include "dex/quick/dex_file_method_inliner.h" - -namespace art { - -class ArmDexFileMethodInliner : public DexFileMethodInliner { - public: - ArmDexFileMethodInliner(); - ~ArmDexFileMethodInliner(); - - void FindIntrinsics(const DexFile* dex_file); - - private: - static const IntrinsicDef kIntrinsicMethods[]; -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_ diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 51aca85..23ea407 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -434,7 +434,7 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { rARM_LR); // Materialize a pointer to the fill data image NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec)); - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); } @@ -471,7 +471,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { // TODO: move to a slow path. // Go expensive route - artLockObjectFromCode(obj); LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); @@ -490,7 +490,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { OpIT(kCondNe, "T"); // Go expensive route - artLockObjectFromCode(self, obj); LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR); MarkSafepointPC(call_inst); GenMemBarrier(kLoadLoad); @@ -530,7 +530,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { // TODO: move to a slow path. // Go expensive route - artUnlockObjectFromCode(obj); LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx, rARM_LR); MarkSafepointPC(call_inst); @@ -549,7 +549,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { StoreWordDisp/*eq*/(r0, mirror::Object::MonitorOffset().Int32Value(), r3); // Go expensive route - UnlockObjectFromCode(obj); LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR); MarkSafepointPC(call_inst); GenMemBarrier(kStoreLoad); diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index de3223a..25ddc94 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -60,7 +60,7 @@ class ArmMir2Lir : public Mir2Lir { uint32_t FpRegMask(); uint64_t GetRegMaskCommon(int reg); void AdjustSpillMask(); - void ClobberCalleeSave(); + void ClobberCallerSave(); void FlushReg(int reg); void FlushRegWide(int reg1, int reg2); void FreeCallTemps(); diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc index 1575ece..dc2e0d0 100644 --- a/compiler/dex/quick/arm/fp_arm.cc +++ b/compiler/dex/quick/arm/fp_arm.cc @@ -315,7 +315,7 @@ bool ArmMir2Lir::GenInlinedSqrt(CallInfo* info) { S2d(rl_result.low_reg, rl_result.high_reg)); NewLIR0(kThumb2Fmstat); branch = NewLIR2(kThumbBCond, 0, kArmCondEq); - ClobberCalleeSave(); + ClobberCallerSave(); LockCallTemps(); // Using fixed registers int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt)); NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg)); diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 52aba9b..48c9af5 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -653,7 +653,7 @@ bool ArmMir2Lir::IsFpReg(int reg) { } /* Clobber all regs that might be used by an external C call */ -void ArmMir2Lir::ClobberCalleeSave() { +void ArmMir2Lir::ClobberCallerSave() { Clobber(r0); Clobber(r1); Clobber(r2); diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 4bc0b35..5d78ed5 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -24,6 +24,28 @@ namespace art { +namespace { + +/* Dump a mapping table */ +template <typename It> +void DumpMappingTable(const char* table_name, const char* descriptor, const char* name, + const Signature& signature, uint32_t size, It first) { + if (size != 0) { + std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, + descriptor, name, signature.ToString().c_str(), size)); + std::replace(line.begin(), line.end(), ';', '_'); + LOG(INFO) << line; + for (uint32_t i = 0; i != size; ++i) { + line = StringPrintf(" {0x%05x, 0x%04x},", first.NativePcOffset(), first.DexPc()); + ++first; + LOG(INFO) << line; + } + LOG(INFO) <<" };\n\n"; + } +} + +} // anonymous namespace + bool Mir2Lir::IsInexpensiveConstant(RegLocation rl_src) { bool res = false; if (rl_src.is_const) { @@ -251,23 +273,6 @@ void Mir2Lir::DumpPromotionMap() { } } -/* Dump a mapping table */ -void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor, - const char* name, const Signature& signature, - const std::vector<uint32_t>& v) { - if (v.size() > 0) { - std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, - descriptor, name, signature.ToString().c_str(), v.size())); - std::replace(line.begin(), line.end(), ';', '_'); - LOG(INFO) << line; - for (uint32_t i = 0; i < v.size(); i+=2) { - line = StringPrintf(" {0x%05x, 0x%04x},", v[i], v[i+1]); - LOG(INFO) << line; - } - LOG(INFO) <<" };\n\n"; - } -} - /* Dump instructions and constant pool contents */ void Mir2Lir::CodegenDump() { LOG(INFO) << "Dumping LIR insns for " @@ -302,8 +307,13 @@ void Mir2Lir::CodegenDump() { const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id)); // Dump mapping tables - DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_); - DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_); + if (!encoded_mapping_table_.empty()) { + MappingTable table(&encoded_mapping_table_[0]); + DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, + table.PcToDexSize(), table.PcToDexBegin()); + DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, + table.DexToPcSize(), table.DexToPcBegin()); + } } /* @@ -522,79 +532,128 @@ static int AssignLiteralPointerOffsetCommon(LIR* lir, CodeOffset offset) { // Make sure we have a code address for every declared catch entry bool Mir2Lir::VerifyCatchEntries() { + MappingTable table(&encoded_mapping_table_[0]); + std::vector<uint32_t> dex_pcs; + dex_pcs.reserve(table.DexToPcSize()); + for (auto it = table.DexToPcBegin(), end = table.DexToPcEnd(); it != end; ++it) { + dex_pcs.push_back(it.DexPc()); + } + // Sort dex_pcs, so that we can quickly check it against the ordered mir_graph_->catches_. + std::sort(dex_pcs.begin(), dex_pcs.end()); + bool success = true; - for (std::set<uint32_t>::const_iterator it = mir_graph_->catches_.begin(); - it != mir_graph_->catches_.end(); ++it) { - uint32_t dex_pc = *it; - bool found = false; - for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) { - if (dex_pc == dex2pc_mapping_table_[i+1]) { - found = true; - break; - } - } - if (!found) { - LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc; + auto it = dex_pcs.begin(), end = dex_pcs.end(); + for (uint32_t dex_pc : mir_graph_->catches_) { + while (it != end && *it < dex_pc) { + LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << *it; + ++it; success = false; } - } - // Now, try in the other direction - for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) { - uint32_t dex_pc = dex2pc_mapping_table_[i+1]; - if (mir_graph_->catches_.find(dex_pc) == mir_graph_->catches_.end()) { - LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << dex_pc; + if (it == end || *it > dex_pc) { + LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc; success = false; + } else { + ++it; } } if (!success) { LOG(INFO) << "Bad dex2pcMapping table in " << PrettyMethod(cu_->method_idx, *cu_->dex_file); LOG(INFO) << "Entries @ decode: " << mir_graph_->catches_.size() << ", Entries in table: " - << dex2pc_mapping_table_.size()/2; + << table.DexToPcSize(); } return success; } void Mir2Lir::CreateMappingTables() { + uint32_t pc2dex_data_size = 0u; + uint32_t pc2dex_entries = 0u; + uint32_t pc2dex_offset = 0u; + uint32_t pc2dex_dalvik_offset = 0u; + uint32_t dex2pc_data_size = 0u; + uint32_t dex2pc_entries = 0u; + uint32_t dex2pc_offset = 0u; + uint32_t dex2pc_dalvik_offset = 0u; for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { - pc2dex_mapping_table_.push_back(tgt_lir->offset); - pc2dex_mapping_table_.push_back(tgt_lir->dalvik_offset); + pc2dex_entries += 1; + DCHECK(pc2dex_offset <= tgt_lir->offset); + pc2dex_data_size += UnsignedLeb128Size(tgt_lir->offset - pc2dex_offset); + pc2dex_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) - + static_cast<int32_t>(pc2dex_dalvik_offset)); + pc2dex_offset = tgt_lir->offset; + pc2dex_dalvik_offset = tgt_lir->dalvik_offset; } if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) { - dex2pc_mapping_table_.push_back(tgt_lir->offset); - dex2pc_mapping_table_.push_back(tgt_lir->dalvik_offset); + dex2pc_entries += 1; + DCHECK(dex2pc_offset <= tgt_lir->offset); + dex2pc_data_size += UnsignedLeb128Size(tgt_lir->offset - dex2pc_offset); + dex2pc_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) - + static_cast<int32_t>(dex2pc_dalvik_offset)); + dex2pc_offset = tgt_lir->offset; + dex2pc_dalvik_offset = tgt_lir->dalvik_offset; } } - if (kIsDebugBuild) { - CHECK(VerifyCatchEntries()); + + uint32_t total_entries = pc2dex_entries + dex2pc_entries; + uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries); + uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size; + encoded_mapping_table_.resize(data_size); + uint8_t* write_pos = &encoded_mapping_table_[0]; + write_pos = EncodeUnsignedLeb128(write_pos, total_entries); + write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries); + DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), hdr_data_size); + uint8_t* write_pos2 = write_pos + pc2dex_data_size; + + pc2dex_offset = 0u; + pc2dex_dalvik_offset = 0u; + dex2pc_offset = 0u; + dex2pc_dalvik_offset = 0u; + for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { + if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { + DCHECK(pc2dex_offset <= tgt_lir->offset); + write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset); + write_pos = EncodeSignedLeb128(write_pos, static_cast<int32_t>(tgt_lir->dalvik_offset) - + static_cast<int32_t>(pc2dex_dalvik_offset)); + pc2dex_offset = tgt_lir->offset; + pc2dex_dalvik_offset = tgt_lir->dalvik_offset; + } + if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) { + DCHECK(dex2pc_offset <= tgt_lir->offset); + write_pos2 = EncodeUnsignedLeb128(write_pos2, tgt_lir->offset - dex2pc_offset); + write_pos2 = EncodeSignedLeb128(write_pos2, static_cast<int32_t>(tgt_lir->dalvik_offset) - + static_cast<int32_t>(dex2pc_dalvik_offset)); + dex2pc_offset = tgt_lir->offset; + dex2pc_dalvik_offset = tgt_lir->dalvik_offset; + } } - CHECK_EQ(pc2dex_mapping_table_.size() & 1, 0U); - CHECK_EQ(dex2pc_mapping_table_.size() & 1, 0U); - uint32_t total_entries = (pc2dex_mapping_table_.size() + dex2pc_mapping_table_.size()) / 2; - uint32_t pc2dex_entries = pc2dex_mapping_table_.size() / 2; - encoded_mapping_table_.PushBack(total_entries); - encoded_mapping_table_.PushBack(pc2dex_entries); - encoded_mapping_table_.InsertBack(pc2dex_mapping_table_.begin(), pc2dex_mapping_table_.end()); - encoded_mapping_table_.InsertBack(dex2pc_mapping_table_.begin(), dex2pc_mapping_table_.end()); + DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), + hdr_data_size + pc2dex_data_size); + DCHECK_EQ(static_cast<size_t>(write_pos2 - &encoded_mapping_table_[0]), data_size); + if (kIsDebugBuild) { + CHECK(VerifyCatchEntries()); + // Verify the encoded table holds the expected data. - MappingTable table(&encoded_mapping_table_.GetData()[0]); + MappingTable table(&encoded_mapping_table_[0]); CHECK_EQ(table.TotalSize(), total_entries); CHECK_EQ(table.PcToDexSize(), pc2dex_entries); - CHECK_EQ(table.DexToPcSize(), dex2pc_mapping_table_.size() / 2); - MappingTable::PcToDexIterator it = table.PcToDexBegin(); - for (uint32_t i = 0; i < pc2dex_mapping_table_.size(); ++i, ++it) { - CHECK_EQ(pc2dex_mapping_table_.at(i), it.NativePcOffset()); - ++i; - CHECK_EQ(pc2dex_mapping_table_.at(i), it.DexPc()); - } - MappingTable::DexToPcIterator it2 = table.DexToPcBegin(); - for (uint32_t i = 0; i < dex2pc_mapping_table_.size(); ++i, ++it2) { - CHECK_EQ(dex2pc_mapping_table_.at(i), it2.NativePcOffset()); - ++i; - CHECK_EQ(dex2pc_mapping_table_.at(i), it2.DexPc()); + auto it = table.PcToDexBegin(); + auto it2 = table.DexToPcBegin(); + for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { + if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { + CHECK_EQ(tgt_lir->offset, it.NativePcOffset()); + CHECK_EQ(tgt_lir->dalvik_offset, it.DexPc()); + ++it; + } + if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) { + CHECK_EQ(tgt_lir->offset, it2.NativePcOffset()); + CHECK_EQ(tgt_lir->dalvik_offset, it2.DexPc()); + ++it2; + } } + CHECK(it == table.PcToDexEnd()); + CHECK(it2 == table.DexToPcEnd()); } } @@ -677,25 +736,27 @@ class NativePcToReferenceMapBuilder { }; void Mir2Lir::CreateNativeGcMap() { - const std::vector<uint32_t>& mapping_table = pc2dex_mapping_table_; + DCHECK(!encoded_mapping_table_.empty()); + MappingTable mapping_table(&encoded_mapping_table_[0]); uint32_t max_native_offset = 0; - for (size_t i = 0; i < mapping_table.size(); i += 2) { - uint32_t native_offset = mapping_table[i + 0]; + for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) { + uint32_t native_offset = it.NativePcOffset(); if (native_offset > max_native_offset) { max_native_offset = native_offset; } } MethodReference method_ref(cu_->dex_file, cu_->method_idx); const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref); - verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4); + verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[0]); + DCHECK_EQ(gc_map_raw->size(), dex_gc_map.RawSize()); // Compute native offset to references size. NativePcToReferenceMapBuilder native_gc_map_builder(&native_gc_map_, - mapping_table.size() / 2, max_native_offset, - dex_gc_map.RegWidth()); + mapping_table.PcToDexSize(), + max_native_offset, dex_gc_map.RegWidth()); - for (size_t i = 0; i < mapping_table.size(); i += 2) { - uint32_t native_offset = mapping_table[i + 0]; - uint32_t dex_pc = mapping_table[i + 1]; + for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) { + uint32_t native_offset = it.NativePcOffset(); + uint32_t dex_pc = it.DexPc(); const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc; native_gc_map_builder.AddEntry(native_offset, references); @@ -986,15 +1047,15 @@ CompiledMethod* Mir2Lir::GetCompiledMethod() { for (uint32_t i = 0; i < fp_vmap_table_.size(); i++) { raw_vmap_table.push_back(fp_vmap_table_[i]); } - UnsignedLeb128EncodingVector vmap_encoder; + Leb128EncodingVector vmap_encoder; // Prefix the encoded data with its size. - vmap_encoder.PushBack(raw_vmap_table.size()); + vmap_encoder.PushBackUnsigned(raw_vmap_table.size()); for (uint16_t cur : raw_vmap_table) { - vmap_encoder.PushBack(cur); + vmap_encoder.PushBackUnsigned(cur); } CompiledMethod* result = new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_, - core_spill_mask_, fp_spill_mask_, encoded_mapping_table_.GetData(), + core_spill_mask_, fp_spill_mask_, encoded_mapping_table_, vmap_encoder.GetData(), native_gc_map_); return result; } diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 6c0328e..b21e37e 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -22,6 +22,7 @@ namespace art { +const uint32_t DexFileMethodInliner::kIndexUnresolved; const char* DexFileMethodInliner::kClassCacheNames[] = { "Z", // kClassCacheBoolean "B", // kClassCacheByte @@ -157,8 +158,74 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { kClassCacheJavaLangObject } }, }; -DexFileMethodInliner::~DexFileMethodInliner() { -} +const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = { +#define INTRINSIC(c, n, p, o, d) \ + { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } } + + INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), + INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), + INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), + INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), + + INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord), + INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong), + INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), + + INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), + INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), + INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), + INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), + INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), + INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), + INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), + INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), + INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), + INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), + + INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), + INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), + INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), + INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), + INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), + INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), + + INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), + + INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), + INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord), + INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong), + INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), + INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), + INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord), + INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong), + INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), + + INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, + kIntrinsicFlagNone), + INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, + kIntrinsicFlagIsLong), + INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, + kIntrinsicFlagIsObject), + +#define UNSAFE_GET_PUT(type, code, type_flags) \ + INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ + type_flags & ~kIntrinsicFlagIsObject), \ + INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ + (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ + INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ + type_flags), \ + INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ + type_flags | kIntrinsicFlagIsVolatile), \ + INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ + type_flags | kIntrinsicFlagIsOrdered) + + UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), + UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), + UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), +#undef UNSAFE_GET_PUT + +#undef INTRINSIC +}; DexFileMethodInliner::DexFileMethodInliner() : dex_file_(NULL) { @@ -170,6 +237,9 @@ DexFileMethodInliner::DexFileMethodInliner() COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames); } +DexFileMethodInliner::~DexFileMethodInliner() { +} + bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) const { return intrinsics_.find(method_index) != intrinsics_.end(); } @@ -333,15 +403,15 @@ DexFileMethodInliner::IndexCache::IndexCache() { std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved); } -void DexFileMethodInliner::DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache, - const IntrinsicDef* defs, uint32_t def_count) { +void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { DCHECK(dex_file != nullptr); DCHECK(dex_file_ == nullptr); - for (uint32_t i = 0u; i != def_count; ++i) { - uint32_t method_id = FindMethodIndex(dex_file, cache, defs[i].method_def); + IndexCache cache; + for (const IntrinsicDef& def : kIntrinsicMethods) { + uint32_t method_id = FindMethodIndex(dex_file, &cache, def.method_def); if (method_id != kIndexNotFound) { DCHECK(intrinsics_.find(method_id) == intrinsics_.end()); - intrinsics_[method_id] = defs[i].intrinsic; + intrinsics_[method_id] = def.intrinsic; } } dex_file_ = dex_file; diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index bc00513..948f4bb 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -89,12 +89,8 @@ struct Intrinsic { */ class DexFileMethodInliner { public: - virtual ~DexFileMethodInliner(); - - /** - * Find all known intrinsic methods in the dex_file and cache their indices. - */ - virtual void FindIntrinsics(const DexFile* dex_file) = 0; + DexFileMethodInliner(); + ~DexFileMethodInliner(); /** * Check whether a particular method index corresponds to an intrinsic function. @@ -103,15 +99,10 @@ class DexFileMethodInliner { /** * Generate code for an intrinsic function invocation. - * - * TODO: This should be target-specific. For the time being, - * it's shared since it dispatches everything to backend. */ bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const; - protected: - DexFileMethodInliner(); - + private: /** * To avoid multiple lookups of a class by its descriptor, we cache its * type index in the IndexCache. These are the indexes into the IndexCache @@ -290,6 +281,7 @@ class DexFileMethodInliner { static const char* kClassCacheNames[]; static const char* kNameCacheNames[]; static const ProtoDef kProtoCacheDefs[]; + static const IntrinsicDef kIntrinsicMethods[]; static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1); static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2); @@ -303,14 +295,22 @@ class DexFileMethodInliner { static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache, const MethodDef& method_def); - void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache, - const IntrinsicDef* defs, uint32_t def_count); + /** + * Find all known intrinsic methods in the dex_file and cache their indices. + * + * Only DexFileToMethodInlinerMap may call this function to initialize the inliner. + */ + void FindIntrinsics(const DexFile* dex_file); + + friend class DexFileToMethodInlinerMap; /* * Maps method indexes (for the particular DexFile) to Intrinsic defintions. */ std::map<uint32_t, Intrinsic> intrinsics_; const DexFile* dex_file_; + + DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner); }; } // namespace art diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc index 56a42bc..0107ed3 100644 --- a/compiler/dex/quick/dex_file_to_method_inliner_map.cc +++ b/compiler/dex/quick/dex_file_to_method_inliner_map.cc @@ -22,17 +22,13 @@ #include "base/mutex-inl.h" #include "base/logging.h" #include "driver/compiler_driver.h" -#include "dex/quick/arm/arm_dex_file_method_inliner.h" -#include "dex/quick/mips/mips_dex_file_method_inliner.h" -#include "dex/quick/x86/x86_dex_file_method_inliner.h" #include "dex_file_to_method_inliner_map.h" namespace art { -DexFileToMethodInlinerMap::DexFileToMethodInlinerMap(const CompilerDriver* compiler) - : compiler_(compiler), - mutex_("inline_helper_mutex") { +DexFileToMethodInlinerMap::DexFileToMethodInlinerMap() + : lock_("inline_helper_mutex") { } DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() { @@ -44,31 +40,19 @@ DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() { const DexFileMethodInliner& DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) { Thread* self = Thread::Current(); { - ReaderMutexLock lock(self, mutex_); + ReaderMutexLock lock(self, lock_); auto it = inliners_.find(dex_file); if (it != inliners_.end()) { return *it->second; } } - WriterMutexLock lock(self, mutex_); + WriterMutexLock lock(self, lock_); DexFileMethodInliner** inliner = &inliners_[dex_file]; // inserts new entry if not found if (*inliner) { return **inliner; } - switch (compiler_->GetInstructionSet()) { - case kThumb2: - *inliner = new ArmDexFileMethodInliner; - break; - case kX86: - *inliner = new X86DexFileMethodInliner; - break; - case kMips: - *inliner = new MipsDexFileMethodInliner; - break; - default: - LOG(FATAL) << "Unexpected instruction set: " << compiler_->GetInstructionSet(); - } + *inliner = new DexFileMethodInliner(); DCHECK(*inliner != nullptr); // TODO: per-dex file locking for the intrinsics container filling. (*inliner)->FindIntrinsics(dex_file); diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h index 77f2648..476f002 100644 --- a/compiler/dex/quick/dex_file_to_method_inliner_map.h +++ b/compiler/dex/quick/dex_file_to_method_inliner_map.h @@ -37,15 +37,16 @@ class DexFile; */ class DexFileToMethodInlinerMap { public: - explicit DexFileToMethodInlinerMap(const CompilerDriver* compiler); + DexFileToMethodInlinerMap(); ~DexFileToMethodInlinerMap(); - const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(mutex_); + const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(lock_); private: - const CompilerDriver* const compiler_; - ReaderWriterMutex mutex_; - std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(mutex_); + ReaderWriterMutex lock_; + std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(lock_); + + DISALLOW_COPY_AND_ASSIGN(DexFileToMethodInlinerMap); }; } // namespace art diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index df6493d..a426cc7 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -611,7 +611,7 @@ void Mir2Lir::HandleThrowLaunchPads() { default: LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0]; } - ClobberCalleeSave(); + ClobberCallerSave(); int r_tgt = CallHelperSetup(func_offset); CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */); } @@ -1026,7 +1026,7 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know } } // TODO: only clobber when type isn't final? - ClobberCalleeSave(); + ClobberCallerSave(); /* branch targets here */ LIR* target = NewLIR0(kPseudoTargetLabel); StoreValue(rl_dest, rl_result); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 469c577..e66d4ea 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -62,14 +62,14 @@ LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_p void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) { int r_tgt = CallHelperSetup(helper_offset); LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) { int r_tgt = CallHelperSetup(helper_offset); OpRegCopy(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -81,7 +81,7 @@ void Mir2Lir::CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocati } else { LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1)); } - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -90,7 +90,7 @@ void Mir2Lir::CallRuntimeHelperImmImm(ThreadOffset helper_offset, int arg0, int int r_tgt = CallHelperSetup(helper_offset); LoadConstant(TargetReg(kArg0), arg0); LoadConstant(TargetReg(kArg1), arg1); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -103,7 +103,7 @@ void Mir2Lir::CallRuntimeHelperImmRegLocation(ThreadOffset helper_offset, int ar LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2)); } LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -112,7 +112,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationImm(ThreadOffset helper_offset, RegLoc int r_tgt = CallHelperSetup(helper_offset); LoadValueDirectFixed(arg0, TargetReg(kArg0)); LoadConstant(TargetReg(kArg1), arg1); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -121,7 +121,7 @@ void Mir2Lir::CallRuntimeHelperImmReg(ThreadOffset helper_offset, int arg0, int int r_tgt = CallHelperSetup(helper_offset); OpRegCopy(TargetReg(kArg1), arg1); LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -130,7 +130,7 @@ void Mir2Lir::CallRuntimeHelperRegImm(ThreadOffset helper_offset, int arg0, int int r_tgt = CallHelperSetup(helper_offset); OpRegCopy(TargetReg(kArg0), arg0); LoadConstant(TargetReg(kArg1), arg1); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -138,7 +138,7 @@ void Mir2Lir::CallRuntimeHelperImmMethod(ThreadOffset helper_offset, int arg0, b int r_tgt = CallHelperSetup(helper_offset); LoadCurrMethodDirect(TargetReg(kArg1)); LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -168,7 +168,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(ThreadOffset helper_offset LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3)); } } - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -178,7 +178,7 @@ void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset helper_offset, int arg0, int DCHECK_NE(TargetReg(kArg0), arg1); // check copy into arg0 won't clobber arg1 OpRegCopy(TargetReg(kArg0), arg0); OpRegCopy(TargetReg(kArg1), arg1); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -189,7 +189,7 @@ void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset helper_offset, int arg0, i OpRegCopy(TargetReg(kArg0), arg0); OpRegCopy(TargetReg(kArg1), arg1); LoadConstant(TargetReg(kArg2), arg2); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -199,7 +199,7 @@ void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(ThreadOffset helper_offset, LoadValueDirectFixed(arg2, TargetReg(kArg2)); LoadCurrMethodDirect(TargetReg(kArg1)); LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -209,7 +209,7 @@ void Mir2Lir::CallRuntimeHelperImmMethodImm(ThreadOffset helper_offset, int arg0 LoadCurrMethodDirect(TargetReg(kArg1)); LoadConstant(TargetReg(kArg2), arg2); LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -225,7 +225,7 @@ void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(ThreadOffset helper_off LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3)); } LoadConstant(TargetReg(kArg0), arg0); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -240,7 +240,7 @@ void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation(ThreadOffset he LoadValueDirectFixed(arg1, TargetReg(kArg1)); DCHECK_EQ(arg1.wide, 0U); LoadValueDirectFixed(arg2, TargetReg(kArg2)); - ClobberCalleeSave(); + ClobberCallerSave(); CallHelper(r_tgt, helper_offset, safepoint_pc); } @@ -971,10 +971,17 @@ bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) { RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); if (size == kLong) { RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg); - int reg_tmp = AllocTemp(); - OpRegCopy(reg_tmp, rl_result.low_reg); + int r_i_low = rl_i.low_reg; + if (rl_i.low_reg == rl_result.low_reg) { + // First REV shall clobber rl_result.low_reg, save the value in a temp for the second REV. + r_i_low = AllocTemp(); + OpRegCopy(r_i_low, rl_i.low_reg); + } OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg); - OpRegReg(kOpRev, rl_result.high_reg, reg_tmp); + OpRegReg(kOpRev, rl_result.high_reg, r_i_low); + if (rl_i.low_reg == rl_result.low_reg) { + FreeTemp(r_i_low); + } StoreValueWide(rl_dest, rl_result); } else { DCHECK(size == kWord || size == kSignedHalf); @@ -1076,7 +1083,7 @@ bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { // TODO - add Mips implementation return false; } - ClobberCalleeSave(); + ClobberCallerSave(); LockCallTemps(); // Using fixed registers int reg_ptr = TargetReg(kArg0); int reg_char = TargetReg(kArg1); @@ -1119,7 +1126,7 @@ bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) { // TODO - add Mips implementation return false; } - ClobberCalleeSave(); + ClobberCallerSave(); LockCallTemps(); // Using fixed registers int reg_this = TargetReg(kArg0); int reg_cmp = TargetReg(kArg1); @@ -1334,7 +1341,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) { } MarkSafepointPC(call_inst); - ClobberCalleeSave(); + ClobberCallerSave(); if (info->result.location != kLocInvalid) { // We have a following MOVE_RESULT - do it now. if (info->result.wide) { diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index 18c8cf8..21d5563 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -253,7 +253,7 @@ void MipsMir2Lir::GenFillArrayData(DexOffset table_offset, RegLocation rl_src) { NewLIR4(kMipsDelta, rMIPS_ARG1, 0, WrapPointer(base_label), WrapPointer(tab_rec)); // And go... - ClobberCalleeSave(); + ClobberCallerSave(); LIR* call_inst = OpReg(kOpBlx, r_tgt); // ( array*, fill_data* ) MarkSafepointPC(call_inst); } diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 5dda445..450a44f 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -61,7 +61,7 @@ class MipsMir2Lir : public Mir2Lir { uint32_t FpRegMask(); uint64_t GetRegMaskCommon(int reg); void AdjustSpillMask(); - void ClobberCalleeSave(); + void ClobberCallerSave(); void FlushReg(int reg); void FlushRegWide(int reg1, int reg2); void FreeCallTemps(); diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc b/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc deleted file mode 100644 index 05d8ac8..0000000 --- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "base/logging.h" -#include "base/macros.h" -#include "dex/compiler_enums.h" - -#include "mips_dex_file_method_inliner.h" - -namespace art { - -const DexFileMethodInliner::IntrinsicDef MipsDexFileMethodInliner::kIntrinsicMethods[] = { -#define INTRINSIC(c, n, p, o, d) \ - { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } } - - // INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), - // INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), - // INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), - // INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), - - // INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord), - // INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong), - // INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), - - // INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), - // INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), - // INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), - // INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), - // INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - // INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - // INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - // INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - // INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), - // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), - - // INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), - // INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), - // INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), - // INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), - // INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), - // INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), - - INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), - - INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), - // INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord), - // INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong), - // INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), - INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), - // INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord), - // INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong), - // INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), - - // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, - // kIntrinsicFlagNone), - // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, - // kIntrinsicFlagIsLong), - // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, - // kIntrinsicFlagIsObject), - -#define UNSAFE_GET_PUT(type, code, type_flags) \ - INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - type_flags & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags), \ - INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsVolatile), \ - INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsOrdered) - - // UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), - // UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), - // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), -#undef UNSAFE_GET_PUT - -#undef INTRINSIC -}; - -MipsDexFileMethodInliner::MipsDexFileMethodInliner() { -} - -MipsDexFileMethodInliner::~MipsDexFileMethodInliner() { -} - -void MipsDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { - IndexCache cache; - DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods)); -} - -} // namespace art diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h b/compiler/dex/quick/mips/mips_dex_file_method_inliner.h deleted file mode 100644 index 8fe7ec7..0000000 --- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_ -#define ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_ - -#include "dex/quick/dex_file_method_inliner.h" - -namespace art { - -class MipsDexFileMethodInliner : public DexFileMethodInliner { - public: - MipsDexFileMethodInliner(); - ~MipsDexFileMethodInliner(); - - void FindIntrinsics(const DexFile* dex_file); - - private: - static const IntrinsicDef kIntrinsicMethods[]; -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_ diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 9c598e6..869706f 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -346,7 +346,7 @@ bool MipsMir2Lir::IsFpReg(int reg) { } /* Clobber all regs that might be used by an external C call */ -void MipsMir2Lir::ClobberCalleeSave() { +void MipsMir2Lir::ClobberCallerSave() { Clobber(r_ZERO); Clobber(r_AT); Clobber(r_V0); diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc index 2ba2c84..65c82c0 100644 --- a/compiler/dex/quick/mips/utility_mips.cc +++ b/compiler/dex/quick/mips/utility_mips.cc @@ -504,13 +504,13 @@ LIR* MipsMir2Lir::LoadBaseDispBody(int rBase, int displacement, int r_dest, } } else { if (pair) { - int r_tmp = AllocFreeTemp(); + int r_tmp = AllocTemp(); res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp); load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp); FreeTemp(r_tmp); } else { - int r_tmp = (rBase == r_dest) ? AllocFreeTemp() : r_dest; + int r_tmp = (rBase == r_dest) ? AllocTemp() : r_dest; res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement); load = NewLIR3(opcode, r_dest, 0, r_tmp); if (r_tmp != r_dest) diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index f8a2d03..2a54eb3 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -71,6 +71,7 @@ typedef uint32_t CodeOffset; // Native code offset in bytes. #define REG_USEA (1ULL << kRegUseA) #define REG_USEC (1ULL << kRegUseC) #define REG_USED (1ULL << kRegUseD) +#define REG_USEB (1ULL << kRegUseB) #define REG_USE_FPCS_LIST0 (1ULL << kRegUseFPCSList0) #define REG_USE_FPCS_LIST2 (1ULL << kRegUseFPCSList2) #define REG_USE_LIST0 (1ULL << kRegUseList0) @@ -341,9 +342,6 @@ class Mir2Lir : public Backend { bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); bool IsInexpensiveConstant(RegLocation rl_src); ConditionCode FlipComparisonOrder(ConditionCode before); - void DumpMappingTable(const char* table_name, const char* descriptor, - const char* name, const Signature& signature, - const std::vector<uint32_t>& v); void InstallLiteralPools(); void InstallSwitchTables(); void InstallFillArrayData(); @@ -624,7 +622,7 @@ class Mir2Lir : public Backend { virtual uint32_t FpRegMask() = 0; virtual uint64_t GetRegMaskCommon(int reg) = 0; virtual void AdjustSpillMask() = 0; - virtual void ClobberCalleeSave() = 0; + virtual void ClobberCallerSave() = 0; virtual void FlushReg(int reg) = 0; virtual void FlushRegWide(int reg1, int reg2) = 0; virtual void FreeCallTemps() = 0; @@ -792,17 +790,6 @@ class Mir2Lir : public Backend { GrowableArray<RegisterInfo*> tempreg_info_; GrowableArray<RegisterInfo*> reginfo_map_; GrowableArray<void*> pointer_storage_; - /* - * Holds mapping from native PC to dex PC for safepoints where we may deoptimize. - * Native PC is on the return address of the safepointed operation. Dex PC is for - * the instruction being executed at the safepoint. - */ - std::vector<uint32_t> pc2dex_mapping_table_; - /* - * Holds mapping from Dex PC to native PC for catch entry points. Native PC and Dex PC - * immediately preceed the instruction. - */ - std::vector<uint32_t> dex2pc_mapping_table_; CodeOffset current_code_offset_; // Working byte offset of machine instructons. CodeOffset data_offset_; // starting offset of literal pool. size_t total_size_; // header + code size. @@ -828,7 +815,7 @@ class Mir2Lir : public Backend { int live_sreg_; CodeBuffer code_buffer_; // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix. - UnsignedLeb128EncodingVector encoded_mapping_table_; + std::vector<uint8_t> encoded_mapping_table_; std::vector<uint32_t> core_vmap_table_; std::vector<uint32_t> fp_vmap_table_; std::vector<uint8_t> native_gc_map_; diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc index 41a57af..cef013e 100644 --- a/compiler/dex/quick/ralloc_util.cc +++ b/compiler/dex/quick/ralloc_util.cc @@ -338,7 +338,7 @@ int Mir2Lir::AllocTempDouble() { int Mir2Lir::AllocFreeTemp() { return AllocTempBody(reg_pool_->core_regs, reg_pool_->num_core_regs, - ®_pool_->next_core_reg, true); + ®_pool_->next_core_reg, false); } int Mir2Lir::AllocTemp() { diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 191c9c7..96dc6ee 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -246,7 +246,9 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"), #undef UNARY_ENCODING_MAP - { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" }, + { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" }, + { kX86Push32R, kRegOpcode, IS_UNARY_OP | REG_USE0 | IS_STORE, { 0, 0, 0x50, 0, 0, 0, 0, 0 }, "Push32R", "!0r" }, + { kX86Pop32R, kRegOpcode, IS_UNARY_OP | REG_DEF0 | IS_LOAD, { 0, 0, 0x58, 0, 0, 0, 0, 0 }, "Pop32R", "!0r" }, #define EXT_0F_ENCODING_MAP(opname, prefix, opcode, reg_def) \ { kX86 ## opname ## RR, kRegReg, IS_BINARY_OP | reg_def | REG_USE01, { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \ @@ -306,9 +308,10 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0, { kX86CmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "!0r,!1r" }, { kX86CmpxchgMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1d],!2r" }, { kX86CmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" }, - { kX86LockCmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "!0r,!1r" }, { kX86LockCmpxchgMR, kMemReg, IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1d],!2r" }, { kX86LockCmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" }, + { kX86LockCmpxchg8bM, kMem, IS_STORE | IS_BINARY_OP | REG_USE0 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1d]" }, + { kX86LockCmpxchg8bA, kArray, IS_STORE | IS_QUAD_OP | REG_USE01 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1r<<!2d+!3d]" }, EXT_0F_ENCODING_MAP(Movzx8, 0x00, 0xB6, REG_DEF0), EXT_0F_ENCODING_MAP(Movzx16, 0x00, 0xB7, REG_DEF0), @@ -493,6 +496,37 @@ int X86Mir2Lir::GetInsnSize(LIR* lir) { return 0; } +void X86Mir2Lir::EmitPrefix(const X86EncodingMap* entry) { + if (entry->skeleton.prefix1 != 0) { + code_buffer_.push_back(entry->skeleton.prefix1); + if (entry->skeleton.prefix2 != 0) { + code_buffer_.push_back(entry->skeleton.prefix2); + } + } else { + DCHECK_EQ(0, entry->skeleton.prefix2); + } +} + +void X86Mir2Lir::EmitOpcode(const X86EncodingMap* entry) { + code_buffer_.push_back(entry->skeleton.opcode); + if (entry->skeleton.opcode == 0x0F) { + code_buffer_.push_back(entry->skeleton.extra_opcode1); + if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { + code_buffer_.push_back(entry->skeleton.extra_opcode2); + } else { + DCHECK_EQ(0, entry->skeleton.extra_opcode2); + } + } else { + DCHECK_EQ(0, entry->skeleton.extra_opcode1); + DCHECK_EQ(0, entry->skeleton.extra_opcode2); + } +} + +void X86Mir2Lir::EmitPrefixAndOpcode(const X86EncodingMap* entry) { + EmitPrefix(entry); + EmitOpcode(entry); +} + static uint8_t ModrmForDisp(int base, int disp) { // BP requires an explicit disp, so do not omit it in the 0 case if (disp == 0 && base != rBP) { @@ -504,7 +538,7 @@ static uint8_t ModrmForDisp(int base, int disp) { } } -void X86Mir2Lir::EmitDisp(int base, int disp) { +void X86Mir2Lir::EmitDisp(uint8_t base, int disp) { // BP requires an explicit disp, so do not omit it in the 0 case if (disp == 0 && base != rBP) { return; @@ -518,26 +552,60 @@ void X86Mir2Lir::EmitDisp(int base, int disp) { } } -void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); +void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp) { + DCHECK_LT(reg_or_opcode, 8); + DCHECK_LT(base, 8); + uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base; + code_buffer_.push_back(modrm); + if (base == rX86_SP) { + // Special SIB for SP base + code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP); } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - // There's no 3-byte instruction with +rd - DCHECK_NE(0x38, entry->skeleton.extra_opcode1); - DCHECK_NE(0x3A, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); + EmitDisp(base, disp); +} + +void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index, + int scale, int disp) { + DCHECK_LT(reg_or_opcode, 8); + uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | rX86_SP; + code_buffer_.push_back(modrm); + DCHECK_LT(scale, 4); + DCHECK_LT(index, 8); + DCHECK_LT(base, 8); + uint8_t sib = (scale << 6) | (index << 3) | base; + code_buffer_.push_back(sib); + EmitDisp(base, disp); +} + +void X86Mir2Lir::EmitImm(const X86EncodingMap* entry, int imm) { + switch (entry->skeleton.immediate_bytes) { + case 1: + DCHECK(IS_SIMM8(imm)); + code_buffer_.push_back(imm & 0xFF); + break; + case 2: + DCHECK(IS_SIMM16(imm)); + code_buffer_.push_back(imm & 0xFF); + code_buffer_.push_back((imm >> 8) & 0xFF); + break; + case 4: + code_buffer_.push_back(imm & 0xFF); + code_buffer_.push_back((imm >> 8) & 0xFF); + code_buffer_.push_back((imm >> 16) & 0xFF); + code_buffer_.push_back((imm >> 24) & 0xFF); + break; + default: + LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes + << ") for instruction: " << entry->name; + break; } +} + +void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) { + EmitPrefixAndOpcode(entry); + // There's no 3-byte instruction with +rd + DCHECK(entry->skeleton.opcode != 0x0F || + (entry->skeleton.extra_opcode1 != 0x38 && entry->skeleton.extra_opcode1 != 0x3A)); DCHECK(!X86_FPREG(reg)); DCHECK_LT(reg, 8); code_buffer_.back() += reg; @@ -546,26 +614,7 @@ void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) { } void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } @@ -581,48 +630,28 @@ void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) { } void X86Mir2Lir::EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } + EmitPrefix(entry); code_buffer_.push_back(entry->skeleton.opcode); + DCHECK_NE(0x0F, entry->skeleton.opcode); DCHECK_EQ(0, entry->skeleton.extra_opcode1); DCHECK_EQ(0, entry->skeleton.extra_opcode2); - DCHECK_LT(entry->skeleton.modrm_opcode, 8); - DCHECK_LT(base, 8); - uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base; - code_buffer_.push_back(modrm); - EmitDisp(base, disp); + DCHECK_NE(rX86_SP, base); + EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp); + DCHECK_EQ(0, entry->skeleton.ax_opcode); + DCHECK_EQ(0, entry->skeleton.immediate_bytes); +} + +void X86Mir2Lir::EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index, + int scale, int disp) { + EmitPrefixAndOpcode(entry); + EmitModrmSibDisp(entry->skeleton.modrm_opcode, base, index, scale, disp); DCHECK_EQ(0, entry->skeleton.ax_opcode); DCHECK_EQ(0, entry->skeleton.immediate_bytes); } void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry, uint8_t base, int disp, uint8_t reg) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } @@ -632,15 +661,7 @@ void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry, << entry->name << " " << static_cast<int>(reg) << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file); } - DCHECK_LT(reg, 8); - DCHECK_LT(base, 8); - uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | base; - code_buffer_.push_back(modrm); - if (base == rX86_SP) { - // Special SIB for SP base - code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP); - } - EmitDisp(base, disp); + EmitModrmDisp(reg, base, disp); DCHECK_EQ(0, entry->skeleton.modrm_opcode); DCHECK_EQ(0, entry->skeleton.ax_opcode); DCHECK_EQ(0, entry->skeleton.immediate_bytes); @@ -653,39 +674,12 @@ void X86Mir2Lir::EmitRegMem(const X86EncodingMap* entry, } void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index, - int scale, int disp) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + int scale, int disp) { + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } - DCHECK_LT(reg, 8); - uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | rX86_SP; - code_buffer_.push_back(modrm); - DCHECK_LT(scale, 4); - DCHECK_LT(index, 8); - DCHECK_LT(base, 8); - uint8_t sib = (scale << 6) | (index << 3) | base; - code_buffer_.push_back(sib); - EmitDisp(base, disp); + EmitModrmSibDisp(reg, base, index, scale, disp); DCHECK_EQ(0, entry->skeleton.modrm_opcode); DCHECK_EQ(0, entry->skeleton.ax_opcode); DCHECK_EQ(0, entry->skeleton.immediate_bytes); @@ -699,22 +693,7 @@ void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) { DCHECK_NE(entry->skeleton.prefix1, 0); - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } @@ -735,26 +714,7 @@ void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int dis } void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg1)) { reg1 = reg1 & X86_FP_REG_MASK; } @@ -772,26 +732,7 @@ void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t r void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2, int32_t imm) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); if (X86_FPREG(reg1)) { reg1 = reg1 & X86_FP_REG_MASK; } @@ -804,27 +745,7 @@ void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry, code_buffer_.push_back(modrm); DCHECK_EQ(0, entry->skeleton.modrm_opcode); DCHECK_EQ(0, entry->skeleton.ax_opcode); - switch (entry->skeleton.immediate_bytes) { - case 1: - DCHECK(IS_SIMM8(imm)); - code_buffer_.push_back(imm & 0xFF); - break; - case 2: - DCHECK(IS_SIMM16(imm)); - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - break; - case 4: - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - code_buffer_.push_back((imm >> 16) & 0xFF); - code_buffer_.push_back((imm >> 24) & 0xFF); - break; - default: - LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes - << ") for instruction: " << entry->name; - break; - } + EmitImm(entry, imm); } void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) { @@ -839,95 +760,25 @@ void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) { if (reg == rAX && entry->skeleton.ax_opcode != 0) { code_buffer_.push_back(entry->skeleton.ax_opcode); } else { - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitOpcode(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg; code_buffer_.push_back(modrm); } - switch (entry->skeleton.immediate_bytes) { - case 1: - DCHECK(IS_SIMM8(imm)); - code_buffer_.push_back(imm & 0xFF); - break; - case 2: - DCHECK(IS_SIMM16(imm)); - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - break; - case 4: - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - code_buffer_.push_back((imm >> 16) & 0xFF); - code_buffer_.push_back((imm >> 24) & 0xFF); - break; - default: - LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes - << ") for instruction: " << entry->name; - break; - } + EmitImm(entry, imm); } void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP; code_buffer_.push_back(modrm); code_buffer_.push_back(disp & 0xFF); code_buffer_.push_back((disp >> 8) & 0xFF); code_buffer_.push_back((disp >> 16) & 0xFF); code_buffer_.push_back((disp >> 24) & 0xFF); - switch (entry->skeleton.immediate_bytes) { - case 1: - DCHECK(IS_SIMM8(imm)); - code_buffer_.push_back(imm & 0xFF); - break; - case 2: - DCHECK(IS_SIMM16(imm)); - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - break; - case 4: - code_buffer_.push_back(imm & 0xFF); - code_buffer_.push_back((imm >> 8) & 0xFF); - code_buffer_.push_back((imm >> 16) & 0xFF); - code_buffer_.push_back((imm >> 24) & 0xFF); - break; - default: - LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes - << ") for instruction: " << entry->name; - break; - } + EmitImm(entry, imm); DCHECK_EQ(entry->skeleton.ax_opcode, 0); } @@ -941,31 +792,16 @@ void X86Mir2Lir::EmitMovRegImm(const X86EncodingMap* entry, uint8_t reg, int imm } void X86Mir2Lir::EmitShiftRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } + EmitPrefix(entry); if (imm != 1) { code_buffer_.push_back(entry->skeleton.opcode); } else { // Shorter encoding for 1 bit shift code_buffer_.push_back(entry->skeleton.ax_opcode); } - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + DCHECK_NE(0x0F, entry->skeleton.opcode); + DCHECK_EQ(0, entry->skeleton.extra_opcode1); + DCHECK_EQ(0, entry->skeleton.extra_opcode2); if (reg >= 4) { DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg) << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file); @@ -982,15 +818,9 @@ void X86Mir2Lir::EmitShiftRegImm(const X86EncodingMap* entry, uint8_t reg, int i void X86Mir2Lir::EmitShiftRegCl(const X86EncodingMap* entry, uint8_t reg, uint8_t cl) { DCHECK_EQ(cl, static_cast<uint8_t>(rCX)); - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } + EmitPrefix(entry); code_buffer_.push_back(entry->skeleton.opcode); + DCHECK_NE(0x0F, entry->skeleton.opcode); DCHECK_EQ(0, entry->skeleton.extra_opcode1); DCHECK_EQ(0, entry->skeleton.extra_opcode2); DCHECK_LT(reg, 8); @@ -1060,55 +890,15 @@ void X86Mir2Lir::EmitJcc(const X86EncodingMap* entry, int rel, uint8_t cc) { } void X86Mir2Lir::EmitCallMem(const X86EncodingMap* entry, uint8_t base, int disp) { - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base; - code_buffer_.push_back(modrm); - if (base == rX86_SP) { - // Special SIB for SP base - code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP); - } - EmitDisp(base, disp); + EmitPrefixAndOpcode(entry); + EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp); DCHECK_EQ(0, entry->skeleton.ax_opcode); DCHECK_EQ(0, entry->skeleton.immediate_bytes); } void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) { DCHECK_NE(entry->skeleton.prefix1, 0); - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.opcode == 0x0F) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode1); - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitPrefixAndOpcode(entry); uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP; code_buffer_.push_back(modrm); code_buffer_.push_back(disp & 0xFF); @@ -1132,20 +922,14 @@ void X86Mir2Lir::EmitPcRel(const X86EncodingMap* entry, uint8_t reg, reinterpret_cast<Mir2Lir::EmbeddedData*>(UnwrapPointer(base_or_table)); disp = tab_rec->offset; } - if (entry->skeleton.prefix1 != 0) { - code_buffer_.push_back(entry->skeleton.prefix1); - if (entry->skeleton.prefix2 != 0) { - code_buffer_.push_back(entry->skeleton.prefix2); - } - } else { - DCHECK_EQ(0, entry->skeleton.prefix2); - } + EmitPrefix(entry); if (X86_FPREG(reg)) { reg = reg & X86_FP_REG_MASK; } DCHECK_LT(reg, 8); if (entry->opcode == kX86PcRelLoadRA) { code_buffer_.push_back(entry->skeleton.opcode); + DCHECK_NE(0x0F, entry->skeleton.opcode); DCHECK_EQ(0, entry->skeleton.extra_opcode1); DCHECK_EQ(0, entry->skeleton.extra_opcode2); uint8_t modrm = (2 << 6) | (reg << 3) | rX86_SP; @@ -1321,15 +1105,7 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) { case kNullary: // 1 byte of opcode DCHECK_EQ(0, entry->skeleton.prefix1); DCHECK_EQ(0, entry->skeleton.prefix2); - code_buffer_.push_back(entry->skeleton.opcode); - if (entry->skeleton.extra_opcode1 != 0) { - code_buffer_.push_back(entry->skeleton.extra_opcode1); - if (entry->skeleton.extra_opcode2 != 0) { - code_buffer_.push_back(entry->skeleton.extra_opcode2); - } - } else { - DCHECK_EQ(0, entry->skeleton.extra_opcode2); - } + EmitOpcode(entry); DCHECK_EQ(0, entry->skeleton.modrm_opcode); DCHECK_EQ(0, entry->skeleton.ax_opcode); DCHECK_EQ(0, entry->skeleton.immediate_bytes); @@ -1343,6 +1119,9 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(CodeOffset start_addr) { case kMem: // lir operands - 0: base, 1: disp EmitOpMem(entry, lir->operands[0], lir->operands[1]); break; + case kArray: // lir operands - 0: base, 1: index, 2: scale, 3: disp + EmitOpArray(entry, lir->operands[0], lir->operands[1], lir->operands[2], lir->operands[3]); + break; case kMemReg: // lir operands - 0: base, 1: disp, 2: reg EmitMemReg(entry, lir->operands[0], lir->operands[1], lir->operands[2]); break; diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index ffe2d67..6552607 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -61,7 +61,7 @@ class X86Mir2Lir : public Mir2Lir { uint32_t FpRegMask(); uint64_t GetRegMaskCommon(int reg); void AdjustSpillMask(); - void ClobberCalleeSave(); + void ClobberCallerSave(); void FlushReg(int reg); void FlushRegWide(int reg1, int reg2); void FreeCallTemps(); @@ -171,10 +171,18 @@ class X86Mir2Lir : public Mir2Lir { bool InexpensiveConstantDouble(int64_t value); private: - void EmitDisp(int base, int disp); + void EmitPrefix(const X86EncodingMap* entry); + void EmitOpcode(const X86EncodingMap* entry); + void EmitPrefixAndOpcode(const X86EncodingMap* entry); + void EmitDisp(uint8_t base, int disp); + void EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp); + void EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index, int scale, int disp); + void EmitImm(const X86EncodingMap* entry, int imm); void EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg); void EmitOpReg(const X86EncodingMap* entry, uint8_t reg); void EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp); + void EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index, + int scale, int disp); void EmitMemReg(const X86EncodingMap* entry, uint8_t base, int disp, uint8_t reg); void EmitRegMem(const X86EncodingMap* entry, uint8_t reg, uint8_t base, int disp); void EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index, diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 01d5c17..0133a0a 100644 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -282,8 +282,69 @@ void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) { } bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { - DCHECK_NE(cu_->instruction_set, kThumb2); - return false; + DCHECK_EQ(cu_->instruction_set, kX86); + // Unused - RegLocation rl_src_unsafe = info->args[0]; + RegLocation rl_src_obj = info->args[1]; // Object - known non-null + RegLocation rl_src_offset = info->args[2]; // long low + rl_src_offset.wide = 0; // ignore high half in info->args[3] + RegLocation rl_src_expected = info->args[4]; // int, long or Object + // If is_long, high half is in info->args[5] + RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object + // If is_long, high half is in info->args[7] + + if (is_long) { + FlushAllRegs(); + LockCallTemps(); + NewLIR1(kX86Push32R, rDI); + MarkTemp(rDI); + LockTemp(rDI); + NewLIR1(kX86Push32R, rSI); + MarkTemp(rSI); + LockTemp(rSI); + LoadValueDirectFixed(rl_src_obj, rDI); + LoadValueDirectFixed(rl_src_offset, rSI); + LoadValueDirectWideFixed(rl_src_expected, rAX, rDX); + LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX); + NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0); + FreeTemp(rSI); + UnmarkTemp(rSI); + NewLIR1(kX86Pop32R, rSI); + FreeTemp(rDI); + UnmarkTemp(rDI); + NewLIR1(kX86Pop32R, rDI); + FreeCallTemps(); + } else { + // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX. + FlushReg(r0); + LockTemp(r0); + + // Release store semantics, get the barrier out of the way. TODO: revisit + GenMemBarrier(kStoreLoad); + + RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg); + RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg); + + if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) { + // Mark card for object assuming new value is stored. + FreeTemp(r0); // Temporarily release EAX for MarkGCCard(). + MarkGCCard(rl_new_value.low_reg, rl_object.low_reg); + LockTemp(r0); + } + + RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg); + LoadValueDirect(rl_src_expected, r0); + NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg); + + FreeTemp(r0); + } + + // Convert ZF to boolean + RegLocation rl_dest = InlineTarget(info); // boolean place for result + RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); + NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ); + NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg); + StoreValue(rl_dest, rl_result); + return true; } LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) { diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 878fa76..0b8c07e 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -165,6 +165,10 @@ void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { if (flags & REG_USED) { SetupRegMask(&lir->u.m.use_mask, rDX); } + + if (flags & REG_USEB) { + SetupRegMask(&lir->u.m.use_mask, rBX); + } } /* For dumping instructions */ @@ -350,10 +354,11 @@ bool X86Mir2Lir::IsFpReg(int reg) { } /* Clobber all regs that might be used by an external C call */ -void X86Mir2Lir::ClobberCalleeSave() { +void X86Mir2Lir::ClobberCallerSave() { Clobber(rAX); Clobber(rCX); Clobber(rDX); + Clobber(rBX); } RegLocation X86Mir2Lir::GetReturnWideAlt() { diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc b/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc deleted file mode 100644 index b788c3c..0000000 --- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#include "base/logging.h" -#include "base/macros.h" -#include "dex/compiler_enums.h" - -#include "x86_dex_file_method_inliner.h" - -namespace art { - -const DexFileMethodInliner::IntrinsicDef X86DexFileMethodInliner::kIntrinsicMethods[] = { -#define INTRINSIC(c, n, p, o, d) \ - { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } } - - INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0), - INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0), - INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), - INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0), - - INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord), - INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong), - INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), - - INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), - INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), - INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0), - INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0), - INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin), - INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax), - // INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0), - // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0), - - INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0), - INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0), - INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty), - INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone), - INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0), - INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength), - - INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0), - - INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte), - INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord), - INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong), - INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf), - INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte), - INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord), - INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong), - INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf), - - // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas, - // kIntrinsicFlagNone), - // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas, - // kIntrinsicFlagIsLong), - // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas, - // kIntrinsicFlagIsObject), - -#define UNSAFE_GET_PUT(type, code, type_flags) \ - INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - type_flags & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \ - (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \ - INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags), \ - INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsVolatile), \ - INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \ - type_flags | kIntrinsicFlagIsOrdered) - - UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone), - UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong), - - // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject), - // PutObject: "TODO: fix X86, it exhausts registers for card marking." - INTRINSIC(SunMiscUnsafe, GetObject, ObjectJ_Object, kIntrinsicUnsafeGet, - kIntrinsicFlagNone), - INTRINSIC(SunMiscUnsafe, GetObjectVolatile, ObjectJ_Object, kIntrinsicUnsafeGet, - kIntrinsicFlagIsVolatile), -#undef UNSAFE_GET_PUT - -#undef INTRINSIC -}; - -X86DexFileMethodInliner::X86DexFileMethodInliner() { -} - -X86DexFileMethodInliner::~X86DexFileMethodInliner() { -} - -void X86DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) { - IndexCache cache; - DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods)); -} - -} // namespace art diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h b/compiler/dex/quick/x86/x86_dex_file_method_inliner.h deleted file mode 100644 index 7813e44..0000000 --- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_ -#define ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_ - -#include "dex/quick/dex_file_method_inliner.h" - -namespace art { - -class X86DexFileMethodInliner : public DexFileMethodInliner { - public: - X86DexFileMethodInliner(); - ~X86DexFileMethodInliner(); - - void FindIntrinsics(const DexFile* dex_file); - - private: - static const IntrinsicDef kIntrinsicMethods[]; -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_ diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h index 3518131..5fe76fe 100644 --- a/compiler/dex/quick/x86/x86_lir.h +++ b/compiler/dex/quick/x86/x86_lir.h @@ -314,6 +314,7 @@ enum X86OpCode { UnaryOpcode(kX86Divmod, DaR, DaM, DaA), UnaryOpcode(kX86Idivmod, DaR, DaM, DaA), kX86Bswap32R, + kX86Push32R, kX86Pop32R, #undef UnaryOpcode #define Binary0fOpCode(opcode) \ opcode ## RR, opcode ## RM, opcode ## RA @@ -354,7 +355,8 @@ enum X86OpCode { Binary0fOpCode(kX86Imul16), // 16bit multiply Binary0fOpCode(kX86Imul32), // 32bit multiply kX86CmpxchgRR, kX86CmpxchgMR, kX86CmpxchgAR, // compare and exchange - kX86LockCmpxchgRR, kX86LockCmpxchgMR, kX86LockCmpxchgAR, // locked compare and exchange + kX86LockCmpxchgMR, kX86LockCmpxchgAR, // locked compare and exchange + kX86LockCmpxchg8bM, kX86LockCmpxchg8bA, // locked compare and exchange Binary0fOpCode(kX86Movzx8), // zero-extend 8-bit value Binary0fOpCode(kX86Movzx16), // zero-extend 16-bit value Binary0fOpCode(kX86Movsx8), // sign-extend 8-bit value diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 7b42879..8e666dd 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1596,7 +1596,8 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i ClassLinker* class_linker = manager->GetClassLinker(); const DexFile& dex_file = *manager->GetDexFile(); SirtRef<mirror::DexCache> dex_cache(soa.Self(), class_linker->FindDexCache(dex_file)); - SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())); + SirtRef<mirror::ClassLoader> class_loader( + soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())); mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader); if (klass == NULL) { @@ -1651,8 +1652,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ jobject jclass_loader = manager->GetClassLoader(); SirtRef<mirror::ClassLoader> class_loader( soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader)); - mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); - if (klass == NULL) { + SirtRef<mirror::Class> klass(soa.Self(), class_linker->FindClass(descriptor, class_loader)); + if (klass.get() == nullptr) { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); @@ -1669,8 +1670,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor) << " because: " << error_msg; } - } else if (!SkipClass(jclass_loader, dex_file, klass)) { - CHECK(klass->IsResolved()) << PrettyClass(klass); + } else if (!SkipClass(jclass_loader, dex_file, klass.get())) { + CHECK(klass->IsResolved()) << PrettyClass(klass.get()); class_linker->VerifyClass(klass); if (klass->IsErroneous()) { @@ -1680,7 +1681,7 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ } CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) - << PrettyDescriptor(klass) << ": state=" << klass->GetStatus(); + << PrettyDescriptor(klass.get()) << ": state=" << klass->GetStatus(); } soa.Self()->AssertNoPendingException(); } @@ -2123,9 +2124,10 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl ScopedObjectAccess soa(Thread::Current()); SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader)); - mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); + SirtRef<mirror::Class> klass(soa.Self(), + manager->GetClassLinker()->FindClass(descriptor, class_loader)); - if (klass != NULL && !SkipClass(jclass_loader, dex_file, klass)) { + if (klass.get() != nullptr && !SkipClass(jclass_loader, dex_file, klass.get())) { // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { // Attempt to initialize the class but bail if we either need to initialize the super-class @@ -2140,7 +2142,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl // parent-to-child and a child-to-parent lock ordering and consequent potential deadlock. // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather // than use a special Object for the purpose we use the Class of java.lang.Class. - ObjectLock lock(soa.Self(), klass->GetClass()); + SirtRef<mirror::Class> sirt_klass(soa.Self(), klass->GetClass()); + ObjectLock<mirror::Class> lock(soa.Self(), &sirt_klass); // Attempt to initialize allowing initialization of parent classes but still not static // fields. manager->GetClassLinker()->EnsureInitialized(klass, false, true); @@ -2164,10 +2167,11 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl VLOG(compiler) << "Initializing: " << descriptor; if (strcmp("Ljava/lang/Void;", descriptor) == 0) { // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. - ObjectLock lock(soa.Self(), klass); + ObjectLock<mirror::Class> lock(soa.Self(), &klass); mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields(); CHECK_EQ(fields->GetLength(), 1); - fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V')); + fields->Get(0)->SetObj(klass.get(), + manager->GetClassLinker()->FindPrimitiveClass('V')); klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self()); } else { manager->GetClassLinker()->EnsureInitialized(klass, true, true); @@ -2180,7 +2184,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl // If successfully initialized place in SSB array. if (klass->IsInitialized()) { int32_t ssb_index = klass->GetDexTypeIndex(); - klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass); + klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass.get()); } } // Record the final class status if necessary. diff --git a/compiler/image_test.cc b/compiler/image_test.cc index c71cc97..3406fe6 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -152,14 +152,14 @@ TEST_F(ImageTest, WriteRead) { const DexFile::ClassDef& class_def = dex->GetClassDef(i); const char* descriptor = dex->GetClassDescriptor(class_def); mirror::Class* klass = class_linker_->FindSystemClass(descriptor); - EXPECT_TRUE(klass != NULL) << descriptor; - EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor; + EXPECT_TRUE(klass != nullptr) << descriptor; if (image_classes.find(descriptor) != image_classes.end()) { - // image classes should be located before the end of the image. + // Image classes should be located inside the image. + EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor; EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor; } else { - // non image classes should be in a space after the image. - EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor; + EXPECT_TRUE(reinterpret_cast<byte*>(klass) >= image_end || + reinterpret_cast<byte*>(klass) < image_begin) << descriptor; } EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord())); } diff --git a/compiler/leb128_encoder.h b/compiler/leb128_encoder.h index e9a1c32..6766683 100644 --- a/compiler/leb128_encoder.h +++ b/compiler/leb128_encoder.h @@ -18,33 +18,79 @@ #define ART_COMPILER_LEB128_ENCODER_H_ #include "base/macros.h" +#include "leb128.h" namespace art { +static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) { + uint8_t out = value & 0x7f; + value >>= 7; + while (value != 0) { + *dest++ = out | 0x80; + out = value & 0x7f; + value >>= 7; + } + *dest++ = out; + return dest; +} + +static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) { + uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6; + uint8_t out = value & 0x7f; + while (extra_bits != 0u) { + *dest++ = out | 0x80; + value >>= 7; + out = value & 0x7f; + extra_bits >>= 7; + } + *dest++ = out; + return dest; +} + // An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format. -class UnsignedLeb128EncodingVector { +class Leb128EncodingVector { public: - UnsignedLeb128EncodingVector() { + Leb128EncodingVector() { } - void PushBack(uint32_t value) { - bool done = false; - do { - uint8_t out = value & 0x7f; - if (out != value) { - data_.push_back(out | 0x80); - value >>= 7; - } else { - data_.push_back(out); - done = true; - } - } while (!done); + void Reserve(uint32_t size) { + data_.reserve(size); + } + + void PushBackUnsigned(uint32_t value) { + uint8_t out = value & 0x7f; + value >>= 7; + while (value != 0) { + data_.push_back(out | 0x80); + out = value & 0x7f; + value >>= 7; + } + data_.push_back(out); + } + + template<typename It> + void InsertBackUnsigned(It cur, It end) { + for (; cur != end; ++cur) { + PushBackUnsigned(*cur); + } + } + + void PushBackSigned(int32_t value) { + uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6; + uint8_t out = value & 0x7f; + while (extra_bits != 0u) { + data_.push_back(out | 0x80); + value >>= 7; + out = value & 0x7f; + extra_bits >>= 7; + } + data_.push_back(out); } template<typename It> - void InsertBack(It cur, It end) { + void InsertBackSigned(It cur, It end) { for (; cur != end; ++cur) { - PushBack(*cur); + PushBackSigned(*cur); } } @@ -55,7 +101,7 @@ class UnsignedLeb128EncodingVector { private: std::vector<uint8_t> data_; - DISALLOW_COPY_AND_ASSIGN(UnsignedLeb128EncodingVector); + DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector); }; } // namespace art diff --git a/compiler/leb128_encoder_test.cc b/compiler/leb128_encoder_test.cc index 4fa8075..c63dfa2 100644 --- a/compiler/leb128_encoder_test.cc +++ b/compiler/leb128_encoder_test.cc @@ -42,11 +42,62 @@ static DecodeUnsignedLeb128TestCase uleb128_tests[] = { {0xFFFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xF}}, }; -TEST_F(Leb128Test, Singles) { +struct DecodeSignedLeb128TestCase { + int32_t decoded; + uint8_t leb128_data[5]; +}; + +static DecodeSignedLeb128TestCase sleb128_tests[] = { + {0, {0, 0, 0, 0, 0}}, + {1, {1, 0, 0, 0, 0}}, + {0x3F, {0x3F, 0, 0, 0, 0}}, + {0x40, {0xC0, 0 /* sign bit */, 0, 0, 0}}, + {0x41, {0xC1, 0 /* sign bit */, 0, 0, 0}}, + {0x80, {0x80, 1, 0, 0, 0}}, + {0xFF, {0xFF, 1, 0, 0, 0}}, + {0x1FFF, {0xFF, 0x3F, 0, 0, 0}}, + {0x2000, {0x80, 0xC0, 0 /* sign bit */, 0, 0}}, + {0x2001, {0x81, 0xC0, 0 /* sign bit */, 0, 0}}, + {0x2081, {0x81, 0xC1, 0 /* sign bit */, 0, 0}}, + {0x4000, {0x80, 0x80, 1, 0, 0}}, + {0x0FFFFF, {0xFF, 0xFF, 0x3F, 0, 0}}, + {0x100000, {0x80, 0x80, 0xC0, 0 /* sign bit */, 0}}, + {0x100001, {0x81, 0x80, 0xC0, 0 /* sign bit */, 0}}, + {0x100081, {0x81, 0x81, 0xC0, 0 /* sign bit */, 0}}, + {0x104081, {0x81, 0x81, 0xC1, 0 /* sign bit */, 0}}, + {0x200000, {0x80, 0x80, 0x80, 1, 0}}, + {0x7FFFFFF, {0xFF, 0xFF, 0xFF, 0x3F, 0}}, + {0x8000000, {0x80, 0x80, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8000001, {0x81, 0x80, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8000081, {0x81, 0x81, 0x80, 0xC0, 0 /* sign bit */}}, + {0x8004081, {0x81, 0x81, 0x81, 0xC0, 0 /* sign bit */}}, + {0x8204081, {0x81, 0x81, 0x81, 0xC1, 0 /* sign bit */}}, + {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0 /* sign bit */}}, + {0x10000000, {0x80, 0x80, 0x80, 0x80, 1}}, + {0x7FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0x7}}, + {-1, {0x7F, 0, 0, 0, 0}}, + {-2, {0x7E, 0, 0, 0, 0}}, + {-0x3F, {0x41, 0, 0, 0, 0}}, + {-0x40, {0x40, 0, 0, 0, 0}}, + {-0x41, {0xBF, 0x7F, 0, 0, 0}}, + {-0x80, {0x80, 0x7F, 0, 0, 0}}, + {-0x81, {0xFF, 0x7E, 0, 0, 0}}, + {-0x00002000, {0x80, 0x40, 0, 0, 0}}, + {-0x00002001, {0xFF, 0xBF, 0x7F, 0, 0}}, + {-0x00100000, {0x80, 0x80, 0x40, 0, 0}}, + {-0x00100001, {0xFF, 0xFF, 0xBF, 0x7F, 0}}, + {-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}}, + {-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}}, + {-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}}, + {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}}, +}; + +TEST_F(Leb128Test, UnsignedSinglesVector) { // Test individual encodings. for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { - UnsignedLeb128EncodingVector builder; - builder.PushBack(uleb128_tests[i].decoded); + Leb128EncodingVector builder; + builder.PushBackUnsigned(uleb128_tests[i].decoded); + EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), builder.GetData().size()); const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; const uint8_t* encoded_data_ptr = &builder.GetData()[0]; for (size_t j = 0; j < 5; ++j) { @@ -60,33 +111,158 @@ TEST_F(Leb128Test, Singles) { } } -TEST_F(Leb128Test, Stream) { +TEST_F(Leb128Test, UnsignedSingles) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + uint8_t encoded_data[5]; + uint8_t* end = EncodeUnsignedLeb128(encoded_data, uleb128_tests[i].decoded); + size_t data_size = static_cast<size_t>(end - encoded_data); + EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), data_size); + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < data_size) { + EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST_F(Leb128Test, UnsignedStreamVector) { // Encode a number of entries. - UnsignedLeb128EncodingVector builder; + Leb128EncodingVector builder; for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { - builder.PushBack(uleb128_tests[i].decoded); + builder.PushBackUnsigned(uleb128_tests[i].decoded); } const uint8_t* encoded_data_ptr = &builder.GetData()[0]; for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(builder.GetData().size(), + static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0])); +} + +TEST_F(Leb128Test, UnsignedStream) { + // Encode a number of entries. + uint8_t encoded_data[5 * arraysize(uleb128_tests)]; + uint8_t* end = encoded_data; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + end = EncodeUnsignedLeb128(end, uleb128_tests[i].decoded); + } + size_t data_size = static_cast<size_t>(end - encoded_data); + const uint8_t* encoded_data_ptr = encoded_data; + for (size_t i = 0; i < arraysize(uleb128_tests); ++i) { + const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data)); +} + +TEST_F(Leb128Test, SignedSinglesVector) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + Leb128EncodingVector builder; + builder.PushBackSigned(sleb128_tests[i].decoded); + EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), builder.GetData().size()); + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; for (size_t j = 0; j < 5; ++j) { - if (data_ptr[j] != 0) { + if (j < builder.GetData().size()) { EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; } } - EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i; + EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST_F(Leb128Test, SignedSingles) { + // Test individual encodings. + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + uint8_t encoded_data[5]; + uint8_t* end = EncodeSignedLeb128(encoded_data, sleb128_tests[i].decoded); + size_t data_size = static_cast<size_t>(end - encoded_data); + EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), data_size); + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < 5; ++j) { + if (j < data_size) { + EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j; + } else { + EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j; + } + } + EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } +} + +TEST_F(Leb128Test, SignedStreamVector) { + // Encode a number of entries. + Leb128EncodingVector builder; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + builder.PushBackSigned(sleb128_tests[i].decoded); + } + const uint8_t* encoded_data_ptr = &builder.GetData()[0]; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i; + } + EXPECT_EQ(builder.GetData().size(), + static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0])); +} + +TEST_F(Leb128Test, SignedStream) { + // Encode a number of entries. + uint8_t encoded_data[5 * arraysize(sleb128_tests)]; + uint8_t* end = encoded_data; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + end = EncodeSignedLeb128(end, sleb128_tests[i].decoded); + } + size_t data_size = static_cast<size_t>(end - encoded_data); + const uint8_t* encoded_data_ptr = encoded_data; + for (size_t i = 0; i < arraysize(sleb128_tests); ++i) { + const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0]; + for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) { + EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j; + } + for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) { + EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j; + } + EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i; } + EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data)); } TEST_F(Leb128Test, Speed) { UniquePtr<Histogram<uint64_t> > enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5)); UniquePtr<Histogram<uint64_t> > dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5)); - UnsignedLeb128EncodingVector builder; + Leb128EncodingVector builder; // Push back 1024 chunks of 1024 values measuring encoding speed. uint64_t last_time = NanoTime(); for (size_t i = 0; i < 1024; i++) { for (size_t j = 0; j < 1024; j++) { - builder.PushBack((i * 1024) + j); + builder.PushBackUnsigned((i * 1024) + j); } uint64_t cur_time = NanoTime(); enc_hist->AddValue(cur_time - last_time); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 8b23270..28d6649 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -213,7 +213,7 @@ class Dex2Oat { if (zip_archive.get() == NULL) { return NULL; } - UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename)); + UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg)); if (zip_entry.get() == NULL) { *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename, zip_filename, error_msg->c_str()); diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc index 9ed65cd..8781c7a 100644 --- a/disassembler/disassembler_x86.cc +++ b/disassembler/disassembler_x86.cc @@ -520,6 +520,13 @@ DISASSEMBLER_ENTRY(cmp, case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; + case 0xC7: + static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" }; + modrm_opcodes = x0FxC7_opcodes; + has_modrm = true; + reg_is_opcode = true; + store = true; + break; case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: opcode << "bswap"; reg_in_opcode = true; diff --git a/runtime/Android.mk b/runtime/Android.mk index 16f11c6..2c13284 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -344,10 +344,10 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT LOCAL_SHARED_LIBRARIES += liblog libnativehelper LOCAL_SHARED_LIBRARIES += libbacktrace # native stack trace support ifeq ($$(art_target_or_host),target) - LOCAL_SHARED_LIBRARIES += libcutils libz libdl libselinux + LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils + LOCAL_STATIC_LIBRARIES := libziparchive libz else # host - LOCAL_STATIC_LIBRARIES += libcutils - LOCAL_SHARED_LIBRARIES += libz-host + LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils LOCAL_LDLIBS += -ldl -lpthread ifeq ($(HOST_OS),linux) LOCAL_LDLIBS += -lrt diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc index c8dee6d..fe18f66 100644 --- a/runtime/base/timing_logger.cc +++ b/runtime/base/timing_logger.cc @@ -31,6 +31,8 @@ namespace art { +constexpr size_t CumulativeLogger::kLowMemoryBucketCount; +constexpr size_t CumulativeLogger::kDefaultBucketCount; CumulativeLogger::CumulativeLogger(const std::string& name) : name_(name), lock_name_("CumulativeLoggerLock" + name), @@ -43,6 +45,7 @@ CumulativeLogger::~CumulativeLogger() { } void CumulativeLogger::SetName(const std::string& name) { + MutexLock mu(Thread::Current(), lock_); name_.assign(name); } @@ -61,6 +64,7 @@ void CumulativeLogger::Reset() { } uint64_t CumulativeLogger::GetTotalNs() const { + MutexLock mu(Thread::Current(), lock_); return GetTotalTime() * kAdjust; } diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h index c1ff0a3..b0bcf10 100644 --- a/runtime/base/timing_logger.h +++ b/runtime/base/timing_logger.h @@ -31,16 +31,15 @@ class TimingLogger; class CumulativeLogger { public: explicit CumulativeLogger(const std::string& name); - void prepare_stats(); ~CumulativeLogger(); void Start(); - void End(); - void Reset(); + void End() LOCKS_EXCLUDED(lock_); + void Reset() LOCKS_EXCLUDED(lock_); void Dump(std::ostream& os) LOCKS_EXCLUDED(lock_); uint64_t GetTotalNs() const; // Allow the name to be modified, particularly when the cumulative logger is a field within a // parent class that is unable to determine the "name" of a sub-class. - void SetName(const std::string& name); + void SetName(const std::string& name) LOCKS_EXCLUDED(lock_); void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_); size_t GetIterations() const; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 500cb59..a98673d 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -530,7 +530,8 @@ void ClassLinker::RunRootClinits() { for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) { mirror::Class* c = GetClassRoot(ClassRoot(i)); if (!c->IsArrayClass() && !c->IsPrimitive()) { - EnsureInitialized(GetClassRoot(ClassRoot(i)), true, true); + SirtRef<mirror::Class> sirt_class(self, GetClassRoot(ClassRoot(i))); + EnsureInitialized(sirt_class, true, true); self->AssertNoPendingException(); } } @@ -673,18 +674,19 @@ OatFile& ClassLinker::GetImageOatFile(gc::space::ImageSpace* space) { } const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) { - return FindOpenedOatFileFromDexLocation(dex_file.GetLocation().c_str(), - dex_file.GetLocationChecksum()); + const char* dex_location = dex_file.GetLocation().c_str(); + uint32_t dex_location_checksum = dex_file.GetLocationChecksum(); + return FindOpenedOatFileFromDexLocation(dex_location, &dex_location_checksum); } const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const char* dex_location, - uint32_t dex_location_checksum) { + const uint32_t* const dex_location_checksum) { ReaderMutexLock mu(Thread::Current(), dex_lock_); for (size_t i = 0; i < oat_files_.size(); i++) { const OatFile* oat_file = oat_files_[i]; DCHECK(oat_file != NULL); const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, - &dex_location_checksum, + dex_location_checksum, false); if (oat_dex_file != NULL) { return oat_file; @@ -943,13 +945,13 @@ const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& o } const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_location, - uint32_t dex_location_checksum, + const uint32_t* const dex_location_checksum, std::string* error_msg) { const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location, dex_location_checksum); if (open_oat_file != nullptr) { const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location, - &dex_location_checksum); + dex_location_checksum); return oat_dex_file->OpenDexFile(error_msg); } @@ -962,6 +964,12 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_ if (dex_file != nullptr) { return dex_file; } + if (dex_location_checksum == nullptr) { + *error_msg = StringPrintf("Failed to open oat file from %s and no classes.dex found in %s: %s", + odex_filename.c_str(), dex_location, error_msg->c_str()); + return nullptr; + } + std::string cache_error_msg; std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location)); dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg, @@ -978,7 +986,7 @@ const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_ // Try to generate oat file if it wasn't found or was obsolete. error_msg->clear(); - return FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum, + return FindOrCreateOatFileForDexLocation(dex_location, *dex_location_checksum, cache_location.c_str(), error_msg); } @@ -1133,7 +1141,7 @@ void ClassLinker::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, b } { - ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_); + WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); if (!only_dirty || class_table_dirty_) { for (std::pair<const size_t, mirror::Class*>& it : class_table_) { it.second = down_cast<mirror::Class*>(visitor(it.second, arg)); @@ -1156,7 +1164,7 @@ void ClassLinker::VisitClasses(ClassVisitor* visitor, void* arg) { if (dex_cache_image_class_lookup_required_) { MoveImageClassesToClassTable(); } - ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); for (const std::pair<size_t, mirror::Class*>& it : class_table_) { if (!visitor(it.second, arg)) { return; @@ -1249,7 +1257,10 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl size_t class_size) { DCHECK_GE(class_size, sizeof(mirror::Class)); gc::Heap* heap = Runtime::Current()->GetHeap(); - mirror::Object* k = heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size); + mirror::Object* k = + kMovingClasses ? + heap->AllocObject<true>(self, java_lang_Class, class_size) : + heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size); if (UNLIKELY(k == NULL)) { CHECK(self->IsExceptionPending()); // OOME. return NULL; @@ -1287,21 +1298,23 @@ static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass) DCHECK(klass != NULL); // Wait for the class if it has not already been linked. if (!klass->IsResolved() && !klass->IsErroneous()) { - ObjectLock lock(self, klass); + SirtRef<mirror::Class> sirt_class(self, klass); + ObjectLock<mirror::Class> lock(self, &sirt_class); // Check for circular dependencies between classes. - if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) { - ThrowClassCircularityError(klass); - klass->SetStatus(mirror::Class::kStatusError, self); - return NULL; + if (!sirt_class->IsResolved() && sirt_class->GetClinitThreadId() == self->GetTid()) { + ThrowClassCircularityError(sirt_class.get()); + sirt_class->SetStatus(mirror::Class::kStatusError, self); + return nullptr; } // Wait for the pending initialization to complete. - while (!klass->IsResolved() && !klass->IsErroneous()) { + while (!sirt_class->IsResolved() && !sirt_class->IsErroneous()) { lock.WaitIgnoringInterrupts(); } + klass = sirt_class.get(); } if (klass->IsErroneous()) { ThrowEarlierClassFailure(klass); - return NULL; + return nullptr; } // Return the loaded class. No exceptions should be pending. CHECK(klass->IsResolved()) << PrettyClass(klass); @@ -1320,7 +1333,7 @@ mirror::Class* ClassLinker::FindSystemClass(const char* descriptor) { } mirror::Class* ClassLinker::FindClass(const char* descriptor, - SirtRef<mirror::ClassLoader>& class_loader) { + const SirtRef<mirror::ClassLoader>& class_loader) { DCHECK_NE(*descriptor, '\0') << "descriptor is empty string"; Thread* self = Thread::Current(); DCHECK(self != NULL); @@ -1403,7 +1416,7 @@ mirror::Class* ClassLinker::FindClass(const char* descriptor, } mirror::Class* ClassLinker::DefineClass(const char* descriptor, - SirtRef<mirror::ClassLoader>& class_loader, + const SirtRef<mirror::ClassLoader>& class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { Thread* self = Thread::Current(); @@ -1440,7 +1453,7 @@ mirror::Class* ClassLinker::DefineClass(const char* descriptor, klass->SetStatus(mirror::Class::kStatusError, self); return NULL; } - ObjectLock lock(self, klass.get()); + ObjectLock<mirror::Class> lock(self, &klass); klass->SetClinitThreadId(self->GetTid()); // Add the newly loaded class to the loaded classes table. mirror::Class* existing = InsertClass(descriptor, klass.get(), Hash(descriptor)); @@ -1695,7 +1708,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // Ignore virtual methods on the iterator. } -static void LinkCode(SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class, +static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class, uint32_t method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Method shouldn't have already been linked. @@ -1741,7 +1754,7 @@ static void LinkCode(SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass void ClassLinker::LoadClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - SirtRef<mirror::Class>& klass, + const SirtRef<mirror::Class>& klass, mirror::ClassLoader* class_loader) { CHECK(klass.get() != NULL); CHECK(klass->GetDexCache() != NULL); @@ -1861,7 +1874,8 @@ void ClassLinker::LoadClass(const DexFile& dex_file, } void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it, - SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst) { + const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ArtField>& dst) { uint32_t field_idx = it.GetMemberIndex(); dst->SetDexFieldIndex(field_idx); dst->SetDeclaringClass(klass.get()); @@ -1870,7 +1884,7 @@ void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIter mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it, - SirtRef<mirror::Class>& klass) { + const SirtRef<mirror::Class>& klass) { uint32_t dex_method_idx = it.GetMemberIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); @@ -1941,7 +1955,8 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file) { AppendToBootClassPath(dex_file, dex_cache); } -void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { +void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, + const SirtRef<mirror::DexCache>& dex_cache) { CHECK(dex_cache.get() != NULL) << dex_file.GetLocation(); boot_class_path_.push_back(&dex_file); RegisterDexFile(dex_file, dex_cache); @@ -1962,7 +1977,8 @@ bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const { return IsDexFileRegisteredLocked(dex_file); } -void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { +void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, + const SirtRef<mirror::DexCache>& dex_cache) { dex_lock_.AssertExclusiveHeld(Thread::Current()); CHECK(dex_cache.get() != NULL) << dex_file.GetLocation(); CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation())) @@ -1994,7 +2010,8 @@ void ClassLinker::RegisterDexFile(const DexFile& dex_file) { } } -void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) { +void ClassLinker::RegisterDexFile(const DexFile& dex_file, + const SirtRef<mirror::DexCache>& dex_cache) { WriterMutexLock mu(Thread::Current(), dex_lock_); RegisterDexFileLocked(dex_file, dex_cache); } @@ -2040,11 +2057,13 @@ mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type t return InitializePrimitiveClass(klass, type); } -mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) { +mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, + Primitive::Type type) { CHECK(primitive_class != NULL); // Must hold lock on object when initializing. Thread* self = Thread::Current(); - ObjectLock lock(self, primitive_class); + SirtRef<mirror::Class> sirt_class(self, primitive_class); + ObjectLock<mirror::Class> lock(self, &sirt_class); primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract); primitive_class->SetPrimitiveType(type); primitive_class->SetStatus(mirror::Class::kStatusInitialized, self); @@ -2068,7 +2087,7 @@ mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_cl // // Returns NULL with an exception raised on failure. mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor, - SirtRef<mirror::ClassLoader>& class_loader) { + const SirtRef<mirror::ClassLoader>& class_loader) { // Identify the underlying component type CHECK_EQ('[', descriptor[0]); mirror::Class* component_type = FindClass(descriptor + 1, class_loader); @@ -2138,7 +2157,7 @@ mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor, } new_class->SetComponentType(component_type); } - ObjectLock lock(self, new_class.get()); // Must hold lock on object when initializing. + ObjectLock<mirror::Class> lock(self, &new_class); // Must hold lock on object when initializing. DCHECK(new_class->GetComponentType() != NULL); mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject); new_class->SetSuperClass(java_lang_Object); @@ -2421,10 +2440,10 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Clas } } -void ClassLinker::VerifyClass(mirror::Class* klass) { +void ClassLinker::VerifyClass(const SirtRef<mirror::Class>& klass) { // TODO: assert that the monitor on the Class is held Thread* self = Thread::Current(); - ObjectLock lock(self, klass); + ObjectLock<mirror::Class> lock(self, &klass); // Don't attempt to re-verify if already sufficiently verified. if (klass->IsVerified() || @@ -2435,7 +2454,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { // The class might already be erroneous, for example at compile time if we attempted to verify // this class as a parent to another. if (klass->IsErroneous()) { - ThrowEarlierClassFailure(klass); + ThrowEarlierClassFailure(klass.get()); return; } @@ -2443,7 +2462,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { klass->SetStatus(mirror::Class::kStatusVerifying, self); } else { CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime) - << PrettyClass(klass); + << PrettyClass(klass.get()); CHECK(!Runtime::Current()->IsCompiler()); klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self); } @@ -2452,23 +2471,23 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { SirtRef<mirror::Class> super(self, klass->GetSuperClass()); if (super.get() != NULL) { // Acquire lock to prevent races on verifying the super class. - ObjectLock lock(self, super.get()); + ObjectLock<mirror::Class> lock(self, &super); if (!super->IsVerified() && !super->IsErroneous()) { - VerifyClass(super.get()); + VerifyClass(super); } if (!super->IsCompileTimeVerified()) { std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s", - PrettyDescriptor(klass).c_str(), + PrettyDescriptor(klass.get()).c_str(), PrettyDescriptor(super.get()).c_str())); LOG(ERROR) << error_msg << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); SirtRef<mirror::Throwable> cause(self, self->GetException(NULL)); - if (cause.get() != NULL) { + if (cause.get() != nullptr) { self->ClearException(); } - ThrowVerifyError(klass, "%s", error_msg.c_str()); - if (cause.get() != NULL) { - self->GetException(NULL)->SetCause(cause.get()); + ThrowVerifyError(klass.get(), "%s", error_msg.c_str()); + if (cause.get() != nullptr) { + self->GetException(nullptr)->SetCause(cause.get()); } klass->SetStatus(mirror::Class::kStatusError, self); return; @@ -2478,26 +2497,26 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { // Try to use verification information from the oat file, otherwise do runtime verification. const DexFile& dex_file = *klass->GetDexCache()->GetDexFile(); mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady); - bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status); + bool preverified = VerifyClassUsingOatFile(dex_file, klass.get(), oat_file_class_status); if (oat_file_class_status == mirror::Class::kStatusError) { VLOG(class_linker) << "Skipping runtime verification of erroneous class " - << PrettyDescriptor(klass) << " in " + << PrettyDescriptor(klass.get()) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8(); - ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification", - PrettyDescriptor(klass).c_str()); + ThrowVerifyError(klass.get(), "Rejecting class %s because it failed compile-time verification", + PrettyDescriptor(klass.get()).c_str()); klass->SetStatus(mirror::Class::kStatusError, self); return; } verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { - verifier_failure = verifier::MethodVerifier::VerifyClass(klass, + verifier_failure = verifier::MethodVerifier::VerifyClass(klass.get(), Runtime::Current()->IsCompiler(), &error_msg); } if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { - VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass) + VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.get()) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() << " because: " << error_msg; } @@ -2527,11 +2546,11 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { } } } else { - LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass) + LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass.get()) << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8() << " because: " << error_msg; self->AssertNoPendingException(); - ThrowVerifyError(klass, "%s", error_msg.c_str()); + ThrowVerifyError(klass.get(), "%s", error_msg.c_str()); klass->SetStatus(mirror::Class::kStatusError, self); } if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) { @@ -2625,7 +2644,8 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class return false; } -void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass) { +void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, + const SirtRef<mirror::Class>& klass) { for (size_t i = 0; i < klass->NumDirectMethods(); i++) { ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i)); } @@ -2763,13 +2783,13 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccess& soa, jstring na self->AssertNoPendingException(); { - ObjectLock lock(self, klass.get()); // Must hold lock on object when resolved. + ObjectLock<mirror::Class> lock(self, &klass); // Must hold lock on object when resolved. // Link the fields and virtual methods, creating vtable and iftables SirtRef<mirror::ObjectArray<mirror::Class> > sirt_interfaces( self, soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)); if (!LinkClass(self, klass, sirt_interfaces)) { klass->SetStatus(mirror::Class::kStatusError, self); - return NULL; + return nullptr; } interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)); @@ -2840,7 +2860,7 @@ mirror::ArtMethod* ClassLinker::FindMethodForProxy(const mirror::Class* proxy_cl mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self, - SirtRef<mirror::Class>& klass, + const SirtRef<mirror::Class>& klass, mirror::Class* proxy_class) { // Create constructor for Proxy that must initialize h mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods = @@ -2870,8 +2890,9 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor) DCHECK(constructor->IsPublic()); } -mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass, - SirtRef<mirror::ArtMethod>& prototype) { +mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, + const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ArtMethod>& prototype) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(), @@ -2966,7 +2987,7 @@ bool ClassLinker::IsInitialized() const { return init_done_; } -bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, +bool ClassLinker::InitializeClass(const SirtRef<mirror::Class>& klass, bool can_init_statics, bool can_init_parents) { // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol @@ -2978,14 +2999,14 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } // Fast fail if initialization requires a full runtime. Not part of the JLS. - if (!CanWeInitializeClass(klass, can_init_statics, can_init_parents)) { + if (!CanWeInitializeClass(klass.get(), can_init_statics, can_init_parents)) { return false; } Thread* self = Thread::Current(); uint64_t t0; { - ObjectLock lock(self, klass); + ObjectLock<mirror::Class> lock(self, &klass); // Re-check under the lock in case another thread initialized ahead of us. if (klass->IsInitialized()) { @@ -2994,11 +3015,11 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, // Was the class already found to be erroneous? Done under the lock to match the JLS. if (klass->IsErroneous()) { - ThrowEarlierClassFailure(klass); + ThrowEarlierClassFailure(klass.get()); return false; } - CHECK(klass->IsResolved()) << PrettyClass(klass) << ": state=" << klass->GetStatus(); + CHECK(klass->IsResolved()) << PrettyClass(klass.get()) << ": state=" << klass->GetStatus(); if (!klass->IsVerified()) { VerifyClass(klass); @@ -3035,7 +3056,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, return false; } - CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass); + CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass.get()); // From here out other threads may observe that we're initializing and so changes of state // require the a notification. @@ -3051,16 +3072,17 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, if (!super_class->IsInitialized()) { CHECK(!super_class->IsInterface()); CHECK(can_init_parents); - bool super_initialized = InitializeClass(super_class, can_init_statics, true); + SirtRef<mirror::Class> sirt_super(self, super_class); + bool super_initialized = InitializeClass(sirt_super, can_init_statics, true); if (!super_initialized) { // The super class was verified ahead of entering initializing, we should only be here if // the super class became erroneous due to initialization. - CHECK(super_class->IsErroneous() && self->IsExceptionPending()) - << "Super class initialization failed for " << PrettyDescriptor(super_class) - << " that has unexpected status " << super_class->GetStatus() + CHECK(sirt_super->IsErroneous() && self->IsExceptionPending()) + << "Super class initialization failed for " << PrettyDescriptor(sirt_super.get()) + << " that has unexpected status " << sirt_super->GetStatus() << "\nPending exception:\n" << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : ""); - ObjectLock lock(self, klass); + ObjectLock<mirror::Class> lock(self, &klass); // Initialization failed because the super-class is erroneous. klass->SetStatus(mirror::Class::kStatusError, self); return false; @@ -3069,7 +3091,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } if (klass->NumStaticFields() > 0) { - ClassHelper kh(klass); + ClassHelper kh(klass.get()); const DexFile::ClassDef* dex_class_def = kh.GetClassDef(); CHECK(dex_class_def != NULL); const DexFile& dex_file = kh.GetDexFile(); @@ -3081,7 +3103,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, CHECK(can_init_statics); // We reordered the fields, so we need to be able to map the field indexes to the right fields. SafeMap<uint32_t, mirror::ArtField*> field_map; - ConstructFieldMap(dex_file, *dex_class_def, klass, field_map); + ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map); for (size_t i = 0; it.HasNext(); i++, it.Next()) { it.ReadValueToField(field_map.Get(i)); } @@ -3100,13 +3122,13 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } // Opportunistically set static method trampolines to their destination. - FixupStaticTrampolines(klass); + FixupStaticTrampolines(klass.get()); uint64_t t1 = NanoTime(); bool success = true; { - ObjectLock lock(self, klass); + ObjectLock<mirror::Class> lock(self, &klass); if (self->IsExceptionPending()) { WrapExceptionInInitializer(); @@ -3122,7 +3144,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, // Set the class as initialized except if failed to initialize static fields. klass->SetStatus(mirror::Class::kStatusInitialized, self); if (VLOG_IS_ON(class_linker)) { - ClassHelper kh(klass); + ClassHelper kh(klass.get()); LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation(); } } @@ -3130,7 +3152,8 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, return success; } -bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock) +bool ClassLinker::WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self, + ObjectLock<mirror::Class>& lock) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { while (true) { self->AssertNoPendingException(); @@ -3157,47 +3180,49 @@ bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, Obj // The caller wants an exception, but it was thrown in a // different thread. Synthesize one here. ThrowNoClassDefFoundError("<clinit> failed for class %s; see exception in other thread", - PrettyDescriptor(klass).c_str()); + PrettyDescriptor(klass.get()).c_str()); return false; } if (klass->IsInitialized()) { return true; } - LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass) << " is " << klass->GetStatus(); + LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass.get()) << " is " + << klass->GetStatus(); } - LOG(FATAL) << "Not Reached" << PrettyClass(klass); + LOG(FATAL) << "Not Reached" << PrettyClass(klass.get()); } -bool ClassLinker::ValidateSuperClassDescriptors(const mirror::Class* klass) { +bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass) { if (klass->IsInterface()) { return true; } + Thread* self = Thread::Current(); // begin with the methods local to the superclass if (klass->HasSuperClass() && klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) { - const mirror::Class* super = klass->GetSuperClass(); + SirtRef<mirror::Class> super(self, klass->GetSuperClass()); for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) { const mirror::ArtMethod* method = klass->GetVTable()->Get(i); if (method != super->GetVTable()->Get(i) && - !IsSameMethodSignatureInDifferentClassContexts(method, super, klass)) { - ThrowLinkageError(klass, "Class %s method %s resolves differently in superclass %s", - PrettyDescriptor(klass).c_str(), PrettyMethod(method).c_str(), - PrettyDescriptor(super).c_str()); + !IsSameMethodSignatureInDifferentClassContexts(method, super.get(), klass.get())) { + ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s", + PrettyDescriptor(klass.get()).c_str(), PrettyMethod(method).c_str(), + PrettyDescriptor(super.get()).c_str()); return false; } } } for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { - mirror::Class* interface = klass->GetIfTable()->GetInterface(i); + SirtRef<mirror::Class> interface(self, klass->GetIfTable()->GetInterface(i)); if (klass->GetClassLoader() != interface->GetClassLoader()) { for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) { const mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j); - if (!IsSameMethodSignatureInDifferentClassContexts(method, interface, + if (!IsSameMethodSignatureInDifferentClassContexts(method, interface.get(), method->GetDeclaringClass())) { - ThrowLinkageError(klass, "Class %s method %s resolves differently in interface %s", + ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s", PrettyDescriptor(method->GetDeclaringClass()).c_str(), PrettyMethod(method).c_str(), - PrettyDescriptor(interface).c_str()); + PrettyDescriptor(interface.get()).c_str()); return false; } } @@ -3214,17 +3239,22 @@ bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::Ar if (klass1 == klass2) { return true; } + Thread* self = Thread::Current(); + CHECK(klass1 != nullptr); + CHECK(klass2 != nullptr); + SirtRef<mirror::ClassLoader> loader1(self, klass1->GetClassLoader()); + SirtRef<mirror::ClassLoader> loader2(self, klass2->GetClassLoader()); const DexFile& dex_file = *method->GetDeclaringClass()->GetDexCache()->GetDexFile(); const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(dex_file.GetMethodId(method->GetDexMethodIndex())); for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) { const char* descriptor = it.GetDescriptor(); - if (descriptor == NULL) { + if (descriptor == nullptr) { break; } if (descriptor[0] == 'L' || descriptor[0] == '[') { // Found a non-primitive type. - if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) { + if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) { return false; } } @@ -3232,47 +3262,42 @@ bool ClassLinker::IsSameMethodSignatureInDifferentClassContexts(const mirror::Ar // Check the return type const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id); if (descriptor[0] == 'L' || descriptor[0] == '[') { - if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) { + if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) { return false; } } return true; } -// Returns true if the descriptor resolves to the same class in the context of klass1 and klass2. +// Returns true if the descriptor resolves to the same class in the context of loader1 and loader2. bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descriptor, - const mirror::Class* klass1, - const mirror::Class* klass2) { - CHECK(descriptor != NULL); - CHECK(klass1 != NULL); - CHECK(klass2 != NULL); - if (klass1 == klass2) { - return true; - } + SirtRef<mirror::ClassLoader>& loader1, + SirtRef<mirror::ClassLoader>& loader2) { + CHECK(descriptor != nullptr); Thread* self = Thread::Current(); - SirtRef<mirror::ClassLoader> class_loader1(self, klass1->GetClassLoader()); - mirror::Class* found1 = FindClass(descriptor, class_loader1); - if (found1 == NULL) { - Thread::Current()->ClearException(); + SirtRef<mirror::Class> found1(self, FindClass(descriptor, loader1)); + if (found1.get() == nullptr) { + self->ClearException(); } - SirtRef<mirror::ClassLoader> class_loader2(self, klass2->GetClassLoader()); - mirror::Class* found2 = FindClass(descriptor, class_loader2); - if (found2 == NULL) { - Thread::Current()->ClearException(); + mirror::Class* found2 = FindClass(descriptor, loader2); + if (found2 == nullptr) { + self->ClearException(); } - return found1 == found2; + return found1.get() == found2; } -bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool can_init_parents) { - DCHECK(c != NULL); +bool ClassLinker::EnsureInitialized(const SirtRef<mirror::Class>& c, bool can_init_fields, + bool can_init_parents) { + DCHECK(c.get() != NULL); if (c->IsInitialized()) { return true; } bool success = InitializeClass(c, can_init_fields, can_init_parents); if (!success) { - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending() || !can_init_fields || !can_init_parents) << PrettyClass(c); + if (can_init_fields && can_init_parents) { + CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.get()); + } } return success; } @@ -3285,13 +3310,14 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas Thread* self = Thread::Current(); SirtRef<mirror::DexCache> dex_cache(self, c->GetDexCache()); SirtRef<mirror::ClassLoader> class_loader(self, c->GetClassLoader()); + CHECK(!kMovingFields); for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { field_map.Put(i, ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true)); } } -bool ClassLinker::LinkClass(Thread* self, SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { +bool ClassLinker::LinkClass(Thread* self, const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus()); if (!LinkSuperClass(klass)) { return false; @@ -3312,7 +3338,8 @@ bool ClassLinker::LinkClass(Thread* self, SirtRef<mirror::Class>& klass, return true; } -bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file) { +bool ClassLinker::LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass, + const DexFile& dex_file) { CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex()); uint16_t super_class_idx = class_def.superclass_idx_; @@ -3355,7 +3382,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const De return true; } -bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) { +bool ClassLinker::LinkSuperClass(const SirtRef<mirror::Class>& klass) { CHECK(!klass->IsPrimitive()); mirror::Class* super = klass->GetSuperClass(); if (klass.get() == GetClassRoot(kJavaLangObject)) { @@ -3414,8 +3441,8 @@ bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) { } // Populate the class vtable and itable. Compute return type indices. -bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { +bool ClassLinker::LinkMethods(const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { if (klass->IsInterface()) { // No vtable. size_t count = klass->NumVirtualMethods(); @@ -3435,7 +3462,7 @@ bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass, return true; } -bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { +bool ClassLinker::LinkVirtualMethods(const SirtRef<mirror::Class>& klass) { Thread* self = Thread::Current(); if (klass->HasSuperClass()) { uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength(); @@ -3518,8 +3545,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { return true; } -bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { +bool ClassLinker::LinkInterfaceMethods(const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) { // Set the imt table to be all conflicts by default. klass->SetImTable(Runtime::Current()->GetDefaultImt()); size_t super_ifcount; @@ -3529,14 +3556,17 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, super_ifcount = 0; } size_t ifcount = super_ifcount; - ClassHelper kh(klass.get()); - uint32_t num_interfaces = - interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength(); - ifcount += num_interfaces; - for (size_t i = 0; i < num_interfaces; i++) { - mirror::Class* interface = - interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i); - ifcount += interface->GetIfTableCount(); + uint32_t num_interfaces; + { + ClassHelper kh(klass.get()); + num_interfaces = + interfaces.get() == nullptr ? kh.NumDirectInterfaces() : interfaces->GetLength(); + ifcount += num_interfaces; + for (size_t i = 0; i < num_interfaces; i++) { + mirror::Class* interface = + interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i); + ifcount += interface->GetIfTableCount(); + } } if (ifcount == 0) { // Class implements no interfaces. @@ -3576,6 +3606,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, // Flatten the interface inheritance hierarchy. size_t idx = super_ifcount; for (size_t i = 0; i < num_interfaces; i++) { + ClassHelper kh(klass.get()); mirror::Class* interface = interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i); DCHECK(interface != NULL); @@ -3640,11 +3671,8 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, return false; } std::vector<mirror::ArtMethod*> miranda_list; - MethodHelper vtable_mh(NULL); - MethodHelper interface_mh(NULL); for (size_t i = 0; i < ifcount; ++i) { - mirror::Class* interface = iftable->GetInterface(i); - size_t num_methods = interface->NumVirtualMethods(); + size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); if (num_methods > 0) { SirtRef<mirror::ObjectArray<mirror::ArtMethod> > method_array(self, AllocArtMethodArray(self, num_methods)); @@ -3656,8 +3684,8 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, SirtRef<mirror::ObjectArray<mirror::ArtMethod> > vtable(self, klass->GetVTableDuringLinking()); for (size_t j = 0; j < num_methods; ++j) { - mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j); - interface_mh.ChangeMethod(interface_method); + mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j); + MethodHelper interface_mh(interface_method); int32_t k; // For each method listed in the interface's method list, find the // matching method in our class's method list. We want to favor the @@ -3669,7 +3697,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, // matter which direction we go. We walk it backward anyway.) for (k = vtable->GetLength() - 1; k >= 0; --k) { mirror::ArtMethod* vtable_method = vtable->Get(k); - vtable_mh.ChangeMethod(vtable_method); + MethodHelper vtable_mh(vtable_method); if (interface_mh.HasSameNameAndSignature(&vtable_mh)) { if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) { ThrowIllegalAccessError(klass.get(), @@ -3694,7 +3722,7 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtMethod> miranda_method(self, NULL); for (size_t mir = 0; mir < miranda_list.size(); mir++) { mirror::ArtMethod* mir_method = miranda_list[mir]; - vtable_mh.ChangeMethod(mir_method); + MethodHelper vtable_mh(mir_method); if (interface_mh.HasSameNameAndSignature(&vtable_mh)) { miranda_method.reset(miranda_list[mir]); break; @@ -3772,12 +3800,12 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, return true; } -bool ClassLinker::LinkInstanceFields(SirtRef<mirror::Class>& klass) { +bool ClassLinker::LinkInstanceFields(const SirtRef<mirror::Class>& klass) { CHECK(klass.get() != NULL); return LinkFields(klass, false); } -bool ClassLinker::LinkStaticFields(SirtRef<mirror::Class>& klass) { +bool ClassLinker::LinkStaticFields(const SirtRef<mirror::Class>& klass) { CHECK(klass.get() != NULL); size_t allocated_class_size = klass->GetClassSize(); bool success = LinkFields(klass, true); @@ -3813,7 +3841,7 @@ struct LinkFieldsComparator { } }; -bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { +bool ClassLinker::LinkFields(const SirtRef<mirror::Class>& klass, bool is_static) { size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields(); @@ -3972,7 +4000,7 @@ bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) { // Set the bitmap of reference offsets, refOffsets, from the ifields // list. -void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) { +void ClassLinker::CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass) { uint32_t reference_offsets = 0; mirror::Class* super_class = klass->GetSuperClass(); if (super_class != NULL) { @@ -3986,11 +4014,11 @@ void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) CreateReferenceOffsets(klass, false, reference_offsets); } -void ClassLinker::CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass) { +void ClassLinker::CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass) { CreateReferenceOffsets(klass, true, 0); } -void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static, +void ClassLinker::CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static, uint32_t reference_offsets) { size_t num_reference_fields = is_static ? klass->NumReferenceStaticFieldsDuringLinking() @@ -4023,7 +4051,7 @@ void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_ } mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx, - SirtRef<mirror::DexCache>& dex_cache) { + const SirtRef<mirror::DexCache>& dex_cache) { DCHECK(dex_cache.get() != nullptr); mirror::String* resolved = dex_cache->GetResolvedString(string_idx); if (resolved != NULL) { @@ -4045,8 +4073,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i } mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader) { + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader) { DCHECK(dex_cache.get() != NULL); mirror::Class* resolved = dex_cache->GetResolvedType(type_idx); if (resolved == NULL) { @@ -4064,9 +4092,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i // Convert a ClassNotFoundException to a NoClassDefFoundError. SirtRef<mirror::Throwable> cause(self, self->GetException(NULL)); if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) { + SirtRef<mirror::Class> sirt_resolved(self, resolved); Thread::Current()->ClearException(); ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor); self->GetException(NULL)->SetCause(cause.get()); + resolved = sirt_resolved.get(); } } } @@ -4077,8 +4107,8 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader, + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader, const mirror::ArtMethod* referrer, InvokeType type) { DCHECK(dex_cache.get() != NULL); @@ -4223,8 +4253,8 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, } mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader, + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader, bool is_static) { DCHECK(dex_cache.get() != nullptr); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); @@ -4263,8 +4293,8 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t fi mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader) { + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader) { DCHECK(dex_cache.get() != nullptr); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 4e2cc06..d468e1e 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -45,7 +45,7 @@ namespace mirror { } // namespace mirror class InternTable; -class ObjectLock; +template<class T> class ObjectLock; class ScopedObjectAccess; template<class T> class SirtRef; @@ -72,7 +72,7 @@ class ClassLinker { // Finds a class by its descriptor, loading it if necessary. // If class_loader is null, searches boot_class_path_. - mirror::Class* FindClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader) + mirror::Class* FindClass(const char* descriptor, const SirtRef<mirror::ClassLoader>& class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::Class* FindSystemClass(const char* descriptor) @@ -82,7 +82,8 @@ class ClassLinker { bool IsInitialized() const; // Define a new a class based on a ClassDef from a DexFile - mirror::Class* DefineClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader, + mirror::Class* DefineClass(const char* descriptor, + const SirtRef<mirror::ClassLoader>& class_loader, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -126,7 +127,7 @@ class ClassLinker { // Resolve a String with the given index from the DexFile, storing the // result in the DexCache. mirror::String* ResolveString(const DexFile& dex_file, uint32_t string_idx, - SirtRef<mirror::DexCache>& dex_cache) + const SirtRef<mirror::DexCache>& dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a Type with the given index from the DexFile, storing the @@ -150,8 +151,8 @@ class ClassLinker { // type, since it may be referenced from but not contained within // the given DexFile. mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader) + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Resolve a method with a given ID from the DexFile, storing the @@ -161,8 +162,8 @@ class ClassLinker { // virtual method. mirror::ArtMethod* ResolveMethod(const DexFile& dex_file, uint32_t method_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader, + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader, const mirror::ArtMethod* referrer, InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -182,8 +183,8 @@ class ClassLinker { // field. mirror::ArtField* ResolveField(const DexFile& dex_file, uint32_t field_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader, + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -193,8 +194,8 @@ class ClassLinker { // field resolution semantics are followed. mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx, - SirtRef<mirror::DexCache>& dex_cache, - SirtRef<mirror::ClassLoader>& class_loader) + const SirtRef<mirror::DexCache>& dex_cache, + const SirtRef<mirror::ClassLoader>& class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get shorty from method index without resolution. Used to do handlerization. @@ -204,7 +205,8 @@ class ClassLinker { // Returns true on success, false if there's an exception pending. // can_run_clinit=false allows the compiler to attempt to init a class, // given the restriction that no <clinit> execution is possible. - bool EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool can_init_fields) + bool EnsureInitialized(const SirtRef<mirror::Class>& c, + bool can_init_fields, bool can_init_parents) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Initializes classes that have instances in the image but that have @@ -214,7 +216,7 @@ class ClassLinker { void RegisterDexFile(const DexFile& dex_file) LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) + void RegisterDexFile(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache) LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -268,7 +270,7 @@ class ClassLinker { // that this returns null if the location checksum of the DexFile // does not match the OatFile. const DexFile* FindDexFileInOatFileFromDexLocation(const char* location, - uint32_t location_checksum, + const uint32_t* const location_checksum, std::string* error_msg) LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_); @@ -303,11 +305,12 @@ class ClassLinker { size_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void VerifyClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void VerifyClass(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass, mirror::Class::Status& oat_file_class_status) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass) + void ResolveClassExceptionHandlerTypes(const DexFile& dex_file, + const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -380,7 +383,8 @@ class ClassLinker { // Alloc* convenience functions to avoid needing to pass in mirror::Class* // values that are known to the ClassLinker such as // kObjectArrayClass and kJavaLangString etc. - mirror::Class* AllocClass(Thread* self, size_t class_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Class* AllocClass(Thread* self, size_t class_size) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::ArtField* AllocArtField(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -392,12 +396,12 @@ class ClassLinker { mirror::Class* CreateArrayClass(const char* descriptor, - SirtRef<mirror::ClassLoader>& class_loader) + const SirtRef<mirror::ClassLoader>& class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void AppendToBootClassPath(const DexFile& dex_file) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) + void AppendToBootClassPath(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, @@ -409,17 +413,17 @@ class ClassLinker { void LoadClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - SirtRef<mirror::Class>& klass, + const SirtRef<mirror::Class>& klass, mirror::ClassLoader* class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it, - SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst) + const SirtRef<mirror::Class>& klass, const SirtRef<mirror::ArtField>& dst) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& dex_method, - SirtRef<mirror::Class>& klass) + const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -428,20 +432,22 @@ class ClassLinker { const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) + void RegisterDexFileLocked(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache) EXCLUSIVE_LOCKS_REQUIRED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsDexFileRegisteredLocked(const DexFile& dex_file) const SHARED_LOCKS_REQUIRED(dex_lock_); - bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents) + bool InitializeClass(const SirtRef<mirror::Class>& klass, bool can_run_clinit, + bool can_init_parents) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock); - bool ValidateSuperClassDescriptors(const mirror::Class* klass) + bool WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self, + ObjectLock<mirror::Class>& lock); + bool ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsSameDescriptorInDifferentClassContexts(const char* descriptor, - const mirror::Class* klass1, - const mirror::Class* klass2) + SirtRef<mirror::ClassLoader>& class_loader1, + SirtRef<mirror::ClassLoader>& class_loader2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsSameMethodSignatureInDifferentClassContexts(const mirror::ArtMethod* method, @@ -449,40 +455,40 @@ class ClassLinker { const mirror::Class* klass2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkClass(Thread* self, SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) + bool LinkClass(Thread* self, const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkSuperClass(SirtRef<mirror::Class>& klass) + bool LinkSuperClass(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file) + bool LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass, const DexFile& dex_file) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkMethods(SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) + bool LinkMethods(const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkVirtualMethods(SirtRef<mirror::Class>& klass) + bool LinkVirtualMethods(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkInterfaceMethods(SirtRef<mirror::Class>& klass, - SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) + bool LinkInterfaceMethods(const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkStaticFields(SirtRef<mirror::Class>& klass) + bool LinkStaticFields(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkInstanceFields(SirtRef<mirror::Class>& klass) + bool LinkInstanceFields(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool LinkFields(SirtRef<mirror::Class>& klass, bool is_static) + bool LinkFields(const SirtRef<mirror::Class>& klass, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) + void CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass) + void CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static, + void CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static, uint32_t reference_offsets) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -495,7 +501,7 @@ class ClassLinker { LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location, - uint32_t dex_location_checksum) + const uint32_t* const dex_location_checksum) LOCKS_EXCLUDED(dex_lock); const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location) LOCKS_EXCLUDED(dex_lock_); @@ -511,11 +517,11 @@ class ClassLinker { bool* open_failed) LOCKS_EXCLUDED(dex_lock_); - mirror::ArtMethod* CreateProxyConstructor(Thread* self, SirtRef<mirror::Class>& klass, + mirror::ArtMethod* CreateProxyConstructor(Thread* self, const SirtRef<mirror::Class>& klass, mirror::Class* proxy_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - mirror::ArtMethod* CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass, - SirtRef<mirror::ArtMethod>& prototype) + mirror::ArtMethod* CreateProxyMethod(Thread* self, const SirtRef<mirror::Class>& klass, + const SirtRef<mirror::ArtMethod>& prototype) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); std::vector<const DexFile*> boot_class_path_; diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index b8bc474..34134fa 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -95,8 +95,10 @@ class ClassLinkerTest : public CommonTest { const std::string& component_type, mirror::ClassLoader* class_loader) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - SirtRef<mirror::ClassLoader> loader(Thread::Current(), class_loader); - mirror::Class* array = class_linker_->FindClass(array_descriptor.c_str(), loader); + Thread* self = Thread::Current(); + SirtRef<mirror::ClassLoader> loader(self, class_loader); + SirtRef<mirror::Class> array(self, + class_linker_->FindClass(array_descriptor.c_str(), loader)); ClassHelper array_component_ch(array->GetComponentType()); EXPECT_STREQ(component_type.c_str(), array_component_ch.GetDescriptor()); EXPECT_EQ(class_loader, array->GetClassLoader()); @@ -104,10 +106,10 @@ class ClassLinkerTest : public CommonTest { AssertArrayClass(array_descriptor, array); } - void AssertArrayClass(const std::string& array_descriptor, mirror::Class* array) + void AssertArrayClass(const std::string& array_descriptor, const SirtRef<mirror::Class>& array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ClassHelper kh(array); - ASSERT_TRUE(array != NULL); + ClassHelper kh(array.get()); + ASSERT_TRUE(array.get() != NULL); ASSERT_TRUE(array->GetClass() != NULL); ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass()); EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL); @@ -135,15 +137,14 @@ class ClassLinkerTest : public CommonTest { EXPECT_EQ(0U, array->NumVirtualMethods()); EXPECT_EQ(0U, array->NumInstanceFields()); EXPECT_EQ(0U, array->NumStaticFields()); - kh.ChangeClass(array); + kh.ChangeClass(array.get()); EXPECT_EQ(2U, kh.NumDirectInterfaces()); EXPECT_TRUE(array->GetVTable() != NULL); EXPECT_EQ(2, array->GetIfTableCount()); - mirror::IfTable* iftable = array->GetIfTable(); - ASSERT_TRUE(iftable != NULL); + ASSERT_TRUE(array->GetIfTable() != NULL); kh.ChangeClass(kh.GetDirectInterface(0)); EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;"); - kh.ChangeClass(array); + kh.ChangeClass(array.get()); kh.ChangeClass(kh.GetDirectInterface(1)); EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;"); } @@ -179,9 +180,9 @@ class ClassLinkerTest : public CommonTest { EXPECT_TRUE(fh.GetType() != NULL); } - void AssertClass(const std::string& descriptor, mirror::Class* klass) + void AssertClass(const std::string& descriptor, const SirtRef<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - ClassHelper kh(klass); + ClassHelper kh(klass.get()); EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor()); if (descriptor == "Ljava/lang/Object;") { EXPECT_FALSE(klass->HasSuperClass()); @@ -197,7 +198,7 @@ class ClassLinkerTest : public CommonTest { EXPECT_FALSE(klass->IsErroneous()); EXPECT_FALSE(klass->IsArrayClass()); EXPECT_TRUE(klass->GetComponentType() == NULL); - EXPECT_TRUE(klass->IsInSamePackage(klass)); + EXPECT_TRUE(klass->IsInSamePackage(klass.get())); EXPECT_TRUE(mirror::Class::IsInSamePackage(kh.GetDescriptor(), kh.GetDescriptor())); if (klass->IsInterface()) { EXPECT_TRUE(klass->IsAbstract()); @@ -239,31 +240,31 @@ class ClassLinkerTest : public CommonTest { } EXPECT_FALSE(klass->IsPrimitive()); - EXPECT_TRUE(klass->CanAccess(klass)); + EXPECT_TRUE(klass->CanAccess(klass.get())); for (size_t i = 0; i < klass->NumDirectMethods(); i++) { mirror::ArtMethod* method = klass->GetDirectMethod(i); AssertMethod(method); EXPECT_TRUE(method->IsDirect()); - EXPECT_EQ(klass, method->GetDeclaringClass()); + EXPECT_EQ(klass.get(), method->GetDeclaringClass()); } for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { mirror::ArtMethod* method = klass->GetVirtualMethod(i); AssertMethod(method); EXPECT_FALSE(method->IsDirect()); - EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass)); + EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass.get())); } for (size_t i = 0; i < klass->NumInstanceFields(); i++) { mirror::ArtField* field = klass->GetInstanceField(i); - AssertField(klass, field); + AssertField(klass.get(), field); EXPECT_FALSE(field->IsStatic()); } for (size_t i = 0; i < klass->NumStaticFields(); i++) { mirror::ArtField* field = klass->GetStaticField(i); - AssertField(klass, field); + AssertField(klass.get(), field); EXPECT_TRUE(field->IsStatic()); } @@ -291,24 +292,24 @@ class ClassLinkerTest : public CommonTest { } size_t total_num_reference_instance_fields = 0; - mirror::Class* k = klass; + mirror::Class* k = klass.get(); while (k != NULL) { total_num_reference_instance_fields += k->NumReferenceInstanceFields(); k = k->GetSuperClass(); } - EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0, - total_num_reference_instance_fields == 0); + EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0, total_num_reference_instance_fields == 0); } void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ASSERT_TRUE(descriptor != NULL); - mirror::Class* klass = class_linker_->FindSystemClass(descriptor.c_str()); - ASSERT_TRUE(klass != NULL); - EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor()); + SirtRef<mirror::Class> klass(Thread::Current(), + class_linker_->FindSystemClass(descriptor.c_str())); + ASSERT_TRUE(klass.get() != nullptr); + EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass.get()).GetDescriptor()); EXPECT_EQ(class_loader, klass->GetClassLoader()); if (klass->IsPrimitive()) { - AssertPrimitiveClass(descriptor, klass); + AssertPrimitiveClass(descriptor, klass.get()); } else if (klass->IsArrayClass()) { AssertArrayClass(descriptor, klass); } else { @@ -852,7 +853,7 @@ TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) { TEST_F(ClassLinkerTest, StaticFields) { ScopedObjectAccess soa(Thread::Current()); SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))); - mirror::Class* statics = class_linker_->FindClass("LStatics;", class_loader); + SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass("LStatics;", class_loader)); class_linker_->EnsureInitialized(statics, true, true); // Static final primitives that are initialized by a compile-time constant @@ -867,68 +868,68 @@ TEST_F(ClassLinkerTest, StaticFields) { FieldHelper fh(s0); EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/ArtField;"); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean); - EXPECT_EQ(true, s0->GetBoolean(statics)); - s0->SetBoolean(statics, false); + EXPECT_EQ(true, s0->GetBoolean(statics.get())); + s0->SetBoolean(statics.get(), false); mirror::ArtField* s1 = statics->FindStaticField("s1", "B"); fh.ChangeField(s1); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte); - EXPECT_EQ(5, s1->GetByte(statics)); - s1->SetByte(statics, 6); + EXPECT_EQ(5, s1->GetByte(statics.get())); + s1->SetByte(statics.get(), 6); mirror::ArtField* s2 = statics->FindStaticField("s2", "C"); fh.ChangeField(s2); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar); - EXPECT_EQ('a', s2->GetChar(statics)); - s2->SetChar(statics, 'b'); + EXPECT_EQ('a', s2->GetChar(statics.get())); + s2->SetChar(statics.get(), 'b'); mirror::ArtField* s3 = statics->FindStaticField("s3", "S"); fh.ChangeField(s3); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort); - EXPECT_EQ(-536, s3->GetShort(statics)); - s3->SetShort(statics, -535); + EXPECT_EQ(-536, s3->GetShort(statics.get())); + s3->SetShort(statics.get(), -535); mirror::ArtField* s4 = statics->FindStaticField("s4", "I"); fh.ChangeField(s4); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt); - EXPECT_EQ(2000000000, s4->GetInt(statics)); - s4->SetInt(statics, 2000000001); + EXPECT_EQ(2000000000, s4->GetInt(statics.get())); + s4->SetInt(statics.get(), 2000000001); mirror::ArtField* s5 = statics->FindStaticField("s5", "J"); fh.ChangeField(s5); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong); - EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics)); - s5->SetLong(statics, 0x34567890abcdef12LL); + EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get())); + s5->SetLong(statics.get(), 0x34567890abcdef12LL); mirror::ArtField* s6 = statics->FindStaticField("s6", "F"); fh.ChangeField(s6); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat); - EXPECT_EQ(0.5, s6->GetFloat(statics)); - s6->SetFloat(statics, 0.75); + EXPECT_EQ(0.5, s6->GetFloat(statics.get())); + s6->SetFloat(statics.get(), 0.75); mirror::ArtField* s7 = statics->FindStaticField("s7", "D"); fh.ChangeField(s7); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble); - EXPECT_EQ(16777217, s7->GetDouble(statics)); - s7->SetDouble(statics, 16777219); + EXPECT_EQ(16777217, s7->GetDouble(statics.get())); + s7->SetDouble(statics.get(), 16777219); mirror::ArtField* s8 = statics->FindStaticField("s8", "Ljava/lang/String;"); fh.ChangeField(s8); EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot); - EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("android")); + EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android")); s8->SetObject(s8->GetDeclaringClass(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot")); // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ // http://code.google.com/p/googletest/issues/detail?id=322 - EXPECT_FALSE(s0->GetBoolean(statics)); - EXPECT_EQ(6, s1->GetByte(statics)); - EXPECT_EQ('b', s2->GetChar(statics)); - EXPECT_EQ(-535, s3->GetShort(statics)); - EXPECT_EQ(2000000001, s4->GetInt(statics)); - EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics)); - EXPECT_EQ(0.75, s6->GetFloat(statics)); - EXPECT_EQ(16777219, s7->GetDouble(statics)); - EXPECT_TRUE(s8->GetObject(statics)->AsString()->Equals("robot")); + EXPECT_FALSE(s0->GetBoolean(statics.get())); + EXPECT_EQ(6, s1->GetByte(statics.get())); + EXPECT_EQ('b', s2->GetChar(statics.get())); + EXPECT_EQ(-535, s3->GetShort(statics.get())); + EXPECT_EQ(2000000001, s4->GetInt(statics.get())); + EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics.get())); + EXPECT_EQ(0.75, s6->GetFloat(statics.get())); + EXPECT_EQ(16777219, s7->GetDouble(statics.get())); + EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("robot")); } TEST_F(ClassLinkerTest, Interfaces) { diff --git a/runtime/debugger.cc b/runtime/debugger.cc index edfd21f..bcf7267 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -452,6 +452,7 @@ void Dbg::StartJdwp() { void Dbg::StopJdwp() { delete gJdwpState; + gJdwpState = NULL; delete gRegistry; gRegistry = NULL; } @@ -1132,7 +1133,7 @@ bool Dbg::MatchType(JDWP::RefTypeId instance_class_id, JDWP::RefTypeId class_id) CHECK(c1 != NULL); mirror::Class* c2 = DecodeClass(class_id, status); CHECK(c2 != NULL); - return c1->IsAssignableFrom(c2); + return c2->IsAssignableFrom(c1); } static JDWP::FieldId ToFieldId(const mirror::ArtField* f) @@ -2731,7 +2732,7 @@ JDWP::JdwpError Dbg::InvokeMethod(JDWP::ObjectId thread_id, JDWP::ObjectId objec if (argument == ObjectRegistry::kInvalidObject) { return JDWP::ERR_INVALID_OBJECT; } - if (!argument->InstanceOf(parameter_type)) { + if (argument != NULL && !argument->InstanceOf(parameter_type)) { return JDWP::ERR_ILLEGAL_ARGUMENT; } @@ -2835,30 +2836,30 @@ void Dbg::ExecuteMethod(DebugInvokeReq* pReq) { } // Translate the method through the vtable, unless the debugger wants to suppress it. - mirror::ArtMethod* m = pReq->method; + SirtRef<mirror::ArtMethod> m(soa.Self(), pReq->method); if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != NULL) { mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(pReq->method); - if (actual_method != m) { - VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m) << " to " << PrettyMethod(actual_method); - m = actual_method; + if (actual_method != m.get()) { + VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.get()) << " to " << PrettyMethod(actual_method); + m.reset(actual_method); } } - VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m) + VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m.get()) << " receiver=" << pReq->receiver << " arg_count=" << pReq->arg_count; - CHECK(m != NULL); + CHECK(m.get() != nullptr); CHECK_EQ(sizeof(jvalue), sizeof(uint64_t)); - MethodHelper mh(m); + MethodHelper mh(m.get()); ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength()); arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values)); - InvokeWithArgArray(soa, m, &arg_array, &pReq->result_value, mh.GetShorty()[0]); + InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty()[0]); mirror::Throwable* exception = soa.Self()->GetException(NULL); soa.Self()->ClearException(); pReq->exception = gRegistry->Add(exception); - pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m).GetShorty()); + pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.get()).GetShorty()); if (pReq->exception != 0) { VLOG(jdwp) << " JDWP invocation returning with exception=" << exception << " " << exception->Dump(); diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 517f96c..429c516 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -98,9 +98,10 @@ bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* *error_msg = StringPrintf("Failed to open zip archive '%s'", filename); return false; } - UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex)); + UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex, error_msg)); if (zip_entry.get() == NULL) { - *error_msg = StringPrintf("Zip archive '%s' doesn\'t contain %s", filename, kClassesDex); + *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename, + kClassesDex, error_msg->c_str()); return false; } *checksum = zip_entry->GetCrc32(); @@ -176,7 +177,7 @@ const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify, struct stat sbuf; memset(&sbuf, 0, sizeof(sbuf)); if (fstat(fd, &sbuf) == -1) { - *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno)); + *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location, strerror(errno)); return nullptr; } if (S_ISDIR(sbuf.st_mode)) { @@ -193,7 +194,7 @@ const DexFile* DexFile::OpenFile(int fd, const char* location, bool verify, if (map->Size() < sizeof(DexFile::Header)) { *error_msg = StringPrintf( - "DexFile: failed to open dex file \'%s\' that is too short to have a header", location); + "DexFile: failed to open dex file '%s' that is too short to have a header", location); return nullptr; } @@ -240,9 +241,8 @@ const DexFile* DexFile::OpenMemory(const std::string& location, const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location, std::string* error_msg) { CHECK(!location.empty()); - UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex)); + UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex, error_msg)); if (zip_entry.get() == NULL) { - *error_msg = StringPrintf("Failed to find classes.dex within '%s'", location.c_str()); return nullptr; } UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex, error_msg)); diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 56bf21d..dc9d337 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -16,6 +16,8 @@ #include "dex_file_verifier.h" +#include <zlib.h> + #include "base/stringprintf.h" #include "dex_file-inl.h" #include "leb128.h" @@ -23,7 +25,6 @@ #include "UniquePtr.h" #include "utf-inl.h" #include "utils.h" -#include "zip_archive.h" namespace art { diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc index 9961df9..2941db6 100644 --- a/runtime/dex_method_iterator_test.cc +++ b/runtime/dex_method_iterator_test.cc @@ -36,7 +36,7 @@ class DexMethodIteratorTest : public CommonTest { TEST_F(DexMethodIteratorTest, Basic) { ScopedObjectAccess soa(Thread::Current()); std::vector<const DexFile*> dex_files; - dex_files.push_back(OpenDexFile("core")); + dex_files.push_back(OpenDexFile("core-libart")); dex_files.push_back(OpenDexFile("conscrypt")); dex_files.push_back(OpenDexFile("okhttp")); dex_files.push_back(OpenDexFile("core-junit")); diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 2806f94..3ab8888 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -57,7 +57,7 @@ static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror: ThrowLocation throw_location = self->GetCurrentLocationForThrow(); DCHECK(throw_location.GetMethod() == referrer); self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;", - "Found type %s; filled-new-array not implemented for anything but \'int\'", + "Found type %s; filled-new-array not implemented for anything but 'int'", PrettyDescriptor(klass).c_str()); } return nullptr; // Failure diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 747dd56..bfdbd74 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -72,7 +72,7 @@ ALWAYS_INLINE static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx, if (UNLIKELY(!klass->IsInitialized())) { SirtRef<mirror::Class> sirt_klass(self, klass); // The class initializer might cause a GC. - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(klass, true, true)) { + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { DCHECK(self->IsExceptionPending()); return nullptr; // Failure } @@ -246,12 +246,15 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, const mirr // If the class is initialized we're done. if (LIKELY(fields_class->IsInitialized())) { return resolved_field; - } else if (LIKELY(class_linker->EnsureInitialized(fields_class, true, true))) { - // Otherwise let's ensure the class is initialized before resolving the field. - return resolved_field; } else { - DCHECK(self->IsExceptionPending()); // Throw exception and unwind - return nullptr; // failure + SirtRef<mirror::Class> sirt_class(self, fields_class); + if (LIKELY(class_linker->EnsureInitialized(sirt_class, true, true))) { + // Otherwise let's ensure the class is initialized before resolving the field. + return resolved_field; + } else { + DCHECK(self->IsExceptionPending()); // Throw exception and unwind + return nullptr; // failure + } } } } @@ -535,12 +538,13 @@ static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) { return klass; } - if (!class_linker->EnsureInitialized(klass, true, true)) { + SirtRef<mirror::Class> sirt_class(self, klass); + if (!class_linker->EnsureInitialized(sirt_class, true, true)) { CHECK(self->IsExceptionPending()); return NULL; // Failure - Indicate to caller to deliver exception } - referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass); - return klass; + referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, sirt_class.get()); + return sirt_class.get(); } extern void ThrowStackOverflowError(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index 05c02f2..0df00c2 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -33,12 +33,15 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m if (method->IsStatic()) { mirror::Class* declaringClass = method->GetDeclaringClass(); if (UNLIKELY(!declaringClass->IsInitializing())) { - if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass, - true, true))) { - DCHECK(Thread::Current()->IsExceptionPending()); + self->PushShadowFrame(shadow_frame); + SirtRef<mirror::Class> sirt_c(self, declaringClass); + if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true))) { + self->PopShadowFrame(); + DCHECK(self->IsExceptionPending()); return; } - CHECK(declaringClass->IsInitializing()); + self->PopShadowFrame(); + CHECK(sirt_c->IsInitializing()); } } uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_; diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc index 16364fc..4d1e531 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.cc +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -50,7 +50,7 @@ static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) { intptr_t value = *arg_ptr; mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value); mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL; - CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) + CHECK(Runtime::Current()->GetHeap()->IsValidObjectAddress(value_as_work_around_rep)) << value_as_work_around_rep; *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep); } diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc index 8a2c899..4f19964 100644 --- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc @@ -36,11 +36,7 @@ class ShadowFrameCopyVisitor : public StackVisitor { ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc); const uint8_t* gc_map = method->GetNativeGcMap(); - uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) | - (gc_map[1] << 16) | - (gc_map[2] << 8) | - (gc_map[3] << 0)); - verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length); + verifier::DexPcToReferenceMap dex_gc_map(gc_map); const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc); for (size_t reg = 0; reg < num_regs; ++reg) { if (TestBitmap(reg, reg_bitmap)) { diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc index 61f7440..2162dcc 100644 --- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -208,8 +208,8 @@ extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Th if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) { // Ensure static method's class is initialized. - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(), - true, true)) { + SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass()); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) { DCHECK(Thread::Current()->IsExceptionPending()); self->PopManagedStackFragment(fragment); return 0; @@ -390,7 +390,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called const void* code = NULL; if (LIKELY(!thread->IsExceptionPending())) { // Ensure that the called method's class is initialized. - mirror::Class* called_class = called->GetDeclaringClass(); + SirtRef<mirror::Class> called_class(thread, called->GetDeclaringClass()); linker->EnsureInitialized(called_class, true, true); if (LIKELY(called_class->IsInitialized())) { code = called->GetEntryPointFromCompiledCode(); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 8ba08ee..b589384 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -298,8 +298,8 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) { // Ensure static method's class is initialized. - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(), - true, true)) { + SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass()); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) { DCHECK(Thread::Current()->IsExceptionPending()); self->PopManagedStackFragment(fragment); return 0; @@ -564,7 +564,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, } } // Ensure that the called method's class is initialized. - mirror::Class* called_class = called->GetDeclaringClass(); + SirtRef<mirror::Class> called_class(soa.Self(), called->GetDeclaringClass()); linker->EnsureInitialized(called_class, true, true); if (LIKELY(called_class->IsInitialized())) { code = called->GetEntryPointFromCompiledCode(); diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index e9a6e4f..978faeb 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -37,11 +37,13 @@ class ExceptionTest : public CommonTest { CommonTest::SetUp(); ScopedObjectAccess soa(Thread::Current()); - SirtRef<mirror::ClassLoader> class_loader(soa.Self(), - soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))); + SirtRef<mirror::ClassLoader> class_loader( + soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))); my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader); ASSERT_TRUE(my_klass_ != NULL); - class_linker_->EnsureInitialized(my_klass_, true, true); + SirtRef<mirror::Class> sirt_klass(soa.Self(), my_klass_); + class_linker_->EnsureInitialized(sirt_klass, true, true); + my_klass_ = sirt_klass.get(); dex_ = my_klass_->GetDexCache()->GetDexFile(); @@ -54,17 +56,17 @@ class ExceptionTest : public CommonTest { fake_code_.push_back(0x70 | i); } - fake_mapping_data_.PushBack(4); // first element is count - fake_mapping_data_.PushBack(4); // total (non-length) elements - fake_mapping_data_.PushBack(2); // count of pc to dex elements + fake_mapping_data_.PushBackUnsigned(4); // first element is count + fake_mapping_data_.PushBackUnsigned(4); // total (non-length) elements + fake_mapping_data_.PushBackUnsigned(2); // count of pc to dex elements // --- pc to dex table - fake_mapping_data_.PushBack(3); // offset 3 - fake_mapping_data_.PushBack(3); // maps to dex offset 3 + fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3 + fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3 // --- dex to pc table - fake_mapping_data_.PushBack(3); // offset 3 - fake_mapping_data_.PushBack(3); // maps to dex offset 3 + fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3 + fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3 - fake_vmap_table_data_.PushBack(0); + fake_vmap_table_data_.PushBackUnsigned(0); fake_gc_map_.push_back(0); // 0 bytes to encode references and native pc offsets. fake_gc_map_.push_back(0); @@ -91,8 +93,8 @@ class ExceptionTest : public CommonTest { const DexFile* dex_; std::vector<uint8_t> fake_code_; - UnsignedLeb128EncodingVector fake_mapping_data_; - UnsignedLeb128EncodingVector fake_vmap_table_data_; + Leb128EncodingVector fake_mapping_data_; + Leb128EncodingVector fake_vmap_table_data_; std::vector<uint8_t> fake_gc_map_; mirror::ArtMethod* method_f_; diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index 7818bc8..e099137 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -95,8 +95,8 @@ void CardTable::ClearSpaceCards(space::ContinuousSpace* space) { } void CardTable::ClearCardTable() { - // TODO: clear just the range of the table that has been modified - memset(mem_map_->Begin(), kCardClean, mem_map_->Size()); + COMPILE_ASSERT(kCardClean == 0, clean_card_must_be_0); + madvise(mem_map_->Begin(), mem_map_->Size(), MADV_DONTNEED); } bool CardTable::AddrIsInCardTable(const void* addr) const { diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index faa198a..b428e74 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -82,7 +82,7 @@ class ModUnionUpdateObjectReferencesVisitor { if (ref != nullptr) { Object* new_ref = visitor_(ref, arg_); if (new_ref != ref) { - obj->SetFieldObject(offset, new_ref, true); + obj->SetFieldPtr(offset, new_ref, true); } } } diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h index 7a51553..9c1c5dc 100644 --- a/runtime/gc/collector/mark_sweep-inl.h +++ b/runtime/gc/collector/mark_sweep-inl.h @@ -69,15 +69,14 @@ inline void MarkSweep::VisitObjectReferences(mirror::Object* obj, const Visitor& DCHECK(obj->GetClass() != NULL); mirror::Class* klass = obj->GetClass(); DCHECK(klass != NULL); - if (visit_class) { - visitor(obj, klass, mirror::Object::ClassOffset(), false); - } if (klass == mirror::Class::GetJavaLangClass()) { DCHECK_EQ(klass->GetClass(), mirror::Class::GetJavaLangClass()); VisitClassReferences(klass, obj, visitor); } else { if (klass->IsArrayClass()) { - visitor(obj, klass, mirror::Object::ClassOffset(), false); + if (visit_class) { + visitor(obj, klass, mirror::Object::ClassOffset(), false); + } if (klass->IsObjectArrayClass()) { VisitObjectArrayReferences(obj->AsObjectArray<mirror::Object>(), visitor); } diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 53d85b0..62991bb 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -89,10 +89,12 @@ class MarkSweep : public GarbageCollector { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void MarkNonThreadRoots() - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void MarkConcurrentRoots(); - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); + void MarkConcurrentRoots() + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void MarkRootsCheckpoint(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index 3939354..b75b493 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -78,6 +78,8 @@ namespace collector { static constexpr bool kProtectFromSpace = true; static constexpr bool kResetFromSpace = true; +// TODO: move this to a new file as a new garbage collector? +static constexpr bool kEnableSimplePromo = false; // TODO: Unduplicate logic. void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) { @@ -134,7 +136,9 @@ SemiSpace::SemiSpace(Heap* heap, const std::string& name_prefix) finalizer_reference_list_(nullptr), phantom_reference_list_(nullptr), cleared_reference_list_(nullptr), - self_(nullptr) { + self_(nullptr), + last_gc_to_space_end_(nullptr), + bytes_promoted_(0) { } void SemiSpace::InitializePhase() { @@ -169,10 +173,25 @@ void SemiSpace::MarkingPhase() { // Need to do this with mutators paused so that somebody doesn't accidentally allocate into the // wrong space. heap_->SwapSemiSpaces(); + if (kEnableSimplePromo) { + // If last_gc_to_space_end_ is out of the bounds of the from-space + // (the to-space from last GC), then point it to the beginning of + // the from-space. For example, the very first GC or the + // pre-zygote compaction. + if (!from_space_->HasAddress(reinterpret_cast<mirror::Object*>(last_gc_to_space_end_))) { + last_gc_to_space_end_ = from_space_->Begin(); + } + // Reset this before the marking starts below. + bytes_promoted_ = 0; + } // Assume the cleared space is already empty. BindBitmaps(); // Process dirty cards and add dirty cards to mod-union tables. heap_->ProcessCards(timings_); + // Clear the whole card table since we can not get any additional dirty cards during the + // paused GC. This saves memory but only works for pause the world collectors. + timings_.NewSplit("ClearCardTable"); + heap_->GetCardTable()->ClearCardTable(); // Need to do this before the checkpoint since we don't want any threads to add references to // the live stack during the recursive mark. timings_.NewSplit("SwapStacks"); @@ -268,6 +287,13 @@ void SemiSpace::ReclaimPhase() { } else { mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ); } + + if (kEnableSimplePromo) { + // Record the end (top) of the to space so we can distinguish + // between objects that were allocated since the last GC and the + // older objects. + last_gc_to_space_end_ = to_space_->End(); + } } void SemiSpace::ResizeMarkStack(size_t new_size) { @@ -308,20 +334,48 @@ Object* SemiSpace::MarkObject(Object* obj) { if (from_space_->HasAddress(obj)) { mirror::Object* forward_address = GetForwardingAddressInFromSpace(obj); // If the object has already been moved, return the new forward address. - if (!to_space_->HasAddress(forward_address)) { + if (forward_address == nullptr) { // Otherwise, we need to move the object and add it to the markstack for processing. size_t object_size = obj->SizeOf(); size_t dummy = 0; - forward_address = to_space_->Alloc(self_, object_size, &dummy); + if (kEnableSimplePromo && reinterpret_cast<byte*>(obj) < last_gc_to_space_end_) { + // If it's allocated before the last GC (older), move (pseudo-promote) it to + // the non-moving space (as sort of an old generation.) + size_t bytes_promoted; + space::MallocSpace* non_moving_space = GetHeap()->GetNonMovingSpace(); + forward_address = non_moving_space->Alloc(self_, object_size, &bytes_promoted); + if (forward_address == nullptr) { + // If out of space, fall back to the to-space. + forward_address = to_space_->Alloc(self_, object_size, &dummy); + } else { + GetHeap()->num_bytes_allocated_.fetch_add(bytes_promoted); + bytes_promoted_ += bytes_promoted; + // Mark forward_address on the live bit map. + accounting::SpaceBitmap* live_bitmap = non_moving_space->GetLiveBitmap(); + DCHECK(live_bitmap != nullptr); + DCHECK(!live_bitmap->Test(forward_address)); + live_bitmap->Set(forward_address); + // Mark forward_address on the mark bit map. + accounting::SpaceBitmap* mark_bitmap = non_moving_space->GetMarkBitmap(); + DCHECK(mark_bitmap != nullptr); + DCHECK(!mark_bitmap->Test(forward_address)); + mark_bitmap->Set(forward_address); + } + DCHECK(forward_address != nullptr); + } else { + // If it's allocated after the last GC (younger), copy it to the to-space. + forward_address = to_space_->Alloc(self_, object_size, &dummy); + } // Copy over the object and add it to the mark stack since we still need to update it's // references. memcpy(reinterpret_cast<void*>(forward_address), obj, object_size); // Make sure to only update the forwarding address AFTER you copy the object so that the // monitor word doesn't get stomped over. - COMPILE_ASSERT(sizeof(uint32_t) == sizeof(mirror::Object*), - monitor_size_must_be_same_as_object); obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address))); MarkStackPush(forward_address); + } else { + DCHECK(to_space_->HasAddress(forward_address) || + (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forward_address))); } ret = forward_address; // TODO: Do we need this if in the else statement? @@ -508,7 +562,10 @@ void SemiSpace::ScanObject(Object* obj) { mirror::Object* new_address = MarkObject(ref); if (new_address != ref) { DCHECK(new_address != nullptr); - obj->SetFieldObject(offset, new_address, false); + // Don't need to mark the card since we updating the object address and not changing the + // actual objects its pointing to. Using SetFieldPtr is better in this case since it does not + // dirty cards and use additional memory. + obj->SetFieldPtr(offset, new_address, false); } }, kMovingClasses); mirror::Class* klass = obj->GetClass(); @@ -535,7 +592,9 @@ inline Object* SemiSpace::GetMarkedForwardAddress(mirror::Object* obj) const if (from_space_->HasAddress(obj)) { mirror::Object* forwarding_address = GetForwardingAddressInFromSpace(const_cast<Object*>(obj)); // If the object is forwarded then it MUST be marked. - if (to_space_->HasAddress(forwarding_address)) { + DCHECK(forwarding_address == nullptr || to_space_->HasAddress(forwarding_address) || + (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forwarding_address))); + if (forwarding_address != nullptr) { return forwarding_address; } // Must not be marked, return nullptr; diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index 0f0cae1..b0724f9 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -281,6 +281,15 @@ class SemiSpace : public GarbageCollector { Thread* self_; + // Used for kEnableSimplePromo. The end/top of the bump pointer + // space at the end of the last collection. + byte* last_gc_to_space_end_; + + // Used for kEnableSimplePromo. During a collection, keeps track of + // how many bytes of objects have been copied so far from the bump + // pointer space to the non-moving space. + uint64_t bytes_promoted_; + private: DISALLOW_COPY_AND_ASSIGN(SemiSpace); }; diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h index ba3cad6..06395cf 100644 --- a/runtime/gc/collector_type.h +++ b/runtime/gc/collector_type.h @@ -24,6 +24,8 @@ namespace gc { // Which types of collections are able to be performed. enum CollectorType { + // No collector selected. + kCollectorTypeNone, // Non concurrent mark-sweep. kCollectorTypeMS, // Concurrent mark-sweep. diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index 5eda0b9..99f084a 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -41,24 +41,20 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas // done in the runnable state where suspension is expected. DCHECK_EQ(self->GetState(), kRunnable); self->AssertThreadSuspensionIsAllowable(); + // Need to check that we arent the large object allocator since the large object allocation code + // path this function. If we didn't check we would have an infinite loop. + if (allocator != kAllocatorTypeLOS && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) { + return AllocLargeObject<kInstrumented, PreFenceVisitor>(self, klass, byte_count, + pre_fence_visitor); + } mirror::Object* obj; size_t bytes_allocated; AllocationTimer alloc_timer(this, &obj); - if (UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) { - obj = TryToAllocate<kInstrumented>(self, kAllocatorTypeLOS, byte_count, false, - &bytes_allocated); - allocator = kAllocatorTypeLOS; - } else { - obj = TryToAllocate<kInstrumented>(self, allocator, byte_count, false, &bytes_allocated); - } - + obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count, &bytes_allocated); if (UNLIKELY(obj == nullptr)) { - SirtRef<mirror::Class> sirt_c(self, klass); - obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated); + obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated, &klass); if (obj == nullptr) { return nullptr; - } else { - klass = sirt_c.get(); } } obj->SetClass(klass); @@ -93,7 +89,7 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas } else { DCHECK(!Dbg::IsAllocTrackingEnabled()); } - if (AllocatorHasConcurrentGC(allocator)) { + if (concurrent_gc_) { CheckConcurrentGC(self, new_num_bytes_allocated, obj); } if (kIsDebugBuild) { @@ -105,17 +101,28 @@ inline mirror::Object* Heap::AllocObjectWithAllocator(Thread* self, mirror::Clas return obj; } -template <const bool kInstrumented> +template <bool kInstrumented, typename PreFenceVisitor> +inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class* klass, + size_t byte_count, + const PreFenceVisitor& pre_fence_visitor) { + return AllocObjectWithAllocator<kInstrumented, PreFenceVisitor>(self, klass, byte_count, + kAllocatorTypeLOS, + pre_fence_visitor); +} + +template <const bool kInstrumented, const bool kGrow> inline mirror::Object* Heap::TryToAllocate(Thread* self, AllocatorType allocator_type, - size_t alloc_size, bool grow, - size_t* bytes_allocated) { - if (UNLIKELY(IsOutOfMemoryOnAllocation(alloc_size, grow))) { + size_t alloc_size, size_t* bytes_allocated) { + if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(alloc_size))) { return nullptr; } if (kInstrumented) { if (UNLIKELY(running_on_valgrind_ && allocator_type == kAllocatorTypeFreeList)) { return non_moving_space_->Alloc(self, alloc_size, bytes_allocated); } + } else { + // If running on valgrind, we should be using the instrumented path. + DCHECK(!running_on_valgrind_); } mirror::Object* ret; switch (allocator_type) { @@ -187,18 +194,21 @@ inline bool Heap::ShouldAllocLargeObject(mirror::Class* c, size_t byte_count) co return byte_count >= kLargeObjectThreshold && have_zygote_space_ && c->IsPrimitiveArray(); } -inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow) { +template <const bool kGrow> +inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size) { size_t new_footprint = num_bytes_allocated_ + alloc_size; if (UNLIKELY(new_footprint > max_allowed_footprint_)) { if (UNLIKELY(new_footprint > growth_limit_)) { return true; } if (!concurrent_gc_) { - if (!grow) { + if (!kGrow) { return true; - } else { - max_allowed_footprint_ = new_footprint; } + // TODO: Grow for allocation is racy, fix it. + VLOG(heap) << "Growing heap from " << PrettySize(max_allowed_footprint_) << " to " + << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation"; + max_allowed_footprint_ = new_footprint; } } return false; diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 5e62729..11acd33 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -75,12 +75,13 @@ static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB; Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free, double target_utilization, size_t capacity, const std::string& image_file_name, - CollectorType collector_type, size_t parallel_gc_threads, size_t conc_gc_threads, - bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold, - bool ignore_max_footprint) + CollectorType post_zygote_collector_type, size_t parallel_gc_threads, + size_t conc_gc_threads, bool low_memory_mode, size_t long_pause_log_threshold, + size_t long_gc_log_threshold, bool ignore_max_footprint) : non_moving_space_(nullptr), - concurrent_gc_(collector_type == gc::kCollectorTypeCMS), - collector_type_(collector_type), + concurrent_gc_(false), + collector_type_(kCollectorTypeNone), + post_zygote_collector_type_(post_zygote_collector_type), parallel_gc_threads_(parallel_gc_threads), conc_gc_threads_(conc_gc_threads), low_memory_mode_(low_memory_mode), @@ -107,11 +108,9 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max activity_thread_(NULL), application_thread_(NULL), last_process_state_id_(NULL), - // Initially care about pauses in case we never get notified of process states, or if the JNI - // code becomes broken. - care_about_pause_times_(true), - concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes - : std::numeric_limits<size_t>::max()), + // Initially assume we perceive jank in case the process state is never updated. + process_state_(kProcessStateJankPerceptible), + concurrent_start_bytes_(std::numeric_limits<size_t>::max()), total_bytes_freed_ever_(0), total_objects_freed_ever_(0), num_bytes_allocated_(0), @@ -156,8 +155,12 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max // If we aren't the zygote, switch to the default non zygote allocator. This may update the // entrypoints. if (!Runtime::Current()->IsZygote()) { - ChangeCollector(collector_type_); + ChangeCollector(post_zygote_collector_type_); + } else { + // We are the zygote, use bump pointer allocation + semi space collector. + ChangeCollector(kCollectorTypeSS); } + live_bitmap_.reset(new accounting::HeapBitmap(this)); mark_bitmap_.reset(new accounting::HeapBitmap(this)); // Requested begin for the alloc space, to follow the mapped image and oat files @@ -263,9 +266,6 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max garbage_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent)); garbage_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent)); } - gc_plan_.push_back(collector::kGcTypeSticky); - gc_plan_.push_back(collector::kGcTypePartial); - gc_plan_.push_back(collector::kGcTypeFull); if (kMovingCollector) { // TODO: Clean this up. semi_space_collector_ = new collector::SemiSpace(this); @@ -325,6 +325,10 @@ void Heap::DecrementDisableGC(Thread* self) { --gc_disable_count_; } +void Heap::UpdateProcessState(ProcessState process_state) { + process_state_ = process_state; +} + void Heap::CreateThreadPool() { const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_); if (num_threads != 0) { @@ -373,124 +377,6 @@ void Heap::DeleteThreadPool() { thread_pool_.reset(nullptr); } -static bool ReadStaticInt(JNIEnvExt* env, jclass clz, const char* name, int* out_value) { - DCHECK(out_value != NULL); - jfieldID field = env->GetStaticFieldID(clz, name, "I"); - if (field == NULL) { - env->ExceptionClear(); - return false; - } - *out_value = env->GetStaticIntField(clz, field); - return true; -} - -void Heap::ListenForProcessStateChange() { - VLOG(heap) << "Heap notified of process state change"; - - Thread* self = Thread::Current(); - JNIEnvExt* env = self->GetJniEnv(); - - if (!have_zygote_space_) { - return; - } - - if (activity_thread_class_ == NULL) { - jclass clz = env->FindClass("android/app/ActivityThread"); - if (clz == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not find activity thread class in process state change"; - return; - } - activity_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz)); - } - - if (activity_thread_class_ != NULL && activity_thread_ == NULL) { - jmethodID current_activity_method = env->GetStaticMethodID(activity_thread_class_, - "currentActivityThread", - "()Landroid/app/ActivityThread;"); - if (current_activity_method == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get method for currentActivityThread"; - return; - } - - jobject obj = env->CallStaticObjectMethod(activity_thread_class_, current_activity_method); - if (obj == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get current activity"; - return; - } - activity_thread_ = env->NewGlobalRef(obj); - } - - if (process_state_cares_about_pause_time_.empty()) { - // Just attempt to do this the first time. - jclass clz = env->FindClass("android/app/ActivityManager"); - if (clz == NULL) { - LOG(WARNING) << "Activity manager class is null"; - return; - } - ScopedLocalRef<jclass> activity_manager(env, clz); - std::vector<const char*> care_about_pauses; - care_about_pauses.push_back("PROCESS_STATE_TOP"); - care_about_pauses.push_back("PROCESS_STATE_IMPORTANT_BACKGROUND"); - // Attempt to read the constants and classify them as whether or not we care about pause times. - for (size_t i = 0; i < care_about_pauses.size(); ++i) { - int process_state = 0; - if (ReadStaticInt(env, activity_manager.get(), care_about_pauses[i], &process_state)) { - process_state_cares_about_pause_time_.insert(process_state); - VLOG(heap) << "Adding process state " << process_state - << " to set of states which care about pause time"; - } - } - } - - if (application_thread_class_ == NULL) { - jclass clz = env->FindClass("android/app/ActivityThread$ApplicationThread"); - if (clz == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get application thread class"; - return; - } - application_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz)); - last_process_state_id_ = env->GetFieldID(application_thread_class_, "mLastProcessState", "I"); - if (last_process_state_id_ == NULL) { - env->ExceptionClear(); - LOG(WARNING) << "Could not get last process state member"; - return; - } - } - - if (application_thread_class_ != NULL && application_thread_ == NULL) { - jmethodID get_application_thread = - env->GetMethodID(activity_thread_class_, "getApplicationThread", - "()Landroid/app/ActivityThread$ApplicationThread;"); - if (get_application_thread == NULL) { - LOG(WARNING) << "Could not get method ID for get application thread"; - return; - } - - jobject obj = env->CallObjectMethod(activity_thread_, get_application_thread); - if (obj == NULL) { - LOG(WARNING) << "Could not get application thread"; - return; - } - - application_thread_ = env->NewGlobalRef(obj); - } - - if (application_thread_ != NULL && last_process_state_id_ != NULL) { - int process_state = env->GetIntField(application_thread_, last_process_state_id_); - env->ExceptionClear(); - - care_about_pause_times_ = process_state_cares_about_pause_time_.find(process_state) != - process_state_cares_about_pause_time_.end(); - - VLOG(heap) << "New process state " << process_state - << " care about pauses " << care_about_pause_times_; - } -} - void Heap::AddSpace(space::Space* space) { DCHECK(space != NULL); WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); @@ -995,14 +881,17 @@ void Heap::RecordFree(size_t freed_objects, size_t freed_bytes) { } mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocator, - size_t alloc_size, size_t* bytes_allocated) { + size_t alloc_size, size_t* bytes_allocated, + mirror::Class** klass) { mirror::Object* ptr = nullptr; + DCHECK(klass != nullptr); + SirtRef<mirror::Class> sirt_klass(self, *klass); // The allocation failed. If the GC is running, block until it completes, and then retry the // allocation. collector::GcType last_gc = WaitForGcToComplete(self); if (last_gc != collector::kGcTypeNone) { // A GC was in progress and we blocked, retry allocation now that memory has been freed. - ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated); + ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated); } // Loop through our different Gc types and try to Gc until we get enough free memory. @@ -1013,13 +902,13 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocat // Attempt to run the collector, if we succeed, re-try the allocation. if (CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone) { // Did we free sufficient memory for the allocation to succeed? - ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated); + ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated); } } // Allocations have failed after GCs; this is an exceptional state. if (ptr == nullptr) { // Try harder, growing the heap if necessary. - ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated); + ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated); } if (ptr == nullptr) { // Most allocations should have succeeded by now, so the heap is really full, really fragmented, @@ -1032,11 +921,12 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocat // We don't need a WaitForGcToComplete here either. DCHECK(!gc_plan_.empty()); CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true); - ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated); + ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated); if (ptr == nullptr) { ThrowOutOfMemoryError(self, alloc_size, false); } } + *klass = sirt_klass.get(); return ptr; } @@ -1200,22 +1090,46 @@ void Heap::GetReferringObjects(mirror::Object* o, int32_t max_count, void Heap::CollectGarbage(bool clear_soft_references) { // Even if we waited for a GC we still need to do another GC since weaks allocated during the // last GC will not have necessarily been cleared. - CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references); + CollectGarbageInternal(gc_plan_.back(), kGcCauseExplicit, clear_soft_references); } void Heap::ChangeCollector(CollectorType collector_type) { - switch (collector_type) { - case kCollectorTypeSS: { - ChangeAllocator(kAllocatorTypeBumpPointer); - break; + // TODO: Only do this with all mutators suspended to avoid races. + if (collector_type != collector_type_) { + collector_type_ = collector_type; + gc_plan_.clear(); + switch (collector_type_) { + case kCollectorTypeSS: { + concurrent_gc_ = false; + gc_plan_.push_back(collector::kGcTypeFull); + ChangeAllocator(kAllocatorTypeBumpPointer); + break; + } + case kCollectorTypeMS: { + concurrent_gc_ = false; + gc_plan_.push_back(collector::kGcTypeSticky); + gc_plan_.push_back(collector::kGcTypePartial); + gc_plan_.push_back(collector::kGcTypeFull); + ChangeAllocator(kAllocatorTypeFreeList); + break; + } + case kCollectorTypeCMS: { + concurrent_gc_ = true; + gc_plan_.push_back(collector::kGcTypeSticky); + gc_plan_.push_back(collector::kGcTypePartial); + gc_plan_.push_back(collector::kGcTypeFull); + ChangeAllocator(kAllocatorTypeFreeList); + break; + } + default: { + LOG(FATAL) << "Unimplemented"; + } } - case kCollectorTypeMS: - // Fall-through. - case kCollectorTypeCMS: { - ChangeAllocator(kAllocatorTypeFreeList); - break; - default: - LOG(FATAL) << "Unimplemented"; + if (concurrent_gc_) { + concurrent_start_bytes_ = + std::max(max_allowed_footprint_, kMinConcurrentRemainingBytes) - kMinConcurrentRemainingBytes; + } else { + concurrent_start_bytes_ = std::numeric_limits<size_t>::max(); } } } @@ -1234,8 +1148,8 @@ void Heap::PreZygoteFork() { // Trim the pages at the end of the non moving space. non_moving_space_->Trim(); non_moving_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE); - // Change the allocator to the post zygote one. - ChangeCollector(collector_type_); + // Change the collector to the post zygote one. + ChangeCollector(post_zygote_collector_type_); // TODO: Delete bump_pointer_space_ and temp_pointer_space_? if (semi_space_collector_ != nullptr) { // Create a new bump pointer space which we will compact into. @@ -1410,7 +1324,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus } else { LOG(FATAL) << "Invalid current allocator " << current_allocator_; } - CHECK(collector != NULL) + CHECK(collector != nullptr) << "Could not find garbage collector with concurrent=" << concurrent_gc_ << " and type=" << gc_type; @@ -1426,7 +1340,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus // Grow the heap so that we know when to perform the next GC. GrowForUtilization(gc_type, collector->GetDurationNs()); - if (care_about_pause_times_) { + if (CareAboutPauseTimes()) { const size_t duration = collector->GetDurationNs(); std::vector<uint64_t> pauses = collector->GetPauseTimes(); // GC for alloc pauses the allocating thread, so consider it as a pause. @@ -1991,7 +1905,7 @@ void Heap::GrowForUtilization(collector::GcType gc_type, uint64_t gc_duration) { } if (!ignore_max_footprint_) { SetIdealFootprint(target_size); - if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) { + if (concurrent_gc_) { // Calculate when to perform the next ConcurrentGC. // Calculate the estimated GC duration. double gc_duration_seconds = NsToMs(gc_duration) / 1000.0; @@ -2077,7 +1991,6 @@ void Heap::EnqueueClearedReferences() { void Heap::RequestConcurrentGC(Thread* self) { // Make sure that we can do a concurrent GC. Runtime* runtime = Runtime::Current(); - DCHECK(concurrent_gc_); if (runtime == NULL || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) || self->IsHandlingStackOverflow()) { return; @@ -2143,10 +2056,9 @@ void Heap::RequestHeapTrim() { } last_trim_time_ms_ = ms_time; - ListenForProcessStateChange(); // Trim only if we do not currently care about pause times. - if (!care_about_pause_times_) { + if (!CareAboutPauseTimes()) { JNIEnv* env = self->GetJniEnv(); DCHECK(WellKnownClasses::java_lang_Daemons != NULL); DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL); @@ -2212,7 +2124,7 @@ void Heap::RegisterNativeAllocation(JNIEnv* env, int bytes) { // finalizers released native managed allocations. UpdateMaxNativeFootprint(); } else if (!IsGCRequestPending()) { - if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) { + if (concurrent_gc_) { RequestConcurrentGC(self); } else { CollectGarbageInternal(gc_type, kGcCauseForAlloc, false); diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 8c5746d..9788064 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -119,6 +119,13 @@ static constexpr HeapVerificationMode kDesiredHeapVerification = kNoHeapVerifica // If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace static constexpr bool kUseRosAlloc = true; +// The process state passed in from the activity manager, used to determine when to do trimming +// and compaction. +enum ProcessState { + kProcessStateJankPerceptible = 0, + kProcessStateJankImperceptible = 1, +}; + class Heap { public: // If true, measure the total allocation time. @@ -287,6 +294,9 @@ class Heap { // waited for. collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_); + // Update the heap's process state to a new value, may cause compaction to occur. + void UpdateProcessState(ProcessState process_state); + const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const { return continuous_spaces_; } @@ -451,10 +461,7 @@ class Heap { // Mark the specified allocation stack as live. void MarkAllocStackAsLive(accounting::ObjectStack* stack) - EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); - - // Gets called when we get notified by ActivityThread that the process state has changed. - void ListenForProcessStateChange(); + EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_); // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added. // Assumes there is only one image space. @@ -475,7 +482,7 @@ class Heap { // Returns true if we currently care about pause times. bool CareAboutPauseTimes() const { - return care_about_pause_times_; + return process_state_ == kProcessStateJankPerceptible; } // Thread pool. @@ -510,10 +517,16 @@ class Heap { ALWAYS_INLINE void CheckConcurrentGC(Thread* self, size_t new_num_bytes_allocated, mirror::Object* obj); + // We don't force this to be inline since it is a slow path. + template <bool kInstrumented, typename PreFenceVisitor> + mirror::Object* AllocLargeObject(Thread* self, mirror::Class* klass, size_t byte_count, + const PreFenceVisitor& pre_fence_visitor) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Handles Allocate()'s slow allocation path with GC involved after // an initial allocation attempt failed. mirror::Object* AllocateInternalWithGc(Thread* self, AllocatorType allocator, size_t num_bytes, - size_t* bytes_allocated) + size_t* bytes_allocated, mirror::Class** klass) LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -524,15 +537,15 @@ class Heap { // Try to allocate a number of bytes, this function never does any GCs. Needs to be inlined so // that the switch statement is constant optimized in the entrypoints. - template <const bool kInstrumented> + template <const bool kInstrumented, const bool kGrow> ALWAYS_INLINE mirror::Object* TryToAllocate(Thread* self, AllocatorType allocator_type, - size_t alloc_size, bool grow, - size_t* bytes_allocated) + size_t alloc_size, size_t* bytes_allocated) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow); + template <const bool kGrow> + bool IsOutOfMemoryOnAllocation(size_t alloc_size); // Pushes a list of cleared references out to the managed heap. void SetReferenceReferent(mirror::Object* reference, mirror::Object* referent) @@ -632,12 +645,14 @@ class Heap { // A mod-union table remembers all of the references from the it's space to other spaces. SafeMap<space::Space*, accounting::ModUnionTable*> mod_union_tables_; - // What kind of concurrency behavior is the runtime after? True for concurrent mark sweep GC, - // false for stop-the-world mark sweep. - const bool concurrent_gc_; + // What kind of concurrency behavior is the runtime after? Currently true for concurrent mark + // sweep GC, false for other GC types. + bool concurrent_gc_; // The current collector type. CollectorType collector_type_; + // Which collector we will switch to after zygote fork. + CollectorType post_zygote_collector_type_; // How many GC threads we may use for paused parts of garbage collection. const size_t parallel_gc_threads_; @@ -713,11 +728,8 @@ class Heap { jobject application_thread_; jfieldID last_process_state_id_; - // Process states which care about pause times. - std::set<int> process_state_cares_about_pause_time_; - // Whether or not we currently care about pause times. - bool care_about_pause_times_; + ProcessState process_state_; // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that // it completes ahead of an allocation failing. diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc index 6b597ae..60c3b1c 100644 --- a/runtime/gc/space/space_test.cc +++ b/runtime/gc/space/space_test.cc @@ -31,10 +31,6 @@ namespace space { class SpaceTest : public CommonTest { public: - void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size, - int round, size_t growth_limit); - void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size); - void AddSpace(ContinuousSpace* space) { // For RosAlloc, revoke the thread local runs before moving onto a // new alloc space. @@ -55,6 +51,26 @@ class SpaceTest : public CommonTest { arr->SetLength(length); EXPECT_EQ(arr->SizeOf(), size); } + + static MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit, + size_t capacity, byte* requested_begin) { + return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin); + } + static MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit, + size_t capacity, byte* requested_begin) { + return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin); + } + + typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit, + size_t capacity, byte* requested_begin); + void InitTestBody(CreateSpaceFn create_space); + void ZygoteSpaceTestBody(CreateSpaceFn create_space); + void AllocAndFreeTestBody(CreateSpaceFn create_space); + void AllocAndFreeListTestBody(CreateSpaceFn create_space); + + void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size, + int round, size_t growth_limit); + void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space); }; static size_t test_rand(size_t* seed) { @@ -62,128 +78,143 @@ static size_t test_rand(size_t* seed) { return *seed; } -TEST_F(SpaceTest, Init) { +void SpaceTest::InitTestBody(CreateSpaceFn create_space) { { // Init < max == growth - UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 32 * MB, 32 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 16 * MB, 32 * MB, 32 * MB, NULL)); EXPECT_TRUE(space.get() != NULL); } { // Init == max == growth - UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 16 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 16 * MB, NULL)); EXPECT_TRUE(space.get() != NULL); } { // Init > max == growth - UniquePtr<Space> space(DlMallocSpace::Create("test", 32 * MB, 16 * MB, 16 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 32 * MB, 16 * MB, 16 * MB, NULL)); EXPECT_TRUE(space.get() == NULL); } { // Growth == init < max - UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 32 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 32 * MB, NULL)); EXPECT_TRUE(space.get() != NULL); } { // Growth < init < max - UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 8 * MB, 32 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 16 * MB, 8 * MB, 32 * MB, NULL)); EXPECT_TRUE(space.get() == NULL); } { // Init < growth < max - UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 16 * MB, 32 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 8 * MB, 16 * MB, 32 * MB, NULL)); EXPECT_TRUE(space.get() != NULL); } { // Init < max < growth - UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 32 * MB, 16 * MB, NULL)); + UniquePtr<Space> space(create_space("test", 8 * MB, 32 * MB, 16 * MB, NULL)); EXPECT_TRUE(space.get() == NULL); } } +TEST_F(SpaceTest, Init_DlMallocSpace) { + InitTestBody(SpaceTest::CreateDlMallocSpace); +} +TEST_F(SpaceTest, Init_RosAllocSpace) { + InitTestBody(SpaceTest::CreateRosAllocSpace); +} + // TODO: This test is not very good, we should improve it. // The test should do more allocations before the creation of the ZygoteSpace, and then do // allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that // the GC works with the ZygoteSpace. -TEST_F(SpaceTest, ZygoteSpace) { - size_t dummy = 0; - MallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); - ASSERT_TRUE(space != NULL); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space); - Thread* self = Thread::Current(); - - // Succeeds, fits without adjusting the footprint limit. - mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy); - EXPECT_TRUE(ptr1 != NULL); - InstallClass(ptr1, 1 * MB); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy); - EXPECT_TRUE(ptr2 == NULL); - - // Succeeds, adjusts the footprint. - size_t ptr3_bytes_allocated; - mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated); - EXPECT_TRUE(ptr3 != NULL); - EXPECT_LE(8U * MB, ptr3_bytes_allocated); - InstallClass(ptr3, 8 * MB); - - // Fails, requires a higher footprint limit. - mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy); - EXPECT_TRUE(ptr4 == NULL); - - // Also fails, requires a higher allowed footprint. - mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy); - EXPECT_TRUE(ptr5 == NULL); - - // Release some memory. - size_t free3 = space->AllocationSize(ptr3); - EXPECT_EQ(free3, ptr3_bytes_allocated); - EXPECT_EQ(free3, space->Free(self, ptr3)); - EXPECT_LE(8U * MB, free3); - - // Succeeds, now that memory has been freed. - mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy); - EXPECT_TRUE(ptr6 != NULL); - InstallClass(ptr6, 9 * MB); - - // Final clean up. - size_t free1 = space->AllocationSize(ptr1); - space->Free(self, ptr1); - EXPECT_LE(1U * MB, free1); - - // Make sure that the zygote space isn't directly at the start of the space. - space->Alloc(self, 1U * MB, &dummy); - space = space->CreateZygoteSpace("alloc space"); - - // Make space findable to the heap, will also delete space when runtime is cleaned up - AddSpace(space); - - // Succeeds, fits without adjusting the footprint limit. - ptr1 = space->Alloc(self, 1 * MB, &dummy); - EXPECT_TRUE(ptr1 != NULL); - InstallClass(ptr1, 1 * MB); - - // Fails, requires a higher footprint limit. - ptr2 = space->Alloc(self, 8 * MB, &dummy); - EXPECT_TRUE(ptr2 == NULL); - - // Succeeds, adjusts the footprint. - ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy); - EXPECT_TRUE(ptr3 != NULL); - InstallClass(ptr3, 2 * MB); - space->Free(self, ptr3); - - // Final clean up. - free1 = space->AllocationSize(ptr1); - space->Free(self, ptr1); - EXPECT_LE(1U * MB, free1); +void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) { + size_t dummy = 0; + MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL)); + ASSERT_TRUE(space != NULL); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space); + Thread* self = Thread::Current(); + + // Succeeds, fits without adjusting the footprint limit. + mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy); + EXPECT_TRUE(ptr1 != NULL); + InstallClass(ptr1, 1 * MB); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy); + EXPECT_TRUE(ptr2 == NULL); + + // Succeeds, adjusts the footprint. + size_t ptr3_bytes_allocated; + mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated); + EXPECT_TRUE(ptr3 != NULL); + EXPECT_LE(8U * MB, ptr3_bytes_allocated); + InstallClass(ptr3, 8 * MB); + + // Fails, requires a higher footprint limit. + mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy); + EXPECT_TRUE(ptr4 == NULL); + + // Also fails, requires a higher allowed footprint. + mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy); + EXPECT_TRUE(ptr5 == NULL); + + // Release some memory. + size_t free3 = space->AllocationSize(ptr3); + EXPECT_EQ(free3, ptr3_bytes_allocated); + EXPECT_EQ(free3, space->Free(self, ptr3)); + EXPECT_LE(8U * MB, free3); + + // Succeeds, now that memory has been freed. + mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy); + EXPECT_TRUE(ptr6 != NULL); + InstallClass(ptr6, 9 * MB); + + // Final clean up. + size_t free1 = space->AllocationSize(ptr1); + space->Free(self, ptr1); + EXPECT_LE(1U * MB, free1); + + // Make sure that the zygote space isn't directly at the start of the space. + space->Alloc(self, 1U * MB, &dummy); + space = space->CreateZygoteSpace("alloc space"); + + // Make space findable to the heap, will also delete space when runtime is cleaned up + AddSpace(space); + + // Succeeds, fits without adjusting the footprint limit. + ptr1 = space->Alloc(self, 1 * MB, &dummy); + EXPECT_TRUE(ptr1 != NULL); + InstallClass(ptr1, 1 * MB); + + // Fails, requires a higher footprint limit. + ptr2 = space->Alloc(self, 8 * MB, &dummy); + EXPECT_TRUE(ptr2 == NULL); + + // Succeeds, adjusts the footprint. + ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy); + EXPECT_TRUE(ptr3 != NULL); + InstallClass(ptr3, 2 * MB); + space->Free(self, ptr3); + + // Final clean up. + free1 = space->AllocationSize(ptr1); + space->Free(self, ptr1); + EXPECT_LE(1U * MB, free1); +} + +TEST_F(SpaceTest, ZygoteSpace_DlMallocSpace) { + ZygoteSpaceTestBody(SpaceTest::CreateDlMallocSpace); } -TEST_F(SpaceTest, AllocAndFree) { +TEST_F(SpaceTest, ZygoteSpace_RosAllocSpace) { + ZygoteSpaceTestBody(SpaceTest::CreateRosAllocSpace); +} + +void SpaceTest::AllocAndFreeTestBody(CreateSpaceFn create_space) { size_t dummy = 0; - DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); + MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL)); ASSERT_TRUE(space != NULL); Thread* self = Thread::Current(); @@ -231,6 +262,13 @@ TEST_F(SpaceTest, AllocAndFree) { EXPECT_LE(1U * MB, free1); } +TEST_F(SpaceTest, AllocAndFree_DlMallocSpace) { + AllocAndFreeTestBody(SpaceTest::CreateDlMallocSpace); +} +TEST_F(SpaceTest, AllocAndFree_RosAllocSpace) { + AllocAndFreeTestBody(SpaceTest::CreateRosAllocSpace); +} + TEST_F(SpaceTest, LargeObjectTest) { size_t rand_seed = 0; for (size_t i = 0; i < 2; ++i) { @@ -292,8 +330,8 @@ TEST_F(SpaceTest, LargeObjectTest) { } } -TEST_F(SpaceTest, AllocAndFreeList) { - DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); +void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) { + MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL)); ASSERT_TRUE(space != NULL); // Make space findable to the heap, will also delete space when runtime is cleaned up @@ -332,7 +370,14 @@ TEST_F(SpaceTest, AllocAndFreeList) { } } -void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size, +TEST_F(SpaceTest, AllocAndFreeList_DlMallocSpace) { + AllocAndFreeListTestBody(SpaceTest::CreateDlMallocSpace); +} +TEST_F(SpaceTest, AllocAndFreeList_RosAllocSpace) { + AllocAndFreeListTestBody(SpaceTest::CreateRosAllocSpace); +} + +void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size, int round, size_t growth_limit) { if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) || ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) { @@ -493,11 +538,11 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr EXPECT_LE(space->Size(), growth_limit); } -void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) { +void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space) { size_t initial_size = 4 * MB; size_t growth_limit = 8 * MB; size_t capacity = 16 * MB; - DlMallocSpace* space(DlMallocSpace::Create("test", initial_size, growth_limit, capacity, NULL)); + MallocSpace* space(create_space("test", initial_size, growth_limit, capacity, NULL)); ASSERT_TRUE(space != NULL); // Basic sanity @@ -518,16 +563,25 @@ void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) { } #define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \ - TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \ - SizeFootPrintGrowthLimitAndTrimDriver(size); \ + TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_DlMallocSpace) { \ + SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateDlMallocSpace); \ + } \ + TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_DlMallocSpace) { \ + SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateDlMallocSpace); \ } \ - TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \ - SizeFootPrintGrowthLimitAndTrimDriver(-size); \ + TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_RosAllocSpace) { \ + SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateRosAllocSpace); \ + } \ + TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_RosAllocSpace) { \ + SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateRosAllocSpace); \ } // Each size test is its own test so that we get a fresh heap each time -TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B) { - SizeFootPrintGrowthLimitAndTrimDriver(12); +TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_DlMallocSpace) { + SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateDlMallocSpace); +} +TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_RosAllocSpace) { + SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateRosAllocSpace); } TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16) TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24) diff --git a/runtime/globals.h b/runtime/globals.h index c2fe67e..a0d7e48 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -82,7 +82,7 @@ static constexpr bool kUsePortableCompiler = false; // Garbage collector constants. static constexpr bool kMovingCollector = true && !kUsePortableCompiler; // True if we allow moving classes. -static constexpr bool kMovingClasses = false; +static constexpr bool kMovingClasses = true; // True if we allow moving fields. static constexpr bool kMovingFields = false; // True if we allow moving methods. diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 9938478..02c9012 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -343,12 +343,13 @@ void EnterInterpreterFromInvoke(Thread* self, ArtMethod* method, Object* receive ++cur_reg; } else if (UNLIKELY(!method->GetDeclaringClass()->IsInitializing())) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (UNLIKELY(!class_linker->EnsureInitialized(method->GetDeclaringClass(), true, true))) { + SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass()); + if (UNLIKELY(!class_linker->EnsureInitialized(sirt_c, true, true))) { CHECK(self->IsExceptionPending()); self->PopShadowFrame(); return; } - CHECK(method->GetDeclaringClass()->IsInitializing()); + CHECK(sirt_c->IsInitializing()); } const char* shorty = mh.GetShorty(); for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) { @@ -428,7 +429,7 @@ extern "C" void artInterpreterToInterpreterBridge(Thread* self, MethodHelper& mh ArtMethod* method = shadow_frame->GetMethod(); // Ensure static methods are initialized. if (method->IsStatic()) { - Class* declaringClass = method->GetDeclaringClass(); + SirtRef<Class> declaringClass(self, method->GetDeclaringClass()); if (UNLIKELY(!declaringClass->IsInitializing())) { if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass, true, true))) { diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index c9756ac..5b9e55f 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -188,7 +188,7 @@ bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame, } else { self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(), "Ljava/lang/InternalError;", - "Found type %s; filled-new-array not implemented for anything but \'int\'", + "Found type %s; filled-new-array not implemented for anything but 'int'", PrettyDescriptor(componentClass).c_str()); } return false; @@ -231,7 +231,10 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, // In a runtime that's not started we intercept certain methods to avoid complicated dependency // problems in core libraries. std::string name(PrettyMethod(shadow_frame->GetMethod())); - if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") { + if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)" + || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") { + // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the + // other variants that take more arguments should also be added. std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str())); SirtRef<ClassLoader> class_loader(self, nullptr); // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader(); @@ -240,6 +243,13 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: " << PrettyDescriptor(descriptor); result->SetL(found); + } else if (name == "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") { + SirtRef<ClassLoader> class_loader(self, down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset))); + std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str())); + + Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(), + class_loader); + result->SetL(found); } else if (name == "java.lang.Object java.lang.Class.newInstance()") { Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V"); diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 0bc834c..3b8d50b 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -334,13 +334,14 @@ static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instructio // java.lang.String class is initialized. static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(!kMovingMethods); Class* java_lang_string_class = String::GetJavaLangString(); if (UNLIKELY(!java_lang_string_class->IsInitialized())) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class, - true, true))) { + SirtRef<mirror::Class> sirt_class(self, java_lang_string_class); + if (UNLIKELY(!class_linker->EnsureInitialized(sirt_class, true, true))) { DCHECK(self->IsExceptionPending()); - return NULL; + return nullptr; } } return mh.ResolveString(string_idx); diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc index b2371e8..369eddd 100644 --- a/runtime/jdwp/object_registry.cc +++ b/runtime/jdwp/object_registry.cc @@ -118,6 +118,9 @@ mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id) { } jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) { + if (id == 0) { + return NULL; + } Thread* self = Thread::Current(); MutexLock mu(self, lock_); id_iterator it = id_to_entry_.find(id); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 466edeb..6690519 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -225,13 +225,24 @@ static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, Class* c, kind, ClassHelper(c).GetDescriptor(), name, sig); } +static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (LIKELY(klass->IsInitialized())) { + return klass; + } + SirtRef<mirror::Class> sirt_klass(self, klass); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { + return nullptr; + } + return sirt_klass.get(); +} + static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class, const char* name, const char* sig, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Class* c = soa.Decode<Class*>(jni_class); - DCHECK(c != nullptr); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class)); + if (c == nullptr) { + return nullptr; } ArtMethod* method = NULL; @@ -284,16 +295,16 @@ static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa) static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name, const char* sig, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Class* c = soa.Decode<Class*>(jni_class); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class)); + if (c == nullptr) { + return nullptr; } ArtField* field = NULL; Class* field_type; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); if (sig[1] != '\0') { - SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa)); + SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader()); field_type = class_linker->FindClass(sig, class_loader); } else { field_type = class_linker->FindPrimitiveClass(*sig); @@ -910,9 +921,9 @@ class JNI { static jobject AllocObject(JNIEnv* env, jclass java_class) { CHECK_NON_NULL_ARGUMENT(AllocObject, java_class); ScopedObjectAccess soa(env); - Class* c = soa.Decode<Class*>(java_class); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class)); + if (c == nullptr) { + return nullptr; } return soa.AddLocalReference<jobject>(c->AllocObject(soa.Self())); } @@ -931,20 +942,20 @@ class JNI { CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class); CHECK_NON_NULL_ARGUMENT(NewObjectV, mid); ScopedObjectAccess soa(env); - Class* c = soa.Decode<Class*>(java_class); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class)); + if (c == nullptr) { + return nullptr; } Object* result = c->AllocObject(soa.Self()); - if (result == NULL) { - return NULL; + if (result == nullptr) { + return nullptr; } jobject local_result = soa.AddLocalReference<jobject>(result); CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args); if (!soa.Self()->IsExceptionPending()) { return local_result; } else { - return NULL; + return nullptr; } } @@ -952,9 +963,9 @@ class JNI { CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class); CHECK_NON_NULL_ARGUMENT(NewObjectA, mid); ScopedObjectAccess soa(env); - Class* c = soa.Decode<Class*>(java_class); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class)); + if (c == nullptr) { + return nullptr; } Object* result = c->AllocObject(soa.Self()); if (result == NULL) { @@ -3303,8 +3314,9 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) { // If this is a static method, it could be called before the class // has been initialized. if (m->IsStatic()) { - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { - return NULL; + c = EnsureInitialized(Thread::Current(), c); + if (c == nullptr) { + return nullptr; } } else { CHECK(c->IsInitializing()) << c->GetStatus() << " " << PrettyMethod(m); diff --git a/runtime/leb128.h b/runtime/leb128.h index 6041f8c..7a7d38d 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_LEB128_H_ #include "globals.h" +#include "utils.h" namespace art { @@ -95,12 +96,20 @@ static inline int32_t DecodeSignedLeb128(const uint8_t** data) { // Returns the number of bytes needed to encode the value in unsigned LEB128. static inline uint32_t UnsignedLeb128Size(uint32_t data) { - uint32_t count = 0; - do { - data >>= 7; - count++; - } while (data != 0); - return count; + // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1 // 32 - CLZ(data | 1) + // bytes = ceil(bits_to_encode / 7.0); // (6 + bits_to_encode) / 7 + uint32_t x = 6 + 32 - CLZ(data | 1); + // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7). + // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85. + return (x * 37) >> 8; +} + +// Returns the number of bytes needed to encode the value in unsigned LEB128. +static inline uint32_t SignedLeb128Size(int32_t data) { + // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign. + data = data ^ (data >> 31); + uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1); + return (x * 37) >> 8; } } // namespace art diff --git a/runtime/mapping_table.h b/runtime/mapping_table.h index c468c1e..a82bc1c 100644 --- a/runtime/mapping_table.h +++ b/runtime/mapping_table.h @@ -72,7 +72,8 @@ class MappingTable { if (end_ > 0) { encoded_table_ptr_ = table_->FirstDexToPcPtr(); native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); - dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + // First delta is always positive. + dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); } } else { // An iterator wanted from the end. DCHECK_EQ(table_->DexToPcSize(), element); @@ -87,8 +88,9 @@ class MappingTable { void operator++() { ++element_; if (element_ != end_) { // Avoid reading beyond the end of the table. - native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); - dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_); + // For negative delta, unsigned overflow after static_cast does exactly what we need. + dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); } } bool operator==(const DexToPcIterator& rhs) const { @@ -147,7 +149,8 @@ class MappingTable { if (end_ > 0) { encoded_table_ptr_ = table_->FirstPcToDexPtr(); native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); - dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + // First delta is always positive. + dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); } } else { // An iterator wanted from the end. DCHECK_EQ(table_->PcToDexSize(), element); @@ -162,8 +165,9 @@ class MappingTable { void operator++() { ++element_; if (element_ != end_) { // Avoid reading beyond the end of the table. - native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); - dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_); + // For negative delta, unsigned overflow after static_cast does exactly what we need. + dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_)); } } bool operator==(const PcToDexIterator& rhs) const { diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index a754b69..cf4b48c 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -108,6 +108,13 @@ inline Array* Array::Alloc(Thread* self, Class* array_class, int32_t component_c Runtime::Current()->GetHeap()->GetCurrentAllocator()); } +template<class T> +inline void PrimitiveArray<T>::VisitRoots(RootVisitor* visitor, void* arg) { + if (array_class_ != nullptr) { + array_class_ = down_cast<Class*>(visitor(array_class_, arg)); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index a332f97..5265946 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -149,6 +149,9 @@ class MANAGED PrimitiveArray : public Array { array_class_ = NULL; } + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + private: static Class* array_class_; diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc index a8bbe4b..c3a4efb 100644 --- a/runtime/mirror/art_field.cc +++ b/runtime/mirror/art_field.cc @@ -52,5 +52,12 @@ void ArtField::SetOffset(MemberOffset num_bytes) { SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false); } +void ArtField::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_reflect_ArtField_ != nullptr) { + java_lang_reflect_ArtField_ = down_cast<mirror::Class*>( + visitor(java_lang_reflect_ArtField_, arg)); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h index ae34cb1..62bcf06 100644 --- a/runtime/mirror/art_field.h +++ b/runtime/mirror/art_field.h @@ -130,6 +130,8 @@ class MANAGED ArtField : public Object { static void SetClass(Class* java_lang_reflect_ArtField); static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsVolatile() const { return (GetAccessFlags() & kAccVolatile) != 0; diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index f5c0e9f..a4f6b3b 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -40,6 +40,13 @@ extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, // TODO: get global references for these Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL; +void ArtMethod::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_reflect_ArtMethod_ != nullptr) { + java_lang_reflect_ArtMethod_ = down_cast<mirror::Class*>( + visitor(java_lang_reflect_ArtMethod_, arg)); + } +} + InvokeType ArtMethod::GetInvokeType() const { // TODO: kSuper? if (GetDeclaringClass()->IsInterface()) { diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index f396fbe..d5524ec 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -23,6 +23,7 @@ #include "locks.h" #include "modifiers.h" #include "object.h" +#include "root_visitor.h" namespace art { @@ -381,6 +382,9 @@ class MANAGED ArtMethod : public Object { static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index cdc5ab2..2746e1e 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -50,6 +50,12 @@ void Class::ResetClass() { java_lang_Class_ = NULL; } +void Class::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_Class_ != nullptr) { + java_lang_Class_ = down_cast<Class*>(visitor(java_lang_Class_, arg)); + } +} + void Class::SetStatus(Status new_status, Thread* self) { Status old_status = GetStatus(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 5f64bb4..50ede66 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -787,6 +787,8 @@ class MANAGED Class : public StaticStorageBase { // Can't call this SetClass or else gets called instead of Object::SetClass in places. static void SetClassClass(Class* java_lang_Class); static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // When class is verified, set the kAccPreverified flag on each method. void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 0fb2039..fe89b7e 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -225,6 +225,11 @@ class MANAGED Object { void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile); + template<typename T> + void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) { + SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid); + } + protected: // Accessors for non-Java type fields template<class T> @@ -232,11 +237,6 @@ class MANAGED Object { return reinterpret_cast<T>(GetField32(field_offset, is_volatile)); } - template<typename T> - void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) { - SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid); - } - private: static void VerifyObject(const Object* obj) ALWAYS_INLINE; // Verify the type correctness of stores to fields. diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 8272ff8..3637181 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -221,8 +221,8 @@ TEST_F(ObjectTest, CheckAndAllocArrayFromCode) { java_lang_dex_file_->GetIndexForStringId(*string_id)); ASSERT_TRUE(type_id != NULL); uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id); - Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current(), false, - Runtime::Current()->GetHeap()->GetCurrentAllocator()); + Object* array = CheckAndAllocArrayFromCodeInstrumented(type_idx, sort, 3, Thread::Current(), false, + Runtime::Current()->GetHeap()->GetCurrentAllocator()); EXPECT_TRUE(array->IsArrayInstance()); EXPECT_EQ(3, array->AsArray()->GetLength()); EXPECT_TRUE(array->GetClass()->IsArrayClass()); diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc index 32a50fe..a7ebe07 100644 --- a/runtime/mirror/stack_trace_element.cc +++ b/runtime/mirror/stack_trace_element.cc @@ -58,5 +58,12 @@ StackTraceElement* StackTraceElement::Alloc(Thread* self, return trace; } +void StackTraceElement::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_StackTraceElement_ != nullptr) { + java_lang_StackTraceElement_ = down_cast<Class*>(visitor(java_lang_StackTraceElement_, arg)); + } +} + + } // namespace mirror } // namespace art diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h index 2af5128..d1be4dc 100644 --- a/runtime/mirror/stack_trace_element.h +++ b/runtime/mirror/stack_trace_element.h @@ -57,8 +57,9 @@ class MANAGED StackTraceElement : public Object { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void SetClass(Class* java_lang_StackTraceElement); - static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index b372fe7..d6e509d 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -122,7 +122,7 @@ String* String::AllocFromUtf16(Thread* self, const uint16_t* utf16_data_in, int32_t hash_code) { CHECK(utf16_data_in != NULL || utf16_length == 0); - String* string = Alloc(self, GetJavaLangString(), utf16_length); + String* string = Alloc(self, utf16_length); if (UNLIKELY(string == nullptr)) { return nullptr; } @@ -152,7 +152,7 @@ String* String::AllocFromModifiedUtf8(Thread* self, const char* utf) { String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, const char* utf8_data_in) { - String* string = Alloc(self, GetJavaLangString(), utf16_length); + String* string = Alloc(self, utf16_length); if (UNLIKELY(string == nullptr)) { return nullptr; } @@ -163,21 +163,20 @@ String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length, return string; } -String* String::Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length) { - CharArray* array = CharArray::Alloc(self, utf16_length); - if (UNLIKELY(array == nullptr)) { +String* String::Alloc(Thread* self, int32_t utf16_length) { + SirtRef<CharArray> array(self, CharArray::Alloc(self, utf16_length)); + if (UNLIKELY(array.get() == nullptr)) { return nullptr; } - return Alloc(self, java_lang_String, array); + return Alloc(self, array); } -String* String::Alloc(Thread* self, Class* java_lang_String, CharArray* array) { +String* String::Alloc(Thread* self, const SirtRef<CharArray>& array) { // Hold reference in case AllocObject causes GC. - SirtRef<CharArray> array_ref(self, array); - String* string = down_cast<String*>(java_lang_String->AllocObject(self)); + String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self)); if (LIKELY(string != nullptr)) { - string->SetArray(array_ref.get()); - string->SetCount(array_ref->GetLength()); + string->SetArray(array.get()); + string->SetCount(array->GetLength()); } return string; } @@ -287,5 +286,11 @@ int32_t String::CompareTo(String* rhs) const { return countDiff; } +void String::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_String_ != nullptr) { + java_lang_String_ = down_cast<Class*>(visitor(java_lang_String_, arg)); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 7520c4d..4bbcb9c 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -19,6 +19,7 @@ #include "class.h" #include "gtest/gtest.h" +#include "root_visitor.h" namespace art { @@ -77,12 +78,6 @@ class MANAGED String : public Object { const char* utf8_data_in) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static String* Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - static String* Alloc(Thread* self, Class* java_lang_String, CharArray* array) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - bool Equals(const char* modified_utf8) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -114,6 +109,8 @@ class MANAGED String : public Object { static void SetClass(Class* java_lang_String); static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: void SetHashCode(int32_t new_hash_code) { @@ -132,6 +129,12 @@ class MANAGED String : public Object { SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false); } + static String* Alloc(Thread* self, int32_t utf16_length) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static String* Alloc(Thread* self, const SirtRef<CharArray>& array) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index 961f6de..b55db72 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -93,5 +93,11 @@ void Throwable::ResetClass() { java_lang_Throwable_ = NULL; } +void Throwable::VisitRoots(RootVisitor* visitor, void* arg) { + if (java_lang_Throwable_ != nullptr) { + java_lang_Throwable_ = down_cast<Class*>(visitor(java_lang_Throwable_, arg)); + } +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index 27f6e12..5a90599 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_MIRROR_THROWABLE_H_ #include "object.h" +#include "root_visitor.h" #include "string.h" namespace art { @@ -50,6 +51,8 @@ class MANAGED Throwable : public Object { static void SetClass(Class* java_lang_Throwable); static void ResetClass(); + static void VisitRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); private: Object* GetStackState() const { diff --git a/runtime/monitor.cc b/runtime/monitor.cc index af93a56..ef9a9ce 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -633,8 +633,7 @@ void Monitor::InflateThinLocked(Thread* self, SirtRef<mirror::Object>& obj, Lock ScopedThreadStateChange tsc(self, kBlocked); if (lock_word == obj->GetLockWord()) { // If lock word hasn't changed. bool timed_out; - Thread* owner = thread_list->SuspendThreadByThreadId(lock_word.ThinLockOwner(), false, - &timed_out); + Thread* owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out); if (owner != nullptr) { // We succeeded in suspending the thread, check the lock's status didn't change. lock_word = obj->GetLockWord(); diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index c9e0e83..600045f 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -95,20 +95,27 @@ static jint DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNam } uint32_t dex_location_checksum; + uint32_t* dex_location_checksum_pointer = &dex_location_checksum; std::string error_msg; - if (!DexFile::GetChecksum(sourceName.c_str(), &dex_location_checksum, &error_msg)) { - ScopedObjectAccess soa(env); - DCHECK(!error_msg.empty()); - ThrowIOException("%s", error_msg.c_str()); - return 0; + if (!DexFile::GetChecksum(sourceName.c_str(), dex_location_checksum_pointer, &error_msg)) { + dex_location_checksum_pointer = NULL; } ClassLinker* linker = Runtime::Current()->GetClassLinker(); const DexFile* dex_file; if (outputName.c_str() == nullptr) { + // FindOrCreateOatFileForDexLocation can tolerate a missing dex_location_checksum + error_msg.clear(); dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(), - dex_location_checksum, &error_msg); + dex_location_checksum_pointer, &error_msg); } else { + // FindOrCreateOatFileForDexLocation requires the dex_location_checksum + if (dex_location_checksum_pointer == NULL) { + ScopedObjectAccess soa(env); + DCHECK(!error_msg.empty()); + ThrowIOException("%s", error_msg.c_str()); + return 0; + } dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum, outputName.c_str(), &error_msg); } diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index fd3d91e..726a8f1 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -166,6 +166,10 @@ static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) { Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes); } +static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) { + Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state)); +} + static void VMRuntime_trimHeap(JNIEnv*, jobject) { Runtime::Current()->GetHeap()->Trim(); } @@ -496,6 +500,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"), NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"), NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"), + NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"), NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"), NATIVE_METHOD(VMRuntime, trimHeap, "()V"), NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"), diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 3389107..3e3f608 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -46,8 +46,8 @@ static mirror::Class* DecodeClass(const ScopedFastNativeObjectAccess& soa, jobje static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) { ScopedObjectAccess soa(env); ScopedUtfChars name(env, javaName); - if (name.c_str() == NULL) { - return NULL; + if (name.c_str() == nullptr) { + return nullptr; } // We need to validate and convert the name (from x.y.z to x/y/z). This @@ -57,27 +57,27 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ClassNotFoundException;", "Invalid name: %s", name.c_str()); - return NULL; + return nullptr; } std::string descriptor(DotToDescriptor(name.c_str())); SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(javaLoader)); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - mirror::Class* c = class_linker->FindClass(descriptor.c_str(), class_loader); - if (c == NULL) { + SirtRef<mirror::Class> c(soa.Self(), class_linker->FindClass(descriptor.c_str(), class_loader)); + if (c.get() == nullptr) { ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred()); env->ExceptionClear(); jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException, WellKnownClasses::java_lang_ClassNotFoundException_init, javaName, cause.get())); env->Throw(cnfe); - return NULL; + return nullptr; } if (initialize) { class_linker->EnsureInitialized(c, true, true); } - return soa.AddLocalReference<jclass>(c); + return soa.AddLocalReference<jclass>(c.get()); } static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index af1b548..314cdb1 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -78,7 +78,7 @@ static jstring VMClassLoader_getBootClassPathResource(JNIEnv* env, jclass, jstri LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg; return NULL; } - UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str())); + UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str(), &error_msg)); if (zip_entry.get() == NULL) { return NULL; } diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 04dfcb5..5811992 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -41,24 +41,24 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod); mirror::ArtMethod* m = soa.Decode<mirror::Object*>(art_method)->AsArtMethod(); - mirror::Class* c = m->GetDeclaringClass(); + SirtRef<mirror::Class> c(soa.Self(), m->GetDeclaringClass()); if (UNLIKELY(c->IsAbstract())) { ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow(); soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/InstantiationException;", "Can't instantiate %s %s", c->IsInterface() ? "interface" : "abstract class", - PrettyDescriptor(c).c_str()); - return NULL; + PrettyDescriptor(c.get()).c_str()); + return nullptr; } if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { DCHECK(soa.Self()->IsExceptionPending()); - return NULL; + return nullptr; } mirror::Object* receiver = c->AllocNonMovableObject(soa.Self()); - if (receiver == NULL) { - return NULL; + if (receiver == nullptr) { + return nullptr; } jobject javaReceiver = soa.AddLocalReference<jobject>(receiver); diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 4d69a68..553aeb8 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -31,10 +31,13 @@ static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa, mirror::Objec mirror::ArtField* f, JValue& value, bool allow_references) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_EQ(value.GetJ(), 0LL); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), - true, true)) { + CHECK(!kMovingFields); + SirtRef<mirror::Object> sirt_obj(soa.Self(), o); + SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass()); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { return false; } + o = sirt_obj.get(); switch (FieldHelper(f).GetTypeAsPrimitiveType()) { case Primitive::kPrimBoolean: value.SetZ(f->GetBoolean(o)); @@ -168,13 +171,16 @@ static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) { return GetPrimitiveField(env, javaField, javaObj, 'S').GetS(); } -static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, const JValue& new_value, - bool allow_references) +static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o, + mirror::ArtField* f, const JValue& new_value, bool allow_references) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), - true, true)) { + CHECK(!kMovingFields); + SirtRef<mirror::Object> sirt_obj(soa.Self(), o); + SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass()); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) { return; } + o = sirt_obj.get(); switch (FieldHelper(f).GetTypeAsPrimitiveType()) { case Primitive::kPrimBoolean: f->SetBoolean(o, new_value.GetZ()); @@ -237,7 +243,7 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j return; } - SetFieldValue(o, f, unboxed_value, true); + SetFieldValue(soa, o, f, unboxed_value, true); } static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor, @@ -264,7 +270,7 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, c } // Write the value. - SetFieldValue(o, f, wide_value, false); + SetFieldValue(soa, o, f, wide_value, false); } static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) { diff --git a/runtime/oat.cc b/runtime/oat.cc index 50069b2..52e74ab 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', '1', '1', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '1', '2', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index e37510c..cc996bc 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -34,34 +34,36 @@ namespace art { +template <typename T> class ObjectLock { public: - explicit ObjectLock(Thread* self, mirror::Object* object) + explicit ObjectLock(Thread* self, const SirtRef<T>* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : self_(self), obj_(object) { - CHECK(object != NULL); - obj_->MonitorEnter(self_); + CHECK(object != nullptr); + CHECK(object->get() != nullptr); + obj_->get()->MonitorEnter(self_); } ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->MonitorExit(self_); + obj_->get()->MonitorExit(self_); } void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - Monitor::Wait(self_, obj_, 0, 0, false, kWaiting); + Monitor::Wait(self_, obj_->get(), 0, 0, false, kWaiting); } void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->Notify(self_); + obj_->get()->Notify(self_); } void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - obj_->NotifyAll(self_); + obj_->get()->NotifyAll(self_); } private: Thread* const self_; - mirror::Object* obj_; + const SirtRef<T>* obj_; DISALLOW_COPY_AND_ASSIGN(ObjectLock); }; diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 80e16aa..ac8f5ef 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -39,8 +39,12 @@ jobject InvokeMethod(const ScopedObjectAccess& soa, jobject javaMethod, jobject mirror::ArtMethod* m = soa.DecodeMethod(mid); mirror::Class* declaring_class = m->GetDeclaringClass(); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true, true)) { - return NULL; + if (UNLIKELY(!declaring_class->IsInitialized())) { + SirtRef<mirror::Class> sirt_c(soa.Self(), declaring_class); + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) { + return nullptr; + } + declaring_class = sirt_c.get(); } mirror::Object* receiver = NULL; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 6bd2560..e1b4d7e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -47,6 +47,7 @@ #include "mirror/array.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" +#include "mirror/stack_trace_element.h" #include "mirror/throwable.h" #include "monitor.h" #include "oat_file.h" @@ -86,6 +87,7 @@ Runtime::Runtime() resolution_method_(NULL), imt_conflict_method_(NULL), default_imt_(NULL), + method_verifiers_lock_("Method verifiers lock"), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), shutting_down_(false), @@ -131,11 +133,6 @@ Runtime::~Runtime() { heap_->WaitForGcToComplete(self); heap_->DeleteThreadPool(); - // For RosAlloc, revoke thread local runs. Note that in tests - // (common_test.h) we repeat allocating and deleting Runtime - // objects. - heap_->RevokeAllThreadLocalBuffers(); - // Make sure our internal threads are dead before we start tearing down things they're using. Dbg::StopJdwp(); delete signal_catcher_; @@ -704,35 +701,38 @@ jobject CreateSystemClassLoader() { } ScopedObjectAccess soa(Thread::Current()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); - mirror::Class* class_loader_class = - soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader); - CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(class_loader_class, true, true)); + SirtRef<mirror::Class> class_loader_class( + soa.Self(), soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)); + CHECK(cl->EnsureInitialized(class_loader_class, true, true)); mirror::ArtMethod* getSystemClassLoader = class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;"); CHECK(getSystemClassLoader != NULL); JValue result; - ArgArray arg_array(NULL, 0); + ArgArray arg_array(nullptr, 0); InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, 'L'); - mirror::ClassLoader* class_loader = down_cast<mirror::ClassLoader*>(result.GetL()); - CHECK(class_loader != NULL); - + SirtRef<mirror::ClassLoader> class_loader(soa.Self(), + down_cast<mirror::ClassLoader*>(result.GetL())); + CHECK(class_loader.get() != nullptr); JNIEnv* env = soa.Self()->GetJniEnv(); - ScopedLocalRef<jobject> system_class_loader(env, soa.AddLocalReference<jobject>(class_loader)); - CHECK(system_class_loader.get() != NULL); + ScopedLocalRef<jobject> system_class_loader(env, + soa.AddLocalReference<jobject>(class_loader.get())); + CHECK(system_class_loader.get() != nullptr); - soa.Self()->SetClassLoaderOverride(class_loader); + soa.Self()->SetClassLoaderOverride(class_loader.get()); - mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread); - CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(thread_class, true, true)); + SirtRef<mirror::Class> thread_class(soa.Self(), + soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)); + CHECK(cl->EnsureInitialized(thread_class, true, true)); - mirror::ArtField* contextClassLoader = thread_class->FindDeclaredInstanceField("contextClassLoader", - "Ljava/lang/ClassLoader;"); + mirror::ArtField* contextClassLoader = + thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;"); CHECK(contextClassLoader != NULL); - contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader); + contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader.get()); return env->NewGlobalRef(system_class_loader.get()); } @@ -1193,9 +1193,25 @@ void Runtime::VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_di } void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) { + // Visit the classes held as static in mirror classes. + mirror::ArtField::VisitRoots(visitor, arg); + mirror::ArtMethod::VisitRoots(visitor, arg); + mirror::Class::VisitRoots(visitor, arg); + mirror::StackTraceElement::VisitRoots(visitor, arg); + mirror::String::VisitRoots(visitor, arg); + mirror::Throwable::VisitRoots(visitor, arg); + // Visit all the primitive array types classes. + mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor, arg); // BooleanArray + mirror::PrimitiveArray<int8_t>::VisitRoots(visitor, arg); // ByteArray + mirror::PrimitiveArray<uint16_t>::VisitRoots(visitor, arg); // CharArray + mirror::PrimitiveArray<double>::VisitRoots(visitor, arg); // DoubleArray + mirror::PrimitiveArray<float>::VisitRoots(visitor, arg); // FloatArray + mirror::PrimitiveArray<int32_t>::VisitRoots(visitor, arg); // IntArray + mirror::PrimitiveArray<int64_t>::VisitRoots(visitor, arg); // LongArray + mirror::PrimitiveArray<int16_t>::VisitRoots(visitor, arg); // ShortArray java_vm_->VisitRoots(visitor, arg); if (pre_allocated_OutOfMemoryError_ != nullptr) { - pre_allocated_OutOfMemoryError_ = reinterpret_cast<mirror::Throwable*>( + pre_allocated_OutOfMemoryError_ = down_cast<mirror::Throwable*>( visitor(pre_allocated_OutOfMemoryError_, arg)); DCHECK(pre_allocated_OutOfMemoryError_ != nullptr); } @@ -1214,6 +1230,12 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) { visitor(callee_save_methods_[i], arg)); } } + { + MutexLock mu(Thread::Current(), method_verifiers_lock_); + for (verifier::MethodVerifier* verifier : method_verifiers_) { + verifier->VisitRoots(visitor, arg); + } + } } void Runtime::VisitNonConcurrentRoots(RootVisitor* visitor, void* arg) { @@ -1360,4 +1382,18 @@ void Runtime::SetCompileTimeClassPath(jobject class_loader, std::vector<const De compile_time_class_paths_.Put(class_loader, class_path); } +void Runtime::AddMethodVerifier(verifier::MethodVerifier* verifier) { + DCHECK(verifier != nullptr); + MutexLock mu(Thread::Current(), method_verifiers_lock_); + method_verifiers_.insert(verifier); +} + +void Runtime::RemoveMethodVerifier(verifier::MethodVerifier* verifier) { + DCHECK(verifier != nullptr); + MutexLock mu(Thread::Current(), method_verifiers_lock_); + auto it = method_verifiers_.find(verifier); + CHECK(it != method_verifiers_.end()); + method_verifiers_.erase(it); +} + } // namespace art diff --git a/runtime/runtime.h b/runtime/runtime.h index e6951d9..01a605a 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -52,6 +52,9 @@ namespace mirror { class String; class Throwable; } // namespace mirror +namespace verifier { +class MethodVerifier; +} class ClassLinker; class DexFile; class InternTable; @@ -320,14 +323,16 @@ class Runtime { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Visit all of the roots we can do safely do concurrently. - void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty); + void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Visit all of the non thread roots, we can do this with mutators unpaused. - void VisitNonThreadRoots(RootVisitor* visitor, void* arg); + void VisitNonThreadRoots(RootVisitor* visitor, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Visit all other roots which must be done with mutators suspended. void VisitNonConcurrentRoots(RootVisitor* visitor, void* arg) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Sweep system weaks, the system weak is deleted if the visitor return nullptr. Otherwise, the // system weak is updated to be the visitor's returned value. @@ -438,6 +443,9 @@ class Runtime { return use_compile_time_class_path_; } + void AddMethodVerifier(verifier::MethodVerifier* verifier); + void RemoveMethodVerifier(verifier::MethodVerifier* verifier); + const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader); void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path); @@ -520,6 +528,10 @@ class Runtime { mirror::ObjectArray<mirror::ArtMethod>* default_imt_; + // Method verifier set, used so that we can update their GC roots. + Mutex method_verifiers_lock_; + std::set<verifier::MethodVerifier*> method_verifiers_; + // 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/stack.cc b/runtime/stack.cc index a505383..4e3fb4a 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -259,6 +259,7 @@ std::string StackVisitor::DescribeLocation() const { } instrumentation::InstrumentationStackFrame& StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const { + CHECK_LT(depth, thread_->GetInstrumentationStack()->size()); return thread_->GetInstrumentationStack()->at(depth); } diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h index 8449607..e47fd37 100644 --- a/runtime/thread-inl.h +++ b/runtime/thread-inl.h @@ -50,7 +50,8 @@ inline ThreadState Thread::SetState(ThreadState new_state) { // old_state_and_flags.suspend_request is true. DCHECK_NE(new_state, kRunnable); DCHECK_EQ(this, Thread::Current()); - union StateAndFlags old_state_and_flags = state_and_flags_; + union StateAndFlags old_state_and_flags; + old_state_and_flags.as_int = state_and_flags_.as_int; state_and_flags_.as_struct.state = new_state; return static_cast<ThreadState>(old_state_and_flags.as_struct.state); } @@ -87,7 +88,7 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) { union StateAndFlags old_state_and_flags; union StateAndFlags new_state_and_flags; do { - old_state_and_flags = state_and_flags_; + old_state_and_flags.as_int = state_and_flags_.as_int; if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) { RunCheckpointFunction(); continue; @@ -104,22 +105,23 @@ inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) { inline ThreadState Thread::TransitionFromSuspendedToRunnable() { bool done = false; - union StateAndFlags old_state_and_flags = state_and_flags_; + union StateAndFlags old_state_and_flags; + old_state_and_flags.as_int = state_and_flags_.as_int; int16_t old_state = old_state_and_flags.as_struct.state; DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable); do { Locks::mutator_lock_->AssertNotHeld(this); // Otherwise we starve GC.. - old_state_and_flags = state_and_flags_; + old_state_and_flags.as_int = state_and_flags_.as_int; DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) { // Wait while our suspend count is non-zero. MutexLock mu(this, *Locks::thread_suspend_count_lock_); - old_state_and_flags = state_and_flags_; + old_state_and_flags.as_int = state_and_flags_.as_int; DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) { // Re-check when Thread::resume_cond_ is notified. Thread::resume_cond_->Wait(this); - old_state_and_flags = state_and_flags_; + old_state_and_flags.as_int = state_and_flags_.as_int; DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); } DCHECK_EQ(GetSuspendCount(), 0); @@ -127,10 +129,11 @@ inline ThreadState Thread::TransitionFromSuspendedToRunnable() { // Re-acquire shared mutator_lock_ access. Locks::mutator_lock_->SharedLock(this); // Atomically change from suspended to runnable if no suspend request pending. - old_state_and_flags = state_and_flags_; + old_state_and_flags.as_int = state_and_flags_.as_int; DCHECK_EQ(old_state_and_flags.as_struct.state, old_state); if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) { - union StateAndFlags new_state_and_flags = old_state_and_flags; + union StateAndFlags new_state_and_flags; + new_state_and_flags.as_int = old_state_and_flags.as_int; new_state_and_flags.as_struct.state = kRunnable; // CAS the value without a memory barrier, that occurred in the lock above. done = android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int, diff --git a/runtime/thread.cc b/runtime/thread.cc index 1add507..2861213 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -579,19 +579,21 @@ void Thread::RunCheckpointFunction() { } bool Thread::RequestCheckpoint(Closure* function) { - union StateAndFlags old_state_and_flags = state_and_flags_; + union StateAndFlags old_state_and_flags; + old_state_and_flags.as_int = state_and_flags_.as_int; if (old_state_and_flags.as_struct.state != kRunnable) { return false; // Fail, thread is suspended and so can't run a checkpoint. } if ((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0) { return false; // Fail, already a checkpoint pending. } - CHECK(checkpoint_function_ == NULL); + CHECK(checkpoint_function_ == nullptr); checkpoint_function_ = function; // Checkpoint function installed now install flag bit. // We must be runnable to request a checkpoint. - old_state_and_flags.as_struct.state = kRunnable; - union StateAndFlags new_state_and_flags = old_state_and_flags; + DCHECK_EQ(old_state_and_flags.as_struct.state, kRunnable); + union StateAndFlags new_state_and_flags; + new_state_and_flags.as_int = old_state_and_flags.as_int; new_state_and_flags.as_struct.flags |= kCheckpointRequest; int succeeded = android_atomic_cmpxchg(old_state_and_flags.as_int, new_state_and_flags.as_int, &state_and_flags_.as_int); @@ -985,8 +987,9 @@ void Thread::Destroy() { mirror::Object* lock = soa.DecodeField(WellKnownClasses::java_lang_Thread_lock)->GetObject(opeer_); // (This conditional is only needed for tests, where Thread.lock won't have been set.) - if (lock != NULL) { - ObjectLock locker(self, lock); + if (lock != nullptr) { + SirtRef<mirror::Object> sirt_obj(self, lock); + ObjectLock<mirror::Object> locker(self, &sirt_obj); locker.Notify(); } } @@ -1281,7 +1284,7 @@ class BuildInternalStackTraceVisitor : public StackVisitor { return true; // Ignore runtime frames (in particular callee save). } method_trace_->Set(count_, m); - dex_pc_trace_->Set(count_, GetDexPc()); + dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc()); ++count_; return true; } @@ -1363,19 +1366,31 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job // Prepare parameters for StackTraceElement(String cls, String method, String file, int line) mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i)); MethodHelper mh(method); - mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth)); - uint32_t dex_pc = pc_trace->Get(i); - int32_t line_number = mh.GetLineNumFromDexPC(dex_pc); - // Allocate element, potentially triggering GC - // TODO: reuse class_name_object via Class::name_? - const char* descriptor = mh.GetDeclaringClassDescriptor(); - CHECK(descriptor != NULL); - std::string class_name(PrettyDescriptor(descriptor)); - SirtRef<mirror::String> class_name_object(soa.Self(), - mirror::String::AllocFromModifiedUtf8(soa.Self(), - class_name.c_str())); - if (class_name_object.get() == NULL) { - return NULL; + int32_t line_number; + SirtRef<mirror::String> class_name_object(soa.Self(), NULL); + SirtRef<mirror::String> source_name_object(soa.Self(), NULL); + if (method->IsProxyMethod()) { + line_number = -1; + class_name_object.reset(method->GetDeclaringClass()->GetName()); + // source_name_object intentionally left null for proxy methods + } else { + mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth)); + uint32_t dex_pc = pc_trace->Get(i); + line_number = mh.GetLineNumFromDexPC(dex_pc); + // Allocate element, potentially triggering GC + // TODO: reuse class_name_object via Class::name_? + const char* descriptor = mh.GetDeclaringClassDescriptor(); + CHECK(descriptor != NULL); + std::string class_name(PrettyDescriptor(descriptor)); + class_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str())); + if (class_name_object.get() == NULL) { + return NULL; + } + const char* source_file = mh.GetDeclaringClassSourceFile(); + source_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file)); + if (source_name_object.get() == NULL) { + return NULL; + } } const char* method_name = mh.GetName(); CHECK(method_name != NULL); @@ -1385,10 +1400,6 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job if (method_name_object.get() == NULL) { return NULL; } - const char* source_file = mh.GetDeclaringClassSourceFile(); - SirtRef<mirror::String> source_name_object(soa.Self(), - mirror::String::AllocFromModifiedUtf8(soa.Self(), - source_file)); mirror::StackTraceElement* obj = mirror::StackTraceElement::Alloc( soa.Self(), class_name_object, method_name_object, source_name_object, line_number); if (obj == NULL) { @@ -1434,9 +1445,9 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location, ClearException(); Runtime* runtime = Runtime::Current(); - mirror::ClassLoader* cl = NULL; - if (throw_location.GetMethod() != NULL) { - cl = throw_location.GetMethod()->GetDeclaringClass()->GetClassLoader(); + mirror::ClassLoader* cl = nullptr; + if (saved_throw_method.get() != nullptr) { + cl = saved_throw_method.get()->GetDeclaringClass()->GetClassLoader(); } SirtRef<mirror::ClassLoader> class_loader(this, cl); SirtRef<mirror::Class> @@ -1448,7 +1459,7 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location, return; } - if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class.get(), true, true))) { + if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class, true, true))) { DCHECK(IsExceptionPending()); return; } @@ -1458,7 +1469,9 @@ void Thread::ThrowNewWrappedException(const ThrowLocation& throw_location, // If we couldn't allocate the exception, throw the pre-allocated out of memory exception. if (exception.get() == nullptr) { - SetException(throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError()); + ThrowLocation gc_safe_throw_location(saved_throw_this.get(), saved_throw_method.get(), + throw_location.GetDexPc()); + SetException(gc_safe_throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError()); return; } @@ -1818,6 +1831,12 @@ class CatchBlockStackVisitor : public StackVisitor { self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_); // Do instrumentation events after allowing thread suspension again. instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); + if (!is_deoptimization_) { + // The debugger may suspend this thread and walk its stack. Let's do this before popping + // instrumentation frames. + instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_, + exception_); + } for (size_t i = 0; i < instrumentation_frames_to_pop_; ++i) { // We pop the instrumentation stack here so as not to corrupt it during the stack walk. if (i != instrumentation_frames_to_pop_ - 1 || self_->GetInstrumentationStack()->front().method_ != catch_method) { @@ -1825,10 +1844,7 @@ class CatchBlockStackVisitor : public StackVisitor { instrumentation->PopMethodForUnwind(self_, is_deoptimization_); } } - if (!is_deoptimization_) { - instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_, - exception_); - } else { + if (is_deoptimization_) { // TODO: proper return value. self_->SetDeoptimizationShadowFrame(top_shadow_frame_); } @@ -1984,11 +2000,7 @@ class ReferenceMapVisitor : public StackVisitor { // Portable path use DexGcMap and store in Method.native_gc_map_. const uint8_t* gc_map = m->GetNativeGcMap(); CHECK(gc_map != NULL) << PrettyMethod(m); - uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) | - (gc_map[1] << 16) | - (gc_map[2] << 8) | - (gc_map[3] << 0)); - verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length); + verifier::DexPcToReferenceMap dex_gc_map(gc_map); uint32_t dex_pc = GetDexPc(); const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc); DCHECK(reg_bitmap != NULL); @@ -2112,12 +2124,11 @@ void Thread::VisitRoots(RootVisitor* visitor, void* arg) { opeer_ = visitor(opeer_, arg); } if (exception_ != nullptr) { - exception_ = reinterpret_cast<mirror::Throwable*>(visitor(exception_, arg)); + exception_ = down_cast<mirror::Throwable*>(visitor(exception_, arg)); } throw_location_.VisitRoots(visitor, arg); if (class_loader_override_ != nullptr) { - class_loader_override_ = reinterpret_cast<mirror::ClassLoader*>( - visitor(class_loader_override_, arg)); + class_loader_override_ = down_cast<mirror::ClassLoader*>(visitor(class_loader_override_, arg)); } jni_env_->locals.VisitRoots(visitor, arg); jni_env_->monitors.VisitRoots(visitor, arg); @@ -2136,7 +2147,7 @@ void Thread::VisitRoots(RootVisitor* visitor, void* arg) { frame.this_object_ = visitor(frame.this_object_, arg); } DCHECK(frame.method_ != nullptr); - frame.method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(frame.method_, arg)); + frame.method_ = down_cast<mirror::ArtMethod*>(visitor(frame.method_, arg)); } } diff --git a/runtime/thread.h b/runtime/thread.h index db2f7b4..44b2186 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -147,7 +147,8 @@ class PACKED(4) Thread { } bool IsSuspended() const { - union StateAndFlags state_and_flags = state_and_flags_; + union StateAndFlags state_and_flags; + state_and_flags.as_int = state_and_flags_.as_int; return state_and_flags.as_struct.state != kRunnable && (state_and_flags.as_struct.flags & kSuspendRequest) != 0; } @@ -638,7 +639,8 @@ class PACKED(4) Thread { // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to // change from being Suspended to Runnable without a suspend request occurring. - union StateAndFlags { + union PACKED(4) StateAndFlags { + StateAndFlags() {} struct PACKED(4) { // Bitfield of flag values. Must be changed atomically so that flag values aren't lost. See // ThreadFlags for bit field meanings. @@ -650,6 +652,11 @@ class PACKED(4) Thread { volatile uint16_t state; } as_struct; volatile int32_t as_int; + + private: + // gcc does not handle struct with volatile member assignments correctly. + // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409 + DISALLOW_COPY_AND_ASSIGN(StateAndFlags); }; union StateAndFlags state_and_flags_; COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t), diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index dd3f11c..aed8c77 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -162,6 +162,35 @@ static void UnsafeLogFatalForThreadSuspendAllTimeout(Thread* self) NO_THREAD_SAF } #endif +// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an +// individual thread requires polling. delay_us is the requested sleep and total_delay_us +// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield, +// subsequently sleeps increase delay_us from 1ms to 500ms by doubling. +static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us, + bool holding_locks) { + if (!holding_locks) { + for (int i = kLockLevelCount - 1; i >= 0; --i) { + BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i)); + if (held_mutex != NULL) { + LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension"; + } + } + } + useconds_t new_delay_us = (*delay_us) * 2; + CHECK_GE(new_delay_us, *delay_us); + if (new_delay_us < 500000) { // Don't allow sleeping to be more than 0.5s. + *delay_us = new_delay_us; + } + if (*delay_us == 0) { + sched_yield(); + // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep). + *delay_us = 500; + } else { + usleep(*delay_us); + *total_delay_us += *delay_us; + } +} + size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) { Thread* self = Thread::Current(); if (kIsDebugBuild) { @@ -208,17 +237,15 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) { for (const auto& thread : suspended_count_modified_threads) { if (!thread->IsSuspended()) { // Wait until the thread is suspended. - uint64_t start = NanoTime(); + useconds_t total_delay_us = 0; do { - // Sleep for 100us. - usleep(100); + useconds_t delay_us = 100; + ThreadSuspendSleep(self, &delay_us, &total_delay_us, true); } while (!thread->IsSuspended()); - uint64_t end = NanoTime(); - // Shouldn't need to wait for longer than 1 millisecond. - const uint64_t threshold = 1; - if (NsToMs(end - start) > threshold) { - LOG(INFO) << "Warning: waited longer than " << threshold - << " ms for thread suspend\n"; + // Shouldn't need to wait for longer than 1000 microseconds. + constexpr useconds_t kLongWaitThresholdUS = 1000; + if (UNLIKELY(total_delay_us > kLongWaitThresholdUS)) { + LOG(WARNING) << "Waited " << total_delay_us << " us for thread suspend!"; } } // We know for sure that the thread is suspended at this point. @@ -354,34 +381,6 @@ static void ThreadSuspendByPeerWarning(Thread* self, int level, const char* mess } } -// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an -// individual thread requires polling. delay_us is the requested sleep and total_delay_us -// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield, -// subsequently sleeps increase delay_us from 1ms to 500ms by doubling. -static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us) { - for (int i = kLockLevelCount - 1; i >= 0; --i) { - BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i)); - if (held_mutex != NULL) { - LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension"; - } - } - { - useconds_t new_delay_us = (*delay_us) * 2; - CHECK_GE(new_delay_us, *delay_us); - if (new_delay_us < 500000) { // Don't allow sleeping to be more than 0.5s. - *delay_us = new_delay_us; - } - } - if ((*delay_us) == 0) { - sched_yield(); - // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep). - (*delay_us) = 500; - } else { - usleep(*delay_us); - (*total_delay_us) += (*delay_us); - } -} - Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension, bool debug_suspension, bool* timed_out) { static const useconds_t kTimeoutUs = 30 * 1000000; // 30s. @@ -432,7 +431,7 @@ Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension, } // Release locks and come out of runnable state. } - ThreadSuspendSleep(self, &delay_us, &total_delay_us); + ThreadSuspendSleep(self, &delay_us, &total_delay_us, false); } } @@ -445,13 +444,13 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe static const useconds_t kTimeoutUs = 30 * 1000000; // 30s. useconds_t total_delay_us = 0; useconds_t delay_us = 0; - bool did_suspend_request = false; *timed_out = false; + Thread* suspended_thread = nullptr; Thread* self = Thread::Current(); CHECK_NE(thread_id, kInvalidThreadId); while (true) { - Thread* thread = NULL; { + Thread* thread = NULL; ScopedObjectAccess soa(self); MutexLock mu(self, *Locks::thread_list_lock_); for (const auto& it : list_) { @@ -460,17 +459,20 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe break; } } - if (thread == NULL) { + if (thread == nullptr) { + CHECK(suspended_thread == nullptr) << "Suspended thread " << suspended_thread + << " no longer in thread list"; // There's a race in inflating a lock and the owner giving up ownership and then dying. ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id); return NULL; } { MutexLock mu(self, *Locks::thread_suspend_count_lock_); - if (!did_suspend_request) { + if (suspended_thread == nullptr) { thread->ModifySuspendCount(self, +1, debug_suspension); - did_suspend_request = true; + suspended_thread = thread; } else { + CHECK_EQ(suspended_thread, thread); // If the caller isn't requesting suspension, a suspension should have already occurred. CHECK_GT(thread->GetSuspendCount(), 0); } @@ -487,7 +489,7 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe } if (total_delay_us >= kTimeoutUs) { ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id); - if (did_suspend_request) { + if (suspended_thread != nullptr) { thread->ModifySuspendCount(soa.Self(), -1, debug_suspension); } *timed_out = true; @@ -496,7 +498,7 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspe } // Release locks and come out of runnable state. } - ThreadSuspendSleep(self, &delay_us, &total_delay_us); + ThreadSuspendSleep(self, &delay_us, &total_delay_us, false); } } @@ -719,9 +721,7 @@ void ThreadList::Unregister(Thread* self) { self->Destroy(); uint32_t thin_lock_id = self->thin_lock_thread_id_; - self->thin_lock_thread_id_ = 0; - ReleaseThreadId(self, thin_lock_id); - while (self != NULL) { + while (self != nullptr) { // Remove and delete the Thread* while holding the thread_list_lock_ and // thread_suspend_count_lock_ so that the unregistering thread cannot be suspended. // Note: deliberately not using MutexLock that could hold a stale self pointer. @@ -732,10 +732,14 @@ void ThreadList::Unregister(Thread* self) { if (!self->IsSuspended()) { list_.remove(self); delete self; - self = NULL; + self = nullptr; } Locks::thread_list_lock_->ExclusiveUnlock(self); } + // Release the thread ID after the thread is finished and deleted to avoid cases where we can + // temporarily have multiple threads with the same thread id. When this occurs, it causes + // problems in FindThreadByThreadId / SuspendThreadByThreadId. + ReleaseThreadId(nullptr, thin_lock_id); // Clear the TLS data, so that the underlying native thread is recognizably detached. // (It may wish to reattach later.) diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc index 01497ef..1cc3e74 100644 --- a/runtime/throw_location.cc +++ b/runtime/throw_location.cc @@ -25,7 +25,7 @@ namespace art { std::string ThrowLocation::Dump() const { - if (method_ != NULL) { + if (method_ != nullptr) { return StringPrintf("%s:%d", PrettyMethod(method_).c_str(), MethodHelper(method_).GetLineNumFromDexPC(dex_pc_)); } else { @@ -35,12 +35,11 @@ std::string ThrowLocation::Dump() const { void ThrowLocation::VisitRoots(RootVisitor* visitor, void* arg) { if (this_object_ != nullptr) { - this_object_ = const_cast<mirror::Object*>(visitor(this_object_, arg)); + this_object_ = visitor(this_object_, arg); DCHECK(this_object_ != nullptr); } if (method_ != nullptr) { - method_ = const_cast<mirror::ArtMethod*>( - reinterpret_cast<const mirror::ArtMethod*>(visitor(method_, arg))); + method_ = down_cast<mirror::ArtMethod*>(visitor(method_, arg)); DCHECK(method_ != nullptr); } } diff --git a/runtime/verifier/dex_gc_map.h b/runtime/verifier/dex_gc_map.h index 2a95ba2..4570ae8 100644 --- a/runtime/verifier/dex_gc_map.h +++ b/runtime/verifier/dex_gc_map.h @@ -38,11 +38,13 @@ enum RegisterMapFormat { // Lightweight wrapper for Dex PC to reference bit maps. class DexPcToReferenceMap { public: - DexPcToReferenceMap(const uint8_t* data, size_t data_length) : data_(data) { + explicit DexPcToReferenceMap(const uint8_t* data) : data_(data) { CHECK(data_ != NULL); - // Check the size of the table agrees with the number of entries - size_t data_size = data_length - 4; - DCHECK_EQ(EntryWidth() * NumEntries(), data_size); + } + + // The total size of the reference bit map including header. + size_t RawSize() const { + return EntryWidth() * NumEntries() + 4u /* header */; } // The number of entries in the table diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 1e45c60..9183b5f 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -319,10 +319,12 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, SirtRef<mirror::DexCache allow_soft_failures_(allow_soft_failures), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { + Runtime::Current()->AddMethodVerifier(this); DCHECK(class_def != nullptr); } MethodVerifier::~MethodVerifier() { + Runtime::Current()->RemoveMethodVerifier(this); STLDeleteElements(&failure_messages_); } @@ -1068,13 +1070,13 @@ bool MethodVerifier::VerifyCodeFlow() { bool compile = IsCandidateForCompilation(ref, method_access_flags_); if (compile) { /* Generate a register map and add it to the method. */ - const std::vector<uint8_t>* dex_gc_map = GenerateLengthPrefixedGcMap(); + const std::vector<uint8_t>* dex_gc_map = GenerateGcMap(); if (dex_gc_map == NULL) { DCHECK_NE(failures_.size(), 0U); return false; // Not a real failure, but a failure to encode } if (kIsDebugBuild) { - VerifyLengthPrefixedGcMap(*dex_gc_map); + VerifyGcMap(*dex_gc_map); } verifier::MethodVerifier::SetDexGcMap(ref, dex_gc_map); } @@ -4054,7 +4056,7 @@ MethodVerifier::PcToConcreteMethodMap* MethodVerifier::GenerateDevirtMap() { return pc_to_concrete_method_map.release(); } -const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() { +const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() { size_t num_entries, ref_bitmap_bits, pc_bits; ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits); // There's a single byte to encode the size of each bitmap @@ -4092,12 +4094,7 @@ const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")"; return NULL; } - table->reserve(table_size + 4); // table_size plus the length prefix - // Write table size - table->push_back((table_size & 0xff000000) >> 24); - table->push_back((table_size & 0x00ff0000) >> 16); - table->push_back((table_size & 0x0000ff00) >> 8); - table->push_back((table_size & 0x000000ff) >> 0); + table->reserve(table_size); // Write table header table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) & ~DexPcToReferenceMap::kRegMapFormatMask)); @@ -4115,18 +4112,15 @@ const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() { line->WriteReferenceBitMap(*table, ref_bitmap_bytes); } } - DCHECK_EQ(table->size(), table_size + 4); // table_size plus the length prefix + DCHECK_EQ(table->size(), table_size); return table; } -void MethodVerifier::VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data) { +void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) { // Check that for every GC point there is a map entry, there aren't entries for non-GC points, // that the table data is well formed and all references are marked (or not) in the bitmap - DCHECK_GE(data.size(), 4u); - size_t table_size = data.size() - 4u; - DCHECK_EQ(table_size, static_cast<size_t>((data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | (data[3] << 0))); - DexPcToReferenceMap map(&data[4], table_size); + DexPcToReferenceMap map(&data[0]); + DCHECK_EQ(data.size(), map.RawSize()); size_t map_index = 0; for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) { const uint8_t* reg_bitmap = map.FindBitMap(i, false); @@ -4393,5 +4387,9 @@ bool MethodVerifier::IsClassRejected(ClassReference ref) { return (rejected_classes_->find(ref) != rejected_classes_->end()); } +void MethodVerifier::VisitRoots(RootVisitor* visitor, void* arg) { + reg_types_.VisitRoots(visitor, arg); +} + } // namespace verifier } // namespace art diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index f72898e..6b5747b 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -237,6 +237,8 @@ class MethodVerifier { static bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags); + void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + private: // Adds the given string to the beginning of the last failure message. void PrependToLastFailMessage(std::string); @@ -614,10 +616,10 @@ class MethodVerifier { * encode it in some clever fashion. * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure. */ - const std::vector<uint8_t>* GenerateLengthPrefixedGcMap(); + const std::vector<uint8_t>* GenerateGcMap(); // Verify that the GC map associated with method_ is well formed - void VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data); + void VerifyGcMap(const std::vector<uint8_t>& data); // Compute sizes for GC map data void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc); diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index d82e75d..f394bce 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -969,6 +969,12 @@ void RegType::CheckInvariants() const { } } +void RegType::VisitRoots(RootVisitor* visitor, void* arg) { + if (klass_ != nullptr) { + klass_ = down_cast<mirror::Class*>(visitor(klass_, arg)); + } +} + void UninitializedThisReferenceType::CheckInvariants() const { CHECK_EQ(GetAllocationPc(), 0U) << *this; } diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index f371733..8df481f 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -20,6 +20,7 @@ #include "base/macros.h" #include "globals.h" #include "primitive.h" +#include "root_visitor.h" #include "jni.h" @@ -269,6 +270,8 @@ class RegType { virtual ~RegType() {} + void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + protected: RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) @@ -282,7 +285,7 @@ class RegType { const std::string descriptor_; - mirror::Class* const klass_; + mirror::Class* klass_; const uint16_t cache_id_; friend class RegTypeCache; diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 9c9673a..3d24414 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -554,5 +554,11 @@ void RegTypeCache::Dump(std::ostream& os) { } } +void RegTypeCache::VisitRoots(RootVisitor* visitor, void* arg) { + for (RegType* entry : entries_) { + entry->VisitRoots(visitor, arg); + } +} + } // namespace verifier } // namespace art diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index a9f8bff..a811696 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -21,6 +21,7 @@ #include "base/macros.h" #include "base/stl_util.h" #include "reg_type.h" +#include "root_visitor.h" #include "runtime.h" #include <stdint.h> @@ -139,6 +140,8 @@ class RegTypeCache { void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const RegType& RegTypeFromPrimitiveType(Primitive::Type) const; + void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + private: void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader) diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc index db273ec..8cb1993 100644 --- a/runtime/zip_archive.cc +++ b/runtime/zip_archive.cc @@ -30,272 +30,23 @@ namespace art { -static const size_t kBufSize = 32 * KB; - -// Get 2 little-endian bytes. -static uint32_t Le16ToHost(const byte* src) { - return ((src[0] << 0) | - (src[1] << 8)); -} - -// Get 4 little-endian bytes. -static uint32_t Le32ToHost(const byte* src) { - return ((src[0] << 0) | - (src[1] << 8) | - (src[2] << 16) | - (src[3] << 24)); -} - -uint16_t ZipEntry::GetCompressionMethod() { - return Le16ToHost(ptr_ + ZipArchive::kCDEMethod); -} - -uint32_t ZipEntry::GetCompressedLength() { - return Le32ToHost(ptr_ + ZipArchive::kCDECompLen); -} - uint32_t ZipEntry::GetUncompressedLength() { - return Le32ToHost(ptr_ + ZipArchive::kCDEUncompLen); + return zip_entry_->uncompressed_length; } uint32_t ZipEntry::GetCrc32() { - return Le32ToHost(ptr_ + ZipArchive::kCDECRC); + return zip_entry_->crc32; } -off64_t ZipEntry::GetDataOffset() { - // All we have is the offset to the Local File Header, which is - // variable size, so we have to read the contents of the struct to - // figure out where the actual data starts. - - // We also need to make sure that the lengths are not so large that - // somebody trying to map the compressed or uncompressed data runs - // off the end of the mapped region. - - off64_t dir_offset = zip_archive_->dir_offset_; - int64_t lfh_offset = Le32ToHost(ptr_ + ZipArchive::kCDELocalOffset); - if (lfh_offset + ZipArchive::kLFHLen >= dir_offset) { - LOG(WARNING) << "Zip: bad LFH offset in zip"; - return -1; - } - - if (lseek64(zip_archive_->fd_, lfh_offset, SEEK_SET) != lfh_offset) { - PLOG(WARNING) << "Zip: failed seeking to LFH at offset " << lfh_offset; - return -1; - } - - uint8_t lfh_buf[ZipArchive::kLFHLen]; - ssize_t actual = TEMP_FAILURE_RETRY(read(zip_archive_->fd_, lfh_buf, sizeof(lfh_buf))); - if (actual != sizeof(lfh_buf)) { - LOG(WARNING) << "Zip: failed reading LFH from offset " << lfh_offset; - return -1; - } - - if (Le32ToHost(lfh_buf) != ZipArchive::kLFHSignature) { - LOG(WARNING) << "Zip: didn't find signature at start of LFH, offset " << lfh_offset; - return -1; - } - - uint32_t gpbf = Le16ToHost(lfh_buf + ZipArchive::kLFHGPBFlags); - if ((gpbf & ZipArchive::kGPFUnsupportedMask) != 0) { - LOG(WARNING) << "Invalid General Purpose Bit Flag: " << gpbf; - return -1; - } - - off64_t data_offset = (lfh_offset + ZipArchive::kLFHLen - + Le16ToHost(lfh_buf + ZipArchive::kLFHNameLen) - + Le16ToHost(lfh_buf + ZipArchive::kLFHExtraLen)); - if (data_offset >= dir_offset) { - LOG(WARNING) << "Zip: bad data offset " << data_offset << " in zip"; - return -1; - } - - // check lengths - - if (static_cast<off64_t>(data_offset + GetCompressedLength()) > dir_offset) { - LOG(WARNING) << "Zip: bad compressed length in zip " - << "(" << data_offset << " + " << GetCompressedLength() - << " > " << dir_offset << ")"; - return -1; - } - - if (GetCompressionMethod() == kCompressStored - && static_cast<off64_t>(data_offset + GetUncompressedLength()) > dir_offset) { - LOG(WARNING) << "Zip: bad uncompressed length in zip " - << "(" << data_offset << " + " << GetUncompressedLength() - << " > " << dir_offset << ")"; - return -1; - } - - return data_offset; -} - -static bool CopyFdToMemory(uint8_t* begin, size_t size, int in, size_t count) { - uint8_t* dst = begin; - std::vector<uint8_t> buf(kBufSize); - while (count != 0) { - size_t bytes_to_read = (count > kBufSize) ? kBufSize : count; - ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read)); - if (actual != static_cast<ssize_t>(bytes_to_read)) { - PLOG(WARNING) << "Zip: short read"; - return false; - } - memcpy(dst, &buf[0], bytes_to_read); - dst += bytes_to_read; - count -= bytes_to_read; - } - DCHECK_EQ(dst, begin + size); - return true; -} - -class ZStream { - public: - ZStream(byte* write_buf, size_t write_buf_size) { - // Initialize the zlib stream struct. - memset(&zstream_, 0, sizeof(zstream_)); - zstream_.zalloc = Z_NULL; - zstream_.zfree = Z_NULL; - zstream_.opaque = Z_NULL; - zstream_.next_in = NULL; - zstream_.avail_in = 0; - zstream_.next_out = reinterpret_cast<Bytef*>(write_buf); - zstream_.avail_out = write_buf_size; - zstream_.data_type = Z_UNKNOWN; - } - - z_stream& Get() { - return zstream_; - } - - ~ZStream() { - inflateEnd(&zstream_); - } - private: - z_stream zstream_; -}; - -static bool InflateToMemory(uint8_t* begin, size_t size, - int in, size_t uncompressed_length, size_t compressed_length) { - uint8_t* dst = begin; - UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]); - UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]); - if (read_buf.get() == NULL || write_buf.get() == NULL) { - LOG(WARNING) << "Zip: failed to allocate buffer to inflate"; - return false; - } - - UniquePtr<ZStream> zstream(new ZStream(write_buf.get(), kBufSize)); - - // Use the undocumented "negative window bits" feature to tell zlib - // that there's no zlib header waiting for it. - int zerr = inflateInit2(&zstream->Get(), -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")"; - } else { - LOG(WARNING) << "Call to inflateInit2 failed (zerr=" << zerr << ")"; - } - return false; - } - - size_t remaining = compressed_length; - do { - // read as much as we can - if (zstream->Get().avail_in == 0) { - size_t bytes_to_read = (remaining > kBufSize) ? kBufSize : remaining; - - ssize_t actual = TEMP_FAILURE_RETRY(read(in, read_buf.get(), bytes_to_read)); - if (actual != static_cast<ssize_t>(bytes_to_read)) { - LOG(WARNING) << "Zip: inflate read failed (" << actual << " vs " << bytes_to_read << ")"; - return false; - } - remaining -= bytes_to_read; - zstream->Get().next_in = read_buf.get(); - zstream->Get().avail_in = bytes_to_read; - } - - // uncompress the data - zerr = inflate(&zstream->Get(), Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - LOG(WARNING) << "Zip: inflate zerr=" << zerr - << " (next_in=" << zstream->Get().next_in - << " avail_in=" << zstream->Get().avail_in - << " next_out=" << zstream->Get().next_out - << " avail_out=" << zstream->Get().avail_out - << ")"; - return false; - } - - // write when we're full or when we're done - if (zstream->Get().avail_out == 0 || - (zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) { - size_t bytes_to_write = zstream->Get().next_out - write_buf.get(); - memcpy(dst, write_buf.get(), bytes_to_write); - dst += bytes_to_write; - zstream->Get().next_out = write_buf.get(); - zstream->Get().avail_out = kBufSize; - } - } while (zerr == Z_OK); - - DCHECK_EQ(zerr, Z_STREAM_END); // other errors should've been caught - - // paranoia - if (zstream->Get().total_out != uncompressed_length) { - LOG(WARNING) << "Zip: size mismatch on inflated file (" - << zstream->Get().total_out << " vs " << uncompressed_length << ")"; - return false; - } - - DCHECK_EQ(dst, begin + size); - return true; -} bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) { - uint32_t length = GetUncompressedLength(); - int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length)); - if (result == -1) { - *error_msg = StringPrintf("Zip: failed to ftruncate '%s' to length %ud", file.GetPath().c_str(), - length); - return false; - } - - UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0, - file.GetPath().c_str(), error_msg)); - if (map.get() == NULL) { - *error_msg = StringPrintf("Zip: failed to mmap space for '%s': %s", file.GetPath().c_str(), - error_msg->c_str()); - return false; - } - - return ExtractToMemory(map->Begin(), map->Size(), error_msg); -} - -bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg) { - // If size is zero, data offset will be meaningless, so bail out early. - if (size == 0) { - return true; - } - off64_t data_offset = GetDataOffset(); - if (data_offset == -1) { - *error_msg = StringPrintf("Zip: data_offset=%lld", data_offset); - return false; - } - if (lseek64(zip_archive_->fd_, data_offset, SEEK_SET) != data_offset) { - *error_msg = StringPrintf("Zip: lseek to data at %lld failed", data_offset); + const int32_t error = ExtractEntryToFile(handle_, zip_entry_, file.Fd()); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); return false; } - // TODO: this doesn't verify the data's CRC, but probably should (especially - // for uncompressed data). - switch (GetCompressionMethod()) { - case kCompressStored: - return CopyFdToMemory(begin, size, zip_archive_->fd_, GetUncompressedLength()); - case kCompressDeflated: - return InflateToMemory(begin, size, zip_archive_->fd_, - GetUncompressedLength(), GetCompressedLength()); - default: - *error_msg = StringPrintf("Zip: unknown compression method 0x%x", GetCompressionMethod()); - return false; - } + return true; } MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error_msg) { @@ -303,18 +54,18 @@ MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error name += " extracted in memory from "; name += entry_filename; UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(), - NULL, - GetUncompressedLength(), + NULL, GetUncompressedLength(), PROT_READ | PROT_WRITE, error_msg)); if (map.get() == nullptr) { DCHECK(!error_msg->empty()); - return NULL; + return nullptr; } - bool success = ExtractToMemory(map->Begin(), map->Size(), error_msg); - if (!success) { - LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory"; - return NULL; + const int32_t error = ExtractToMemory(handle_, zip_entry_, + map->Begin(), map->Size()); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + return nullptr; } return map.release(); @@ -336,238 +87,47 @@ static void SetCloseOnExec(int fd) { ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) { DCHECK(filename != nullptr); - int fd = open(filename, O_RDONLY, 0); - if (fd == -1) { - *error_msg = StringPrintf("Zip: unable to open '%s': %s", filename, strerror(errno)); - return NULL; - } - return OpenFromFd(fd, filename, error_msg); -} -ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) { - SetCloseOnExec(fd); - UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd, filename)); - CHECK(zip_archive.get() != nullptr); - if (!zip_archive->MapCentralDirectory(error_msg)) { - zip_archive->Close(); - return NULL; - } - if (!zip_archive->Parse(error_msg)) { - zip_archive->Close(); - return NULL; + ZipArchiveHandle handle; + const int32_t error = OpenArchive(filename, &handle); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + CloseArchive(handle); + return nullptr; } - return zip_archive.release(); -} - -ZipEntry* ZipArchive::Find(const char* name) const { - DCHECK(name != NULL); - DirEntries::const_iterator it = dir_entries_.find(name); - if (it == dir_entries_.end()) { - return NULL; - } - return new ZipEntry(this, (*it).second); -} -void ZipArchive::Close() { - if (fd_ != -1) { - close(fd_); - } - fd_ = -1; - num_entries_ = 0; - dir_offset_ = 0; -} - -std::string ZipArchive::ErrorStringPrintf(const char* fmt, ...) { - va_list ap; - va_start(ap, fmt); - std::string result(StringPrintf("Zip '%s' : ", filename_.c_str())); - StringAppendV(&result, fmt, ap); - va_end(ap); - return result; + SetCloseOnExec(GetFileDescriptor(handle)); + return new ZipArchive(handle); } -// Find the zip Central Directory and memory-map it. -// -// On success, returns true after populating fields from the EOCD area: -// num_entries_ -// dir_offset_ -// dir_map_ -bool ZipArchive::MapCentralDirectory(std::string* error_msg) { - /* - * Get and test file length. - */ - off64_t file_length = lseek64(fd_, 0, SEEK_END); - if (file_length < kEOCDLen) { - *error_msg = ErrorStringPrintf("length %lld is too small to be zip", file_length); - return false; - } - - size_t read_amount = kMaxEOCDSearch; - if (file_length < off64_t(read_amount)) { - read_amount = file_length; - } - - UniquePtr<uint8_t[]> scan_buf(new uint8_t[read_amount]); - CHECK(scan_buf.get() != nullptr); - - /* - * Make sure this is a Zip archive. - */ - if (lseek64(fd_, 0, SEEK_SET) != 0) { - *error_msg = ErrorStringPrintf("seek to start failed: %s", strerror(errno)); - return false; - } - - ssize_t actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), sizeof(int32_t))); - if (actual != static_cast<ssize_t>(sizeof(int32_t))) { - *error_msg = ErrorStringPrintf("couldn\'t read first signature from zip archive: %s", - strerror(errno)); - return false; - } - - unsigned int header = Le32ToHost(scan_buf.get()); - if (header != kLFHSignature) { - *error_msg = ErrorStringPrintf("not a zip archive (found 0x%x)", header); - return false; - } - - // Perform the traditional EOCD snipe hunt. - // - // We're searching for the End of Central Directory magic number, - // which appears at the start of the EOCD block. It's followed by - // 18 bytes of EOCD stuff and up to 64KB of archive comment. We - // need to read the last part of the file into a buffer, dig through - // it to find the magic number, parse some values out, and use those - // to determine the extent of the CD. - // - // We start by pulling in the last part of the file. - off64_t search_start = file_length - read_amount; - - if (lseek64(fd_, search_start, SEEK_SET) != search_start) { - *error_msg = ErrorStringPrintf("seek %lld failed: %s", search_start, strerror(errno)); - return false; - } - actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), read_amount)); - if (actual != static_cast<ssize_t>(read_amount)) { - *error_msg = ErrorStringPrintf("read %lld, expected %zd. %s", search_start, read_amount, - strerror(errno)); - return false; - } - - - // Scan backward for the EOCD magic. In an archive without a trailing - // comment, we'll find it on the first try. (We may want to consider - // doing an initial minimal read; if we don't find it, retry with a - // second read as above.) - int i; - for (i = read_amount - kEOCDLen; i >= 0; i--) { - if (scan_buf.get()[i] == 0x50 && Le32ToHost(&(scan_buf.get())[i]) == kEOCDSignature) { - break; - } - } - if (i < 0) { - *error_msg = ErrorStringPrintf("EOCD not found, not a zip file"); - return false; - } - - off64_t eocd_offset = search_start + i; - const byte* eocd_ptr = scan_buf.get() + i; - - CHECK(eocd_offset < file_length); - - // Grab the CD offset and size, and the number of entries in the - // archive. Verify that they look reasonable. - uint16_t disk_number = Le16ToHost(eocd_ptr + kEOCDDiskNumber); - uint16_t disk_with_central_dir = Le16ToHost(eocd_ptr + kEOCDDiskNumberForCD); - uint16_t num_entries = Le16ToHost(eocd_ptr + kEOCDNumEntries); - uint16_t total_num_entries = Le16ToHost(eocd_ptr + kEOCDTotalNumEntries); - uint32_t dir_size = Le32ToHost(eocd_ptr + kEOCDSize); - uint32_t dir_offset = Le32ToHost(eocd_ptr + kEOCDFileOffset); - uint16_t comment_size = Le16ToHost(eocd_ptr + kEOCDCommentSize); - - if ((uint64_t) dir_offset + (uint64_t) dir_size > (uint64_t) eocd_offset) { - *error_msg = ErrorStringPrintf("bad offsets (dir=%ud, size=%ud, eocd=%lld)", - dir_offset, dir_size, eocd_offset); - return false; - } - if (num_entries == 0) { - *error_msg = ErrorStringPrintf("empty archive?"); - return false; - } else if (num_entries != total_num_entries || disk_number != 0 || disk_with_central_dir != 0) { - *error_msg = ErrorStringPrintf("spanned archives not supported"); - return false; - } - - // Check to see if comment is a sane size - if ((comment_size > (file_length - kEOCDLen)) - || (eocd_offset > (file_length - kEOCDLen) - comment_size)) { - *error_msg = ErrorStringPrintf("comment size runs off end of file"); - return false; - } +ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) { + DCHECK(filename != nullptr); + DCHECK_GT(fd, 0); - // It all looks good. Create a mapping for the CD. - dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset, - filename_.c_str(), error_msg)); - if (dir_map_.get() == NULL) { - return false; + ZipArchiveHandle handle; + const int32_t error = OpenArchiveFd(fd, filename, &handle); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + CloseArchive(handle); + return nullptr; } - num_entries_ = num_entries; - dir_offset_ = dir_offset; - return true; + SetCloseOnExec(GetFileDescriptor(handle)); + return new ZipArchive(handle); } -bool ZipArchive::Parse(std::string* error_msg) { - const byte* cd_ptr = dir_map_->Begin(); - size_t cd_length = dir_map_->Size(); +ZipEntry* ZipArchive::Find(const char* name, std::string* error_msg) const { + DCHECK(name != nullptr); - // Walk through the central directory, adding entries to the hash - // table and verifying values. - const byte* ptr = cd_ptr; - for (int i = 0; i < num_entries_; i++) { - if (Le32ToHost(ptr) != kCDESignature) { - *error_msg = ErrorStringPrintf("missed a central dir sig (at %d)", i); - return false; - } - if (ptr + kCDELen > cd_ptr + cd_length) { - *error_msg = ErrorStringPrintf("ran off the end (at %d)", i); - return false; - } - - int64_t local_hdr_offset = Le32ToHost(ptr + kCDELocalOffset); - if (local_hdr_offset >= dir_offset_) { - *error_msg = ErrorStringPrintf("bad LFH offset %lld at entry %d", local_hdr_offset, i); - return false; - } - - uint16_t gpbf = Le16ToHost(ptr + kCDEGPBFlags); - if ((gpbf & kGPFUnsupportedMask) != 0) { - *error_msg = ErrorStringPrintf("invalid general purpose bit flag %x", gpbf); - return false; - } - - uint16_t name_len = Le16ToHost(ptr + kCDENameLen); - uint16_t extra_len = Le16ToHost(ptr + kCDEExtraLen); - uint16_t comment_len = Le16ToHost(ptr + kCDECommentLen); - - // add the CDE filename to the hash table - const char* name = reinterpret_cast<const char*>(ptr + kCDELen); - - // Check name for NULL characters - if (memchr(name, 0, name_len) != NULL) { - *error_msg = ErrorStringPrintf("filename contains NUL byte"); - return false; - } - - dir_entries_.Put(StringPiece(name, name_len), ptr); - ptr += kCDELen + name_len + extra_len + comment_len; - if (ptr > cd_ptr + cd_length) { - *error_msg = ErrorStringPrintf("bad CD advance (%p vs %p) at entry %d", - ptr, cd_ptr + cd_length, i); - return false; - } + // Resist the urge to delete the space. <: is a bigraph sequence. + UniquePtr< ::ZipEntry> zip_entry(new ::ZipEntry); + const int32_t error = FindEntry(handle_, name, zip_entry.get()); + if (error) { + *error_msg = std::string(ErrorCodeString(error)); + return nullptr; } - return true; + + return new ZipEntry(handle_, zip_entry.release()); } } // namespace art diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h index 8ff952b..1f48e0a 100644 --- a/runtime/zip_archive.h +++ b/runtime/zip_archive.h @@ -18,8 +18,8 @@ #define ART_RUNTIME_ZIP_ARCHIVE_H_ #include <stdint.h> -#include <zlib.h> #include <string> +#include <ziparchive/zip_archive.h> #include "base/logging.h" #include "base/stringpiece.h" @@ -38,33 +38,17 @@ class MemMap; class ZipEntry { public: bool ExtractToFile(File& file, std::string* error_msg); - bool ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg); MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg); uint32_t GetUncompressedLength(); uint32_t GetCrc32(); private: - ZipEntry(const ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {} + ZipEntry(ZipArchiveHandle handle, + ::ZipEntry* zip_entry) : handle_(handle), zip_entry_(zip_entry) {} - // Zip compression methods - enum { - kCompressStored = 0, // no compression - kCompressDeflated = 8, // standard deflate - }; - - // kCompressStored, kCompressDeflated, ... - uint16_t GetCompressionMethod(); - - uint32_t GetCompressedLength(); - - // returns -1 on error - off64_t GetDataOffset(); - - const ZipArchive* zip_archive_; - - // pointer to zip entry within central directory - const byte* ptr_; + ZipArchiveHandle handle_; + ::ZipEntry* const zip_entry_; friend class ZipArchive; DISALLOW_COPY_AND_ASSIGN(ZipEntry); @@ -72,74 +56,23 @@ class ZipEntry { class ZipArchive { public: - // Zip file constants. - static const uint32_t kEOCDSignature = 0x06054b50; - static const int32_t kEOCDLen = 22; - static const int32_t kEOCDDiskNumber = 4; // number of the current disk - static const int32_t kEOCDDiskNumberForCD = 6; // disk number with the Central Directory - static const int32_t kEOCDNumEntries = 8; // offset to #of entries in file - static const int32_t kEOCDTotalNumEntries = 10; // offset to total #of entries in spanned archives - static const int32_t kEOCDSize = 12; // size of the central directory - static const int32_t kEOCDFileOffset = 16; // offset to central directory - static const int32_t kEOCDCommentSize = 20; // offset to the length of the file comment - - static const int32_t kMaxCommentLen = 65535; // longest possible in uint16_t - static const int32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen); - - static const uint32_t kLFHSignature = 0x04034b50; - static const int32_t kLFHLen = 30; // excluding variable-len fields - static const int32_t kLFHGPBFlags = 6; // offset to GPB flags - static const int32_t kLFHNameLen = 26; // offset to filename length - static const int32_t kLFHExtraLen = 28; // offset to extra length - - static const uint32_t kCDESignature = 0x02014b50; - static const int32_t kCDELen = 46; // excluding variable-len fields - static const int32_t kCDEGPBFlags = 8; // offset to GPB flags - static const int32_t kCDEMethod = 10; // offset to compression method - static const int32_t kCDEModWhen = 12; // offset to modification timestamp - static const int32_t kCDECRC = 16; // offset to entry CRC - static const int32_t kCDECompLen = 20; // offset to compressed length - static const int32_t kCDEUncompLen = 24; // offset to uncompressed length - static const int32_t kCDENameLen = 28; // offset to filename length - static const int32_t kCDEExtraLen = 30; // offset to extra length - static const int32_t kCDECommentLen = 32; // offset to comment length - static const int32_t kCDELocalOffset = 42; // offset to local hdr - - // General Purpose Bit Flag - static const int32_t kGPFEncryptedFlag = (1 << 0); - static const int32_t kGPFUnsupportedMask = (kGPFEncryptedFlag); - // return new ZipArchive instance on success, NULL on error. static ZipArchive* Open(const char* filename, std::string* error_msg); static ZipArchive* OpenFromFd(int fd, const char* filename, std::string* error_msg); - ZipEntry* Find(const char* name) const; + ZipEntry* Find(const char* name, std::string* error_msg) const; ~ZipArchive() { - Close(); + CloseArchive(handle_); } private: - explicit ZipArchive(int fd, const char* filename) - : fd_(fd), num_entries_(0), dir_offset_(0), filename_(filename) {} - - bool MapCentralDirectory(std::string* error_msg); - bool Parse(std::string* error_msg); - void Close(); - std::string ErrorStringPrintf(const char* fmt, ...) - __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; - - int fd_; - uint16_t num_entries_; - off64_t dir_offset_; - UniquePtr<MemMap> dir_map_; - typedef SafeMap<StringPiece, const byte*> DirEntries; - DirEntries dir_entries_; - // Containing file for error reporting. - const std::string filename_; + explicit ZipArchive(ZipArchiveHandle handle) : handle_(handle) {} friend class ZipEntry; + ZipArchiveHandle handle_; + DISALLOW_COPY_AND_ASSIGN(ZipArchive); }; diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index 622dc89..16394b0 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -19,6 +19,7 @@ #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> +#include <zlib.h> #include "UniquePtr.h" #include "common_test.h" @@ -33,8 +34,9 @@ TEST_F(ZipArchiveTest, FindAndExtract) { UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg)); ASSERT_TRUE(zip_archive.get() != false) << error_msg; ASSERT_TRUE(error_msg.empty()); - UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex")); + UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg)); ASSERT_TRUE(zip_entry.get() != false); + ASSERT_TRUE(error_msg.empty()); ScratchFile tmp; ASSERT_NE(-1, tmp.GetFd()); diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt index 13e3a28..12df250 100644 --- a/test/044-proxy/expected.txt +++ b/test/044-proxy/expected.txt @@ -42,6 +42,7 @@ Invoke public abstract java.lang.String Shapes.blob() (no args) --- blob Success: method blob res=mix +$Proxy1.getTrace null:-1 Invoke public abstract void Shapes.upChuck() (no args) Got expected ioobe @@ -49,8 +50,8 @@ Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedExcepti (no args) Got expected ie -Proxy interfaces: [interface Quads, interface Colors] -Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()] +Proxy interfaces: [interface Quads, interface Colors, interface Trace] +Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()] Decl annos: [] Param annos (0) : [] Dupe threw expected exception diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java index 46aa3fe..ea46f49 100644 --- a/test/044-proxy/src/BasicTest.java +++ b/test/044-proxy/src/BasicTest.java @@ -51,6 +51,8 @@ public class BasicTest { colors.blue(777); colors.mauve("sorry"); colors.blob(); + Trace trace = (Trace) proxy; + trace.getTrace(); try { shapes.upChuck(); @@ -96,7 +98,7 @@ public class BasicTest { /* create the proxy class */ Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(), - new Class[] { Quads.class, Colors.class }); + new Class[] { Quads.class, Colors.class, Trace.class }); /* create a proxy object, passing the handler object in */ Object proxy = null; @@ -156,6 +158,10 @@ interface Colors { public R0aa checkMe(); } +interface Trace { + public void getTrace(); +} + /* * Some return types. */ @@ -248,6 +254,20 @@ class MyInvocationHandler implements InvocationHandler { throw new RuntimeException("huh?"); } + if (method.getDeclaringClass() == Trace.class) { + if (method.getName().equals("getTrace")) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement ste = stackTrace[i]; + if (ste.getMethodName().equals("getTrace")) { + System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " + + ste.getFileName() + ":" + ste.getLineNumber()); + } + } + return null; + } + } + System.out.println("Invoke " + method); if (args == null || args.length == 0) { System.out.println(" (no args)"); diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java index a1b1f0c..9194da5 100644 --- a/test/JniTest/JniTest.java +++ b/test/JniTest/JniTest.java @@ -20,12 +20,24 @@ class JniTest { public static void main(String[] args) { System.loadLibrary("arttest"); testFindClassOnAttachedNativeThread(); + testFindFieldOnAttachedNativeThread(); testCallStaticVoidMethodOnSubClass(); testGetMirandaMethod(); } private static native void testFindClassOnAttachedNativeThread(); + private static boolean testFindFieldOnAttachedNativeThreadField; + + private static void testFindFieldOnAttachedNativeThread() { + testFindFieldOnAttachedNativeThreadNative(); + if (!testFindFieldOnAttachedNativeThreadField) { + throw new AssertionError(); + } + } + + private static native void testFindFieldOnAttachedNativeThreadNative(); + private static void testCallStaticVoidMethodOnSubClass() { testCallStaticVoidMethodOnSubClassNative(); if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) { diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc index cfcbb64..d15e180 100644 --- a/test/JniTest/jni_test.cc +++ b/test/JniTest/jni_test.cc @@ -67,6 +67,42 @@ extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindClassOnAttachedNativeThre assert(pthread_join_result == 0); } +static void* testFindFieldOnAttachedNativeThread(void*) { + assert(jvm != NULL); + + JNIEnv* env = NULL; + JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL }; + int attach_result = jvm->AttachCurrentThread(&env, &args); + assert(attach_result == 0); + + jclass clazz = env->FindClass("JniTest"); + assert(clazz != NULL); + assert(!env->ExceptionCheck()); + + jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z"); + assert(field != NULL); + assert(!env->ExceptionCheck()); + + env->SetStaticBooleanField(clazz, field, JNI_TRUE); + + int detach_result = jvm->DetachCurrentThread(); + assert(detach_result == 0); + return NULL; +} + +extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindFieldOnAttachedNativeThreadNative(JNIEnv*, + jclass) { + pthread_t pthread; + int pthread_create_result = pthread_create(&pthread, + NULL, + testFindFieldOnAttachedNativeThread, + NULL); + assert(pthread_create_result == 0); + int pthread_join_result = pthread_join(pthread, NULL); + assert(pthread_join_result == 0); +} + + // http://b/11243757 extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, jclass) { diff --git a/test/ThreadStress/ThreadStress.java b/test/ThreadStress/ThreadStress.java index 8d8135d..795c790 100644 --- a/test/ThreadStress/ThreadStress.java +++ b/test/ThreadStress/ThreadStress.java @@ -128,13 +128,13 @@ class ThreadStress implements Runnable { Thread[] runners = new Thread[numberOfThreads]; for (int r = 0; r < runners.length; r++) { final ThreadStress ts = threadStresses[r]; - runners[r] = new Thread() { + runners[r] = new Thread("Runner thread " + r) { final ThreadStress threadStress = ts; public void run() { int id = threadStress.id; - System.out.println("Starting runner for " + id); + System.out.println("Starting worker for " + id); while (threadStress.nextOperation < operationsPerThread) { - Thread thread = new Thread(ts); + Thread thread = new Thread(ts, "Worker thread " + id); thread.start(); try { thread.join(); @@ -144,14 +144,14 @@ class ThreadStress implements Runnable { + (operationsPerThread - threadStress.nextOperation) + " operations remaining."); } - System.out.println("Finishing runner for " + id); + System.out.println("Finishing worker for " + id); } }; } // The notifier thread is a daemon just loops forever to wake // up threads in Operation.WAIT - Thread notifier = new Thread() { + Thread notifier = new Thread("Notifier") { public void run() { while (true) { synchronized (lock) { diff --git a/tools/cpplint.py b/tools/cpplint.py index 30b5216..c2f6514 100755 --- a/tools/cpplint.py +++ b/tools/cpplint.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Copyright (c) 2009 Google Inc. All rights reserved. # diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py index 0c085fb..19266b4 100755 --- a/tools/generate-operator-out.py +++ b/tools/generate-operator-out.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Copyright (C) 2012 The Android Open Source Project # |