diff options
163 files changed, 1648 insertions, 953 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index ed34a8df5f..11af1c0ca8 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -125,6 +125,7 @@ ART_GTEST_stub_test_DEX_DEPS := AllFields ART_GTEST_transaction_test_DEX_DEPS := Transaction ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup ART_GTEST_unstarted_runtime_test_DEX_DEPS := Nested +ART_GTEST_heap_verification_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps VerifierDepsMulti MultiDex ART_GTEST_dex_to_dex_decompiler_test_DEX_DEPS := VerifierDeps DexToDexDecompiler @@ -655,6 +656,7 @@ ART_GTEST_reflection_test_DEX_DEPS := ART_GTEST_stub_test_DEX_DEPS := ART_GTEST_transaction_test_DEX_DEPS := ART_GTEST_dex2oat_environment_tests_DEX_DEPS := +ART_GTEST_heap_verification_test_DEX_DEPS := ART_GTEST_verifier_deps_test_DEX_DEPS := ART_VALGRIND_DEPENDENCIES := ART_VALGRIND_TARGET_DEPENDENCIES := diff --git a/compiler/Android.bp b/compiler/Android.bp index 312fc7b35a..dec8b577d8 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -29,6 +29,7 @@ art_cc_defaults { "debug/elf_debug_writer.cc", "dex/dex_to_dex_compiler.cc", "dex/dex_to_dex_decompiler.cc", + "dex/inline_method_analyser.cc", "dex/verified_method.cc", "dex/verification_results.cc", "dex/quick_compiler_callbacks.cc", diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 8b3029261f..39edd1eb02 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -18,7 +18,7 @@ #include "arch/instruction_set_features.h" #include "art_field-inl.h" -#include "art_method.h" +#include "art_method-inl.h" #include "base/enums.h" #include "class_linker.h" #include "compiled_method.h" diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 30d4b47c6a..558c7d5754 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -21,6 +21,7 @@ #include <unordered_set> #include <vector> +#include "art_field-inl.h" #include "debug/dwarf/debug_abbrev_writer.h" #include "debug/dwarf/debug_info_entry_writer.h" #include "debug/elf_compilation_unit.h" diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 538fe93793..1573062033 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -27,7 +27,6 @@ #include "dex_instruction-inl.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" -#include "mirror/class-inl.h" #include "mirror/dex_cache.h" #include "thread-inl.h" diff --git a/runtime/quick/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index 3347070468..e691a67dc0 100644 --- a/runtime/quick/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -26,7 +26,6 @@ #include "dex_instruction_utils.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" -#include "verifier/method_verifier-inl.h" /* * NOTE: This code is part of the quick compiler. It lives in the runtime @@ -391,7 +390,6 @@ bool AnalyseConstructor(const DexFile::CodeItem* code_item, #undef STORE_IPUT result->opcode = kInlineOpConstructor; - result->flags = kInlineSpecial; result->d.constructor_data.reserved = 0u; return true; } @@ -429,25 +427,6 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) == static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); -// This is used by compiler and debugger. We look into the dex cache for resolved methods and -// fields. However, in the context of the debugger, not all methods and fields are resolved. Since -// we need to be able to detect possibly inlined method, we pass a null inline method to indicate -// we don't want to take unresolved methods and fields into account during analysis. -bool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier, - InlineMethod* result) { - DCHECK(verifier != nullptr); - if (!Runtime::Current()->UseJitCompilation()) { - DCHECK_EQ(verifier->CanLoadClasses(), result != nullptr); - } - - // Note: verifier->GetMethod() may be null. - return AnalyseMethodCode(verifier->CodeItem(), - verifier->GetMethodReference(), - (verifier->GetAccessFlags() & kAccStatic) != 0u, - verifier->GetMethod(), - result); -} - bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { const DexFile::CodeItem* code_item = method->GetCodeItem(); if (code_item == nullptr) { @@ -473,7 +452,6 @@ bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item, case Instruction::RETURN_VOID: if (result != nullptr) { result->opcode = kInlineOpNop; - result->flags = kInlineSpecial; result->d.data = 0u; } return true; @@ -549,7 +527,6 @@ bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_ite if (result != nullptr) { result->opcode = kInlineOpReturnArg; - result->flags = kInlineSpecial; InlineReturnArgData* data = &result->d.return_data; data->arg = reg - arg_start; data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; @@ -586,7 +563,6 @@ bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item } if (result != nullptr) { result->opcode = kInlineOpNonWideConst; - result->flags = kInlineSpecial; result->d.data = static_cast<uint64_t>(const_value); } return true; @@ -647,7 +623,6 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, return false; } result->opcode = kInlineOpIGet; - result->flags = kInlineSpecial; data->op_variant = IGetVariant(opcode); data->method_is_static = is_static ? 1u : 0u; data->object_arg = object_arg; // Allow IGET on any register, not just "this". @@ -716,7 +691,6 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, return false; } result->opcode = kInlineOpIPut; - result->flags = kInlineSpecial; data->op_variant = IPutVariant(opcode); data->method_is_static = is_static ? 1u : 0u; data->object_arg = object_arg; // Allow IPUT on any register, not just "this". diff --git a/runtime/quick/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h index 2df2ced7f4..a35e97fa11 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/compiler/dex/inline_method_analyser.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ -#define ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ +#ifndef ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_ +#define ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_ #include "base/macros.h" #include "base/mutex.h" @@ -36,128 +36,12 @@ class MethodVerifier; class ArtMethod; enum InlineMethodOpcode : uint16_t { - kIntrinsicDoubleCvt, - kIntrinsicFloatCvt, - kIntrinsicFloat2Int, - kIntrinsicDouble2Long, - kIntrinsicFloatIsInfinite, - kIntrinsicDoubleIsInfinite, - kIntrinsicFloatIsNaN, - kIntrinsicDoubleIsNaN, - kIntrinsicReverseBits, - kIntrinsicReverseBytes, - kIntrinsicBitCount, - kIntrinsicCompare, - kIntrinsicHighestOneBit, - kIntrinsicLowestOneBit, - kIntrinsicNumberOfLeadingZeros, - kIntrinsicNumberOfTrailingZeros, - kIntrinsicRotateRight, - kIntrinsicRotateLeft, - kIntrinsicSignum, - kIntrinsicAbsInt, - kIntrinsicAbsLong, - kIntrinsicAbsFloat, - kIntrinsicAbsDouble, - kIntrinsicMinMaxInt, - kIntrinsicMinMaxLong, - kIntrinsicMinMaxFloat, - kIntrinsicMinMaxDouble, - kIntrinsicCos, - kIntrinsicSin, - kIntrinsicAcos, - kIntrinsicAsin, - kIntrinsicAtan, - kIntrinsicAtan2, - kIntrinsicCbrt, - kIntrinsicCosh, - kIntrinsicExp, - kIntrinsicExpm1, - kIntrinsicHypot, - kIntrinsicLog, - kIntrinsicLog10, - kIntrinsicNextAfter, - kIntrinsicSinh, - kIntrinsicTan, - kIntrinsicTanh, - kIntrinsicSqrt, - kIntrinsicCeil, - kIntrinsicFloor, - kIntrinsicRint, - kIntrinsicRoundFloat, - kIntrinsicRoundDouble, - kIntrinsicReferenceGetReferent, - kIntrinsicCharAt, - kIntrinsicCompareTo, - kIntrinsicEquals, - kIntrinsicGetCharsNoCheck, - kIntrinsicIsEmptyOrLength, - kIntrinsicIndexOf, - kIntrinsicNewStringFromBytes, - kIntrinsicNewStringFromChars, - kIntrinsicNewStringFromString, - kIntrinsicCurrentThread, - kIntrinsicPeek, - kIntrinsicPoke, - kIntrinsicCas, - kIntrinsicUnsafeGet, - kIntrinsicUnsafePut, - - // 1.8. - kIntrinsicUnsafeGetAndAddInt, - kIntrinsicUnsafeGetAndAddLong, - kIntrinsicUnsafeGetAndSetInt, - kIntrinsicUnsafeGetAndSetLong, - kIntrinsicUnsafeGetAndSetObject, - kIntrinsicUnsafeLoadFence, - kIntrinsicUnsafeStoreFence, - kIntrinsicUnsafeFullFence, - - kIntrinsicSystemArrayCopyCharArray, - kIntrinsicSystemArrayCopy, - kInlineOpNop, kInlineOpReturnArg, kInlineOpNonWideConst, kInlineOpIGet, kInlineOpIPut, kInlineOpConstructor, - kInlineStringInit, -}; -std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs); - -enum InlineMethodFlags : uint16_t { - kNoInlineMethodFlags = 0x0000, - kInlineIntrinsic = 0x0001, - kInlineSpecial = 0x0002, -}; - -// IntrinsicFlags are stored in InlineMethod::d::raw_data -enum IntrinsicFlags { - kIntrinsicFlagNone = 0, - - // kIntrinsicMinMaxInt - kIntrinsicFlagMax = kIntrinsicFlagNone, - kIntrinsicFlagMin = 1, - - // kIntrinsicIsEmptyOrLength - kIntrinsicFlagLength = kIntrinsicFlagNone, - kIntrinsicFlagIsEmpty = kIntrinsicFlagMin, - - // kIntrinsicIndexOf - kIntrinsicFlagBase0 = kIntrinsicFlagMin, - - // kIntrinsicUnsafeGet, kIntrinsicUnsafePut, kIntrinsicUnsafeCas - kIntrinsicFlagIsLong = kIntrinsicFlagMin, - // kIntrinsicUnsafeGet, kIntrinsicUnsafePut - kIntrinsicFlagIsVolatile = 2, - // kIntrinsicUnsafePut, kIntrinsicUnsafeCas - kIntrinsicFlagIsObject = 4, - // kIntrinsicUnsafePut - kIntrinsicFlagIsOrdered = 8, - - // kIntrinsicDoubleCvt, kIntrinsicFloatCvt. - kIntrinsicFlagToFloatingPoint = kIntrinsicFlagMin, }; struct InlineIGetIPutData { @@ -198,7 +82,6 @@ static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t), struct InlineMethod { InlineMethodOpcode opcode; - InlineMethodFlags flags; union { uint64_t data; InlineIGetIPutData ifield_data; @@ -213,12 +96,8 @@ class InlineMethodAnalyser { * Analyse method code to determine if the method is a candidate for inlining. * If it is, record the inlining data. * - * @param verifier the method verifier holding data about the method to analyse. - * @param method placeholder for the inline method data. * @return true if the method is a candidate for inlining, false otherwise. */ - static bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* result) - REQUIRES_SHARED(Locks::mutator_lock_); static bool AnalyseMethodCode(ArtMethod* method, InlineMethod* result) REQUIRES_SHARED(Locks::mutator_lock_); @@ -274,4 +153,4 @@ class InlineMethodAnalyser { } // namespace art -#endif // ART_RUNTIME_QUICK_INLINE_METHOD_ANALYSER_H_ +#endif // ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_ diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc index cbca33320d..608a18aa66 100644 --- a/compiler/dex/verified_method.cc +++ b/compiler/dex/verified_method.cc @@ -18,22 +18,15 @@ #include <algorithm> #include <memory> -#include <vector> -#include "art_method-inl.h" -#include "base/enums.h" #include "base/logging.h" -#include "base/stl_util.h" #include "dex_file.h" #include "dex_instruction-inl.h" -#include "dex_instruction_utils.h" -#include "mirror/class-inl.h" -#include "mirror/dex_cache-inl.h" -#include "mirror/object-inl.h" -#include "utils.h" +#include "runtime.h" #include "verifier/method_verifier-inl.h" #include "verifier/reg_type-inl.h" #include "verifier/register_line-inl.h" +#include "verifier/verifier_deps.h" namespace art { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 1a4452429e..805c5dadc1 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -61,6 +61,7 @@ #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/throwable.h" #include "scoped_thread_state_change-inl.h" diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc index 0c0609009d..37e4f113fa 100644 --- a/compiler/elf_writer.cc +++ b/compiler/elf_writer.cc @@ -16,17 +16,8 @@ #include "elf_writer.h" -#include "art_method-inl.h" #include "base/unix_file/fd_file.h" -#include "class_linker.h" -#include "dex_file-inl.h" -#include "dex_method_iterator.h" -#include "driver/compiler_driver.h" #include "elf_file.h" -#include "invoke_type.h" -#include "mirror/object-inl.h" -#include "oat.h" -#include "scoped_thread_state_change-inl.h" namespace art { diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index c975944a04..dc880b089e 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -30,7 +30,7 @@ #include "mirror/stack_trace_element.h" #include "oat_quick_method_header.h" #include "optimizing/stack_map_stream.h" -#include "runtime.h" +#include "runtime-inl.h" #include "scoped_thread_state_change-inl.h" #include "handle_scope-inl.h" #include "thread.h" diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 897d81993d..7e53d8d2ab 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -22,6 +22,7 @@ #include "android-base/stringprintf.h" +#include "art_method-inl.h" #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" #include "compiler_callbacks.h" diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d129249d63..952a7c637a 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -59,6 +59,7 @@ #include "mirror/executable.h" #include "mirror/method.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" #include "oat.h" diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 21042a337d..b34d9385c8 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -27,6 +27,7 @@ #include "dex_file.h" #include "gtest/gtest.h" #include "indirect_reference_table.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mem_map.h" #include "mirror/class-inl.h" diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index b7c80756b0..5136d7d2b8 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -42,18 +42,23 @@ #endif #include "bytecode_utils.h" +#include "class_linker.h" #include "compiled_method.h" #include "dex/verified_method.h" #include "driver/compiler_driver.h" #include "graph_visualizer.h" +#include "intern_table.h" #include "intrinsics.h" #include "leb128.h" #include "mirror/array-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object_reference.h" +#include "mirror/reference.h" #include "mirror/string.h" #include "parallel_move_resolver.h" #include "ssa_liveness_analysis.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "utils/assembler.h" namespace art { diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 58feea2423..332ab49153 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -321,7 +321,9 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { vixl::aarch64::MemOperand CreateVecMemRegisters( HVecMemoryOperation* instruction, Location* reg_loc, - bool is_load); + bool is_load, + // This function may acquire a scratch register. + vixl::aarch64::UseScratchRegisterScope* temps_scope); Arm64Assembler* const assembler_; CodeGeneratorARM64* const codegen_; diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc index b3eb639142..93befa439c 100644 --- a/compiler/optimizing/code_generator_vector_arm64.cc +++ b/compiler/optimizing/code_generator_vector_arm64.cc @@ -27,6 +27,7 @@ using helpers::HeapOperand; using helpers::InputRegisterAt; using helpers::Int64ConstantFrom; using helpers::XRegisterFrom; +using helpers::WRegisterFrom; #define __ GetVIXLAssembler()-> @@ -774,7 +775,8 @@ static void CreateVecMemLocations(ArenaAllocator* arena, MemOperand InstructionCodeGeneratorARM64::CreateVecMemRegisters( HVecMemoryOperation* instruction, Location* reg_loc, - bool is_load) { + bool is_load, + UseScratchRegisterScope* temps_scope) { LocationSummary* locations = instruction->GetLocations(); Register base = InputRegisterAt(instruction, 0); Location index = locations->InAt(1); @@ -784,20 +786,18 @@ MemOperand InstructionCodeGeneratorARM64::CreateVecMemRegisters( uint32_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(packed_type)).Uint32Value(); size_t shift = Primitive::ComponentSizeShift(packed_type); - UseScratchRegisterScope temps(GetVIXLAssembler()); - Register temp = temps.AcquireSameSizeAs(base); + // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet. + DCHECK(!instruction->InputAt(0)->IsIntermediateAddress()); + if (index.IsConstant()) { offset += Int64ConstantFrom(index) << shift; - __ Add(temp, base, offset); + return HeapOperand(base, offset); } else { - if (instruction->InputAt(0)->IsIntermediateAddress()) { - temp = base; - } else { - __ Add(temp, base, offset); - } - __ Add(temp.X(), temp.X(), Operand(XRegisterFrom(index), LSL, shift)); + Register temp = temps_scope->AcquireSameSizeAs(base); + __ Add(temp, base, Operand(WRegisterFrom(index), LSL, shift)); + + return HeapOperand(temp, offset); } - return HeapOperand(temp); } void LocationsBuilderARM64::VisitVecLoad(HVecLoad* instruction) { @@ -806,28 +806,22 @@ void LocationsBuilderARM64::VisitVecLoad(HVecLoad* instruction) { void InstructionCodeGeneratorARM64::VisitVecLoad(HVecLoad* instruction) { Location reg_loc = Location::NoLocation(); - MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ true); + UseScratchRegisterScope temps(GetVIXLAssembler()); + MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ true, &temps); VRegister reg = VRegisterFrom(reg_loc); + switch (instruction->GetPackedType()) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: - DCHECK_EQ(16u, instruction->GetVectorLength()); - __ Ld1(reg.V16B(), mem); - break; case Primitive::kPrimChar: case Primitive::kPrimShort: - DCHECK_EQ(8u, instruction->GetVectorLength()); - __ Ld1(reg.V8H(), mem); - break; case Primitive::kPrimInt: case Primitive::kPrimFloat: - DCHECK_EQ(4u, instruction->GetVectorLength()); - __ Ld1(reg.V4S(), mem); - break; case Primitive::kPrimLong: case Primitive::kPrimDouble: - DCHECK_EQ(2u, instruction->GetVectorLength()); - __ Ld1(reg.V2D(), mem); + DCHECK_LE(2u, instruction->GetVectorLength()); + DCHECK_LE(instruction->GetVectorLength(), 16u); + __ Ldr(reg, mem); break; default: LOG(FATAL) << "Unsupported SIMD type"; @@ -841,28 +835,22 @@ void LocationsBuilderARM64::VisitVecStore(HVecStore* instruction) { void InstructionCodeGeneratorARM64::VisitVecStore(HVecStore* instruction) { Location reg_loc = Location::NoLocation(); - MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ false); + UseScratchRegisterScope temps(GetVIXLAssembler()); + MemOperand mem = CreateVecMemRegisters(instruction, ®_loc, /*is_load*/ false, &temps); VRegister reg = VRegisterFrom(reg_loc); + switch (instruction->GetPackedType()) { case Primitive::kPrimBoolean: case Primitive::kPrimByte: - DCHECK_EQ(16u, instruction->GetVectorLength()); - __ St1(reg.V16B(), mem); - break; case Primitive::kPrimChar: case Primitive::kPrimShort: - DCHECK_EQ(8u, instruction->GetVectorLength()); - __ St1(reg.V8H(), mem); - break; case Primitive::kPrimInt: case Primitive::kPrimFloat: - DCHECK_EQ(4u, instruction->GetVectorLength()); - __ St1(reg.V4S(), mem); - break; case Primitive::kPrimLong: case Primitive::kPrimDouble: - DCHECK_EQ(2u, instruction->GetVectorLength()); - __ St1(reg.V2D(), mem); + DCHECK_LE(2u, instruction->GetVectorLength()); + DCHECK_LE(instruction->GetVectorLength(), 16u); + __ Str(reg, mem); break; default: LOG(FATAL) << "Unsupported SIMD type"; diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 4af2539812..1f8a58cdaa 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -22,6 +22,7 @@ #include "class_linker.h" #include "constant_folding.h" #include "dead_code_elimination.h" +#include "dex/inline_method_analyser.h" #include "dex/verified_method.h" #include "dex/verification_results.h" #include "driver/compiler_driver-inl.h" @@ -37,7 +38,6 @@ #include "optimizing_compiler.h" #include "reference_type_propagation.h" #include "register_allocator_linear_scan.h" -#include "quick/inline_method_analyser.h" #include "sharpening.h" #include "ssa_builder.h" #include "ssa_phi_elimination.h" diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 60790e5b84..2dcc12e294 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -16,6 +16,8 @@ #include "instruction_simplifier.h" +#include "art_method-inl.h" +#include "class_linker-inl.h" #include "escape.h" #include "intrinsics.h" #include "mirror/class-inl.h" diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc index 5f5e29b024..3fc7c50bb1 100644 --- a/compiler/optimizing/instruction_simplifier_arm.cc +++ b/compiler/optimizing/instruction_simplifier_arm.cc @@ -19,6 +19,7 @@ #include "instruction_simplifier_arm.h" #include "instruction_simplifier_shared.h" #include "mirror/array-inl.h" +#include "mirror/string.h" #include "nodes.h" namespace art { diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 8df80adc9f..6236bd87ab 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -16,7 +16,8 @@ #include "intrinsics.h" -#include "art_method.h" +#include "art_field-inl.h" +#include "art_method-inl.h" #include "class_linker.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index 1006a776f0..750f9cc213 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -22,9 +22,13 @@ #include "entrypoints/quick/quick_entrypoints.h" #include "intrinsics.h" #include "intrinsics_utils.h" +#include "lock_word.h" #include "mirror/array-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/reference.h" #include "mirror/string.h" -#include "thread.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "utils/arm/assembler_arm.h" namespace art { diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 47bcb5d000..4d360158a2 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -22,9 +22,13 @@ #include "common_arm64.h" #include "entrypoints/quick/quick_entrypoints.h" #include "intrinsics.h" +#include "lock_word.h" #include "mirror/array-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/reference.h" #include "mirror/string-inl.h" -#include "thread.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "utils/arm64/assembler_arm64.h" using namespace vixl::aarch64; // NOLINT(build/namespaces) diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 0d933eaf82..fd8a37ae05 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -17,10 +17,16 @@ #include "intrinsics_arm_vixl.h" #include "arch/arm/instruction_set_features_arm.h" +#include "art_method.h" #include "code_generator_arm_vixl.h" #include "common_arm.h" #include "lock_word.h" #include "mirror/array-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/reference.h" +#include "mirror/string.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "aarch32/constants-aarch32.h" diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index ecf919bceb..8e4574774f 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -25,9 +25,13 @@ #include "entrypoints/quick/quick_entrypoints.h" #include "intrinsics.h" #include "intrinsics_utils.h" +#include "lock_word.h" #include "mirror/array-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/reference.h" #include "mirror/string.h" -#include "thread.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "utils/x86/assembler_x86.h" #include "utils/x86/constants_x86.h" diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 13956dfb8e..8ed2ad86bf 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -19,15 +19,19 @@ #include <limits> #include "arch/x86_64/instruction_set_features_x86_64.h" -#include "art_method-inl.h" +#include "art_method.h" #include "base/bit_utils.h" #include "code_generator_x86_64.h" #include "entrypoints/quick/quick_entrypoints.h" #include "intrinsics.h" #include "intrinsics_utils.h" +#include "lock_word.h" #include "mirror/array-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/reference.h" #include "mirror/string.h" -#include "thread.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" #include "utils/x86_64/assembler_x86_64.h" #include "utils/x86_64/constants_x86_64.h" diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index e71fea92a9..ca953a1a7e 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -17,6 +17,8 @@ #include <cfloat> +#include "art_method-inl.h" +#include "class_linker-inl.h" #include "code_generator.h" #include "common_dominator.h" #include "ssa_builder.h" diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index af953c8f99..8368026e92 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1362,7 +1362,6 @@ class HLoopInformationOutwardIterator : public ValueObject { M(UShr, BinaryOperation) \ M(Xor, BinaryOperation) \ M(VecReplicateScalar, VecUnaryOperation) \ - M(VecSetScalars, VecUnaryOperation) \ M(VecSumReduce, VecUnaryOperation) \ M(VecCnv, VecUnaryOperation) \ M(VecNeg, VecUnaryOperation) \ @@ -1382,6 +1381,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(VecShl, VecBinaryOperation) \ M(VecShr, VecBinaryOperation) \ M(VecUShr, VecBinaryOperation) \ + M(VecSetScalars, VecOperation) \ M(VecMultiplyAccumulate, VecOperation) \ M(VecLoad, VecMemoryOperation) \ M(VecStore, VecMemoryOperation) \ diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h index 450691c1ea..fb9dfb7afa 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -116,16 +116,23 @@ class HVecOperation : public HVariableInputSizeInstruction { class HVecUnaryOperation : public HVecOperation { public: HVecUnaryOperation(ArenaAllocator* arena, + HInstruction* input, Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc) : HVecOperation(arena, packed_type, SideEffects::None(), - /*number_of_inputs*/ 1, + /* number_of_inputs */ 1, vector_length, - dex_pc) { } + dex_pc) { + SetRawInputAt(0, input); + } + + HInstruction* GetInput() const { return InputAt(0); } + DECLARE_ABSTRACT_INSTRUCTION(VecUnaryOperation); + private: DISALLOW_COPY_AND_ASSIGN(HVecUnaryOperation); }; @@ -134,20 +141,26 @@ class HVecUnaryOperation : public HVecOperation { class HVecBinaryOperation : public HVecOperation { public: HVecBinaryOperation(ArenaAllocator* arena, + HInstruction* left, + HInstruction* right, Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc) : HVecOperation(arena, packed_type, SideEffects::None(), - /*number_of_inputs*/ 2, + /* number_of_inputs */ 2, vector_length, - dex_pc) { } + dex_pc) { + SetRawInputAt(0, left); + SetRawInputAt(1, right); + } HInstruction* GetLeft() const { return InputAt(0); } HInstruction* GetRight() const { return InputAt(1); } DECLARE_ABSTRACT_INSTRUCTION(VecBinaryOperation); + private: DISALLOW_COPY_AND_ASSIGN(HVecBinaryOperation); }; @@ -179,7 +192,7 @@ class HVecMemoryOperation : public HVecOperation { }; // -// Definitions of concrete vector operations in HIR. +// Definitions of concrete unary vector operations in HIR. // // Replicates the given scalar into a vector, @@ -191,32 +204,14 @@ class HVecReplicateScalar FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { - SetRawInputAt(0, scalar); + : HVecUnaryOperation(arena, scalar, packed_type, vector_length, dex_pc) { + DCHECK(!scalar->IsVecOperation()); } DECLARE_INSTRUCTION(VecReplicateScalar); private: DISALLOW_COPY_AND_ASSIGN(HVecReplicateScalar); }; -// Assigns the given scalar elements to a vector, -// viz. set( array(x1, .., xn) ) = [ x1, .. , xn ]. -class HVecSetScalars FINAL : public HVecUnaryOperation { - HVecSetScalars(ArenaAllocator* arena, - HInstruction** scalars, // array - Primitive::Type packed_type, - size_t vector_length, - uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { - for (size_t i = 0; i < vector_length; i++) { - SetRawInputAt(0, scalars[i]); - } - } - DECLARE_INSTRUCTION(VecSetScalars); - private: - DISALLOW_COPY_AND_ASSIGN(HVecSetScalars); -}; - // Sum-reduces the given vector into a shorter vector (m < n) or scalar (m = 1), // viz. sum-reduce[ x1, .. , xn ] = [ y1, .., ym ], where yi = sum_j x_j. class HVecSumReduce FINAL : public HVecUnaryOperation { @@ -225,10 +220,9 @@ class HVecSumReduce FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, input); } // TODO: probably integral promotion @@ -248,10 +242,9 @@ class HVecCnv FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); DCHECK_NE(input->AsVecOperation()->GetPackedType(), packed_type); // actual convert - SetRawInputAt(0, input); } Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); } @@ -272,10 +265,9 @@ class HVecNeg FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, input); } DECLARE_INSTRUCTION(VecNeg); private: @@ -291,10 +283,9 @@ class HVecAbs FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); DCHECK_EQ(input->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, input); } DECLARE_INSTRUCTION(VecAbs); private: @@ -311,15 +302,18 @@ class HVecNot FINAL : public HVecUnaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecUnaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); - SetRawInputAt(0, input); } DECLARE_INSTRUCTION(VecNot); private: DISALLOW_COPY_AND_ASSIGN(HVecNot); }; +// +// Definitions of concrete binary vector operations in HIR. +// + // Adds every component in the two vectors, // viz. [ x1, .. , xn ] + [ y1, .. , yn ] = [ x1 + y1, .. , xn + yn ]. class HVecAdd FINAL : public HVecBinaryOperation { @@ -330,12 +324,10 @@ class HVecAdd FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecAdd); private: @@ -356,14 +348,12 @@ class HVecHalvingAdd FINAL : public HVecBinaryOperation { bool is_unsigned, bool is_rounded, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc), + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc), is_unsigned_(is_unsigned), is_rounded_(is_rounded) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } bool IsUnsigned() const { return is_unsigned_; } @@ -388,12 +378,10 @@ class HVecSub FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecSub); private: @@ -410,12 +398,10 @@ class HVecMul FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecMul); private: @@ -432,12 +418,10 @@ class HVecDiv FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecDiv); private: @@ -454,12 +438,10 @@ class HVecMin FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecMin); private: @@ -476,12 +458,10 @@ class HVecMax FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); DCHECK_EQ(right->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecMax); private: @@ -498,10 +478,8 @@ class HVecAnd FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecAnd); private: @@ -518,10 +496,8 @@ class HVecAndNot FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecAndNot); private: @@ -538,10 +514,8 @@ class HVecOr FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecOr); private: @@ -558,10 +532,8 @@ class HVecXor FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecXor); private: @@ -578,11 +550,9 @@ class HVecShl FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecShl); private: @@ -599,11 +569,9 @@ class HVecShr FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecShr); private: @@ -620,17 +588,43 @@ class HVecUShr FINAL : public HVecBinaryOperation { Primitive::Type packed_type, size_t vector_length, uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, packed_type, vector_length, dex_pc) { + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation()); DCHECK_EQ(left->AsVecOperation()->GetPackedType(), packed_type); - SetRawInputAt(0, left); - SetRawInputAt(1, right); } DECLARE_INSTRUCTION(VecUShr); private: DISALLOW_COPY_AND_ASSIGN(HVecUShr); }; +// +// Definitions of concrete miscellaneous vector operations in HIR. +// + +// Assigns the given scalar elements to a vector, +// viz. set( array(x1, .., xn) ) = [ x1, .. , xn ]. +class HVecSetScalars FINAL : public HVecOperation { + HVecSetScalars(ArenaAllocator* arena, + HInstruction** scalars, // array + Primitive::Type packed_type, + size_t vector_length, + uint32_t dex_pc = kNoDexPc) + : HVecOperation(arena, + packed_type, + SideEffects::None(), + /* number_of_inputs */ vector_length, + vector_length, + dex_pc) { + for (size_t i = 0; i < vector_length; i++) { + DCHECK(!scalars[i]->IsVecOperation()); + SetRawInputAt(0, scalars[i]); + } + } + DECLARE_INSTRUCTION(VecSetScalars); + private: + DISALLOW_COPY_AND_ASSIGN(HVecSetScalars); +}; + // Multiplies every component in the two vectors, adds the result vector to the accumulator vector. // viz. [ acc1, .., accn ] + [ x1, .. , xn ] * [ y1, .. , yn ] = // [ acc1 + x1 * y1, .. , accn + xn * yn ]. @@ -647,7 +641,7 @@ class HVecMultiplyAccumulate FINAL : public HVecOperation { : HVecOperation(arena, packed_type, SideEffects::None(), - /*number_of_inputs*/ 3, + /* number_of_inputs */ 3, vector_length, dex_pc), op_kind_(op) { @@ -697,7 +691,7 @@ class HVecLoad FINAL : public HVecMemoryOperation { : HVecMemoryOperation(arena, packed_type, SideEffects::ArrayReadOfType(packed_type), - /*number_of_inputs*/ 2, + /* number_of_inputs */ 2, vector_length, dex_pc) { SetRawInputAt(0, base); @@ -722,7 +716,7 @@ class HVecStore FINAL : public HVecMemoryOperation { : HVecMemoryOperation(arena, packed_type, SideEffects::ArrayWriteOfType(packed_type), - /*number_of_inputs*/ 3, + /* number_of_inputs */ 3, vector_length, dex_pc) { DCHECK(value->IsVecOperation()); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index d5637b9b75..98332d35fb 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -16,6 +16,8 @@ #include "reference_type_propagation.h" +#include "art_field-inl.h" +#include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" #include "mirror/class-inl.h" diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 3b6b9cc7f0..0b1ab758b2 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -17,6 +17,7 @@ // Test is in compiler, as it uses compiler related code. #include "verifier/verifier_deps.h" +#include "art_method-inl.h" #include "class_linker.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index f307cbc4f5..06a0f231ba 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -28,6 +28,7 @@ #include "android-base/stringprintf.h" +#include "art_field-inl.h" #include "art_method-inl.h" #include "base/unix_file/fd_file.h" #include "gc/space/image_space.h" diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 0c2717f207..fbb0978d53 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -42,6 +42,7 @@ #include "mirror/dex_cache.h" #include "mirror/executable.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/method.h" #include "mirror/reference.h" #include "noop_compiler_callbacks.h" diff --git a/runtime/Android.bp b/runtime/Android.bp index 8972e91321..0860b2e899 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -93,6 +93,7 @@ cc_defaults { "gc/space/space.cc", "gc/space/zygote_space.cc", "gc/task_processor.cc", + "gc/verification.cc", "hprof/hprof.cc", "image.cc", "indirect_reference_table.cc", @@ -186,13 +187,13 @@ cc_defaults { "plugin.cc", "primitive.cc", "quick_exception_handler.cc", - "quick/inline_method_analyser.cc", "reference_table.cc", "reflection.cc", "runtime.cc", "runtime_callbacks.cc", "runtime_common.cc", "runtime_options.cc", + "scoped_thread_state_change.cc", "signal_catcher.cc", "stack.cc", "stack_map.cc", @@ -451,7 +452,6 @@ gensrcs { "oat.h", "object_callbacks.h", "process_state.h", - "quick/inline_method_analyser.h", "runtime.h", "stack.h", "thread.h", @@ -548,6 +548,7 @@ art_cc_test { "gc/accounting/space_bitmap_test.cc", "gc/collector/immune_spaces_test.cc", "gc/heap_test.cc", + "gc/heap_verification_test.cc", "gc/reference_queue_test.cc", "gc/space/dlmalloc_space_static_test.cc", "gc/space/dlmalloc_space_random_test.cc", diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc index 923ff4ff29..4c15450ff7 100644 --- a/runtime/arch/arm/fault_handler_arm.cc +++ b/runtime/arch/arm/fault_handler_arm.cc @@ -19,14 +19,12 @@ #include <sys/ucontext.h> -#include "art_method-inl.h" +#include "art_method.h" #include "base/enums.h" -#include "base/macros.h" #include "base/hex_dump.h" -#include "globals.h" #include "base/logging.h" -#include "base/hex_dump.h" -#include "thread.h" +#include "base/macros.h" +#include "globals.h" #include "thread-inl.h" // diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc index 193af58f11..dc4e8f389e 100644 --- a/runtime/arch/arm64/fault_handler_arm64.cc +++ b/runtime/arch/arm64/fault_handler_arm64.cc @@ -19,14 +19,13 @@ #include <sys/ucontext.h> -#include "art_method-inl.h" +#include "art_method.h" #include "base/enums.h" +#include "base/hex_dump.h" +#include "base/logging.h" #include "base/macros.h" #include "globals.h" -#include "base/logging.h" -#include "base/hex_dump.h" #include "registers_arm64.h" -#include "thread.h" #include "thread-inl.h" extern "C" void art_quick_throw_stack_overflow(); diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc index f9c19e87e6..7072a8a613 100644 --- a/runtime/arch/mips/fault_handler_mips.cc +++ b/runtime/arch/mips/fault_handler_mips.cc @@ -14,16 +14,16 @@ * limitations under the License. */ -#include "arch/mips/quick_method_frame_info_mips.h" #include "fault_handler.h" #include <sys/ucontext.h> -#include "art_method-inl.h" + +#include "art_method.h" +#include "base/hex_dump.h" +#include "base/logging.h" #include "base/macros.h" #include "globals.h" -#include "base/logging.h" -#include "base/hex_dump.h" +#include "quick_method_frame_info_mips.h" #include "registers_mips.h" -#include "thread.h" #include "thread-inl.h" extern "C" void art_quick_throw_stack_overflow(); diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc index d668d3ab62..f9a92c834e 100644 --- a/runtime/arch/mips64/fault_handler_mips64.cc +++ b/runtime/arch/mips64/fault_handler_mips64.cc @@ -14,16 +14,17 @@ * limitations under the License. */ -#include "arch/mips64/quick_method_frame_info_mips64.h" #include "fault_handler.h" + #include <sys/ucontext.h> -#include "art_method-inl.h" + +#include "art_method.h" +#include "base/hex_dump.h" +#include "base/logging.h" #include "base/macros.h" #include "globals.h" -#include "base/logging.h" -#include "base/hex_dump.h" +#include "quick_method_frame_info_mips64.h" #include "registers_mips64.h" -#include "thread.h" #include "thread-inl.h" extern "C" void art_quick_throw_stack_overflow(); diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc index 014cc15a40..7d8abb8cc5 100644 --- a/runtime/arch/x86/fault_handler_x86.cc +++ b/runtime/arch/x86/fault_handler_x86.cc @@ -19,14 +19,13 @@ #include <sys/ucontext.h> -#include "art_method-inl.h" +#include "art_method.h" #include "base/enums.h" -#include "base/macros.h" -#include "globals.h" -#include "base/logging.h" #include "base/hex_dump.h" +#include "base/logging.h" +#include "base/macros.h" #include "base/safe_copy.h" -#include "thread.h" +#include "globals.h" #include "thread-inl.h" #if defined(__APPLE__) diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 16b73c681f..0de0f02f9b 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -21,6 +21,7 @@ #include "base/logging.h" #include "class_linker.h" +#include "dex_file-inl.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "jvalue.h" @@ -46,16 +47,6 @@ inline void ArtField::SetDeclaringClass(ObjPtr<mirror::Class> new_declaring_clas declaring_class_ = GcRoot<mirror::Class>(new_declaring_class); } -inline uint32_t ArtField::GetAccessFlags() { - DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); - return access_flags_; -} - -inline MemberOffset ArtField::GetOffset() { - DCHECK(GetDeclaringClass()->IsResolved()); - return MemberOffset(offset_); -} - inline MemberOffset ArtField::GetOffsetDuringLinking() { DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); return MemberOffset(offset_); diff --git a/runtime/art_field.cc b/runtime/art_field.cc index 7e131040be..bc728f4476 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -78,5 +78,12 @@ std::string ArtField::PrettyField(bool with_type) { return result; } +void ArtField::GetAccessFlagsDCheck() { + CHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); +} + +void ArtField::GetOffsetDCheck() { + CHECK(GetDeclaringClass()->IsResolved()); +} } // namespace art diff --git a/runtime/art_field.h b/runtime/art_field.h index 666ed8a868..3789b0ce2f 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -51,7 +51,12 @@ class ArtField FINAL { return declaring_class_.AddressWithoutBarrier(); } - uint32_t GetAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t GetAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) { + if (kIsDebugBuild) { + GetAccessFlagsDCheck(); + } + return access_flags_; + } void SetAccessFlags(uint32_t new_access_flags) REQUIRES_SHARED(Locks::mutator_lock_) { // Not called within a transaction. @@ -80,7 +85,12 @@ class ArtField FINAL { } // Offset to field within an Object. - MemberOffset GetOffset() REQUIRES_SHARED(Locks::mutator_lock_); + MemberOffset GetOffset() REQUIRES_SHARED(Locks::mutator_lock_) { + if (kIsDebugBuild) { + GetOffsetDCheck(); + } + return MemberOffset(offset_); + } static MemberOffset OffsetOffset() { return MemberOffset(OFFSETOF_MEMBER(ArtField, offset_)); @@ -227,6 +237,9 @@ class ArtField FINAL { ObjPtr<mirror::DexCache> dex_cache) REQUIRES_SHARED(Locks::mutator_lock_); + void GetAccessFlagsDCheck() REQUIRES_SHARED(Locks::mutator_lock_); + void GetOffsetDCheck() REQUIRES_SHARED(Locks::mutator_lock_); + GcRoot<mirror::Class> declaring_class_; uint32_t access_flags_ = 0; diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 5cf0e0f90c..59cd978a66 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -82,37 +82,6 @@ inline bool ArtMethod::CASDeclaringClass(mirror::Class* expected_class, expected_root, desired_root); } -// AssertSharedHeld doesn't work in GetAccessFlags, so use a NO_THREAD_SAFETY_ANALYSIS helper. -// TODO: Figure out why ASSERT_SHARED_CAPABILITY doesn't work. -template <ReadBarrierOption kReadBarrierOption> -ALWAYS_INLINE static inline void DoGetAccessFlagsHelper(ArtMethod* method) - NO_THREAD_SAFETY_ANALYSIS { - CHECK(method->IsRuntimeMethod() || - method->GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() || - method->GetDeclaringClass<kReadBarrierOption>()->IsErroneous()); -} - -template <ReadBarrierOption kReadBarrierOption> -inline uint32_t ArtMethod::GetAccessFlags() { - if (kCheckDeclaringClassState) { - Thread* self = Thread::Current(); - if (!Locks::mutator_lock_->IsSharedHeld(self)) { - if (self->IsThreadSuspensionAllowable()) { - ScopedObjectAccess soa(self); - CHECK(IsRuntimeMethod() || - GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() || - GetDeclaringClass<kReadBarrierOption>()->IsErroneous()); - } - } else { - // We cannot use SOA in this case. We might be holding the lock, but may not be in the - // runnable state (e.g., during GC). - Locks::mutator_lock_->AssertSharedHeld(self); - DoGetAccessFlagsHelper<kReadBarrierOption>(this); - } - } - return access_flags_.load(std::memory_order_relaxed); -} - inline uint16_t ArtMethod::GetMethodIndex() { DCHECK(IsRuntimeMethod() || GetDeclaringClass()->IsResolved()); return method_index_; @@ -224,10 +193,6 @@ inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) { } } -inline bool ArtMethod::IsRuntimeMethod() { - return dex_method_index_ == DexFile::kDexNoIndex; -} - inline bool ArtMethod::IsCalleeSaveMethod() { if (!IsRuntimeMethod()) { return false; @@ -273,6 +238,11 @@ inline const char* ArtMethod::GetDeclaringClassDescriptor() { return dex_file->GetMethodDeclaringClassDescriptor(dex_file->GetMethodId(dex_method_idx)); } +inline const char* ArtMethod::GetShorty() { + uint32_t unused_length; + return GetShorty(&unused_length); +} + inline const char* ArtMethod::GetShorty(uint32_t* out_length) { DCHECK(!IsProxyMethod()); const DexFile* dex_file = GetDexFile(); diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 76fdd43992..7de8916ad5 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -21,7 +21,6 @@ #include "android-base/stringprintf.h" #include "arch/context.h" -#include "art_field-inl.h" #include "art_method-inl.h" #include "base/stringpiece.h" #include "class_linker-inl.h" @@ -56,6 +55,10 @@ extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, const char*); +// Enforce that we he have the right index for runtime methods. +static_assert(ArtMethod::kRuntimeMethodDexMethodIndex == DexFile::kDexNoIndex, + "Wrong runtime-method dex method index"); + ArtMethod* ArtMethod::GetNonObsoleteMethod() { DCHECK_EQ(kRuntimePointerSize, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); if (LIKELY(!IsObsolete())) { @@ -807,4 +810,35 @@ std::string ArtMethod::JniLongName() { return long_name; } +// AssertSharedHeld doesn't work in GetAccessFlags, so use a NO_THREAD_SAFETY_ANALYSIS helper. +// TODO: Figure out why ASSERT_SHARED_CAPABILITY doesn't work. +template <ReadBarrierOption kReadBarrierOption> +ALWAYS_INLINE static inline void DoGetAccessFlagsHelper(ArtMethod* method) + NO_THREAD_SAFETY_ANALYSIS { + CHECK(method->IsRuntimeMethod() || + method->GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() || + method->GetDeclaringClass<kReadBarrierOption>()->IsErroneous()); +} + +template <ReadBarrierOption kReadBarrierOption> void ArtMethod::GetAccessFlagsDCheck() { + if (kCheckDeclaringClassState) { + Thread* self = Thread::Current(); + if (!Locks::mutator_lock_->IsSharedHeld(self)) { + if (self->IsThreadSuspensionAllowable()) { + ScopedObjectAccess soa(self); + CHECK(IsRuntimeMethod() || + GetDeclaringClass<kReadBarrierOption>()->IsIdxLoaded() || + GetDeclaringClass<kReadBarrierOption>()->IsErroneous()); + } + } else { + // We cannot use SOA in this case. We might be holding the lock, but may not be in the + // runnable state (e.g., during GC). + Locks::mutator_lock_->AssertSharedHeld(self); + DoGetAccessFlagsHelper<kReadBarrierOption>(this); + } + } +} +template void ArtMethod::GetAccessFlagsDCheck<ReadBarrierOption::kWithReadBarrier>(); +template void ArtMethod::GetAccessFlagsDCheck<ReadBarrierOption::kWithoutReadBarrier>(); + } // namespace art diff --git a/runtime/art_method.h b/runtime/art_method.h index b01b344bda..856bfd23e5 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -55,6 +55,10 @@ class ArtMethod FINAL { public: static constexpr bool kCheckDeclaringClassState = kIsDebugBuild; + // The runtime dex_method_index is kDexNoIndex. To lower dependencies, we use this + // constexpr, and ensure that the value is correct in art_method.cc. + static constexpr uint32_t kRuntimeMethodDexMethodIndex = 0xFFFFFFFF; + ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0), method_index_(0), hotness_count_(0) { } @@ -90,7 +94,12 @@ class ArtMethod FINAL { // Note: GetAccessFlags acquires the mutator lock in debug mode to check that it is not called for // a proxy method. template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - ALWAYS_INLINE uint32_t GetAccessFlags(); + uint32_t GetAccessFlags() { + if (kCheckDeclaringClassState) { + GetAccessFlagsDCheck<kReadBarrierOption>(); + } + return access_flags_.load(std::memory_order_relaxed); + } // This version should only be called when it's certain there is no // concurrency so there is no need to guarantee atomicity. For example, @@ -504,7 +513,9 @@ class ArtMethod FINAL { // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal // conventions for a method of managed code. Returns false for Proxy methods. - ALWAYS_INLINE bool IsRuntimeMethod(); + ALWAYS_INLINE bool IsRuntimeMethod() { + return dex_method_index_ == kRuntimeMethodDexMethodIndex;; + } // Is this a hand crafted method used for something like describing callee saves? bool IsCalleeSaveMethod() REQUIRES_SHARED(Locks::mutator_lock_); @@ -532,10 +543,7 @@ class ArtMethod FINAL { const char* GetDeclaringClassDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); - const char* GetShorty() REQUIRES_SHARED(Locks::mutator_lock_) { - uint32_t unused_length; - return GetShorty(&unused_length); - } + ALWAYS_INLINE const char* GetShorty() REQUIRES_SHARED(Locks::mutator_lock_); const char* GetShorty(uint32_t* out_length) REQUIRES_SHARED(Locks::mutator_lock_); @@ -743,6 +751,8 @@ class ArtMethod FINAL { } } + template <ReadBarrierOption kReadBarrierOption> void GetAccessFlagsDCheck(); + DISALLOW_COPY_AND_ASSIGN(ArtMethod); // Need to use CopyFrom to deal with 32 vs 64 bits. }; diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc index f1d0a5fbff..2a2790c7d9 100644 --- a/runtime/base/allocator.cc +++ b/runtime/base/allocator.cc @@ -21,7 +21,6 @@ #include "atomic.h" #include "base/logging.h" -#include "thread-inl.h" namespace art { diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 9ddc6cf0ae..3c51f52616 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -25,7 +25,7 @@ #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" #include "mirror/iftable.h" -#include "mirror/object_array.h" +#include "mirror/object_array-inl.h" #include "handle_scope-inl.h" #include "scoped_thread_state_change-inl.h" @@ -33,10 +33,6 @@ namespace art { -inline mirror::Class* ClassLinker::FindSystemClass(Thread* self, const char* descriptor) { - return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>()); -} - inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class) { for (size_t i = 0; i < kFindArrayCacheSize; ++i) { @@ -65,19 +61,6 @@ inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, return array_class.Ptr(); } -inline mirror::String* ClassLinker::ResolveString(dex::StringIndex string_idx, - ArtMethod* referrer) { - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - const DexFile& dex_file = *dex_cache->GetDexFile(); - string = ResolveString(dex_file, string_idx, dex_cache); - } - return string.Ptr(); -} - inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType( dex::TypeIndex type_idx, ObjPtr<mirror::DexCache> dex_cache, @@ -191,36 +174,6 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, return resolved_field; } -inline mirror::Object* ClassLinker::AllocObject(Thread* self) { - return GetClassRoot(kJavaLangObject)->Alloc<true, false>( - self, - Runtime::Current()->GetHeap()->GetCurrentAllocator()).Ptr(); -} - -template <class T> -inline mirror::ObjectArray<T>* ClassLinker::AllocObjectArray(Thread* self, size_t length) { - return mirror::ObjectArray<T>::Alloc(self, GetClassRoot(kObjectArrayClass), length); -} - -inline mirror::ObjectArray<mirror::Class>* ClassLinker::AllocClassArray(Thread* self, - size_t length) { - return mirror::ObjectArray<mirror::Class>::Alloc(self, GetClassRoot(kClassArrayClass), length); -} - -inline mirror::ObjectArray<mirror::String>* ClassLinker::AllocStringArray(Thread* self, - size_t length) { - return mirror::ObjectArray<mirror::String>::Alloc(self, - GetClassRoot(kJavaLangStringArrayClass), - length); -} - -inline mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) { - return down_cast<mirror::IfTable*>( - mirror::IfTable::Alloc(self, - GetClassRoot(kObjectArrayClass), - ifcount * mirror::IfTable::kMax)); -} - inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root) { DCHECK(!class_roots_.IsNull()); mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read(); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 1d0684202c..ee33fc4c91 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -65,6 +65,7 @@ #include "imtable-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" +#include "java_vm_ext.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profile_compilation_info.h" @@ -8983,6 +8984,13 @@ mirror::Class* ClassLinker::GetHoldingClassOfCopiedMethod(ArtMethod* method) { return visitor.holder_.Ptr(); } +mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) { + return down_cast<mirror::IfTable*>( + mirror::IfTable::Alloc(self, + GetClassRoot(kObjectArrayClass), + ifcount * mirror::IfTable::kMax)); +} + // Instantiate ResolveMethod. template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kForceICCECheck>( const DexFile& dex_file, diff --git a/runtime/class_linker.h b/runtime/class_linker.h index a26e63b49e..1c280a4662 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -185,7 +185,9 @@ class ClassLinker { // boot_class_path_. mirror::Class* FindSystemClass(Thread* self, const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::dex_lock_); + REQUIRES(!Locks::dex_lock_) { + return FindClass(self, descriptor, ScopedNullHandle<mirror::ClassLoader>()); + } // Finds the array class given for the element class. mirror::Class* FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class) @@ -231,12 +233,6 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_); // Resolve a String with the given index from the DexFile, storing the - // result in the DexCache. The referrer is used to identify the - // target DexCache and ClassLoader to use for resolution. - mirror::String* ResolveString(dex::StringIndex string_idx, ArtMethod* referrer) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Resolve a String with the given index from the DexFile, storing the // result in the DexCache. mirror::String* ResolveString(const DexFile& dex_file, dex::StringIndex string_idx, @@ -436,25 +432,6 @@ class ClassLinker { REQUIRES(!Locks::dex_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - // Allocate an instance of a java.lang.Object. - mirror::Object* AllocObject(Thread* self) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - - // TODO: replace this with multiple methods that allocate the correct managed type. - template <class T> - mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - - mirror::ObjectArray<mirror::Class>* AllocClassArray(Thread* self, size_t length) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - - mirror::ObjectArray<mirror::String>* AllocStringArray(Thread* self, size_t length) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - LengthPrefixedArray<ArtField>* AllocArtFieldArray(Thread* self, LinearAlloc* allocator, size_t length); diff --git a/runtime/class_table.cc b/runtime/class_table.cc index 374b711aa8..0891d3f9f5 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -17,6 +17,7 @@ #include "class_table.h" #include "mirror/class-inl.h" +#include "oat_file.h" namespace art { diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 15724a1027..01c6641ae9 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -39,6 +39,7 @@ #include "gtest/gtest.h" #include "handle_scope-inl.h" #include "interpreter/unstarted_runtime.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 63794bff6f..d0b50fe820 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1092,6 +1092,23 @@ JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signatu return JDWP::ERR_NONE; } +JDWP::JdwpError Dbg::GetSourceDebugExtension(JDWP::RefTypeId class_id, + std::string* extension_data) { + JDWP::JdwpError error; + mirror::Class* c = DecodeClass(class_id, &error); + if (c == nullptr) { + return error; + } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> klass(hs.NewHandle(c)); + const char* data = annotations::GetSourceDebugExtension(klass); + if (data == nullptr) { + return JDWP::ERR_ABSENT_INFORMATION; + } + *extension_data = data; + return JDWP::ERR_NONE; +} + JDWP::JdwpError Dbg::GetSourceFile(JDWP::RefTypeId class_id, std::string* result) { JDWP::JdwpError error; mirror::Class* c = DecodeClass(class_id, &error); diff --git a/runtime/debugger.h b/runtime/debugger.h index 27124e19fb..4f3ff40e86 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -288,6 +288,9 @@ class Dbg { REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetSignature(JDWP::RefTypeId ref_type_id, std::string* signature) REQUIRES_SHARED(Locks::mutator_lock_); + static JDWP::JdwpError GetSourceDebugExtension(JDWP::RefTypeId ref_type_id, + std::string* extension_data) + REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetSourceFile(JDWP::RefTypeId ref_type_id, std::string* source_file) REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetObjectTag(JDWP::ObjectId object_id, uint8_t* tag) diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index 6b9654dc49..7d56bca6ce 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -1420,6 +1420,40 @@ mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirro return GetSignatureValue(data, annotation_set); } +const char* GetSourceDebugExtension(Handle<mirror::Class> klass) { + ClassData data(klass); + const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); + if (annotation_set == nullptr) { + return nullptr; + } + const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet( + data.GetDexFile(), + annotation_set, + "Ldalvik/annotation/SourceDebugExtension;", + DexFile::kDexVisibilitySystem); + if (annotation_item == nullptr) { + return nullptr; + } + const uint8_t* annotation = + SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value"); + if (annotation == nullptr) { + return nullptr; + } + DexFile::AnnotationValue annotation_value; + if (!ProcessAnnotationValue<false>(data, + &annotation, + &annotation_value, + ScopedNullHandle<mirror::Class>(), + DexFile::kAllRaw)) { + return nullptr; + } + if (annotation_value.type_ != DexFile::kDexAnnotationString) { + return nullptr; + } + dex::StringIndex index(static_cast<uint32_t>(annotation_value.value_.GetI())); + return data.GetDexFile().StringDataByIdx(index); +} + bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h index c66c5bdb8b..651c9844eb 100644 --- a/runtime/dex_file_annotations.h +++ b/runtime/dex_file_annotations.h @@ -89,6 +89,8 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); +const char* GetSourceDebugExtension(Handle<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index ba8cec3a52..37734e8afb 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -19,6 +19,7 @@ #include "entrypoint_utils.h" +#include "art_field-inl.h" #include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" @@ -39,6 +40,7 @@ #include "runtime.h" #include "stack_map.h" #include "thread.h" +#include "well_known_classes.h" namespace art { @@ -779,9 +781,32 @@ inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx, return h_class.Get(); } +static inline mirror::String* ResolveString(ClassLinker* class_linker, + dex::StringIndex string_idx, + ArtMethod* referrer) + REQUIRES_SHARED(Locks::mutator_lock_) { + Thread::PoisonObjectPointersIfDebug(); + ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); + if (UNLIKELY(string == nullptr)) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + const DexFile& dex_file = *dex_cache->GetDexFile(); + string = class_linker->ResolveString(dex_file, string_idx, dex_cache); + } + return string.Ptr(); +} + inline mirror::String* ResolveStringFromCode(ArtMethod* referrer, dex::StringIndex string_idx) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - return class_linker->ResolveString(string_idx, referrer); + Thread::PoisonObjectPointersIfDebug(); + ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); + if (UNLIKELY(string == nullptr)) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + const DexFile& dex_file = *dex_cache->GetDexFile(); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + string = class_linker->ResolveString(dex_file, string_idx, dex_cache); + } + return string.Ptr(); } inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) { diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index b5130d7999..c340a885c3 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -26,6 +26,7 @@ #include "entrypoints/quick/callee_save_frame.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "gc/accounting/card_table-inl.h" +#include "java_vm_ext.h" #include "mirror/class-inl.h" #include "mirror/method.h" #include "mirror/object-inl.h" diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc index 546e59d223..eeb138b295 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.cc +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -17,6 +17,7 @@ #include "art_method-inl.h" #include "base/logging.h" #include "entrypoints/entrypoint_utils.h" +#include "java_vm_ext.h" #include "mirror/object-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 343343fc3f..3820d854f9 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -14,22 +14,18 @@ * limitations under the License. */ -#include "art_method-inl.h" #include "base/logging.h" +#include "base/mutex.h" #include "callee_save_frame.h" -#include "dex_file-inl.h" #include "interpreter/interpreter.h" -#include "mirror/class-inl.h" -#include "mirror/object_array-inl.h" -#include "mirror/object-inl.h" +#include "obj_ptr-inl.h" // TODO: Find the other include that isn't complete, and clean this up. #include "quick_exception_handler.h" #include "thread.h" -#include "verifier/method_verifier.h" namespace art { NO_RETURN static void artDeoptimizeImpl(Thread* self, bool single_frame) - REQUIRES_SHARED(Locks::mutator_lock_) { + REQUIRES_SHARED(Locks::mutator_lock_) { if (VLOG_IS_ON(deopt)) { if (single_frame) { // Deopt logging will be in DeoptimizeSingleFrame. It is there to take advantage of the diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc index aa547bf04e..81560ccbaf 100644 --- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "art_method-inl.h" +#include "art_method.h" #include "base/enums.h" #include "callee_save_frame.h" #include "entrypoints/runtime_asm_entrypoints.h" diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index a5bb91a71e..34e30c177f 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -26,6 +26,7 @@ #include "gc/space/image_space.h" #include "gc/space/space.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "space_bitmap-inl.h" #include "thread-inl.h" diff --git a/runtime/gc/accounting/remembered_set.cc b/runtime/gc/accounting/remembered_set.cc index 7b1e2b83c3..f2fe58aa83 100644 --- a/runtime/gc/accounting/remembered_set.cc +++ b/runtime/gc/accounting/remembered_set.cc @@ -26,8 +26,9 @@ #include "gc/collector/semi_space.h" #include "gc/heap.h" #include "gc/space/space.h" -#include "mirror/object-inl.h" #include "mirror/class-inl.h" +#include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "space_bitmap-inl.h" #include "thread.h" diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h index 854d0a58ff..dd449f991b 100644 --- a/runtime/gc/collector/concurrent_copying-inl.h +++ b/runtime/gc/collector/concurrent_copying-inl.h @@ -22,7 +22,7 @@ #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" #include "gc/space/region_space.h" -#include "mirror/object-inl.h" +#include "mirror/object-readbarrier-inl.h" #include "lock_word.h" namespace art { @@ -96,7 +96,9 @@ inline mirror::Object* ConcurrentCopying::MarkImmuneSpace(mirror::Object* ref) { } template<bool kGrayImmuneObject, bool kFromGCThread> -inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref) { +inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref, + mirror::Object* holder, + MemberOffset offset) { if (from_ref == nullptr) { return nullptr; } @@ -141,7 +143,7 @@ inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref) { if (immune_spaces_.ContainsObject(from_ref)) { return MarkImmuneSpace<kGrayImmuneObject>(from_ref); } else { - return MarkNonMoving(from_ref); + return MarkNonMoving(from_ref, holder, offset); } default: UNREACHABLE(); diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 792c191017..d5af29e4c6 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -29,10 +29,12 @@ #include "gc/reference_processor.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" +#include "gc/verification.h" #include "image-inl.h" #include "intern_table.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" @@ -374,6 +376,15 @@ class ConcurrentCopying::FlipCallback : public Closure { cc->VerifyGrayImmuneObjects(); } } + // May be null during runtime creation, in this case leave java_lang_Object null. + // This is safe since single threaded behavior should mean FillDummyObject does not + // happen when java_lang_Object_ is null. + if (WellKnownClasses::java_lang_Object != nullptr) { + cc->java_lang_Object_ = down_cast<mirror::Class*>(cc->Mark( + WellKnownClasses::ToClass(WellKnownClasses::java_lang_Object).Ptr())); + } else { + cc->java_lang_Object_ = nullptr; + } } private: @@ -2067,11 +2078,10 @@ void ConcurrentCopying::FillWithDummyObject(mirror::Object* dummy_obj, size_t by size_t data_offset = mirror::Array::DataOffset(component_size).SizeValue(); if (data_offset > byte_size) { // An int array is too big. Use java.lang.Object. - ObjPtr<mirror::Class> java_lang_Object = - WellKnownClasses::ToClass(WellKnownClasses::java_lang_Object); - AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object.Ptr()); - CHECK_EQ(byte_size, (java_lang_Object->GetObjectSize<kVerifyNone, kWithoutReadBarrier>())); - dummy_obj->SetClass(java_lang_Object.Ptr()); + CHECK(java_lang_Object_ != nullptr); + AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object_); + CHECK_EQ(byte_size, (java_lang_Object_->GetObjectSize<kVerifyNone, kWithoutReadBarrier>())); + dummy_obj->SetClass(java_lang_Object_); CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone>())); } else { // Use an int array. @@ -2361,7 +2371,9 @@ bool ConcurrentCopying::IsOnAllocStack(mirror::Object* ref) { return alloc_stack->Contains(ref); } -mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref) { +mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref, + mirror::Object* holder, + MemberOffset offset) { // ref is in a non-moving space (from_ref == to_ref). DCHECK(!region_space_->HasAddress(ref)) << ref; DCHECK(!immune_spaces_.ContainsObject(ref)); @@ -2407,6 +2419,11 @@ mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref) { return ref; } } + if (is_los && !IsAligned<kPageSize>(ref)) { + // Ref is a large object that is not aligned, it must be heap corruption. Dump data before + // AtomicSetReadBarrierState since it will fault if the address is not valid. + heap_->GetVerification()->LogHeapCorruption(ref, offset, holder, /* fatal */ true); + } // Not marked or on the allocation stack. Try to mark it. // This may or may not succeed, which is ok. bool cas_success = false; diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h index a0da9fc58f..c21520d2fa 100644 --- a/runtime/gc/collector/concurrent_copying.h +++ b/runtime/gc/collector/concurrent_copying.h @@ -106,7 +106,9 @@ class ConcurrentCopying : public GarbageCollector { return IsMarked(ref) == ref; } template<bool kGrayImmuneObject = true, bool kFromGCThread = false> - ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref) + ALWAYS_INLINE mirror::Object* Mark(mirror::Object* from_ref, + mirror::Object* holder = nullptr, + MemberOffset offset = MemberOffset(0)) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_); ALWAYS_INLINE mirror::Object* MarkFromReadBarrier(mirror::Object* from_ref) @@ -224,7 +226,10 @@ class ConcurrentCopying : public GarbageCollector { void DisableMarking() REQUIRES_SHARED(Locks::mutator_lock_); void IssueDisableMarkingCheckpoint() REQUIRES_SHARED(Locks::mutator_lock_); void ExpandGcMarkStack() REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Object* MarkNonMoving(mirror::Object* from_ref) REQUIRES_SHARED(Locks::mutator_lock_) + mirror::Object* MarkNonMoving(mirror::Object* from_ref, + mirror::Object* holder = nullptr, + MemberOffset offset = MemberOffset(0)) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_); ALWAYS_INLINE mirror::Object* MarkUnevacFromSpaceRegion(mirror::Object* from_ref, accounting::SpaceBitmap<kObjectAlignment>* bitmap) @@ -316,6 +321,11 @@ class ConcurrentCopying : public GarbageCollector { Mutex immune_gray_stack_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; std::vector<mirror::Object*> immune_gray_stack_ GUARDED_BY(immune_gray_stack_lock_); + // Class of java.lang.Object. Filled in from WellKnownClasses in FlipCallback. Must + // be filled in before flipping thread roots so that FillDummyObject can run. Not + // ObjPtr since the GC may transition to suspended and runnable between phases. + mirror::Class* java_lang_Object_; + class AssertToSpaceInvariantFieldVisitor; class AssertToSpaceInvariantObjectVisitor; class AssertToSpaceInvariantRefsVisitor; diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc index c61f69dad3..cab293f23c 100644 --- a/runtime/gc/collector/mark_compact.cc +++ b/runtime/gc/collector/mark_compact.cc @@ -29,6 +29,7 @@ #include "gc/space/space-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "runtime.h" #include "stack.h" #include "thread-inl.h" diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h index e72277ffb2..e4993ce718 100644 --- a/runtime/gc/collector/mark_sweep-inl.h +++ b/runtime/gc/collector/mark_sweep-inl.h @@ -21,6 +21,7 @@ #include "gc/heap.h" #include "mirror/class-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/reference.h" diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index 67e7383a4f..41e605104c 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -44,6 +44,7 @@ #include "monitor.h" #include "mirror/reference-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "runtime.h" #include "thread-inl.h" #include "thread_list.h" diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 28dd62717a..64dce5f4e7 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -60,16 +60,19 @@ #include "gc/space/space-inl.h" #include "gc/space/zygote_space.h" #include "gc/task_processor.h" +#include "gc/verification.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" #include "gc_pause_listener.h" #include "heap-inl.h" #include "image.h" #include "intern_table.h" +#include "java_vm_ext.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "obj_ptr-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/object_array-inl.h" #include "mirror/reference-inl.h" #include "os.h" @@ -285,6 +288,7 @@ Heap::Heap(size_t initial_size, CHECK_EQ(foreground_collector_type_, kCollectorTypeCC); CHECK_EQ(background_collector_type_, kCollectorTypeCCBackground); } + verification_.reset(new Verification(this)); CHECK_GE(large_object_threshold, kMinLargeObjectThreshold); ScopedTrace trace(__FUNCTION__); Runtime* const runtime = Runtime::Current(); @@ -4266,5 +4270,9 @@ mirror::Object* Heap::AllocWithNewTLAB(Thread* self, return ret; } +const Verification* Heap::GetVerification() const { + return verification_.get(); +} + } // namespace gc } // namespace art diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 241d84ce22..aa123d8736 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -64,6 +64,7 @@ class AllocRecordObjectMap; class GcPauseListener; class ReferenceProcessor; class TaskProcessor; +class Verification; namespace accounting { class HeapBitmap; @@ -821,6 +822,8 @@ class Heap { // reasons, we assume it stays valid when we read it (so that we don't require a lock). void RemoveGcPauseListener(); + const Verification* GetVerification() const; + private: class ConcurrentGCTask; class CollectorTransitionTask; @@ -1433,6 +1436,8 @@ class Heap { // An installed GC Pause listener. Atomic<GcPauseListener*> gc_pause_listener_; + std::unique_ptr<Verification> verification_; + friend class CollectorTransitionTask; friend class collector::GarbageCollector; friend class collector::MarkCompact; diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc new file mode 100644 index 0000000000..c8233e37ab --- /dev/null +++ b/runtime/gc/heap_verification_test.cc @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 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 "common_runtime_test.h" + +#include "class_linker.h" +#include "handle_scope-inl.h" +#include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/string.h" +#include "runtime.h" +#include "scoped_thread_state_change-inl.h" +#include "verification.h" + +namespace art { +namespace gc { + +class VerificationTest : public CommonRuntimeTest { + protected: + VerificationTest() {} + + template <class T> + mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) + REQUIRES_SHARED(Locks::mutator_lock_) { + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + return mirror::ObjectArray<T>::Alloc( + self, + class_linker->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), + length); + } +}; + +TEST_F(VerificationTest, IsValidHeapObjectAddress) { + ScopedObjectAccess soa(Thread::Current()); + const Verification* const v = Runtime::Current()->GetHeap()->GetVerification(); + EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(1))); + EXPECT_FALSE(v->IsValidHeapObjectAddress(reinterpret_cast<const void*>(4))); + EXPECT_FALSE(v->IsValidHeapObjectAddress(nullptr)); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test"))); + EXPECT_TRUE(v->IsValidHeapObjectAddress(string.Get())); + EXPECT_TRUE(v->IsValidHeapObjectAddress(string->GetClass())); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + // Not actually a valid object but the verification can't know that. Guaranteed to be inside a + // heap space. + EXPECT_TRUE(v->IsValidHeapObjectAddress( + reinterpret_cast<const void*>(uint_klass + kObjectAlignment))); + EXPECT_FALSE(v->IsValidHeapObjectAddress( + reinterpret_cast<const void*>(&uint_klass))); +} + +TEST_F(VerificationTest, IsValidClass) { + ScopedObjectAccess soa(Thread::Current()); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "test"))); + const Verification* const v = Runtime::Current()->GetHeap()->GetVerification(); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(1))); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(4))); + EXPECT_FALSE(v->IsValidClass(nullptr)); + EXPECT_FALSE(v->IsValidClass(string.Get())); + EXPECT_TRUE(v->IsValidClass(string->GetClass())); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(uint_klass - kObjectAlignment))); + EXPECT_FALSE(v->IsValidClass(reinterpret_cast<const void*>(&uint_klass))); +} + +TEST_F(VerificationTest, DumpObjectInfo) { + ScopedLogSeverity sls(LogSeverity::INFO); + ScopedObjectAccess soa(Thread::Current()); + Runtime* const runtime = Runtime::Current(); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); + Handle<mirror::ObjectArray<mirror::Object>> arr( + hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256))); + const Verification* const v = runtime->GetHeap()->GetVerification(); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(1), "obj"); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(4), "obj"); + LOG(INFO) << v->DumpObjectInfo(nullptr, "obj"); + LOG(INFO) << v->DumpObjectInfo(string.Get(), "test"); + LOG(INFO) << v->DumpObjectInfo(string->GetClass(), "obj"); + const uintptr_t uint_klass = reinterpret_cast<uintptr_t>(string->GetClass()); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(uint_klass - kObjectAlignment), + "obj"); + LOG(INFO) << v->DumpObjectInfo(reinterpret_cast<const void*>(&uint_klass), "obj"); + LOG(INFO) << v->DumpObjectInfo(arr.Get(), "arr"); +} + +TEST_F(VerificationTest, LogHeapCorruption) { + ScopedLogSeverity sls(LogSeverity::INFO); + ScopedObjectAccess soa(Thread::Current()); + Runtime* const runtime = Runtime::Current(); + VariableSizedHandleScope hs(soa.Self()); + Handle<mirror::String> string( + hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "obj"))); + using ObjArray = mirror::ObjectArray<mirror::Object>; + Handle<ObjArray> arr( + hs.NewHandle(AllocObjectArray<mirror::Object>(soa.Self(), 256))); + const Verification* const v = runtime->GetHeap()->GetVerification(); + arr->Set(0, string.Get()); + // Test normal cases. + v->LogHeapCorruption(arr.Get(), ObjArray::DataOffset(kHeapReferenceSize), string.Get(), false); + v->LogHeapCorruption(string.Get(), mirror::Object::ClassOffset(), string->GetClass(), false); + // Test null holder cases. + v->LogHeapCorruption(nullptr, MemberOffset(0), string.Get(), false); + v->LogHeapCorruption(nullptr, MemberOffset(0), arr.Get(), false); +} + +} // namespace gc +} // namespace art diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index 65a550ee5c..886c950710 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -18,6 +18,7 @@ #include "base/time_utils.h" #include "collector/garbage_collector.h" +#include "java_vm_ext.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/reference-inl.h" diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 662efe2c8d..e9f0758b85 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -25,7 +25,8 @@ #include "android-base/stringprintf.h" #include "android-base/strings.h" -#include "art_method.h" +#include "art_field-inl.h" +#include "art_method-inl.h" #include "base/enums.h" #include "base/macros.h" #include "base/stl_util.h" @@ -38,6 +39,7 @@ #include "image_space_fs.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "oat_file.h" #include "os.h" #include "space-inl.h" diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc index 9b601c0753..dfbbd2a0c1 100644 --- a/runtime/gc/system_weak_test.cc +++ b/runtime/gc/system_weak_test.cc @@ -23,6 +23,7 @@ #include "base/mutex.h" #include "collector_type.h" #include "common_runtime_test.h" +#include "gc_root-inl.h" #include "handle_scope-inl.h" #include "heap.h" #include "mirror/string.h" diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc new file mode 100644 index 0000000000..7b31c8a259 --- /dev/null +++ b/runtime/gc/verification.cc @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2017 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 "verification.h" + +#include <iomanip> +#include <sstream> + +#include "art_field-inl.h" +#include "mirror/class-inl.h" + +namespace art { +namespace gc { + +std::string Verification::DumpObjectInfo(const void* addr, const char* tag) const { + std::ostringstream oss; + oss << tag << "=" << addr; + if (IsValidHeapObjectAddress(addr)) { + mirror::Object* obj = reinterpret_cast<mirror::Object*>(const_cast<void*>(addr)); + mirror::Class* klass = obj->GetClass<kVerifyNone, kWithoutReadBarrier>(); + oss << " klass=" << klass; + if (IsValidClass(klass)) { + oss << "(" << klass->PrettyClass() << ")"; + if (klass->IsArrayClass<kVerifyNone, kWithoutReadBarrier>()) { + oss << " length=" << obj->AsArray<kVerifyNone, kWithoutReadBarrier>()->GetLength(); + } + } else { + oss << " <invalid address>"; + } + space::Space* const space = heap_->FindSpaceFromAddress(addr); + if (space != nullptr) { + oss << " space=" << *space; + } + accounting::CardTable* card_table = heap_->GetCardTable(); + if (card_table->AddrIsInCardTable(addr)) { + oss << " card=" << static_cast<size_t>( + card_table->GetCard(reinterpret_cast<const mirror::Object*>(addr))); + } + // Dump adjacent RAM. + const uintptr_t uint_addr = reinterpret_cast<uintptr_t>(addr); + static constexpr size_t kBytesBeforeAfter = 2 * kObjectAlignment; + const uintptr_t dump_start = uint_addr - kBytesBeforeAfter; + const uintptr_t dump_end = uint_addr + kBytesBeforeAfter; + if (dump_start < dump_end && + IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_start)) && + IsValidHeapObjectAddress(reinterpret_cast<const void*>(dump_end - kObjectAlignment))) { + oss << " adjacent_ram="; + for (uintptr_t p = dump_start; p < dump_end; ++p) { + if (p == uint_addr) { + // Marker of where the object is. + oss << "|"; + } + uint8_t* ptr = reinterpret_cast<uint8_t*>(p); + oss << std::hex << std::setfill('0') << std::setw(2) << static_cast<uintptr_t>(*ptr); + } + } + } else { + oss << " <invalid address>"; + } + return oss.str(); +} + +void Verification::LogHeapCorruption(ObjPtr<mirror::Object> holder, + MemberOffset offset, + mirror::Object* ref, + bool fatal) const { + // Lowest priority logging first: + PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT); + MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true); + // Buffer the output in the string stream since it is more important than the stack traces + // and we want it to have log priority. The stack traces are printed from Runtime::Abort + // which is called from LOG(FATAL) but before the abort message. + std::ostringstream oss; + oss << "GC tried to mark invalid reference " << ref << std::endl; + oss << DumpObjectInfo(ref, "ref") << "\n"; + if (holder != nullptr) { + oss << DumpObjectInfo(holder.Ptr(), "holder"); + mirror::Class* holder_klass = holder->GetClass<kVerifyNone, kWithoutReadBarrier>(); + if (IsValidClass(holder_klass)) { + oss << "field_offset=" << offset.Uint32Value(); + ArtField* field = holder->FindFieldByOffset(offset); + if (field != nullptr) { + oss << " name=" << field->GetName(); + } + } + } + + if (fatal) { + LOG(FATAL) << oss.str(); + } else { + LOG(FATAL_WITHOUT_ABORT) << oss.str(); + } +} + +bool Verification::IsValidHeapObjectAddress(const void* addr, space::Space** out_space) const { + if (!IsAligned<kObjectAlignment>(addr)) { + return false; + } + space::Space* const space = heap_->FindSpaceFromAddress(addr); + if (space != nullptr) { + if (out_space != nullptr) { + *out_space = space; + } + return true; + } + return false; +} + +bool Verification::IsValidClass(const void* addr) const { + if (!IsValidHeapObjectAddress(addr)) { + return false; + } + mirror::Class* klass = reinterpret_cast<mirror::Class*>(const_cast<void*>(addr)); + mirror::Class* k1 = klass->GetClass<kVerifyNone, kWithoutReadBarrier>(); + if (!IsValidHeapObjectAddress(k1)) { + return false; + } + // k should be class class, take the class again to verify. + // Note that this check may not be valid for the no image space since the class class might move + // around from moving GC. + mirror::Class* k2 = k1->GetClass<kVerifyNone, kWithoutReadBarrier>(); + if (!IsValidHeapObjectAddress(k2)) { + return false; + } + return k1 == k2; +} + +} // namespace gc +} // namespace art diff --git a/runtime/gc/verification.h b/runtime/gc/verification.h new file mode 100644 index 0000000000..3d95d93015 --- /dev/null +++ b/runtime/gc/verification.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 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_RUNTIME_GC_VERIFICATION_H_ +#define ART_RUNTIME_GC_VERIFICATION_H_ + +#include "obj_ptr.h" +#include "offsets.h" + +namespace art { + +namespace mirror { +class Class; +class Object; +} // namespace mirror + +namespace gc { + +namespace space { +class Space; +} // namespace space + +class Heap; + +class Verification { + public: + explicit Verification(gc::Heap* heap) : heap_(heap) {} + + // Dump some reveant to debugging info about an object. + std::string DumpObjectInfo(const void* obj, const char* tag) const + REQUIRES_SHARED(Locks::mutator_lock_); + + // Don't use ObjPtr for things that might not be aligned like the invalid reference. + void LogHeapCorruption(ObjPtr<mirror::Object> holder, + MemberOffset offset, + mirror::Object* ref, + bool fatal) const REQUIRES_SHARED(Locks::mutator_lock_); + + + // Return true if the klass is likely to be a valid mirror::Class. + bool IsValidClass(const void* klass) const REQUIRES_SHARED(Locks::mutator_lock_); + + // Does not allow null. + bool IsValidHeapObjectAddress(const void* addr, space::Space** out_space = nullptr) const + REQUIRES_SHARED(Locks::mutator_lock_); + + private: + gc::Heap* const heap_; +}; + +} // namespace gc +} // namespace art + +#endif // ART_RUNTIME_GC_VERIFICATION_H_ diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 495fec7a48..4f390fd30a 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -40,6 +40,7 @@ #include "android-base/stringprintf.h" #include "art_field-inl.h" +#include "art_method-inl.h" #include "base/logging.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" @@ -58,7 +59,7 @@ #include "jdwp/jdwp_priv.h" #include "mirror/class.h" #include "mirror/class-inl.h" -#include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "os.h" #include "safe_map.h" #include "scoped_thread_state_change-inl.h" diff --git a/runtime/image.cc b/runtime/image.cc index b153ea0e02..b2486a1209 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -17,6 +17,7 @@ #include "image.h" #include "base/bit_utils.h" +#include "base/length_prefixed_array.h" #include "mirror/object_array.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h index 24ee22759c..2128f8cde8 100644 --- a/runtime/indirect_reference_table-inl.h +++ b/runtime/indirect_reference_table-inl.h @@ -24,7 +24,6 @@ #include "base/dumpable.h" #include "gc_root-inl.h" #include "obj_ptr-inl.h" -#include "runtime-inl.h" #include "verify_object.h" namespace art { diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index 9fbb2e9930..c852d5af3a 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -18,6 +18,7 @@ #include "base/dumpable-inl.h" #include "base/systrace.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "nth_caller_visitor.h" #include "reference_table.h" diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc index f0d0260482..311515c7ed 100644 --- a/runtime/intern_table_test.cc +++ b/runtime/intern_table_test.cc @@ -18,6 +18,7 @@ #include "base/hash_set.h" #include "common_runtime_test.h" +#include "gc_root-inl.h" #include "mirror/object.h" #include "handle_scope-inl.h" #include "mirror/string.h" diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 8978bfd5af..326f5c96c0 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -28,7 +28,7 @@ #include "mirror/array-inl.h" #include "mirror/class.h" #include "mirror/emulated_stack_frame.h" -#include "mirror/method_handle_impl.h" +#include "mirror/method_handle_impl-inl.h" #include "reflection.h" #include "reflection-inl.h" #include "stack.h" diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 56e261cfc8..c314f3c35e 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -1341,7 +1341,8 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { ASSERT_TRUE(cons != nullptr); Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle( - class_linker->AllocObjectArray<mirror::Object>(self, 1)); + mirror::ObjectArray<mirror::Object>::Alloc( + self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), 1)); ASSERT_TRUE(args != nullptr); args->Set(0, input.Get()); diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index c8dc2f2d20..6d3118e4aa 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -20,7 +20,7 @@ #include "android-base/stringprintf.h" -#include "art_method.h" +#include "art_method-inl.h" #include "base/dumpable.h" #include "base/mutex.h" #include "base/stl_util.h" diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 971d03958c..e8a9904dc6 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -335,7 +335,7 @@ static JdwpError VM_CapabilitiesNew(JdwpState*, Request* request, ExpandBuf* rep expandBufAdd1(reply, false); // canUnrestrictedlyRedefineClasses expandBufAdd1(reply, false); // canPopFrames expandBufAdd1(reply, true); // canUseInstanceFilters - expandBufAdd1(reply, false); // canGetSourceDebugExtension + expandBufAdd1(reply, true); // canGetSourceDebugExtension expandBufAdd1(reply, false); // canRequestVMDeathEvent expandBufAdd1(reply, false); // canSetDefaultStratum expandBufAdd1(reply, true); // 1.6: canGetInstanceInfo @@ -499,13 +499,18 @@ static JdwpError RT_ClassObject(JdwpState*, Request* request, ExpandBuf* pReply) /* * Returns the value of the SourceDebugExtension attribute. - * - * JDB seems interested, but DEX files don't currently support this. */ -static JdwpError RT_SourceDebugExtension(JdwpState*, Request*, ExpandBuf*) +static JdwpError RT_SourceDebugExtension(JdwpState*, Request* request, ExpandBuf* pReply) REQUIRES_SHARED(Locks::mutator_lock_) { /* referenceTypeId in, string out */ - return ERR_ABSENT_INFORMATION; + RefTypeId refTypeId = request->ReadRefTypeId(); + std::string extension_data; + JdwpError status = Dbg::GetSourceDebugExtension(refTypeId, &extension_data); + if (status != ERR_NONE) { + return status; + } + expandBufAddUtf8String(pReply, extension_data); + return ERR_NONE; } static JdwpError RT_Signature(JdwpState*, Request* request, ExpandBuf* pReply, bool with_generic) diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 3631a9d467..b32b272a31 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -23,6 +23,7 @@ #include "debugger.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "interpreter/interpreter.h" +#include "java_vm_ext.h" #include "jit_code_cache.h" #include "oat_file_manager.h" #include "oat_quick_method_header.h" diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc index 2d1601e883..52649c7075 100644 --- a/runtime/jit/profile_compilation_info.cc +++ b/runtime/jit/profile_compilation_info.cc @@ -24,7 +24,6 @@ #include <sys/stat.h> #include <sys/uio.h> -#include "art_method-inl.h" #include "base/mutex.h" #include "base/scoped_flock.h" #include "base/stl_util.h" @@ -33,6 +32,7 @@ #include "jit/profiling_info.h" #include "os.h" #include "safe_map.h" +#include "utils.h" namespace art { diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h index 004f824b9d..25893b7eda 100644 --- a/runtime/jni_env_ext-inl.h +++ b/runtime/jni_env_ext-inl.h @@ -19,9 +19,7 @@ #include "jni_env_ext.h" -#include "indirect_reference_table-inl.h" -#include "obj_ptr-inl.h" -#include "utils.h" +#include "mirror/object.h" namespace art { diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h index 4004c457b5..60e4295e40 100644 --- a/runtime/jni_env_ext.h +++ b/runtime/jni_env_ext.h @@ -23,12 +23,17 @@ #include "base/mutex.h" #include "indirect_reference_table.h" #include "object_callbacks.h" +#include "obj_ptr.h" #include "reference_table.h" namespace art { class JavaVMExt; +namespace mirror { +class Object; +} // namespace mirror + // Number of local references in the indirect reference table. The value is arbitrary but // low enough that it forces sanity checks. static constexpr size_t kLocalsInitial = 512; diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index b6f8a173c0..54d45b1e79 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -22,7 +22,7 @@ #include "jvalue.h" #include "jvalue-inl.h" #include "mirror/emulated_stack_frame.h" -#include "mirror/method_handle_impl.h" +#include "mirror/method_handle_impl-inl.h" #include "mirror/method_type.h" #include "reflection.h" #include "reflection-inl.h" diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index 04c80c5cc0..bfbd4df537 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -24,8 +24,9 @@ #include "base/bit_utils.h" #include "base/casts.h" #include "base/logging.h" -#include "class-inl.h" +#include "class.h" #include "gc/heap-inl.h" +#include "object-inl.h" #include "obj_ptr-inl.h" #include "thread.h" diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 9124a3ad84..6c723efde2 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -19,18 +19,18 @@ #include "class.h" -#include "art_field-inl.h" +#include "art_field.h" #include "art_method.h" -#include "art_method-inl.h" #include "base/array_slice.h" #include "base/length_prefixed_array.h" +#include "class_linker-inl.h" #include "class_loader.h" #include "common_throws.h" -#include "dex_file.h" +#include "dex_file-inl.h" #include "gc/heap-inl.h" #include "iftable.h" -#include "class_ext-inl.h" #include "object_array-inl.h" +#include "object-inl.h" #include "read_barrier-inl.h" #include "reference-inl.h" #include "runtime.h" @@ -343,6 +343,21 @@ inline bool Class::Implements(ObjPtr<Class> klass) { return false; } +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +inline bool Class::IsVariableSize() { + // Classes, arrays, and strings vary in size, and so the object_size_ field cannot + // be used to Get their instance size + return IsClassClass<kVerifyFlags, kReadBarrierOption>() || + IsArrayClass<kVerifyFlags, kReadBarrierOption>() || + IsStringClass(); +} + +inline void Class::SetObjectSize(uint32_t new_object_size) { + DCHECK(!IsVariableSize()); + // Not called within a transaction. + return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size); +} + // Determine whether "this" is assignable from "src", where both of these // are array classes. // @@ -784,32 +799,6 @@ inline uint32_t Class::ComputeClassSize(bool has_embedded_vtable, return size; } -template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor> -inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) { - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor); - // Right after a class is allocated, but not yet loaded - // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it - // and scan it. IsTemp() may call Class::GetAccessFlags() but may - // fail in the DCHECK in Class::GetAccessFlags() because the class - // status is kStatusNotReady. To avoid it, rely on IsResolved() - // only. This is fine because a temp class never goes into the - // kStatusResolved state. - if (IsResolved<kVerifyFlags>()) { - // Temp classes don't ever populate imt/vtable or static fields and they are not even - // allocated with the right size for those. Also, unresolved classes don't have fields - // linked yet. - VisitStaticFieldsReferences<kVerifyFlags, kReadBarrierOption>(this, visitor); - } - if (kVisitNativeRoots) { - // Since this class is reachable, we must also visit the associated roots when we scan it. - VisitNativeRoots<kReadBarrierOption>( - visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); - } -} - template<ReadBarrierOption kReadBarrierOption> inline bool Class::IsReferenceClass() const { return this == Reference::GetJavaLangRefReference<kReadBarrierOption>(); @@ -942,31 +931,6 @@ inline uint32_t Class::NumDirectInterfaces() { } } -template<ReadBarrierOption kReadBarrierOption, class Visitor> -void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) { - for (ArtField& field : GetSFieldsUnchecked()) { - // Visit roots first in case the declaring class gets moved. - field.VisitRoots(visitor); - if (kIsDebugBuild && IsResolved()) { - CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus(); - } - } - for (ArtField& field : GetIFieldsUnchecked()) { - // Visit roots first in case the declaring class gets moved. - field.VisitRoots(visitor); - if (kIsDebugBuild && IsResolved()) { - CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus(); - } - } - for (ArtMethod& method : GetMethods(pointer_size)) { - method.VisitRoots<kReadBarrierOption>(visitor, pointer_size); - } - ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>()); - if (!ext.IsNull()) { - ext->VisitNativeRoots<kReadBarrierOption, Visitor>(visitor, pointer_size); - } -} - inline IterationRange<StrideIterator<ArtMethod>> Class::GetDirectMethods(PointerSize pointer_size) { CheckPointerSize(pointer_size); return GetDirectMethodsSliceUnchecked(pointer_size).AsRange(); @@ -1036,6 +1000,12 @@ inline bool Class::IsArrayClass() { return GetComponentType<kVerifyFlags, kReadBarrierOption>() != nullptr; } +template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> +inline bool Class::IsObjectArrayClass() { + ObjPtr<Class> const component_type = GetComponentType<kVerifyFlags, kReadBarrierOption>(); + return component_type != nullptr && !component_type->IsPrimitive(); +} + inline bool Class::IsAssignableFrom(ObjPtr<Class> src) { DCHECK(src != nullptr); if (this == src) { diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h new file mode 100644 index 0000000000..3d52ead0f4 --- /dev/null +++ b/runtime/mirror/class-refvisitor-inl.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_MIRROR_CLASS_REFVISITOR_INL_H_ +#define ART_RUNTIME_MIRROR_CLASS_REFVISITOR_INL_H_ + +#include "class-inl.h" + +#include "art_field-inl.h" +#include "class_ext-inl.h" + +namespace art { +namespace mirror { + +template <bool kVisitNativeRoots, + VerifyObjectFlags kVerifyFlags, + ReadBarrierOption kReadBarrierOption, + typename Visitor> +inline void Class::VisitReferences(ObjPtr<Class> klass, const Visitor& visitor) { + VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass.Ptr(), visitor); + // Right after a class is allocated, but not yet loaded + // (kStatusNotReady, see ClassLinker::LoadClass()), GC may find it + // and scan it. IsTemp() may call Class::GetAccessFlags() but may + // fail in the DCHECK in Class::GetAccessFlags() because the class + // status is kStatusNotReady. To avoid it, rely on IsResolved() + // only. This is fine because a temp class never goes into the + // kStatusResolved state. + if (IsResolved<kVerifyFlags>()) { + // Temp classes don't ever populate imt/vtable or static fields and they are not even + // allocated with the right size for those. Also, unresolved classes don't have fields + // linked yet. + VisitStaticFieldsReferences<kVerifyFlags, kReadBarrierOption>(this, visitor); + } + if (kVisitNativeRoots) { + // Since this class is reachable, we must also visit the associated roots when we scan it. + VisitNativeRoots<kReadBarrierOption>( + visitor, Runtime::Current()->GetClassLinker()->GetImagePointerSize()); + } +} + +template<ReadBarrierOption kReadBarrierOption, class Visitor> +void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) { + for (ArtField& field : GetSFieldsUnchecked()) { + // Visit roots first in case the declaring class gets moved. + field.VisitRoots(visitor); + if (kIsDebugBuild && IsResolved()) { + CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus(); + } + } + for (ArtField& field : GetIFieldsUnchecked()) { + // Visit roots first in case the declaring class gets moved. + field.VisitRoots(visitor); + if (kIsDebugBuild && IsResolved()) { + CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus(); + } + } + for (ArtMethod& method : GetMethods(pointer_size)) { + method.VisitRoots<kReadBarrierOption>(visitor, pointer_size); + } + ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>()); + if (!ext.IsNull()) { + ext->VisitNativeRoots<kReadBarrierOption, Visitor>(visitor, pointer_size); + } +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_CLASS_REFVISITOR_INL_H_ diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 26af488bd2..06ee3d36fe 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -32,6 +32,7 @@ #include "method.h" #include "object_array-inl.h" #include "object-inl.h" +#include "object-refvisitor-inl.h" #include "object_lock.h" #include "runtime.h" #include "thread.h" diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 27aecd5150..dfb2788c51 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -530,10 +530,7 @@ class MANAGED Class FINAL : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - bool IsObjectArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<Class> const component_type = GetComponentType<kVerifyFlags, kReadBarrierOption>(); - return component_type != nullptr && !component_type->IsPrimitive(); - } + ALWAYS_INLINE bool IsObjectArrayClass() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool IsIntArrayClass() REQUIRES_SHARED(Locks::mutator_lock_) { @@ -561,12 +558,7 @@ class MANAGED Class FINAL : public Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - bool IsVariableSize() REQUIRES_SHARED(Locks::mutator_lock_) { - // Classes, arrays, and strings vary in size, and so the object_size_ field cannot - // be used to Get their instance size - return IsClassClass<kVerifyFlags, kReadBarrierOption>() || - IsArrayClass<kVerifyFlags, kReadBarrierOption>() || IsStringClass(); - } + ALWAYS_INLINE bool IsVariableSize() REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> @@ -614,11 +606,7 @@ class MANAGED Class FINAL : public Object { return OFFSET_OF_OBJECT_MEMBER(Class, object_size_alloc_fast_path_); } - void SetObjectSize(uint32_t new_object_size) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!IsVariableSize()); - // Not called within a transaction. - return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size); - } + ALWAYS_INLINE void SetObjectSize(uint32_t new_object_size) REQUIRES_SHARED(Locks::mutator_lock_); void SetObjectSizeAllocFastPath(uint32_t new_object_size) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 5d3af5071a..18e22ef8f8 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -19,13 +19,15 @@ #include "dex_cache.h" -#include "art_field-inl.h" -#include "art_method-inl.h" +#include "art_field.h" +#include "art_method.h" #include "base/casts.h" #include "base/enums.h" #include "base/logging.h" +#include "class_linker.h" #include "dex_file.h" #include "gc_root.h" +#include "gc/heap-inl.h" #include "mirror/class.h" #include "mirror/call_site.h" #include "mirror/method_type.h" diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index 71a47f66a0..a110ed7f6b 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -18,6 +18,7 @@ #include <stdio.h> +#include "art_method-inl.h" #include "class_linker.h" #include "common_runtime_test.h" #include "linear_alloc.h" diff --git a/runtime/mirror/method_handle_impl-inl.h b/runtime/mirror/method_handle_impl-inl.h new file mode 100644 index 0000000000..0840d16c38 --- /dev/null +++ b/runtime/mirror/method_handle_impl-inl.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_INL_H_ +#define ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_INL_H_ + +#include "method_handle_impl.h" + +#include "art_method-inl.h" +#include "object-inl.h" + +namespace art { +namespace mirror { + +inline mirror::MethodType* MethodHandle::GetMethodType() { + return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_)); +} + +inline mirror::MethodType* MethodHandle::GetNominalType() { + return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, nominal_type_)); +} + +inline ObjPtr<mirror::Class> MethodHandle::GetTargetClass() { + Kind kind = GetHandleKind(); + return (kind <= kLastValidKind) ? + GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass(); +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_INL_H_ diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc index fa4d25a031..42b8473ef0 100644 --- a/runtime/mirror/method_handle_impl.cc +++ b/runtime/mirror/method_handle_impl.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "method_handle_impl.h" +#include "method_handle_impl-inl.h" #include "class-inl.h" #include "gc_root-inl.h" @@ -42,6 +42,10 @@ void MethodHandle::Initialize(uintptr_t art_field_or_method, GcRoot<mirror::Class> MethodHandleImpl::static_class_; +mirror::Class* MethodHandleImpl::StaticClass() { + return static_class_.Read(); +} + void MethodHandleImpl::SetClass(Class* klass) { CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; CHECK(klass != nullptr); diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h index 9938af8abf..c598fa3876 100644 --- a/runtime/mirror/method_handle_impl.h +++ b/runtime/mirror/method_handle_impl.h @@ -21,7 +21,7 @@ #include "art_method.h" #include "class.h" #include "gc_root.h" -#include "object-inl.h" +#include "object.h" #include "method_type.h" namespace art { @@ -65,13 +65,9 @@ class MANAGED MethodHandle : public Object { return static_cast<Kind>(handle_kind); } - mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_)); - } + ALWAYS_INLINE mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_); - mirror::MethodType* GetNominalType() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, nominal_type_)); - } + ALWAYS_INLINE mirror::MethodType* GetNominalType() REQUIRES_SHARED(Locks::mutator_lock_); ArtField* GetTargetField() REQUIRES_SHARED(Locks::mutator_lock_) { return reinterpret_cast<ArtField*>( @@ -83,11 +79,7 @@ class MANAGED MethodHandle : public Object { GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_))); } - ObjPtr<mirror::Class> GetTargetClass() REQUIRES_SHARED(Locks::mutator_lock_) { - Kind kind = GetHandleKind(); - return (kind <= kLastValidKind) ? - GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass(); - } + ALWAYS_INLINE ObjPtr<mirror::Class> GetTargetClass() REQUIRES_SHARED(Locks::mutator_lock_); static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); @@ -132,9 +124,7 @@ class MANAGED MethodHandleImpl : public MethodHandle { Handle<MethodType> method_type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } + static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_); static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/method_handles_lookup.cc b/runtime/mirror/method_handles_lookup.cc index c758e54dd4..0c25fa8ba0 100644 --- a/runtime/mirror/method_handles_lookup.cc +++ b/runtime/mirror/method_handles_lookup.cc @@ -16,7 +16,7 @@ #include "method_handles_lookup.h" -#include "class.h" +#include "class-inl.h" #include "gc_root-inl.h" #include "object-inl.h" #include "handle_scope.h" diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc index 41231ef617..a361772c58 100644 --- a/runtime/mirror/method_type_test.cc +++ b/runtime/mirror/method_type_test.cc @@ -20,7 +20,7 @@ #include <vector> #include "class-inl.h" -#include "class_linker.h" +#include "class_linker-inl.h" #include "class_loader.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index f83645e6e8..baed5f167c 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -23,7 +23,7 @@ #include "art_method.h" #include "atomic.h" #include "array-inl.h" -#include "class.h" +#include "class-inl.h" #include "class_flags.h" #include "class_linker.h" #include "class_loader-inl.h" @@ -32,6 +32,7 @@ #include "monitor.h" #include "object_array-inl.h" #include "object_reference-inl.h" +#include "object-readbarrier-inl.h" #include "obj_ptr-inl.h" #include "read_barrier-inl.h" #include "reference.h" @@ -66,14 +67,6 @@ inline void Object::SetClass(ObjPtr<Class> new_klass) { } template<VerifyObjectFlags kVerifyFlags> -inline LockWord Object::GetLockWord(bool as_volatile) { - if (as_volatile) { - return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); - } - return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); -} - -template<VerifyObjectFlags kVerifyFlags> inline void Object::SetLockWord(LockWord new_val, bool as_volatile) { // Force use of non-transactional mode and do not check. if (as_volatile) { @@ -91,24 +84,12 @@ inline bool Object::CasLockWordWeakSequentiallyConsistent(LockWord old_val, Lock OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); } -inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) { - // Force use of non-transactional mode and do not check. - return CasFieldWeakRelaxed32<false, false>( - OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); -} - inline bool Object::CasLockWordWeakAcquire(LockWord old_val, LockWord new_val) { // Force use of non-transactional mode and do not check. return CasFieldWeakAcquire32<false, false>( OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); } -inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) { - // Force use of non-transactional mode and do not check. - return CasFieldWeakRelease32<false, false>( - OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); -} - inline uint32_t Object::GetLockOwnerThreadId() { return Monitor::GetLockOwnerThreadId(this); } @@ -141,84 +122,6 @@ inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) { Monitor::Wait(self, this, ms, ns, true, kTimedWaiting); } -inline uint32_t Object::GetReadBarrierState(uintptr_t* fake_address_dependency) { - if (!kUseBakerReadBarrier) { - LOG(FATAL) << "Unreachable"; - UNREACHABLE(); - } -#if defined(__arm__) - uintptr_t obj = reinterpret_cast<uintptr_t>(this); - uintptr_t result; - DCHECK_EQ(OFFSETOF_MEMBER(Object, monitor_), 4U); - // Use inline assembly to prevent the compiler from optimizing away the false dependency. - __asm__ __volatile__( - "ldr %[result], [%[obj], #4]\n\t" - // This instruction is enough to "fool the compiler and the CPU" by having `fad` always be - // null, without them being able to assume that fact. - "eor %[fad], %[result], %[result]\n\t" - : [result] "+r" (result), [fad] "=r" (*fake_address_dependency) - : [obj] "r" (obj)); - DCHECK_EQ(*fake_address_dependency, 0U); - LockWord lw(static_cast<uint32_t>(result)); - uint32_t rb_state = lw.ReadBarrierState(); - return rb_state; -#elif defined(__aarch64__) - uintptr_t obj = reinterpret_cast<uintptr_t>(this); - uintptr_t result; - DCHECK_EQ(OFFSETOF_MEMBER(Object, monitor_), 4U); - // Use inline assembly to prevent the compiler from optimizing away the false dependency. - __asm__ __volatile__( - "ldr %w[result], [%[obj], #4]\n\t" - // This instruction is enough to "fool the compiler and the CPU" by having `fad` always be - // null, without them being able to assume that fact. - "eor %[fad], %[result], %[result]\n\t" - : [result] "+r" (result), [fad] "=r" (*fake_address_dependency) - : [obj] "r" (obj)); - DCHECK_EQ(*fake_address_dependency, 0U); - LockWord lw(static_cast<uint32_t>(result)); - uint32_t rb_state = lw.ReadBarrierState(); - return rb_state; -#elif defined(__i386__) || defined(__x86_64__) - LockWord lw = GetLockWord(false); - // i386/x86_64 don't need fake address dependency. Use a compiler fence to avoid compiler - // reordering. - *fake_address_dependency = 0; - std::atomic_signal_fence(std::memory_order_acquire); - uint32_t rb_state = lw.ReadBarrierState(); - return rb_state; -#else - // MIPS32/MIPS64: use a memory barrier to prevent load-load reordering. - LockWord lw = GetLockWord(false); - *fake_address_dependency = 0; - std::atomic_thread_fence(std::memory_order_acquire); - uint32_t rb_state = lw.ReadBarrierState(); - return rb_state; -#endif -} - -inline uint32_t Object::GetReadBarrierState() { - if (!kUseBakerReadBarrier) { - LOG(FATAL) << "Unreachable"; - UNREACHABLE(); - } - DCHECK(kUseBakerReadBarrier); - LockWord lw(GetField<uint32_t, /*kIsVolatile*/false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); - uint32_t rb_state = lw.ReadBarrierState(); - DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; - return rb_state; -} - -inline uint32_t Object::GetReadBarrierStateAcquire() { - if (!kUseBakerReadBarrier) { - LOG(FATAL) << "Unreachable"; - UNREACHABLE(); - } - LockWord lw(GetFieldAcquire<uint32_t>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); - uint32_t rb_state = lw.ReadBarrierState(); - DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; - return rb_state; -} - inline uint32_t Object::GetMarkBit() { #ifdef USE_READ_BARRIER return GetLockWord(false).MarkBitState(); @@ -239,54 +142,6 @@ inline void Object::SetReadBarrierState(uint32_t rb_state) { SetLockWord(lw, false); } -template<bool kCasRelease> -inline bool Object::AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state) { - if (!kUseBakerReadBarrier) { - LOG(FATAL) << "Unreachable"; - UNREACHABLE(); - } - DCHECK(ReadBarrier::IsValidReadBarrierState(expected_rb_state)) << expected_rb_state; - DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; - LockWord expected_lw; - LockWord new_lw; - do { - LockWord lw = GetLockWord(false); - if (UNLIKELY(lw.ReadBarrierState() != expected_rb_state)) { - // Lost the race. - return false; - } - expected_lw = lw; - expected_lw.SetReadBarrierState(expected_rb_state); - new_lw = lw; - new_lw.SetReadBarrierState(rb_state); - // ConcurrentCopying::ProcessMarkStackRef uses this with kCasRelease == true. - // If kCasRelease == true, use a CAS release so that when GC updates all the fields of - // an object and then changes the object from gray to black, the field updates (stores) will be - // visible (won't be reordered after this CAS.) - } while (!(kCasRelease ? - CasLockWordWeakRelease(expected_lw, new_lw) : - CasLockWordWeakRelaxed(expected_lw, new_lw))); - return true; -} - -inline bool Object::AtomicSetMarkBit(uint32_t expected_mark_bit, uint32_t mark_bit) { - LockWord expected_lw; - LockWord new_lw; - do { - LockWord lw = GetLockWord(false); - if (UNLIKELY(lw.MarkBitState() != expected_mark_bit)) { - // Lost the race. - return false; - } - expected_lw = lw; - new_lw = lw; - new_lw.SetMarkBitState(mark_bit); - // Since this is only set from the mutator, we can use the non release Cas. - } while (!CasLockWordWeakRelaxed(expected_lw, new_lw)); - return true; -} - - inline void Object::AssertReadBarrierState() const { CHECK(kUseBakerReadBarrier); Object* obj = const_cast<Object*>(this); @@ -727,24 +582,6 @@ inline bool Object::CasFieldWeakSequentiallyConsistent32(MemberOffset field_offs } template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset, - int32_t old_value, int32_t new_value) { - if (kCheckTransaction) { - DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); - } - if (kTransactionActive) { - Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true); - } - if (kVerifyFlags & kVerifyThis) { - VerifyObject(this); - } - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr); - - return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value); -} - -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> inline bool Object::CasFieldWeakAcquire32(MemberOffset field_offset, int32_t old_value, int32_t new_value) { if (kCheckTransaction) { @@ -798,19 +635,6 @@ inline bool Object::CasFieldStrongSequentiallyConsistent32(MemberOffset field_of return atomic_addr->CompareExchangeStrongSequentiallyConsistent(old_value, new_value); } -template<VerifyObjectFlags kVerifyFlags, bool kIsVolatile> -inline int64_t Object::GetField64(MemberOffset field_offset) { - if (kVerifyFlags & kVerifyThis) { - VerifyObject(this); - } - return GetField<int64_t, kIsVolatile>(field_offset); -} - -template<VerifyObjectFlags kVerifyFlags> -inline int64_t Object::GetField64Volatile(MemberOffset field_offset) { - return GetField64<kVerifyFlags, true>(field_offset); -} - template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags, bool kIsVolatile> inline void Object::SetField64(MemberOffset field_offset, int64_t new_value) { @@ -1075,36 +899,6 @@ inline bool Object::CasFieldWeakRelaxedObjectWithoutWriteBarrier( return success; } -template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> -inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier( - MemberOffset field_offset, - ObjPtr<Object> old_value, - ObjPtr<Object> new_value) { - if (kCheckTransaction) { - DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); - } - if (kVerifyFlags & kVerifyThis) { - VerifyObject(this); - } - if (kVerifyFlags & kVerifyWrites) { - VerifyObject(new_value); - } - if (kVerifyFlags & kVerifyReads) { - VerifyObject(old_value); - } - if (kTransactionActive) { - Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); - } - HeapReference<Object> old_ref(HeapReference<Object>::FromObjPtr(old_value)); - HeapReference<Object> new_ref(HeapReference<Object>::FromObjPtr(new_value)); - uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); - Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); - - bool success = atomic_addr->CompareExchangeStrongRelaxed(old_ref.reference_, - new_ref.reference_); - return success; -} - template<bool kIsStatic, VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, @@ -1186,67 +980,6 @@ inline mirror::DexCache* Object::AsDexCache() { return down_cast<mirror::DexCache*>(this); } -template <bool kVisitNativeRoots, - VerifyObjectFlags kVerifyFlags, - ReadBarrierOption kReadBarrierOption, - typename Visitor, - typename JavaLangRefVisitor> -inline void Object::VisitReferences(const Visitor& visitor, - const JavaLangRefVisitor& ref_visitor) { - ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>(); - visitor(this, ClassOffset(), false); - const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>(); - if (LIKELY(class_flags == kClassFlagNormal)) { - DCHECK((!klass->IsVariableSize<kVerifyFlags, kReadBarrierOption>())); - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); - DCHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); - DCHECK(!klass->IsStringClass()); - DCHECK(!klass->IsClassLoaderClass()); - DCHECK((!klass->IsArrayClass<kVerifyFlags, kReadBarrierOption>())); - } else { - if ((class_flags & kClassFlagNoReferenceFields) == 0) { - DCHECK(!klass->IsStringClass()); - if (class_flags == kClassFlagClass) { - DCHECK((klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); - ObjPtr<Class> as_klass = AsClass<kVerifyNone, kReadBarrierOption>(); - as_klass->VisitReferences<kVisitNativeRoots, kVerifyFlags, kReadBarrierOption>(klass, - visitor); - } else if (class_flags == kClassFlagObjectArray) { - DCHECK((klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); - AsObjectArray<mirror::Object, kVerifyNone, kReadBarrierOption>()->VisitReferences(visitor); - } else if ((class_flags & kClassFlagReference) != 0) { - VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); - ref_visitor(klass, AsReference<kVerifyFlags, kReadBarrierOption>()); - } else if (class_flags == kClassFlagDexCache) { - mirror::DexCache* const dex_cache = AsDexCache<kVerifyFlags, kReadBarrierOption>(); - dex_cache->VisitReferences<kVisitNativeRoots, - kVerifyFlags, - kReadBarrierOption>(klass, visitor); - } else { - mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags, kReadBarrierOption>(); - class_loader->VisitReferences<kVisitNativeRoots, - kVerifyFlags, - kReadBarrierOption>(klass, visitor); - } - } else if (kIsDebugBuild) { - CHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); - CHECK((!klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); - // String still has instance fields for reflection purposes but these don't exist in - // actual string instances. - if (!klass->IsStringClass()) { - size_t total_reference_instance_fields = 0; - ObjPtr<Class> super_class = klass; - do { - total_reference_instance_fields += super_class->NumReferenceInstanceFields(); - super_class = super_class->GetSuperClass<kVerifyFlags, kReadBarrierOption>(); - } while (super_class != nullptr); - // The only reference field should be the object's class. This field is handled at the - // beginning of the function. - CHECK_EQ(total_reference_instance_fields, 1u); - } - } - } -} } // namespace mirror } // namespace art diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h new file mode 100644 index 0000000000..58e7c20667 --- /dev/null +++ b/runtime/mirror/object-readbarrier-inl.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_MIRROR_OBJECT_READBARRIER_INL_H_ +#define ART_RUNTIME_MIRROR_OBJECT_READBARRIER_INL_H_ + +#include "object.h" + +#include "atomic.h" +#include "lock_word-inl.h" +#include "object_reference-inl.h" +#include "read_barrier.h" +#include "runtime.h" + +namespace art { +namespace mirror { + +template<VerifyObjectFlags kVerifyFlags> +inline LockWord Object::GetLockWord(bool as_volatile) { + if (as_volatile) { + return LockWord(GetField32Volatile<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); + } + return LockWord(GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline bool Object::CasFieldWeakRelaxed32(MemberOffset field_offset, + int32_t old_value, int32_t new_value) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kTransactionActive) { + Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + AtomicInteger* atomic_addr = reinterpret_cast<AtomicInteger*>(raw_addr); + + return atomic_addr->CompareExchangeWeakRelaxed(old_value, new_value); +} + +inline bool Object::CasLockWordWeakRelaxed(LockWord old_val, LockWord new_val) { + // Force use of non-transactional mode and do not check. + return CasFieldWeakRelaxed32<false, false>( + OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); +} + +inline bool Object::CasLockWordWeakRelease(LockWord old_val, LockWord new_val) { + // Force use of non-transactional mode and do not check. + return CasFieldWeakRelease32<false, false>( + OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(), new_val.GetValue()); +} + +inline uint32_t Object::GetReadBarrierState(uintptr_t* fake_address_dependency) { + if (!kUseBakerReadBarrier) { + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } +#if defined(__arm__) + uintptr_t obj = reinterpret_cast<uintptr_t>(this); + uintptr_t result; + DCHECK_EQ(OFFSETOF_MEMBER(Object, monitor_), 4U); + // Use inline assembly to prevent the compiler from optimizing away the false dependency. + __asm__ __volatile__( + "ldr %[result], [%[obj], #4]\n\t" + // This instruction is enough to "fool the compiler and the CPU" by having `fad` always be + // null, without them being able to assume that fact. + "eor %[fad], %[result], %[result]\n\t" + : [result] "+r" (result), [fad] "=r" (*fake_address_dependency) + : [obj] "r" (obj)); + DCHECK_EQ(*fake_address_dependency, 0U); + LockWord lw(static_cast<uint32_t>(result)); + uint32_t rb_state = lw.ReadBarrierState(); + return rb_state; +#elif defined(__aarch64__) + uintptr_t obj = reinterpret_cast<uintptr_t>(this); + uintptr_t result; + DCHECK_EQ(OFFSETOF_MEMBER(Object, monitor_), 4U); + // Use inline assembly to prevent the compiler from optimizing away the false dependency. + __asm__ __volatile__( + "ldr %w[result], [%[obj], #4]\n\t" + // This instruction is enough to "fool the compiler and the CPU" by having `fad` always be + // null, without them being able to assume that fact. + "eor %[fad], %[result], %[result]\n\t" + : [result] "+r" (result), [fad] "=r" (*fake_address_dependency) + : [obj] "r" (obj)); + DCHECK_EQ(*fake_address_dependency, 0U); + LockWord lw(static_cast<uint32_t>(result)); + uint32_t rb_state = lw.ReadBarrierState(); + return rb_state; +#elif defined(__i386__) || defined(__x86_64__) + LockWord lw = GetLockWord(false); + // i386/x86_64 don't need fake address dependency. Use a compiler fence to avoid compiler + // reordering. + *fake_address_dependency = 0; + std::atomic_signal_fence(std::memory_order_acquire); + uint32_t rb_state = lw.ReadBarrierState(); + return rb_state; +#else + // MIPS32/MIPS64: use a memory barrier to prevent load-load reordering. + LockWord lw = GetLockWord(false); + *fake_address_dependency = 0; + std::atomic_thread_fence(std::memory_order_acquire); + uint32_t rb_state = lw.ReadBarrierState(); + return rb_state; +#endif +} + +inline uint32_t Object::GetReadBarrierState() { + if (!kUseBakerReadBarrier) { + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } + DCHECK(kUseBakerReadBarrier); + LockWord lw(GetField<uint32_t, /*kIsVolatile*/false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); + uint32_t rb_state = lw.ReadBarrierState(); + DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; + return rb_state; +} + +inline uint32_t Object::GetReadBarrierStateAcquire() { + if (!kUseBakerReadBarrier) { + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } + LockWord lw(GetFieldAcquire<uint32_t>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_))); + uint32_t rb_state = lw.ReadBarrierState(); + DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; + return rb_state; +} + +template<bool kCasRelease> +inline bool Object::AtomicSetReadBarrierState(uint32_t expected_rb_state, uint32_t rb_state) { + if (!kUseBakerReadBarrier) { + LOG(FATAL) << "Unreachable"; + UNREACHABLE(); + } + DCHECK(ReadBarrier::IsValidReadBarrierState(expected_rb_state)) << expected_rb_state; + DCHECK(ReadBarrier::IsValidReadBarrierState(rb_state)) << rb_state; + LockWord expected_lw; + LockWord new_lw; + do { + LockWord lw = GetLockWord(false); + if (UNLIKELY(lw.ReadBarrierState() != expected_rb_state)) { + // Lost the race. + return false; + } + expected_lw = lw; + expected_lw.SetReadBarrierState(expected_rb_state); + new_lw = lw; + new_lw.SetReadBarrierState(rb_state); + // ConcurrentCopying::ProcessMarkStackRef uses this with kCasRelease == true. + // If kCasRelease == true, use a CAS release so that when GC updates all the fields of + // an object and then changes the object from gray to black, the field updates (stores) will be + // visible (won't be reordered after this CAS.) + } while (!(kCasRelease ? + CasLockWordWeakRelease(expected_lw, new_lw) : + CasLockWordWeakRelaxed(expected_lw, new_lw))); + return true; +} + +inline bool Object::AtomicSetMarkBit(uint32_t expected_mark_bit, uint32_t mark_bit) { + LockWord expected_lw; + LockWord new_lw; + do { + LockWord lw = GetLockWord(false); + if (UNLIKELY(lw.MarkBitState() != expected_mark_bit)) { + // Lost the race. + return false; + } + expected_lw = lw; + new_lw = lw; + new_lw.SetMarkBitState(mark_bit); + // Since this is only set from the mutator, we can use the non release Cas. + } while (!CasLockWordWeakRelaxed(expected_lw, new_lw)); + return true; +} + +template<bool kTransactionActive, bool kCheckTransaction, VerifyObjectFlags kVerifyFlags> +inline bool Object::CasFieldStrongRelaxedObjectWithoutWriteBarrier( + MemberOffset field_offset, + ObjPtr<Object> old_value, + ObjPtr<Object> new_value) { + if (kCheckTransaction) { + DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction()); + } + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + if (kVerifyFlags & kVerifyWrites) { + VerifyObject(new_value); + } + if (kVerifyFlags & kVerifyReads) { + VerifyObject(old_value); + } + if (kTransactionActive) { + Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true); + } + HeapReference<Object> old_ref(HeapReference<Object>::FromObjPtr(old_value)); + HeapReference<Object> new_ref(HeapReference<Object>::FromObjPtr(new_value)); + uint8_t* raw_addr = reinterpret_cast<uint8_t*>(this) + field_offset.Int32Value(); + Atomic<uint32_t>* atomic_addr = reinterpret_cast<Atomic<uint32_t>*>(raw_addr); + + bool success = atomic_addr->CompareExchangeStrongRelaxed(old_ref.reference_, + new_ref.reference_); + return success; +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_OBJECT_READBARRIER_INL_H_ diff --git a/runtime/mirror/object-refvisitor-inl.h b/runtime/mirror/object-refvisitor-inl.h new file mode 100644 index 0000000000..49ab7c2a53 --- /dev/null +++ b/runtime/mirror/object-refvisitor-inl.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_MIRROR_OBJECT_REFVISITOR_INL_H_ +#define ART_RUNTIME_MIRROR_OBJECT_REFVISITOR_INL_H_ + +#include "object-inl.h" + +#include "class-refvisitor-inl.h" + +namespace art { +namespace mirror { + +template <bool kVisitNativeRoots, + VerifyObjectFlags kVerifyFlags, + ReadBarrierOption kReadBarrierOption, + typename Visitor, + typename JavaLangRefVisitor> +inline void Object::VisitReferences(const Visitor& visitor, + const JavaLangRefVisitor& ref_visitor) { + ObjPtr<Class> klass = GetClass<kVerifyFlags, kReadBarrierOption>(); + visitor(this, ClassOffset(), false); + const uint32_t class_flags = klass->GetClassFlags<kVerifyNone>(); + if (LIKELY(class_flags == kClassFlagNormal)) { + DCHECK((!klass->IsVariableSize<kVerifyFlags, kReadBarrierOption>())); + VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); + DCHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); + DCHECK(!klass->IsStringClass()); + DCHECK(!klass->IsClassLoaderClass()); + DCHECK((!klass->IsArrayClass<kVerifyFlags, kReadBarrierOption>())); + } else { + if ((class_flags & kClassFlagNoReferenceFields) == 0) { + DCHECK(!klass->IsStringClass()); + if (class_flags == kClassFlagClass) { + DCHECK((klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); + ObjPtr<Class> as_klass = AsClass<kVerifyNone, kReadBarrierOption>(); + as_klass->VisitReferences<kVisitNativeRoots, kVerifyFlags, kReadBarrierOption>(klass, + visitor); + } else if (class_flags == kClassFlagObjectArray) { + DCHECK((klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); + AsObjectArray<mirror::Object, kVerifyNone, kReadBarrierOption>()->VisitReferences(visitor); + } else if ((class_flags & kClassFlagReference) != 0) { + VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); + ref_visitor(klass, AsReference<kVerifyFlags, kReadBarrierOption>()); + } else if (class_flags == kClassFlagDexCache) { + mirror::DexCache* const dex_cache = AsDexCache<kVerifyFlags, kReadBarrierOption>(); + dex_cache->VisitReferences<kVisitNativeRoots, + kVerifyFlags, + kReadBarrierOption>(klass, visitor); + } else { + mirror::ClassLoader* const class_loader = AsClassLoader<kVerifyFlags, kReadBarrierOption>(); + class_loader->VisitReferences<kVisitNativeRoots, + kVerifyFlags, + kReadBarrierOption>(klass, visitor); + } + } else if (kIsDebugBuild) { + CHECK((!klass->IsClassClass<kVerifyFlags, kReadBarrierOption>())); + CHECK((!klass->IsObjectArrayClass<kVerifyFlags, kReadBarrierOption>())); + // String still has instance fields for reflection purposes but these don't exist in + // actual string instances. + if (!klass->IsStringClass()) { + size_t total_reference_instance_fields = 0; + ObjPtr<Class> super_class = klass; + do { + total_reference_instance_fields += super_class->NumReferenceInstanceFields(); + super_class = super_class->GetSuperClass<kVerifyFlags, kReadBarrierOption>(); + } while (super_class != nullptr); + // The only reference field should be the object's class. This field is handled at the + // beginning of the function. + CHECK_EQ(total_reference_instance_fields, 1u); + } + } + } +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_OBJECT_REFVISITOR_INL_H_ diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index eabc29adad..6e5fdb773f 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -30,6 +30,7 @@ #include "iftable-inl.h" #include "monitor.h" #include "object-inl.h" +#include "object-refvisitor-inl.h" #include "object_array-inl.h" #include "runtime.h" #include "handle_scope-inl.h" diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 417a22dfe3..35a1b733e1 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -487,11 +487,18 @@ class MANAGED LOCKABLE Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> ALWAYS_INLINE int64_t GetField64(MemberOffset field_offset) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_) { + if (kVerifyFlags & kVerifyThis) { + VerifyObject(this); + } + return GetField<int64_t, kIsVolatile>(field_offset); + } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE int64_t GetField64Volatile(MemberOffset field_offset) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES_SHARED(Locks::mutator_lock_) { + return GetField64<kVerifyFlags, true>(field_offset); + } template<bool kTransactionActive, bool kCheckTransaction = true, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kIsVolatile = false> diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 3e04bf6474..dbec40c6d0 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -24,8 +24,9 @@ #include "android-base/stringprintf.h" #include "array-inl.h" +#include "class.h" #include "gc/heap.h" -#include "mirror/class.h" +#include "object-inl.h" #include "obj_ptr-inl.h" #include "runtime.h" #include "handle_scope-inl.h" diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index d306f9c391..d7527d59b4 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -73,6 +73,13 @@ class ObjectTest : public CommonRuntimeTest { } EXPECT_EQ(expected_hash, string->GetHashCode()); } + + template <class T> + mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length) + REQUIRES_SHARED(Locks::mutator_lock_) { + return mirror::ObjectArray<T>::Alloc( + self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), length); + } }; // Keep constants in sync. @@ -100,8 +107,7 @@ TEST_F(ObjectTest, IsInSamePackage) { TEST_F(ObjectTest, Clone) { ScopedObjectAccess soa(Thread::Current()); StackHandleScope<2> hs(soa.Self()); - Handle<ObjectArray<Object>> a1( - hs.NewHandle(class_linker_->AllocObjectArray<Object>(soa.Self(), 256))); + Handle<ObjectArray<Object>> a1(hs.NewHandle(AllocObjectArray<Object>(soa.Self(), 256))); size_t s1 = a1->SizeOf(); Object* clone = a1->Clone(soa.Self()); EXPECT_EQ(s1, clone->SizeOf()); @@ -111,8 +117,7 @@ TEST_F(ObjectTest, Clone) { TEST_F(ObjectTest, AllocObjectArray) { ScopedObjectAccess soa(Thread::Current()); StackHandleScope<2> hs(soa.Self()); - Handle<ObjectArray<Object>> oa( - hs.NewHandle(class_linker_->AllocObjectArray<Object>(soa.Self(), 2))); + Handle<ObjectArray<Object>> oa(hs.NewHandle(AllocObjectArray<Object>(soa.Self(), 2))); EXPECT_EQ(2, oa->GetLength()); EXPECT_TRUE(oa->Get(0) == nullptr); EXPECT_TRUE(oa->Get(1) == nullptr); diff --git a/runtime/monitor.cc b/runtime/monitor.cc index f3cb0df80e..e365b42670 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -31,7 +31,6 @@ #include "lock_word-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "thread_list.h" diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 0e61cf64f9..0617dae1ae 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -254,10 +254,11 @@ static jobject DexFile_createCookieWithArray(JNIEnv* env, return CreateSingleDexFileCookie(env, std::move(dex_mem_map)); } +// TODO(calin): clean up the unused parameters (here and in libcore). static jobject DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceName, - jstring javaOutputName, + jstring javaOutputName ATTRIBUTE_UNUSED, jint flags ATTRIBUTE_UNUSED, jobject class_loader, jobjectArray dex_elements) { @@ -265,10 +266,7 @@ static jobject DexFile_openDexFileNative(JNIEnv* env, if (sourceName.c_str() == nullptr) { return 0; } - NullableScopedUtfChars outputName(env, javaOutputName); - if (env->ExceptionCheck()) { - return 0; - } + Runtime* const runtime = Runtime::Current(); ClassLinker* linker = runtime->GetClassLinker(); std::vector<std::unique_ptr<const DexFile>> dex_files; @@ -276,7 +274,6 @@ static jobject DexFile_openDexFileNative(JNIEnv* env, const OatFile* oat_file = nullptr; dex_files = runtime->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), - outputName.c_str(), class_loader, dex_elements, /*out*/ &oat_file, diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index f6a73a8660..5c4e242e4d 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -31,9 +31,12 @@ #include "gc/space/large_object_space.h" #include "gc/space/space-inl.h" #include "gc/space/zygote_space.h" +#include "handle_scope-inl.h" #include "hprof/hprof.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mirror/class.h" +#include "mirror/object_array-inl.h" #include "ScopedLocalRef.h" #include "ScopedUtfChars.h" #include "scoped_fast_native_object_access-inl.h" diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 34bbf32a9a..ff4d93109e 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -46,6 +46,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #include "gc/space/image_space.h" #include "gc/task_processor.h" #include "intern_table.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 836ba81d8e..2eaa8c71b1 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -21,6 +21,7 @@ #include "android-base/stringprintf.h" #include "arch/instruction_set.h" +#include "art_method-inl.h" #include "debugger.h" #include "java_vm_ext.h" #include "jit/jit.h" diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 381dc7beb0..4f999471c6 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -19,8 +19,9 @@ #include <iostream> #include "art_field-inl.h" +#include "art_method-inl.h" #include "base/enums.h" -#include "class_linker.h" +#include "class_linker-inl.h" #include "common_throws.h" #include "dex_file-inl.h" #include "dex_file_annotations.h" diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 54ab8615c0..a9ba33ecc1 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -23,6 +23,7 @@ #include "obj_ptr.h" #include "scoped_fast_native_object_access-inl.h" #include "ScopedUtfChars.h" +#include "well_known_classes.h" #include "zip_archive.h" namespace art { diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc index 96bfd1b4fb..e2b4b82cfb 100644 --- a/runtime/native/java_lang_Void.cc +++ b/runtime/native/java_lang_Void.cc @@ -16,7 +16,7 @@ #include "java_lang_Void.h" -#include "class_linker.h" +#include "class_linker-inl.h" #include "jni_internal.h" #include "runtime.h" #include "scoped_fast_native_object_access-inl.h" diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 9198964f87..0fb3903641 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -18,6 +18,7 @@ #include "android-base/stringprintf.h" +#include "art_field-inl.h" #include "class_linker.h" #include "class_linker-inl.h" #include "common_throws.h" @@ -29,6 +30,7 @@ #include "reflection-inl.h" #include "scoped_fast_native_object_access-inl.h" #include "utils.h" +#include "well_known_classes.h" namespace art { diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h index 50a554c930..b2abc4691a 100644 --- a/runtime/native/scoped_fast_native_object_access-inl.h +++ b/runtime/native/scoped_fast_native_object_access-inl.h @@ -19,7 +19,7 @@ #include "scoped_fast_native_object_access.h" -#include "art_method-inl.h" +#include "art_method.h" #include "scoped_thread_state_change-inl.h" namespace art { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index a00674a9fe..4a85d4795e 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -34,7 +34,7 @@ #include "android-base/stringprintf.h" -#include "art_method-inl.h" +#include "art_method.h" #include "base/bit_vector.h" #include "base/enums.h" #include "base/stl_util.h" diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index db6f8ee488..a7be73a849 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -20,6 +20,7 @@ #include <sys/stat.h> +#include "android-base/stringprintf.h" #include "android-base/strings.h" #include "base/logging.h" diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 9b35489330..4a738ab0a3 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -897,7 +897,6 @@ class RaceGenerateTask : public Task { const OatFile* oat_file = nullptr; dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat( dex_location_.c_str(), - oat_location_.c_str(), /*class_loader*/nullptr, /*dex_elements*/nullptr, &oat_file, diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 139022210c..6799918534 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -615,7 +615,6 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file, std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const char* dex_location, - const char* oat_location, jobject class_loader, jobjectArray dex_elements, const OatFile** out_oat_file, @@ -630,8 +629,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( Locks::mutator_lock_->AssertNotHeld(self); Runtime* const runtime = Runtime::Current(); + // TODO(calin): remove the explicit oat_location for OatFileAssistant OatFileAssistant oat_file_assistant(dex_location, - oat_location, + /*oat_location*/ nullptr, kRuntimeISA, !runtime->IsAotCompiler()); diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index 45ac4b79e7..05a5f5b7b9 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -96,7 +96,6 @@ class OatFileManager { // files. std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat( const char* dex_location, - const char* oat_location, jobject class_loader, jobjectArray dex_elements, /*out*/ const OatFile** out_oat_file, diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc index bdaad20d7e..0b93b079d5 100644 --- a/runtime/openjdkjvm/OpenjdkJvm.cc +++ b/runtime/openjdkjvm/OpenjdkJvm.cc @@ -35,28 +35,31 @@ #include<stdio.h> #include <dlfcn.h> #include <limits.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> #include <unistd.h> +#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it + +#include "base/logging.h" +#include "base/macros.h" #include "common_throws.h" #include "gc/heap.h" -#include "thread.h" -#include "thread_list.h" -#include "runtime.h" #include "handle_scope-inl.h" -#include "scoped_thread_state_change-inl.h" -#include "ScopedUtfChars.h" -#include "mirror/class_loader.h" -#include "verify_object.h" -#include "base/logging.h" -#include "base/macros.h" -#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it +#include "java_vm_ext.h" #include "jni_internal.h" +#include "mirror/class_loader.h" #include "mirror/string-inl.h" +#include "monitor.h" #include "native/scoped_fast_native_object_access-inl.h" +#include "runtime.h" +#include "thread.h" +#include "thread_list.h" +#include "scoped_thread_state_change-inl.h" #include "ScopedLocalRef.h" -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/ioctl.h> +#include "ScopedUtfChars.h" +#include "verify_object.h" #undef LOG_TAG #define LOG_TAG "artopenjdk" diff --git a/runtime/openjdkjvmti/events.cc b/runtime/openjdkjvmti/events.cc index 521494a856..0ec92b7c60 100644 --- a/runtime/openjdkjvmti/events.cc +++ b/runtime/openjdkjvmti/events.cc @@ -36,10 +36,11 @@ #include "gc/allocation_listener.h" #include "gc/gc_pause_listener.h" #include "gc/heap.h" +#include "handle_scope-inl.h" #include "instrumentation.h" #include "jni_env_ext-inl.h" #include "mirror/class.h" -#include "mirror/object.h" +#include "mirror/object-inl.h" #include "runtime.h" #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc index e94c4e6112..e0af6e8dee 100644 --- a/runtime/openjdkjvmti/ti_class.cc +++ b/runtime/openjdkjvmti/ti_class.cc @@ -55,6 +55,7 @@ #include "mirror/object_array-inl.h" #include "mirror/object_reference.h" #include "mirror/object-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/reference.h" #include "primitive.h" #include "reflection.h" @@ -68,6 +69,7 @@ #include "ti_phase.h" #include "ti_redefine.h" #include "utils.h" +#include "well_known_classes.h" namespace openjdkjvmti { diff --git a/runtime/openjdkjvmti/ti_class_definition.cc b/runtime/openjdkjvmti/ti_class_definition.cc index 0671105532..180895b597 100644 --- a/runtime/openjdkjvmti/ti_class_definition.cc +++ b/runtime/openjdkjvmti/ti_class_definition.cc @@ -32,10 +32,12 @@ #include "ti_class_definition.h" #include "base/array_slice.h" +#include "class_linker-inl.h" #include "dex_file.h" #include "fixed_up_dex_file.h" #include "handle_scope-inl.h" #include "handle.h" +#include "mirror/class_ext.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "reflection.h" diff --git a/runtime/openjdkjvmti/ti_class_loader.cc b/runtime/openjdkjvmti/ti_class_loader.cc index 66357eb32f..5544dde219 100644 --- a/runtime/openjdkjvmti/ti_class_loader.cc +++ b/runtime/openjdkjvmti/ti_class_loader.cc @@ -35,6 +35,7 @@ #include "android-base/stringprintf.h" +#include "art_field-inl.h" #include "art_jvmti.h" #include "base/array_slice.h" #include "base/logging.h" diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc index 358bb0f70e..41ed86237f 100644 --- a/runtime/openjdkjvmti/ti_redefine.cc +++ b/runtime/openjdkjvmti/ti_redefine.cc @@ -35,9 +35,12 @@ #include "android-base/stringprintf.h" +#include "art_field-inl.h" +#include "art_method-inl.h" #include "art_jvmti.h" #include "base/array_slice.h" #include "base/logging.h" +#include "class_linker-inl.h" #include "debugger.h" #include "dex_file.h" #include "dex_file_types.h" diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc index f51a98f976..ec139f2004 100644 --- a/runtime/openjdkjvmti/ti_search.cc +++ b/runtime/openjdkjvmti/ti_search.cc @@ -33,6 +33,7 @@ #include "jni.h" +#include "art_field-inl.h" #include "art_jvmti.h" #include "base/enums.h" #include "base/macros.h" @@ -50,6 +51,7 @@ #include "ti_phase.h" #include "thread-inl.h" #include "thread_list.h" +#include "well_known_classes.h" namespace openjdkjvmti { diff --git a/runtime/openjdkjvmti/ti_stack.cc b/runtime/openjdkjvmti/ti_stack.cc index 067c7c153d..1ddf04feb4 100644 --- a/runtime/openjdkjvmti/ti_stack.cc +++ b/runtime/openjdkjvmti/ti_stack.cc @@ -36,8 +36,9 @@ #include <unordered_map> #include <vector> -#include "art_jvmti.h" +#include "art_field-inl.h" #include "art_method-inl.h" +#include "art_jvmti.h" #include "base/bit_utils.h" #include "base/enums.h" #include "base/mutex.h" @@ -54,6 +55,7 @@ #include "thread-inl.h" #include "thread_list.h" #include "thread_pool.h" +#include "well_known_classes.h" namespace openjdkjvmti { diff --git a/runtime/openjdkjvmti/ti_thread.cc b/runtime/openjdkjvmti/ti_thread.cc index e5ff090ddf..3dfa63313d 100644 --- a/runtime/openjdkjvmti/ti_thread.cc +++ b/runtime/openjdkjvmti/ti_thread.cc @@ -32,7 +32,7 @@ #include "ti_thread.h" #include "android-base/strings.h" -#include "art_field.h" +#include "art_field-inl.h" #include "art_jvmti.h" #include "base/logging.h" #include "base/mutex.h" diff --git a/runtime/openjdkjvmti/ti_threadgroup.cc b/runtime/openjdkjvmti/ti_threadgroup.cc index df14333314..dd7be113d6 100644 --- a/runtime/openjdkjvmti/ti_threadgroup.cc +++ b/runtime/openjdkjvmti/ti_threadgroup.cc @@ -31,7 +31,7 @@ #include "ti_threadgroup.h" -#include "art_field.h" +#include "art_field-inl.h" #include "art_jvmti.h" #include "base/logging.h" #include "base/macros.h" diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 5748475163..4e95b019b9 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -21,6 +21,7 @@ #include "base/enums.h" #include "class_linker-inl.h" #include "common_compiler_test.h" +#include "mirror/class-inl.h" #include "mirror/field-inl.h" #include "mirror/method.h" #include "scoped_thread_state_change-inl.h" diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h index c102fb0aa4..d3859b0dfa 100644 --- a/runtime/read_barrier-inl.h +++ b/runtime/read_barrier-inl.h @@ -22,6 +22,7 @@ #include "gc/collector/concurrent_copying-inl.h" #include "gc/heap.h" #include "mirror/object_reference.h" +#include "mirror/object-readbarrier-inl.h" #include "mirror/reference.h" #include "runtime.h" #include "utils.h" diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 4ccfb6d83b..e809ecf1f6 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -18,6 +18,7 @@ #include "android-base/stringprintf.h" +#include "art_method-inl.h" #include "class_linker.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 87bc7df214..e16ef1d77c 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -23,6 +23,7 @@ #include "common_throws.h" #include "dex_file-inl.h" #include "indirect_reference_table-inl.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mirror/class-inl.h" #include "mirror/executable.h" diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc index 2f70ded8eb..1ba4b7b9d1 100644 --- a/runtime/reflection_test.cc +++ b/runtime/reflection_test.cc @@ -23,6 +23,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "common_compiler_test.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "scoped_thread_state_change-inl.h" diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h index 8346550c93..75c25dd21d 100644 --- a/runtime/runtime-inl.h +++ b/runtime/runtime-inl.h @@ -21,6 +21,7 @@ #include "art_method.h" #include "class_linker.h" +#include "gc_root-inl.h" #include "obj_ptr-inl.h" #include "read_barrier-inl.h" diff --git a/runtime/runtime.cc b/runtime/runtime.cc index a48a58d235..93b416ce72 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -83,6 +83,7 @@ #include "instrumentation.h" #include "intern_table.h" #include "interpreter/interpreter.h" +#include "java_vm_ext.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jni_internal.h" diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h index c817a9ee8d..ed6e349de4 100644 --- a/runtime/scoped_thread_state_change-inl.h +++ b/runtime/scoped_thread_state_change-inl.h @@ -19,6 +19,7 @@ #include "scoped_thread_state_change.h" +#include "base/casts.h" #include "jni_env_ext-inl.h" #include "obj_ptr-inl.h" #include "thread-inl.h" @@ -74,8 +75,10 @@ inline ScopedThreadStateChange::~ScopedThreadStateChange() { template<typename T> inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(ObjPtr<mirror::Object> obj) const { Locks::mutator_lock_->AssertSharedHeld(Self()); - DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. - DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal()); + if (kIsDebugBuild) { + CHECK(IsRunnable()); // Don't work with raw objects in non-runnable states. + DCheckObjIsNotClearedJniWeakGlobal(obj); + } return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj); } diff --git a/runtime/scoped_thread_state_change.cc b/runtime/scoped_thread_state_change.cc new file mode 100644 index 0000000000..94354fc586 --- /dev/null +++ b/runtime/scoped_thread_state_change.cc @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "scoped_thread_state_change.h" + +#include <type_traits> + +#include "base/casts.h" +#include "base/logging.h" +#include "java_vm_ext.h" +#include "obj_ptr-inl.h" +#include "runtime-inl.h" + +namespace art { + +// See ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JavaVM*). +static_assert(std::is_base_of<JavaVM, JavaVMExt>::value, "JavaVMExt does not extend JavaVM"); + +void ScopedObjectAccessAlreadyRunnable::DCheckObjIsNotClearedJniWeakGlobal( + ObjPtr<mirror::Object> obj) { + DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal()); +} + +bool ScopedObjectAccessAlreadyRunnable::ForceCopy() const { + return vm_->ForceCopy(); +} + +} // namespace art diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h index 5f03741d1f..02b6124118 100644 --- a/runtime/scoped_thread_state_change.h +++ b/runtime/scoped_thread_state_change.h @@ -17,17 +17,23 @@ #ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ #define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ -#include "art_field.h" -#include "base/casts.h" +#include "jni.h" + +#include "base/macros.h" +#include "base/mutex.h" #include "base/value_object.h" -#include "java_vm_ext.h" #include "thread_state.h" -#include "verify_object.h" namespace art { +class JavaVMExt; struct JNIEnvExt; template<class MirrorType> class ObjPtr; +class Thread; + +namespace mirror { +class Object; +} // namespace mirror // Scoped change into and out of a particular state. Handles Runnable transitions that require // more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and @@ -74,9 +80,7 @@ class ScopedObjectAccessAlreadyRunnable : public ValueObject { return vm_; } - bool ForceCopy() const { - return vm_->ForceCopy(); - } + bool ForceCopy() const; /* * Add a local reference for an object to the indirect reference table associated with the @@ -105,12 +109,17 @@ class ScopedObjectAccessAlreadyRunnable : public ValueObject { // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't // change into Runnable or acquire a share on the mutator_lock_. + // Note: The reinterpret_cast is backed by a static_assert in the cc file. Avoid a down_cast, + // as it prevents forward declaration of JavaVMExt. explicit ScopedObjectAccessAlreadyRunnable(JavaVM* vm) - : self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {} + : self_(nullptr), env_(nullptr), vm_(reinterpret_cast<JavaVMExt*>(vm)) {} // Here purely to force inlining. ALWAYS_INLINE ~ScopedObjectAccessAlreadyRunnable() {} + static void DCheckObjIsNotClearedJniWeakGlobal(ObjPtr<mirror::Object> obj) + REQUIRES_SHARED(Locks::mutator_lock_); + // Self thread, can be null. Thread* const self_; // The full JNIEnv. diff --git a/runtime/thread.cc b/runtime/thread.cc index f887aaa256..201701a510 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -56,6 +56,7 @@ #include "gc/space/space-inl.h" #include "handle_scope-inl.h" #include "indirect_reference_table-inl.h" +#include "java_vm_ext.h" #include "jni_internal.h" #include "mirror/class_loader.h" #include "mirror/class-inl.h" diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 38d151bc67..e1c6af4f71 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3732,7 +3732,7 @@ const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_i self_->ClearException(); } const RegType* result = nullptr; - if (klass != nullptr && !klass->IsErroneous()) { + if (klass != nullptr) { bool precise = klass->CannotBeAssignedFromOtherTypes(); if (precise && !IsInstantiableOrPrimitive(klass)) { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); @@ -4137,6 +4137,12 @@ void MethodVerifier::VerifyInvocationArgsUnresolvedMethod(const Instruction* ins } bool MethodVerifier::CheckCallSite(uint32_t call_site_idx) { + if (call_site_idx >= dex_file_->NumCallSiteIds()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Bad call site id #" << call_site_idx + << " >= " << dex_file_->NumCallSiteIds(); + return false; + } + CallSiteArrayValueIterator it(*dex_file_, dex_file_->GetCallSiteId(call_site_idx)); // Check essential arguments are provided. The dex file verifier has verified indicies of the // main values (method handle, name, method_type). @@ -4147,9 +4153,11 @@ bool MethodVerifier::CheckCallSite(uint32_t call_site_idx) { return false; } - // Get and check the first argument: the method handle. + // Get and check the first argument: the method handle (index range + // checked by the dex file verifier). uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i); it.Next(); + const DexFile::MethodHandleItem& mh = dex_file_->GetMethodHandle(method_handle_idx); if (mh.method_handle_type_ != static_cast<uint16_t>(DexFile::MethodHandleType::kInvokeStatic)) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Call site #" << call_site_idx diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index be5c18b9eb..bdb6b6879d 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -23,7 +23,7 @@ #include "class_linker-inl.h" #include "common_runtime_test.h" -#include "dex_file.h" +#include "dex_file-inl.h" #include "scoped_thread_state_change-inl.h" #include "utils.h" #include "verifier_log_mode.h" diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index 55e793527e..0497a6d6d1 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -18,8 +18,11 @@ #include <cstring> +#include "art_field-inl.h" +#include "art_method-inl.h" #include "base/stl_util.h" #include "compiler_callbacks.h" +#include "dex_file-inl.h" #include "leb128.h" #include "mirror/class-inl.h" #include "obj_ptr-inl.h" diff --git a/test/161-final-abstract-class/expected.txt b/test/161-final-abstract-class/expected.txt new file mode 100644 index 0000000000..1e635844cc --- /dev/null +++ b/test/161-final-abstract-class/expected.txt @@ -0,0 +1 @@ +java.lang.InstantiationError: AbstractFinal diff --git a/test/161-final-abstract-class/info.txt b/test/161-final-abstract-class/info.txt new file mode 100644 index 0000000000..2b7bee7a51 --- /dev/null +++ b/test/161-final-abstract-class/info.txt @@ -0,0 +1 @@ +Regression test for verifier crash when processing a final abstract (erroneous) class. diff --git a/test/161-final-abstract-class/smali/AbstractFinal.smali b/test/161-final-abstract-class/smali/AbstractFinal.smali new file mode 100644 index 0000000000..796fc40760 --- /dev/null +++ b/test/161-final-abstract-class/smali/AbstractFinal.smali @@ -0,0 +1,16 @@ +# Copyright (C) 2017 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. + +.class abstract final LAbstractFinal; +.super Ljava/lang/Object; diff --git a/test/161-final-abstract-class/smali/TestClass.smali b/test/161-final-abstract-class/smali/TestClass.smali new file mode 100644 index 0000000000..fa38f59854 --- /dev/null +++ b/test/161-final-abstract-class/smali/TestClass.smali @@ -0,0 +1,22 @@ +# Copyright (C) 2017 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. + +.class LTestClass; +.super Ljava/lang/Object; + +.method public static test()V + .registers 1 + new-instance v0, LAbstractFinal; + return-void +.end method diff --git a/test/161-final-abstract-class/src/Main.java b/test/161-final-abstract-class/src/Main.java new file mode 100644 index 0000000000..2452490226 --- /dev/null +++ b/test/161-final-abstract-class/src/Main.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class Main { + public static void main(String[] args) { + try { + // Make sure that the abstract final class is marked as erroneous. + Class.forName("AbstractFinal"); + System.out.println("UNREACHABLE!"); + } catch (VerifyError expected) { + } catch (Throwable t) { + t.printStackTrace(System.out); + } + try { + // Verification of TestClass.test() used to crash when processing + // the final abstract (erroneous) class. + Class<?> tc = Class.forName("TestClass"); + Method test = tc.getDeclaredMethod("test"); + test.invoke(null); + System.out.println("UNREACHABLE!"); + } catch (InvocationTargetException ite) { + if (ite.getCause() instanceof InstantiationError) { + System.out.println( + ite.getCause().getClass().getName() + ": " + ite.getCause().getMessage()); + } else { + ite.printStackTrace(System.out); + } + } catch (Throwable t) { + t.printStackTrace(System.out); + } + } +} diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc index 6c73d7d9b6..9ba05bc706 100644 --- a/test/497-inlining-and-class-loader/clear_dex_cache.cc +++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc @@ -14,9 +14,12 @@ * limitations under the License. */ -#include "art_method-inl.h" +#include "art_method.h" #include "base/enums.h" #include "jni.h" +#include "mirror/array-inl.h" +#include "mirror/class-inl.h" +#include "mirror/dex_cache-inl.h" #include "scoped_thread_state_change-inl.h" #include "stack.h" #include "thread.h" diff --git a/test/900-hello-plugin/load_unload.cc b/test/900-hello-plugin/load_unload.cc index 290997aa08..19312b4d71 100644 --- a/test/900-hello-plugin/load_unload.cc +++ b/test/900-hello-plugin/load_unload.cc @@ -20,6 +20,8 @@ #include "art_method-inl.h" #include "base/logging.h" #include "base/macros.h" +#include "java_vm_ext.h" +#include "runtime.h" namespace art { diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt index 2318414010..fb5f71bda2 100644 --- a/test/911-get-stack-trace/expected.txt +++ b/test/911-get-stack-trace/expected.txt @@ -4,7 +4,7 @@ From top --------- getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2 - print (Ljava/lang/Thread;II)V 0 36 + print (Ljava/lang/Thread;II)V 0 38 printOrWait (IILart/ControlData;)V 6 41 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -22,10 +22,9 @@ From top bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 doTest ()V 38 25 - run ()V 20 26 - main ([Ljava/lang/String;)V 0 19 + run ()V 0 30 --------- - print (Ljava/lang/Thread;II)V 0 36 + print (Ljava/lang/Thread;II)V 0 38 printOrWait (IILart/ControlData;)V 6 41 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -43,11 +42,10 @@ From top bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 doTest ()V 42 26 - run ()V 20 26 - main ([Ljava/lang/String;)V 0 19 + run ()V 0 30 --------- getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2 - print (Ljava/lang/Thread;II)V 0 36 + print (Ljava/lang/Thread;II)V 0 38 printOrWait (IILart/ControlData;)V 6 41 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -59,19 +57,19 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 From bottom --------- - main ([Ljava/lang/String;)V 0 19 + run ()V 0 30 --------- + baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 doTest ()V 65 32 - run ()V 20 26 - main ([Ljava/lang/String;)V 0 19 + run ()V 0 30 --------- + bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - doTest ()V 69 33 ################################ ### Other thread (suspended) ### @@ -258,9 +256,12 @@ ReferenceQueueDaemon Signal Catcher --------- -main +Test911 --------- +main +<not printed> +--------- AllTraces Thread 0 wait ()V -1 -2 printOrWait (IILart/ControlData;)V 24 47 @@ -356,14 +357,16 @@ ReferenceQueueDaemon Signal Catcher --------- -main +Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 doTest ()V 128 59 - run ()V 44 38 - main ([Ljava/lang/String;)V 0 19 + run ()V 24 42 --------- +main +<not printed> +--------- AllTraces Thread 0 wait ()V -1 -2 printOrWait (IILart/ControlData;)V 24 47 @@ -589,18 +592,23 @@ ReferenceQueueDaemon Signal Catcher --------- -main +Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 doTest ()V 133 61 - run ()V 44 38 - main ([Ljava/lang/String;)V 0 19 + run ()V 24 42 +--------- +main +<not printed> ######################################## ### Other select threads (suspended) ### ######################################## --------- +Test911 + +--------- ThreadListTraces Thread 0 --------- @@ -616,7 +624,11 @@ ThreadListTraces Thread 6 ThreadListTraces Thread 8 --------- -main +Test911 + getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 + printList ([Ljava/lang/Thread;I)V 0 68 + doTest ()V 116 54 + run ()V 32 46 --------- ThreadListTraces Thread 0 @@ -659,12 +671,11 @@ ThreadListTraces Thread 8 foo (IIILart/ControlData;)I 0 21 --------- -main +Test911 getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 116 54 - run ()V 52 42 - main ([Ljava/lang/String;)V 0 19 + doTest ()V 121 56 + run ()V 32 46 --------- ThreadListTraces Thread 0 @@ -771,25 +782,16 @@ ThreadListTraces Thread 8 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 ---------- -main - getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 - printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 121 56 - run ()V 52 42 - main ([Ljava/lang/String;)V 0 19 - ################### ### Same thread ### ################### -5 +4 JVMTI_ERROR_ILLEGAL_ARGUMENT [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff] [public static void art.Frames.doTestSameThread(), 38] [public static void art.Frames.doTest() throws java.lang.Exception, 0] -[public static void art.Test911.run() throws java.lang.Exception, 3c] -[public static void Main.main(java.lang.String[]) throws java.lang.Exception, 0] +[public void art.Test911$1.run(), 28] JVMTI_ERROR_NO_MORE_FRAMES ################################ diff --git a/test/911-get-stack-trace/src/art/PrintThread.java b/test/911-get-stack-trace/src/art/PrintThread.java index de1da9c8a6..f50a66b963 100644 --- a/test/911-get-stack-trace/src/art/PrintThread.java +++ b/test/911-get-stack-trace/src/art/PrintThread.java @@ -19,6 +19,8 @@ package art; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class PrintThread { public static void print(String[][] stack) { @@ -36,6 +38,20 @@ public class PrintThread { print(getStackTrace(t, start, max)); } + // We have to ignore some threads when printing all stack traces. These are threads that may or + // may not exist depending on the environment. + public final static String IGNORE_THREAD_NAME_REGEX = + "Binder:|RenderThread|hwuiTask|Jit thread pool worker|Instr:|JDWP|Profile Saver|main"; + public final static Matcher IGNORE_THREADS = + Pattern.compile(IGNORE_THREAD_NAME_REGEX).matcher(""); + + // We have to skip the stack of some threads when printing all stack traces. These are threads + // that may have a different call stack (e.g., when run as an app), or may be in a + // non-deterministic state. + public final static String CUT_STACK_THREAD_NAME_REGEX = "Daemon|main"; + public final static Matcher CUT_STACK_THREADS = + Pattern.compile(CUT_STACK_THREAD_NAME_REGEX).matcher(""); + public static void printAll(Object[][] stacks) { List<String> stringified = new ArrayList<String>(stacks.length); @@ -43,11 +59,11 @@ public class PrintThread { Thread t = (Thread)stackInfo[0]; String name = (t != null) ? t.getName() : "null"; String stackSerialization; - if (name.contains("Daemon")) { + if (CUT_STACK_THREADS.reset(name).find()) { // Do not print daemon stacks, as they're non-deterministic. stackSerialization = "<not printed>"; - } else if (name.startsWith("Jit thread pool worker")) { - // Skip JIT thread pool. It may or may not be there depending on configuration. + } else if (IGNORE_THREADS.reset(name).find()) { + // Skip IGNORE_THREADS. continue; } else { StringBuilder sb = new StringBuilder(); diff --git a/test/911-get-stack-trace/src/art/Test911.java b/test/911-get-stack-trace/src/art/Test911.java index 71a5196c22..ee5936823b 100644 --- a/test/911-get-stack-trace/src/art/Test911.java +++ b/test/911-get-stack-trace/src/art/Test911.java @@ -23,27 +23,38 @@ public class Test911 { Main.bindAgentJNIForClass(PrintThread.class); Main.bindAgentJNIForClass(ThreadListTraces.class); - SameThread.doTest(); + Thread t = new Thread("Test911") { + @Override + public void run() { + try { + SameThread.doTest(); - System.out.println(); + System.out.println(); - OtherThread.doTestOtherThreadWait(); + OtherThread.doTestOtherThreadWait(); - System.out.println(); + System.out.println(); - OtherThread.doTestOtherThreadBusyLoop(); + OtherThread.doTestOtherThreadBusyLoop(); - System.out.println(); + System.out.println(); - AllTraces.doTest(); + AllTraces.doTest(); - System.out.println(); + System.out.println(); - ThreadListTraces.doTest(); + ThreadListTraces.doTest(); - System.out.println(); + System.out.println(); - Frames.doTest(); + Frames.doTest(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }; + t.start(); + t.join(); System.out.println("Done"); } diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index c7a57cefb6..b683a27728 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -16,12 +16,14 @@ #include "jni.h" +#include "art_method-inl.h" #include "base/enums.h" #include "base/logging.h" #include "dex_file-inl.h" #include "instrumentation.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" +#include "jit/profiling_info.h" #include "mirror/class-inl.h" #include "oat_quick_method_header.h" #include "runtime.h" diff --git a/test/testrunner/run_build_test_target.py b/test/testrunner/run_build_test_target.py index 0ab50afa40..b1274c901a 100755 --- a/test/testrunner/run_build_test_target.py +++ b/test/testrunner/run_build_test_target.py @@ -62,7 +62,7 @@ custom_env['SOONG_ALLOW_MISSING_DEPENDENCIES'] = 'true' print custom_env os.environ.update(custom_env) -if target.get('make'): +if target.has_key('make'): build_command = 'make' build_command += ' -j' + str(n_threads) build_command += ' -C ' + env.ANDROID_BUILD_TOP @@ -74,7 +74,7 @@ if target.get('make'): if subprocess.call(build_command.split()): sys.exit(1) -if target.get('golem'): +if target.has_key('golem'): machine_type = target.get('golem') # use art-opt-cc by default since it mimics the default preopt config. default_golem_config = 'art-opt-cc' @@ -92,7 +92,7 @@ if target.get('golem'): if subprocess.call(cmd): sys.exit(1) -if target.get('run-test'): +if target.has_key('run-test'): run_test_command = [os.path.join(env.ANDROID_BUILD_TOP, 'art/test/testrunner/testrunner.py')] run_test_command += target.get('run-test', []) diff --git a/test/valgrind-suppressions.txt b/test/valgrind-suppressions.txt index c775f98b70..086a856f51 100644 --- a/test/valgrind-suppressions.txt +++ b/test/valgrind-suppressions.txt @@ -69,3 +69,9 @@ fun:_ZN12BacktraceMap6CreateEib } +{ + process_vm_readv + Memcheck:Param + process_vm_readv(lvec[...]) + fun:process_vm_readv +} diff --git a/test/valgrind-target-suppressions.txt b/test/valgrind-target-suppressions.txt index 452a17412a..0d63a1c7aa 100644 --- a/test/valgrind-target-suppressions.txt +++ b/test/valgrind-target-suppressions.txt @@ -67,3 +67,10 @@ fun:msync fun:_ZN3art6MemMap11MapInternalEPvmiiilb } + +{ + process_vm_readv + Memcheck:Param + process_vm_readv(lvec[...]) + fun:process_vm_readv +} diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index 07c300e7a7..720b1d2f5d 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -108,6 +108,17 @@ while true; do fi done +# The JDWP tests include a class with a SourceDebugExtension attribute. Convert this class into +# a DEX so the JDWP SourceDebugExtension can be tested. There is no corresponding java file as by +# definition the class file is generated from a different language. +jsr45_dex=$ANDROID_HOST_OUT/jsr45-test.dex +(cd $ANDROID_BUILD_TOP/external/apache-harmony/jdwp/src/test/resources && + dx --dex --output=$jsr45_dex org/apache/harmony/jpda/tests/jdwp/Events/SourceDebugExtensionMockClass.class ) +if [ $? -ne 0 ]; then + echo Failed to convert class file to DEX. >&2 + exit 1 +fi + # For the host: # # If, on the other hand, there is a variant set, use it to modify the art_debugee parameter to @@ -160,7 +171,7 @@ vogar $vm_command \ --vm-arg -Djpda.settings.waitingTime=$jdwp_test_timeout \ --vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \ --vm-arg -Djpda.settings.debuggeeJavaPath="$art_debugee $image $debuggee_args" \ - --classpath $test_jack \ + --classpath $test_jack --resource-classpath $jsr45_dex \ --toolchain jack --language JN \ --vm-arg -Xcompiler-option --vm-arg --debuggable \ --jack-arg -g \ |