diff options
191 files changed, 4699 insertions, 3404 deletions
diff --git a/Android.mk b/Android.mk index d6472be895..08a1a105b8 100644 --- a/Android.mk +++ b/Android.mk @@ -487,6 +487,7 @@ build-art-target-golem: dex2oat dalvikvm patchoat linker libstdc++ \ sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt sed -i '/libdexfiled.so/d' $(TARGET_OUT)/etc/public.libraries.txt sed -i '/libprofiled.so/d' $(TARGET_OUT)/etc/public.libraries.txt + sed -i '/libartbased.so/d' $(TARGET_OUT)/etc/public.libraries.txt ######################################################################## # Phony target for building what go/lem requires on host. diff --git a/adbconnection/Android.bp b/adbconnection/Android.bp index 441b706556..95fc274286 100644 --- a/adbconnection/Android.bp +++ b/adbconnection/Android.bp @@ -65,6 +65,7 @@ art_cc_library { defaults: ["adbconnection-defaults"], shared_libs: [ "libart", + "libartbase", ], } @@ -76,5 +77,6 @@ art_cc_library { ], shared_libs: [ "libartd", + "libartbased", ], } diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 3daaf0156e..b481352b60 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -277,6 +277,16 @@ ART_GTEST_dexdump_test_TARGET_DEPS := \ $(TARGET_CORE_IMAGE_DEFAULT_32) \ dexdump2-target +# The dexanalyze test requires an image and the dexanalyze utility. +ART_GTEST_dexanalyze_test_HOST_DEPS := \ + $(HOST_CORE_IMAGE_DEFAULT_64) \ + $(HOST_CORE_IMAGE_DEFAULT_32) \ + dexanalyze-host +ART_GTEST_dexanalyze_test_TARGET_DEPS := \ + $(TARGET_CORE_IMAGE_DEFAULT_64) \ + $(TARGET_CORE_IMAGE_DEFAULT_32) \ + dexanalyze-target + # The dexlayout test requires an image and the dexlayout utility. # TODO: rename into dexdump when migration completes ART_GTEST_dexlayout_test_HOST_DEPS := \ diff --git a/build/art.go b/build/art.go index 59480a0d0f..3dabce3975 100644 --- a/build/art.go +++ b/build/art.go @@ -278,6 +278,7 @@ func init() { android.RegisterModuleType("art_cc_test", artTest) android.RegisterModuleType("art_cc_test_library", artTestLibrary) android.RegisterModuleType("art_cc_defaults", artDefaultsFactory) + android.RegisterModuleType("libart_cc_defaults", libartDefaultsFactory) android.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory) android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory) } @@ -304,6 +305,33 @@ func artDefaultsFactory() android.Module { return module } +func libartDefaultsFactory() android.Module { + c := &codegenProperties{} + module := cc.DefaultsFactory(c) + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + codegen(ctx, c, true) + + type props struct { + Target struct { + Android struct { + Shared_libs []string + } + } + } + + p := &props{} + // TODO: express this in .bp instead b/79671158 + if !envTrue(ctx, "ART_TARGET_LINUX") { + p.Target.Android.Shared_libs = []string { + "libmetricslogger", + } + } + ctx.AppendProperties(p) + }) + + return module +} + func artLibrary() android.Module { m, _ := cc.NewLibrary(android.HostAndDeviceSupported) module := m.Init() diff --git a/compiler/Android.bp b/compiler/Android.bp index 5884a548be..be963fbbdb 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -246,6 +246,7 @@ art_cc_library { "libart", "libprofile", "libdexfile", + "libartbase", ], target: { @@ -295,6 +296,7 @@ art_cc_library { "libartd", "libprofiled", "libdexfiled", + "libartbased", ], } diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 893cad288b..87e679fbea 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -207,11 +207,10 @@ class ElfCompilationUnitWriter { std::vector<DexRegisterMap> dex_reg_maps; if (accessor.HasCodeItem() && mi->code_info != nullptr) { const CodeInfo code_info(mi->code_info); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) { - const StackMap& stack_map = code_info.GetStackMapAt(s, encoding); + for (size_t s = 0; s < code_info.GetNumberOfStackMaps(); ++s) { + const StackMap stack_map = code_info.GetStackMapAt(s); dex_reg_maps.push_back(code_info.GetDexRegisterMapOf( - stack_map, encoding, accessor.RegistersSize())); + stack_map, accessor.RegistersSize())); } } diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h index 44504c1efb..a7adab5506 100644 --- a/compiler/debug/elf_debug_line_writer.h +++ b/compiler/debug/elf_debug_line_writer.h @@ -100,15 +100,14 @@ class ElfDebugLineWriter { if (mi->code_info != nullptr) { // Use stack maps to create mapping table from pc to dex. const CodeInfo code_info(mi->code_info); - const CodeInfoEncoding encoding = code_info.ExtractEncoding(); - pc2dex_map.reserve(code_info.GetNumberOfStackMaps(encoding)); - for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); s++) { - StackMap stack_map = code_info.GetStackMapAt(s, encoding); + pc2dex_map.reserve(code_info.GetNumberOfStackMaps()); + for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { + StackMap stack_map = code_info.GetStackMapAt(s); DCHECK(stack_map.IsValid()); - const uint32_t pc = stack_map.GetNativePcOffset(encoding.stack_map.encoding, isa); - const int32_t dex = stack_map.GetDexPc(encoding.stack_map.encoding); + const uint32_t pc = stack_map.GetNativePcOffset(isa); + const int32_t dex = stack_map.GetDexPc(); pc2dex_map.push_back({pc, dex}); - if (stack_map.HasDexRegisterMap(encoding.stack_map.encoding)) { + if (stack_map.HasDexRegisterMap()) { // Guess that the first map with local variables is the end of prologue. prologue_end = std::min(prologue_end, pc); } diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index 9ea9f01cd9..c1bf915212 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -99,12 +99,11 @@ static std::vector<VariableLocation> GetVariableLocations( // Get stack maps sorted by pc (they might not be sorted internally). // TODO(dsrbecky) Remove this once stackmaps get sorted by pc. const CodeInfo code_info(method_info->code_info); - const CodeInfoEncoding encoding = code_info.ExtractEncoding(); std::map<uint32_t, uint32_t> stack_maps; // low_pc -> stack_map_index. - for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); s++) { - StackMap stack_map = code_info.GetStackMapAt(s, encoding); + for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) { + StackMap stack_map = code_info.GetStackMapAt(s); DCHECK(stack_map.IsValid()); - if (!stack_map.HasDexRegisterMap(encoding.stack_map.encoding)) { + if (!stack_map.HasDexRegisterMap()) { // The compiler creates stackmaps without register maps at the start of // basic blocks in order to keep instruction-accurate line number mapping. // However, we never stop at those (breakpoint locations always have map). @@ -112,7 +111,7 @@ static std::vector<VariableLocation> GetVariableLocations( // The main reason for this is to save space by avoiding undefined gaps. continue; } - const uint32_t pc_offset = stack_map.GetNativePcOffset(encoding.stack_map.encoding, isa); + const uint32_t pc_offset = stack_map.GetNativePcOffset(isa); DCHECK_LE(pc_offset, method_info->code_size); DCHECK_LE(compilation_unit_code_address, method_info->code_address); const uint32_t low_pc = dchecked_integral_cast<uint32_t>( @@ -124,7 +123,7 @@ static std::vector<VariableLocation> GetVariableLocations( for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) { const uint32_t low_pc = it->first; const uint32_t stack_map_index = it->second; - const StackMap& stack_map = code_info.GetStackMapAt(stack_map_index, encoding); + const StackMap stack_map = code_info.GetStackMapAt(stack_map_index); auto next_it = it; next_it++; const uint32_t high_pc = next_it != stack_maps.end() @@ -136,7 +135,7 @@ static std::vector<VariableLocation> GetVariableLocations( } // Check that the stack map is in the requested range. - uint32_t dex_pc = stack_map.GetDexPc(encoding.stack_map.encoding); + uint32_t dex_pc = stack_map.GetDexPc(); if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) { // The variable is not in scope at this PC. Therefore omit the entry. // Note that this is different to None() entry which means in scope, but unknown location. @@ -151,10 +150,10 @@ static std::vector<VariableLocation> GetVariableLocations( DCHECK(dex_register_map.IsValid()); CodeItemDataAccessor accessor(*method_info->dex_file, method_info->code_item); reg_lo = dex_register_map.GetDexRegisterLocation( - vreg, accessor.RegistersSize(), code_info, encoding); + vreg, accessor.RegistersSize(), code_info); if (is64bitValue) { reg_hi = dex_register_map.GetDexRegisterLocation( - vreg + 1, accessor.RegistersSize(), code_info, encoding); + vreg + 1, accessor.RegistersSize(), code_info); } // Add location entry for this address range. diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index f57333741c..de1be5b871 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -771,7 +771,7 @@ void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary( void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) { LocationSummary* locations = method_type->GetLocations(); - MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex()); + MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex().index_); CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>(); InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc()); } @@ -975,11 +975,10 @@ static void CheckCovers(uint32_t dex_pc, const CodeInfo& code_info, const ArenaVector<HSuspendCheck*>& loop_headers, ArenaVector<size_t>* covered) { - CodeInfoEncoding encoding = code_info.ExtractEncoding(); for (size_t i = 0; i < loop_headers.size(); ++i) { if (loop_headers[i]->GetDexPc() == dex_pc) { if (graph.IsCompilingOsr()) { - DCHECK(code_info.GetOsrStackMapForDexPc(dex_pc, encoding).IsValid()); + DCHECK(code_info.GetOsrStackMapForDexPc(dex_pc).IsValid()); } ++(*covered)[i]; } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index bcb25997f4..a340446ac3 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -35,7 +35,6 @@ #include "optimizing_compiler_stats.h" #include "read_barrier_option.h" #include "stack.h" -#include "stack_map.h" #include "utils/label.h" namespace art { diff --git a/compiler/optimizing/data_type.h b/compiler/optimizing/data_type.h index be26e67af3..5ac6e46003 100644 --- a/compiler/optimizing/data_type.h +++ b/compiler/optimizing/data_type.h @@ -216,6 +216,21 @@ class DataType { Size(result_type) > Size(input_type); } + static Type ToSigned(Type type) { + switch (type) { + case Type::kUint8: + return Type::kInt8; + case Type::kUint16: + return Type::kInt16; + case Type::kUint32: + return Type::kInt32; + case Type::kUint64: + return Type::kInt64; + default: + return type; + } + } + static const char* PrettyDescriptor(Type type); private: diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 35a39456a2..24dc2ee9b4 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -448,11 +448,9 @@ void HInstructionBuilder::BuildIntrinsic(ArtMethod* method) { invoke_type, target_method, HInvokeStaticOrDirect::ClinitCheckRequirement::kNone); + RangeInstructionOperands operands(graph_->GetNumberOfVRegs() - in_vregs, in_vregs); HandleInvoke(invoke, - in_vregs, - /* args */ nullptr, - graph_->GetNumberOfVRegs() - in_vregs, - /* is_range */ true, + operands, dex_file_->GetMethodShorty(method_idx), /* clinit_check */ nullptr, /* is_unresolved */ false); @@ -916,10 +914,7 @@ static bool IsStringConstructor(ArtMethod* method) { bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, uint32_t dex_pc, uint32_t method_idx, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index) { + const InstructionOperands& operands) { InvokeType invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode()); const char* descriptor = dex_file_->GetMethodShorty(method_idx); DataType::Type return_type = DataType::FromShorty(descriptor[0]); @@ -943,12 +938,9 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, method_idx, invoke_type); return HandleInvoke(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, + operands, descriptor, - nullptr, /* clinit_check */ + nullptr /* clinit_check */, true /* is_unresolved */); } @@ -976,12 +968,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, invoke_type, target_method, HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit); - return HandleStringInit(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor); + return HandleStringInit(invoke, operands, descriptor); } // Potential class initialization check, in the case of a static method call. @@ -1042,26 +1029,16 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, ImTable::GetImtIndex(resolved_method)); } - return HandleInvoke(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor, - clinit_check, - false /* is_unresolved */); + return HandleInvoke(invoke, operands, descriptor, clinit_check, false /* is_unresolved */); } bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction ATTRIBUTE_UNUSED, uint32_t dex_pc, uint32_t method_idx, - uint32_t proto_idx, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index) { + dex::ProtoIndex proto_idx, + const InstructionOperands& operands) { const char* descriptor = dex_file_->GetShorty(proto_idx); - DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), number_of_vreg_arguments); + DCHECK_EQ(1 + ArtMethod::NumArgRegisters(descriptor), operands.GetNumberOfOperands()); DataType::Type return_type = DataType::FromShorty(descriptor[0]); size_t number_of_arguments = strlen(descriptor); HInvoke* invoke = new (allocator_) HInvokePolymorphic(allocator_, @@ -1070,10 +1047,7 @@ bool HInstructionBuilder::BuildInvokePolymorphic(const Instruction& instruction dex_pc, method_idx); return HandleInvoke(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, + operands, descriptor, nullptr /* clinit_check */, false /* is_unresolved */); @@ -1222,26 +1196,22 @@ HClinitCheck* HInstructionBuilder::ProcessClinitCheckForInvoke( } bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor, size_t start_index, size_t* argument_index) { uint32_t descriptor_index = 1; // Skip the return type. - + const size_t number_of_operands = operands.GetNumberOfOperands(); for (size_t i = start_index; // Make sure we don't go over the expected arguments or over the number of // dex registers given. If the instruction was seen as dead by the verifier, // it hasn't been properly checked. - (i < number_of_vreg_arguments) && (*argument_index < invoke->GetNumberOfArguments()); + (i < number_of_operands) && (*argument_index < invoke->GetNumberOfArguments()); i++, (*argument_index)++) { DataType::Type type = DataType::FromShorty(descriptor[descriptor_index++]); bool is_wide = (type == DataType::Type::kInt64) || (type == DataType::Type::kFloat64); - if (!is_range - && is_wide - && ((i + 1 == number_of_vreg_arguments) || (args[i] + 1 != args[i + 1]))) { + if (is_wide && ((i + 1 == number_of_operands) || + (operands.GetOperand(i) + 1 != operands.GetOperand(i + 1)))) { // Longs and doubles should be in pairs, that is, sequential registers. The verifier should // reject any class where this is violated. However, the verifier only does these checks // on non trivially dead instructions, so we just bailout the compilation. @@ -1252,7 +1222,7 @@ bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke, MethodCompilationStat::kNotCompiledMalformedOpcode); return false; } - HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type); + HInstruction* arg = LoadLocal(operands.GetOperand(i), type); invoke->SetArgumentAt(*argument_index, arg); if (is_wide) { i++; @@ -1279,10 +1249,7 @@ bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke, } bool HInstructionBuilder::HandleInvoke(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor, HClinitCheck* clinit_check, bool is_unresolved) { @@ -1291,7 +1258,7 @@ bool HInstructionBuilder::HandleInvoke(HInvoke* invoke, size_t start_index = 0; size_t argument_index = 0; if (invoke->GetInvokeType() != InvokeType::kStatic) { // Instance call. - uint32_t obj_reg = is_range ? register_index : args[0]; + uint32_t obj_reg = operands.GetOperand(0); HInstruction* arg = is_unresolved ? LoadLocal(obj_reg, DataType::Type::kReference) : LoadNullCheckedLocal(obj_reg, invoke->GetDexPc()); @@ -1300,14 +1267,7 @@ bool HInstructionBuilder::HandleInvoke(HInvoke* invoke, argument_index = 1; } - if (!SetupInvokeArguments(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor, - start_index, - &argument_index)) { + if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) { return false; } @@ -1327,24 +1287,14 @@ bool HInstructionBuilder::HandleInvoke(HInvoke* invoke, } bool HInstructionBuilder::HandleStringInit(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor) { DCHECK(invoke->IsInvokeStaticOrDirect()); DCHECK(invoke->AsInvokeStaticOrDirect()->IsStringInit()); size_t start_index = 1; size_t argument_index = 0; - if (!SetupInvokeArguments(invoke, - number_of_vreg_arguments, - args, - register_index, - is_range, - descriptor, - start_index, - &argument_index)) { + if (!SetupInvokeArguments(invoke, operands, descriptor, start_index, &argument_index)) { return false; } @@ -1352,7 +1302,7 @@ bool HInstructionBuilder::HandleStringInit(HInvoke* invoke, // This is a StringFactory call, not an actual String constructor. Its result // replaces the empty String pre-allocated by NewInstance. - uint32_t orig_this_reg = is_range ? register_index : args[0]; + uint32_t orig_this_reg = operands.GetOperand(0); HInstruction* arg_this = LoadLocal(orig_this_reg, DataType::Type::kReference); // Replacing the NewInstance might render it redundant. Keep a list of these @@ -1360,9 +1310,15 @@ bool HInstructionBuilder::HandleStringInit(HInvoke* invoke, if (arg_this->IsNewInstance()) { ssa_builder_->AddUninitializedString(arg_this->AsNewInstance()); } else { + // The only reason a HPhi can flow in a String.<init> is when there is an + // irreducible loop, which will create HPhi for all dex registers at loop entry. DCHECK(arg_this->IsPhi()); - // NewInstance is not the direct input of the StringFactory call. It might - // be redundant but optimizing this case is not worth the effort. + DCHECK(graph_->HasIrreducibleLoops()); + // Don't bother compiling a method in that situation. While we could look at all + // phis related to the HNewInstance, it's not worth the trouble. + MaybeRecordStat(compilation_stats_, + MethodCompilationStat::kNotCompiledIrreducibleAndStringInit); + return false; } // Walk over all vregs and replace any occurrence of `arg_this` with `invoke`. @@ -1699,11 +1655,9 @@ void HInstructionBuilder::BuildArrayAccess(const Instruction& instruction, HNewArray* HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc, dex::TypeIndex type_index, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index) { - HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc); + const InstructionOperands& operands) { + const size_t number_of_operands = operands.GetNumberOfOperands(); + HInstruction* length = graph_->GetIntConstant(number_of_operands, dex_pc); HLoadClass* cls = BuildLoadClass(type_index, dex_pc); HNewArray* const object = new (allocator_) HNewArray(cls, length, dex_pc); AppendInstruction(object); @@ -1717,8 +1671,8 @@ HNewArray* HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc, bool is_reference_array = (primitive == 'L') || (primitive == '['); DataType::Type type = is_reference_array ? DataType::Type::kReference : DataType::Type::kInt32; - for (size_t i = 0; i < number_of_vreg_arguments; ++i) { - HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type); + for (size_t i = 0; i < number_of_operands; ++i) { + HInstruction* value = LoadLocal(operands.GetOperand(i), type); HInstruction* index = graph_->GetIntConstant(i, dex_pc); HArraySet* aset = new (allocator_) HArraySet(object, index, value, type, dex_pc); ssa_builder_->MaybeAddAmbiguousArraySet(aset); @@ -1896,17 +1850,17 @@ bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle<mirror::Class> klass) } } -void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) { +void HInstructionBuilder::BuildLoadMethodHandle(uint16_t method_handle_index, uint32_t dex_pc) { const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); - HLoadMethodHandle* load_method_handle = - new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc); + HLoadMethodHandle* load_method_handle = new (allocator_) HLoadMethodHandle( + graph_->GetCurrentMethod(), method_handle_index, dex_file, dex_pc); AppendInstruction(load_method_handle); } -void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) { +void HInstructionBuilder::BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc) { const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); HLoadMethodType* load_method_type = - new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc); + new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_index, dex_file, dex_pc); AppendInstruction(load_method_type); } @@ -2151,11 +2105,10 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, } else { method_idx = instruction.VRegB_35c(); } - uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); uint32_t args[5]; - instruction.GetVarArgs(args); - if (!BuildInvoke(instruction, dex_pc, method_idx, - number_of_vreg_arguments, false, args, -1)) { + uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args); + VarArgsInstructionOperands operands(args, number_of_vreg_arguments); + if (!BuildInvoke(instruction, dex_pc, method_idx, operands)) { return false; } break; @@ -2178,10 +2131,8 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, } else { method_idx = instruction.VRegB_3rc(); } - uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); - uint32_t register_index = instruction.VRegC(); - if (!BuildInvoke(instruction, dex_pc, method_idx, - number_of_vreg_arguments, true, nullptr, register_index)) { + RangeInstructionOperands operands(instruction.VRegC(), instruction.VRegA_3rc()); + if (!BuildInvoke(instruction, dex_pc, method_idx, operands)) { return false; } break; @@ -2189,33 +2140,18 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, case Instruction::INVOKE_POLYMORPHIC: { uint16_t method_idx = instruction.VRegB_45cc(); - uint16_t proto_idx = instruction.VRegH_45cc(); - uint32_t number_of_vreg_arguments = instruction.VRegA_45cc(); + dex::ProtoIndex proto_idx(instruction.VRegH_45cc()); uint32_t args[5]; - instruction.GetVarArgs(args); - return BuildInvokePolymorphic(instruction, - dex_pc, - method_idx, - proto_idx, - number_of_vreg_arguments, - false, - args, - -1); + uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args); + VarArgsInstructionOperands operands(args, number_of_vreg_arguments); + return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands); } case Instruction::INVOKE_POLYMORPHIC_RANGE: { uint16_t method_idx = instruction.VRegB_4rcc(); - uint16_t proto_idx = instruction.VRegH_4rcc(); - uint32_t number_of_vreg_arguments = instruction.VRegA_4rcc(); - uint32_t register_index = instruction.VRegC_4rcc(); - return BuildInvokePolymorphic(instruction, - dex_pc, - method_idx, - proto_idx, - number_of_vreg_arguments, - true, - nullptr, - register_index); + dex::ProtoIndex proto_idx(instruction.VRegH_4rcc()); + RangeInstructionOperands operands(instruction.VRegC_4rcc(), instruction.VRegA_4rcc()); + return BuildInvokePolymorphic(instruction, dex_pc, method_idx, proto_idx, operands); } case Instruction::NEG_INT: { @@ -2763,30 +2699,19 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, } case Instruction::FILLED_NEW_ARRAY: { - uint32_t number_of_vreg_arguments = instruction.VRegA_35c(); dex::TypeIndex type_index(instruction.VRegB_35c()); uint32_t args[5]; - instruction.GetVarArgs(args); - HNewArray* new_array = BuildFilledNewArray(dex_pc, - type_index, - number_of_vreg_arguments, - /* is_range */ false, - args, - /* register_index */ 0); + uint32_t number_of_vreg_arguments = instruction.GetVarArgs(args); + VarArgsInstructionOperands operands(args, number_of_vreg_arguments); + HNewArray* new_array = BuildFilledNewArray(dex_pc, type_index, operands); BuildConstructorFenceForAllocation(new_array); break; } case Instruction::FILLED_NEW_ARRAY_RANGE: { - uint32_t number_of_vreg_arguments = instruction.VRegA_3rc(); dex::TypeIndex type_index(instruction.VRegB_3rc()); - uint32_t register_index = instruction.VRegC_3rc(); - HNewArray* new_array = BuildFilledNewArray(dex_pc, - type_index, - number_of_vreg_arguments, - /* is_range */ true, - /* args*/ nullptr, - register_index); + RangeInstructionOperands operands(instruction.VRegC_3rc(), instruction.VRegA_3rc()); + HNewArray* new_array = BuildFilledNewArray(dex_pc, type_index, operands); BuildConstructorFenceForAllocation(new_array); break; } @@ -2949,7 +2874,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, } case Instruction::CONST_METHOD_TYPE: { - uint16_t proto_idx = instruction.VRegB_21c(); + dex::ProtoIndex proto_idx(instruction.VRegB_21c()); BuildLoadMethodType(proto_idx, dex_pc); UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction()); break; diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 95ffa6b054..2218a691ea 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -38,6 +38,7 @@ class CompilerDriver; class DexCompilationUnit; class HBasicBlockBuilder; class Instruction; +class InstructionOperands; class OptimizingCompilerStats; class ScopedObjectAccess; class SsaBuilder; @@ -168,29 +169,20 @@ class HInstructionBuilder : public ValueObject { bool BuildInvoke(const Instruction& instruction, uint32_t dex_pc, uint32_t method_idx, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index); + const InstructionOperands& operands); // Builds an invocation node for invoke-polymorphic and returns whether the // instruction is supported. bool BuildInvokePolymorphic(const Instruction& instruction, uint32_t dex_pc, uint32_t method_idx, - uint32_t proto_idx, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index); + dex::ProtoIndex proto_idx, + const InstructionOperands& operands); // Builds a new array node and the instructions that fill it. HNewArray* BuildFilledNewArray(uint32_t dex_pc, dex::TypeIndex type_index, - uint32_t number_of_vreg_arguments, - bool is_range, - uint32_t* args, - uint32_t register_index); + const InstructionOperands& operands); void BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc); @@ -240,11 +232,11 @@ class HInstructionBuilder : public ValueObject { bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`. + // Builds a `HLoadMethodHandle` loading the given `method_handle_index`. void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc); - // Builds a `HLoadMethodType` loading the given `proto_idx`. - void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc); + // Builds a `HLoadMethodType` loading the given `proto_index`. + void BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc); // Returns the outer-most compiling method's class. ObjPtr<mirror::Class> GetOutermostCompilingClass() const; @@ -260,28 +252,19 @@ class HInstructionBuilder : public ValueObject { HInvoke* invoke); bool SetupInvokeArguments(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor, size_t start_index, size_t* argument_index); bool HandleInvoke(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor, HClinitCheck* clinit_check, bool is_unresolved); bool HandleStringInit(HInvoke* invoke, - uint32_t number_of_vreg_arguments, - uint32_t* args, - uint32_t register_index, - bool is_range, + const InstructionOperands& operands, const char* descriptor); void HandleStringInitResult(HInvokeStaticOrDirect* invoke); diff --git a/compiler/optimizing/load_store_analysis.h b/compiler/optimizing/load_store_analysis.h index f84846d1b0..769a3f1b59 100644 --- a/compiler/optimizing/load_store_analysis.h +++ b/compiler/optimizing/load_store_analysis.h @@ -94,11 +94,13 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> { static constexpr int16_t kDeclaringClassDefIndexForArrays = -1; HeapLocation(ReferenceInfo* ref_info, + DataType::Type type, size_t offset, HInstruction* index, size_t vector_length, int16_t declaring_class_def_index) : ref_info_(ref_info), + type_(DataType::ToSigned(type)), offset_(offset), index_(index), vector_length_(vector_length), @@ -116,6 +118,7 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> { } ReferenceInfo* GetReferenceInfo() const { return ref_info_; } + DataType::Type GetType() const { return type_; } size_t GetOffset() const { return offset_; } HInstruction* GetIndex() const { return index_; } size_t GetVectorLength() const { return vector_length_; } @@ -149,6 +152,10 @@ class HeapLocation : public ArenaObject<kArenaAllocLSA> { private: // Reference for instance/static field, array element or vector data. ReferenceInfo* const ref_info_; + // Type of data residing at HeapLocation (always signed for integral + // data since e.g. a[i] and a[i] & 0xff are represented by differently + // signed types; char vs short are disambiguated through the reference). + const DataType::Type type_; // Offset of static/instance field. // Invalid when this HeapLocation is not field. const size_t offset_; @@ -237,19 +244,31 @@ class HeapLocationCollector : public HGraphVisitor { DCHECK(object != nullptr); DCHECK(field != nullptr); return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(object)), + field->GetFieldType(), field->GetFieldOffset().SizeValue(), nullptr, HeapLocation::kScalar, field->GetDeclaringClassDefIndex()); } - size_t GetArrayHeapLocation(HInstruction* array, - HInstruction* index, - size_t vector_length = HeapLocation::kScalar) const { - DCHECK(array != nullptr); - DCHECK(index != nullptr); - DCHECK_GE(vector_length, HeapLocation::kScalar); + size_t GetArrayHeapLocation(HInstruction* instruction) const { + DCHECK(instruction != nullptr); + HInstruction* array = instruction->InputAt(0); + HInstruction* index = instruction->InputAt(1); + DataType::Type type = instruction->GetType(); + size_t vector_length = HeapLocation::kScalar; + if (instruction->IsArraySet()) { + type = instruction->AsArraySet()->GetComponentType(); + } else if (instruction->IsVecStore() || + instruction->IsVecLoad()) { + HVecOperation* vec_op = instruction->AsVecOperation(); + type = vec_op->GetPackedType(); + vector_length = vec_op->GetVectorLength(); + } else { + DCHECK(instruction->IsArrayGet()); + } return FindHeapLocationIndex(FindReferenceInfoOf(HuntForOriginalReference(array)), + type, HeapLocation::kInvalidFieldOffset, index, vector_length, @@ -279,13 +298,16 @@ class HeapLocationCollector : public HGraphVisitor { // In later analysis, ComputeMayAlias() and MayAlias() compute and tell whether // these indexes alias. size_t FindHeapLocationIndex(ReferenceInfo* ref_info, + DataType::Type type, size_t offset, HInstruction* index, size_t vector_length, int16_t declaring_class_def_index) const { + DataType::Type lookup_type = DataType::ToSigned(type); for (size_t i = 0; i < heap_locations_.size(); i++) { HeapLocation* loc = heap_locations_[i]; if (loc->GetReferenceInfo() == ref_info && + loc->GetType() == lookup_type && loc->GetOffset() == offset && loc->GetIndex() == index && loc->GetVectorLength() == vector_length && @@ -425,6 +447,7 @@ class HeapLocationCollector : public HGraphVisitor { } HeapLocation* GetOrCreateHeapLocation(HInstruction* ref, + DataType::Type type, size_t offset, HInstruction* index, size_t vector_length, @@ -432,10 +455,10 @@ class HeapLocationCollector : public HGraphVisitor { HInstruction* original_ref = HuntForOriginalReference(ref); ReferenceInfo* ref_info = GetOrCreateReferenceInfo(original_ref); size_t heap_location_idx = FindHeapLocationIndex( - ref_info, offset, index, vector_length, declaring_class_def_index); + ref_info, type, offset, index, vector_length, declaring_class_def_index); if (heap_location_idx == kHeapLocationNotFound) { HeapLocation* heap_loc = new (GetGraph()->GetAllocator()) - HeapLocation(ref_info, offset, index, vector_length, declaring_class_def_index); + HeapLocation(ref_info, type, offset, index, vector_length, declaring_class_def_index); heap_locations_.push_back(heap_loc); return heap_loc; } @@ -446,17 +469,23 @@ class HeapLocationCollector : public HGraphVisitor { if (field_info.IsVolatile()) { has_volatile_ = true; } + DataType::Type type = field_info.GetFieldType(); const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex(); const size_t offset = field_info.GetFieldOffset().SizeValue(); return GetOrCreateHeapLocation(ref, + type, offset, nullptr, HeapLocation::kScalar, declaring_class_def_index); } - void VisitArrayAccess(HInstruction* array, HInstruction* index, size_t vector_length) { + void VisitArrayAccess(HInstruction* array, + HInstruction* index, + DataType::Type type, + size_t vector_length) { GetOrCreateHeapLocation(array, + type, HeapLocation::kInvalidFieldOffset, index, vector_length, @@ -510,28 +539,32 @@ class HeapLocationCollector : public HGraphVisitor { void VisitArrayGet(HArrayGet* instruction) OVERRIDE { HInstruction* array = instruction->InputAt(0); HInstruction* index = instruction->InputAt(1); - VisitArrayAccess(array, index, HeapLocation::kScalar); + DataType::Type type = instruction->GetType(); + VisitArrayAccess(array, index, type, HeapLocation::kScalar); CreateReferenceInfoForReferenceType(instruction); } void VisitArraySet(HArraySet* instruction) OVERRIDE { HInstruction* array = instruction->InputAt(0); HInstruction* index = instruction->InputAt(1); - VisitArrayAccess(array, index, HeapLocation::kScalar); + DataType::Type type = instruction->GetComponentType(); + VisitArrayAccess(array, index, type, HeapLocation::kScalar); has_heap_stores_ = true; } void VisitVecLoad(HVecLoad* instruction) OVERRIDE { HInstruction* array = instruction->InputAt(0); HInstruction* index = instruction->InputAt(1); - VisitArrayAccess(array, index, instruction->GetVectorLength()); + DataType::Type type = instruction->GetPackedType(); + VisitArrayAccess(array, index, type, instruction->GetVectorLength()); CreateReferenceInfoForReferenceType(instruction); } void VisitVecStore(HVecStore* instruction) OVERRIDE { HInstruction* array = instruction->InputAt(0); HInstruction* index = instruction->InputAt(1); - VisitArrayAccess(array, index, instruction->GetVectorLength()); + DataType::Type type = instruction->GetPackedType(); + VisitArrayAccess(array, index, type, instruction->GetVectorLength()); has_heap_stores_ = true; } diff --git a/compiler/optimizing/load_store_analysis_test.cc b/compiler/optimizing/load_store_analysis_test.cc index 56361a8c90..bfe7a4f72f 100644 --- a/compiler/optimizing/load_store_analysis_test.cc +++ b/compiler/optimizing/load_store_analysis_test.cc @@ -78,12 +78,16 @@ TEST_F(LoadStoreAnalysisTest, ArrayHeapLocations) { // Test queries on HeapLocationCollector's ref info and index records. ReferenceInfo* ref = heap_location_collector.FindReferenceInfoOf(array); + DataType::Type type = DataType::Type::kInt32; size_t field = HeapLocation::kInvalidFieldOffset; size_t vec = HeapLocation::kScalar; size_t class_def = HeapLocation::kDeclaringClassDefIndexForArrays; - size_t loc1 = heap_location_collector.FindHeapLocationIndex(ref, field, c1, vec, class_def); - size_t loc2 = heap_location_collector.FindHeapLocationIndex(ref, field, c2, vec, class_def); - size_t loc3 = heap_location_collector.FindHeapLocationIndex(ref, field, index, vec, class_def); + size_t loc1 = heap_location_collector.FindHeapLocationIndex( + ref, type, field, c1, vec, class_def); + size_t loc2 = heap_location_collector.FindHeapLocationIndex( + ref, type, field, c2, vec, class_def); + size_t loc3 = heap_location_collector.FindHeapLocationIndex( + ref, type, field, index, vec, class_def); // must find this reference info for array in HeapLocationCollector. ASSERT_TRUE(ref != nullptr); // must find these heap locations; @@ -246,28 +250,28 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexAliasingTest) { size_t loc2 = HeapLocationCollector::kHeapLocationNotFound; // Test alias: array[0] and array[1] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set1); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set2); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+0] and array[i-0] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub0); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set3); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set5); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+1] and array[i-1] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add1); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set6); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+1] and array[1-i] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add1); - loc2 = heap_location_collector.GetArrayHeapLocation(array, rev_sub1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set7); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+1] and array[i-(-1)] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add1); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_neg1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set4); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set8); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); } @@ -409,70 +413,75 @@ TEST_F(LoadStoreAnalysisTest, ArrayAliasingTest) { size_t loc1, loc2; // Test alias: array[0] and array[0,1,2,3] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); + // Test alias: array[0] and array[1,2,3,4] + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_1); + ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); + // Test alias: array[0] and array[8,9,10,11] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[1] and array[8,9,10,11] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c1); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[1] and array[0,1,2,3] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c1); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[0,1,2,3] and array[8,9,10,11] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c0, 4); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(vstore_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_8); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[0,1,2,3] and array[1,2,3,4] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c1, 4); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(vstore_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_1); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[0] and array[i,i+1,i+2,i+3] - loc1 = heap_location_collector.GetArrayHeapLocation(array, c0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i] and array[0,1,2,3] - loc1 = heap_location_collector.GetArrayHeapLocation(array, index); - loc2 = heap_location_collector.GetArrayHeapLocation(array, c0, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_0); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i] and array[i,i+1,i+2,i+3] - loc1 = heap_location_collector.GetArrayHeapLocation(array, index); - loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i] and array[i+8,i+9,i+10,i+11] - loc1 = heap_location_collector.GetArrayHeapLocation(array, index); - loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+6,i+7,i+8,i+9] and array[i+8,i+9,i+10,i+11] // Test partial overlap. - loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 4); - loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+6,i+7] and array[i,i+1,i+2,i+3] // Test different vector lengths. - loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 2); - loc2 = heap_location_collector.GetArrayHeapLocation(array, index, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6_vlen2); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+6,i+7] and array[i+8,i+9,i+10,i+11] - loc1 = heap_location_collector.GetArrayHeapLocation(array, i_add6, 2); - loc2 = heap_location_collector.GetArrayHeapLocation(array, i_add8, 4); + loc1 = heap_location_collector.GetArrayHeapLocation(vstore_i_add6_vlen2); + loc2 = heap_location_collector.GetArrayHeapLocation(vstore_i_add8); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); } @@ -563,33 +572,33 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexCalculationOverflowTest) { size_t loc2 = HeapLocationCollector::kHeapLocationNotFound; // Test alias: array[i+0x80000000] and array[i-0x80000000] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x80000000); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_1); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_2); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+0x10] and array[i-0xFFFFFFF0] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x10); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0xFFFFFFF0); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_3); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_4); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+0x7FFFFFFF] and array[i-0x80000001] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0x7FFFFFFF); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000001); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_5); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_6); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Test alias: array[i+0] and array[i-0] - loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_7); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_8); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); // Should not alias: - loc1 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000001); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_2); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_6); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); // Should not alias: - loc1 = heap_location_collector.GetArrayHeapLocation(array, add_0); - loc2 = heap_location_collector.GetArrayHeapLocation(array, sub_0x80000000); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_7); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_2); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); } @@ -647,10 +656,10 @@ TEST_F(LoadStoreAnalysisTest, TestHuntOriginalRef) { // times the original reference has been transformed by BoundType, // NullCheck, IntermediateAddress, etc. ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 1U); - size_t loc1 = heap_location_collector.GetArrayHeapLocation(array, c1); - size_t loc2 = heap_location_collector.GetArrayHeapLocation(bound_type, c1); - size_t loc3 = heap_location_collector.GetArrayHeapLocation(null_check, c1); - size_t loc4 = heap_location_collector.GetArrayHeapLocation(inter_addr, c1); + size_t loc1 = heap_location_collector.GetArrayHeapLocation(array_get1); + size_t loc2 = heap_location_collector.GetArrayHeapLocation(array_get2); + size_t loc3 = heap_location_collector.GetArrayHeapLocation(array_get3); + size_t loc4 = heap_location_collector.GetArrayHeapLocation(array_get4); ASSERT_TRUE(loc1 != HeapLocationCollector::kHeapLocationNotFound); ASSERT_EQ(loc1, loc2); ASSERT_EQ(loc1, loc3); diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index d598ff592d..35e64f75b9 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -160,7 +160,7 @@ class LSEVisitor : public HGraphDelegateVisitor { // Scan the list of removed loads to see if we can reuse `type_conversion`, if // the other removed load has the same substitute and type and is dominated - // by `type_conversioni`. + // by `type_conversion`. void TryToReuseTypeConversion(HInstruction* type_conversion, size_t index) { size_t size = removed_loads_.size(); HInstruction* load = removed_loads_[index]; @@ -542,16 +542,7 @@ class LSEVisitor : public HGraphDelegateVisitor { } } - void VisitGetLocation(HInstruction* instruction, - HInstruction* ref, - size_t offset, - HInstruction* index, - size_t vector_length, - int16_t declaring_class_def_index) { - HInstruction* original_ref = heap_location_collector_.HuntForOriginalReference(ref); - ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(original_ref); - size_t idx = heap_location_collector_.FindHeapLocationIndex( - ref_info, offset, index, vector_length, declaring_class_def_index); + void VisitGetLocation(HInstruction* instruction, size_t idx) { DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound); ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; @@ -569,23 +560,7 @@ class LSEVisitor : public HGraphDelegateVisitor { heap_values[idx] = instruction; KeepStoresIfAliasedToLocation(heap_values, idx); } else { - if (DataType::Kind(heap_value->GetType()) != DataType::Kind(instruction->GetType())) { - // The only situation where the same heap location has different type is when - // we do an array get on an instruction that originates from the null constant - // (the null could be behind a field access, an array access, a null check or - // a bound type). - // In order to stay properly typed on primitive types, we do not eliminate - // the array gets. - if (kIsDebugBuild) { - DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName(); - DCHECK(instruction->IsArrayGet()) << instruction->DebugName(); - } - // Load isn't eliminated. Put the load as the value into the HeapLocation. - // This acts like GVN but with better aliasing analysis. - heap_values[idx] = instruction; - KeepStoresIfAliasedToLocation(heap_values, idx); - return; - } + // Load is eliminated. AddRemovedLoad(instruction, heap_value); TryRemovingNullCheck(instruction); } @@ -610,21 +585,11 @@ class LSEVisitor : public HGraphDelegateVisitor { return false; } - void VisitSetLocation(HInstruction* instruction, - HInstruction* ref, - size_t offset, - HInstruction* index, - size_t vector_length, - int16_t declaring_class_def_index, - HInstruction* value) { + void VisitSetLocation(HInstruction* instruction, size_t idx, HInstruction* value) { + DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound); DCHECK(!IsStore(value)) << value->DebugName(); // value may already have a substitute. value = FindSubstitute(value); - HInstruction* original_ref = heap_location_collector_.HuntForOriginalReference(ref); - ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf(original_ref); - size_t idx = heap_location_collector_.FindHeapLocationIndex( - ref_info, offset, index, vector_length, declaring_class_def_index); - DCHECK_NE(idx, HeapLocationCollector::kHeapLocationNotFound); ScopedArenaVector<HInstruction*>& heap_values = heap_values_for_[instruction->GetBlock()->GetBlockId()]; HInstruction* heap_value = heap_values[idx]; @@ -644,7 +609,8 @@ class LSEVisitor : public HGraphDelegateVisitor { } else if (!loop_info->IsIrreducible()) { // instruction is a store in the loop so the loop must do write. DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite()); - if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(original_ref)) { + ReferenceInfo* ref_info = heap_location_collector_.GetHeapLocation(idx)->GetReferenceInfo(); + if (ref_info->IsSingleton() && !loop_info->IsDefinedOutOfTheLoop(ref_info->GetReference())) { // original_ref is created inside the loop. Value stored to it isn't needed at // the loop header. This is true for outer loops also. possibly_redundant = true; @@ -686,79 +652,39 @@ class LSEVisitor : public HGraphDelegateVisitor { } void VisitInstanceFieldGet(HInstanceFieldGet* instruction) OVERRIDE { - HInstruction* obj = instruction->InputAt(0); - size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue(); - int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex(); - VisitGetLocation(instruction, - obj, - offset, - nullptr, - HeapLocation::kScalar, - declaring_class_def_index); + HInstruction* object = instruction->InputAt(0); + const FieldInfo& field = instruction->GetFieldInfo(); + VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field)); } void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE { - HInstruction* obj = instruction->InputAt(0); - size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue(); - int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex(); + HInstruction* object = instruction->InputAt(0); + const FieldInfo& field = instruction->GetFieldInfo(); HInstruction* value = instruction->InputAt(1); - VisitSetLocation(instruction, - obj, - offset, - nullptr, - HeapLocation::kScalar, - declaring_class_def_index, - value); + size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field); + VisitSetLocation(instruction, idx, value); } void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE { HInstruction* cls = instruction->InputAt(0); - size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue(); - int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex(); - VisitGetLocation(instruction, - cls, - offset, - nullptr, - HeapLocation::kScalar, - declaring_class_def_index); + const FieldInfo& field = instruction->GetFieldInfo(); + VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field)); } void VisitStaticFieldSet(HStaticFieldSet* instruction) OVERRIDE { HInstruction* cls = instruction->InputAt(0); - size_t offset = instruction->GetFieldInfo().GetFieldOffset().SizeValue(); - int16_t declaring_class_def_index = instruction->GetFieldInfo().GetDeclaringClassDefIndex(); - HInstruction* value = instruction->InputAt(1); - VisitSetLocation(instruction, - cls, - offset, - nullptr, - HeapLocation::kScalar, - declaring_class_def_index, - value); + const FieldInfo& field = instruction->GetFieldInfo(); + size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field); + VisitSetLocation(instruction, idx, instruction->InputAt(1)); } void VisitArrayGet(HArrayGet* instruction) OVERRIDE { - HInstruction* array = instruction->InputAt(0); - HInstruction* index = instruction->InputAt(1); - VisitGetLocation(instruction, - array, - HeapLocation::kInvalidFieldOffset, - index, - HeapLocation::kScalar, - HeapLocation::kDeclaringClassDefIndexForArrays); + VisitGetLocation(instruction, heap_location_collector_.GetArrayHeapLocation(instruction)); } void VisitArraySet(HArraySet* instruction) OVERRIDE { - HInstruction* array = instruction->InputAt(0); - HInstruction* index = instruction->InputAt(1); - HInstruction* value = instruction->InputAt(2); - VisitSetLocation(instruction, - array, - HeapLocation::kInvalidFieldOffset, - index, - HeapLocation::kScalar, - HeapLocation::kDeclaringClassDefIndexForArrays, - value); + size_t idx = heap_location_collector_.GetArrayHeapLocation(instruction); + VisitSetLocation(instruction, idx, instruction->InputAt(2)); } void VisitDeoptimize(HDeoptimize* instruction) { @@ -971,6 +897,7 @@ bool LoadStoreElimination::Run() { lse_visitor.VisitBasicBlock(block); } lse_visitor.RemoveInstructions(); + return true; } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index a7c2d0b125..e786502dee 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -6548,7 +6548,7 @@ class HLoadMethodHandle FINAL : public HInstruction { class HLoadMethodType FINAL : public HInstruction { public: HLoadMethodType(HCurrentMethod* current_method, - uint16_t proto_idx, + dex::ProtoIndex proto_index, const DexFile& dex_file, uint32_t dex_pc) : HInstruction(kLoadMethodType, @@ -6556,7 +6556,7 @@ class HLoadMethodType FINAL : public HInstruction { SideEffectsForArchRuntimeCalls(), dex_pc), special_input_(HUserRecord<HInstruction*>(current_method)), - proto_idx_(proto_idx), + proto_index_(proto_index), dex_file_(dex_file) { } @@ -6568,7 +6568,7 @@ class HLoadMethodType FINAL : public HInstruction { bool IsClonable() const OVERRIDE { return true; } - uint16_t GetProtoIndex() const { return proto_idx_; } + dex::ProtoIndex GetProtoIndex() const { return proto_index_; } const DexFile& GetDexFile() const { return dex_file_; } @@ -6585,7 +6585,7 @@ class HLoadMethodType FINAL : public HInstruction { // The special input is the HCurrentMethod for kRuntimeCall. HUserRecord<HInstruction*> special_input_; - const uint16_t proto_idx_; + const dex::ProtoIndex proto_index_; const DexFile& dex_file_; }; diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 9a26f2f6c4..f246228074 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -50,6 +50,7 @@ enum class MethodCompilationStat { kNotCompiledThrowCatchLoop, kNotCompiledAmbiguousArrayOp, kNotCompiledHugeMethod, + kNotCompiledIrreducibleAndStringInit, kNotCompiledLargeMethodNoBranches, kNotCompiledMalformedOpcode, kNotCompiledNoCodegen, diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc index e014efaf5c..588ea03d69 100644 --- a/compiler/optimizing/scheduler.cc +++ b/compiler/optimizing/scheduler.cc @@ -70,19 +70,19 @@ static bool MayHaveReorderingDependency(SideEffects node, SideEffects other) { return false; } -size_t SchedulingGraph::ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const { +size_t SchedulingGraph::ArrayAccessHeapLocation(HInstruction* instruction) const { DCHECK(heap_location_collector_ != nullptr); - size_t heap_loc = heap_location_collector_->GetArrayHeapLocation(array, index); + size_t heap_loc = heap_location_collector_->GetArrayHeapLocation(instruction); // This array access should be analyzed and added to HeapLocationCollector before. DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound); return heap_loc; } -bool SchedulingGraph::ArrayAccessMayAlias(const HInstruction* node, - const HInstruction* other) const { +bool SchedulingGraph::ArrayAccessMayAlias(HInstruction* node, + HInstruction* other) const { DCHECK(heap_location_collector_ != nullptr); - size_t node_heap_loc = ArrayAccessHeapLocation(node->InputAt(0), node->InputAt(1)); - size_t other_heap_loc = ArrayAccessHeapLocation(other->InputAt(0), other->InputAt(1)); + size_t node_heap_loc = ArrayAccessHeapLocation(node); + size_t other_heap_loc = ArrayAccessHeapLocation(other); // For example: arr[0] and arr[0] if (node_heap_loc == other_heap_loc) { @@ -194,8 +194,8 @@ bool SchedulingGraph::FieldAccessMayAlias(const HInstruction* node, return true; } -bool SchedulingGraph::HasMemoryDependency(const HInstruction* node, - const HInstruction* other) const { +bool SchedulingGraph::HasMemoryDependency(HInstruction* node, + HInstruction* other) const { if (!MayHaveReorderingDependency(node->GetSideEffects(), other->GetSideEffects())) { return false; } @@ -264,8 +264,8 @@ bool SchedulingGraph::HasExceptionDependency(const HInstruction* node, // Check whether `node` depends on `other`, taking into account `SideEffect` // information and `CanThrow` information. -bool SchedulingGraph::HasSideEffectDependency(const HInstruction* node, - const HInstruction* other) const { +bool SchedulingGraph::HasSideEffectDependency(HInstruction* node, + HInstruction* other) const { if (HasMemoryDependency(node, other)) { return true; } diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h index 51cd20aea9..8e98f192d8 100644 --- a/compiler/optimizing/scheduler.h +++ b/compiler/optimizing/scheduler.h @@ -310,12 +310,12 @@ class SchedulingGraph : public ValueObject { void AddOtherDependency(SchedulingNode* node, SchedulingNode* dependency) { AddDependency(node, dependency, /*is_data_dependency*/false); } - bool HasMemoryDependency(const HInstruction* node, const HInstruction* other) const; + bool HasMemoryDependency(HInstruction* node, HInstruction* other) const; bool HasExceptionDependency(const HInstruction* node, const HInstruction* other) const; - bool HasSideEffectDependency(const HInstruction* node, const HInstruction* other) const; - bool ArrayAccessMayAlias(const HInstruction* node, const HInstruction* other) const; + bool HasSideEffectDependency(HInstruction* node, HInstruction* other) const; + bool ArrayAccessMayAlias(HInstruction* node, HInstruction* other) const; bool FieldAccessMayAlias(const HInstruction* node, const HInstruction* other) const; - size_t ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const; + size_t ArrayAccessHeapLocation(HInstruction* instruction) const; size_t FieldAccessHeapLocation(HInstruction* obj, const FieldInfo* field) const; // Add dependencies nodes for the given `HInstruction`: inputs, environments, and side-effects. diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc index fb15fc8975..d4cae72c7e 100644 --- a/compiler/optimizing/scheduler_test.cc +++ b/compiler/optimizing/scheduler_test.cc @@ -296,38 +296,38 @@ class SchedulerTest : public OptimizingUnitTest { size_t loc2 = HeapLocationCollector::kHeapLocationNotFound; // Test side effect dependency: array[0] and array[1] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, c0); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, c1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_0); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_1); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_1, arr_set_0)); // Test side effect dependency based on LSA analysis: array[i] and array[j] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, i); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, j); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_j); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_i)); // Test side effect dependency based on LSA analysis: array[i] and array[i+0] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, i); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, add0); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_add0); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_add0, arr_set_i)); // Test side effect dependency based on LSA analysis: array[i] and array[i-0] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, i); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, sub0); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_sub0); ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub0, arr_set_i)); // Test side effect dependency based on LSA analysis: array[i] and array[i+1] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, i); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, add1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_i); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_add1); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_add1, arr_set_i)); // Test side effect dependency based on LSA analysis: array[i+1] and array[i-1] - loc1 = heap_location_collector.GetArrayHeapLocation(arr, add1); - loc2 = heap_location_collector.GetArrayHeapLocation(arr, sub1); + loc1 = heap_location_collector.GetArrayHeapLocation(arr_set_add1); + loc2 = heap_location_collector.GetArrayHeapLocation(arr_set_sub1); ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2)); ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub1, arr_set_add1)); diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 7010e3f380..aa28c8b500 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -51,15 +51,7 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, if (sp_mask != nullptr) { stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet()); } - if (inlining_depth > 0) { - number_of_stack_maps_with_inline_info_++; - } - // Note: dex_pc can be kNoDexPc for native method intrinsics. - if (dex_pc != dex::kDexNoIndex && (dex_pc_max_ == dex::kDexNoIndex || dex_pc_max_ < dex_pc)) { - dex_pc_max_ = dex_pc; - } - register_mask_max_ = std::max(register_mask_max_, register_mask); current_dex_register_ = 0; } @@ -146,51 +138,6 @@ void StackMapStream::EndInlineInfoEntry() { current_inline_info_ = InlineInfoEntry(); } -CodeOffset StackMapStream::ComputeMaxNativePcCodeOffset() const { - CodeOffset max_native_pc_offset; - for (const StackMapEntry& entry : stack_maps_) { - max_native_pc_offset = std::max(max_native_pc_offset, entry.native_pc_code_offset); - } - return max_native_pc_offset; -} - -size_t StackMapStream::PrepareForFillIn() { - CodeInfoEncoding encoding; - encoding.dex_register_map.num_entries = 0; // TODO: Remove this field. - encoding.dex_register_map.num_bytes = ComputeDexRegisterMapsSize(); - encoding.location_catalog.num_entries = location_catalog_entries_.size(); - encoding.location_catalog.num_bytes = ComputeDexRegisterLocationCatalogSize(); - encoding.inline_info.num_entries = inline_infos_.size(); - // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires - // dex_method_index_idx to be filled in. - PrepareMethodIndices(); - ComputeInlineInfoEncoding(&encoding.inline_info.encoding, - encoding.dex_register_map.num_bytes); - CodeOffset max_native_pc_offset = ComputeMaxNativePcCodeOffset(); - // Prepare the CodeInfo variable-sized encoding. - encoding.stack_mask.encoding.num_bits = stack_mask_max_ + 1; // Need room for max element too. - encoding.stack_mask.num_entries = PrepareStackMasks(encoding.stack_mask.encoding.num_bits); - encoding.register_mask.encoding.num_bits = MinimumBitsToStore(register_mask_max_); - encoding.register_mask.num_entries = PrepareRegisterMasks(); - encoding.stack_map.num_entries = stack_maps_.size(); - encoding.stack_map.encoding.SetFromSizes( - // The stack map contains compressed native PC offsets. - max_native_pc_offset.CompressedValue(), - dex_pc_max_, - encoding.dex_register_map.num_bytes, - encoding.inline_info.num_entries, - encoding.register_mask.num_entries, - encoding.stack_mask.num_entries); - ComputeInvokeInfoEncoding(&encoding); - DCHECK_EQ(code_info_encoding_.size(), 0u); - encoding.Compress(&code_info_encoding_); - encoding.ComputeTableOffsets(); - // Compute table offsets so we can get the non header size. - DCHECK_EQ(encoding.HeaderSize(), code_info_encoding_.size()); - needed_size_ = code_info_encoding_.size() + encoding.NonHeaderSize(); - return needed_size_; -} - size_t StackMapStream::ComputeDexRegisterLocationCatalogSize() const { size_t size = DexRegisterLocationCatalog::kFixedSize; for (const DexRegisterLocation& dex_register_location : location_catalog_entries_) { @@ -204,6 +151,10 @@ size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) con if (num_dex_registers == 0u) { return 0u; // No register map will be emitted. } + size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits(); + if (live_dex_registers_mask->NumSetBits() == 0) { + return 0u; // No register map will be emitted. + } DCHECK(live_dex_registers_mask != nullptr); // Size of the map in bytes. @@ -211,7 +162,6 @@ size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) con // Add the live bit mask for the Dex register liveness. size += DexRegisterMap::GetLiveBitMaskSize(num_dex_registers); // Compute the size of the set of live Dex register entries. - size_t number_of_live_dex_registers = live_dex_registers_mask->NumSetBits(); size_t map_entries_size_in_bits = DexRegisterMap::SingleEntrySizeInBits(catalog_size) * number_of_live_dex_registers; size_t map_entries_size_in_bytes = @@ -220,86 +170,6 @@ size_t StackMapStream::DexRegisterMapEntry::ComputeSize(size_t catalog_size) con return size; } -size_t StackMapStream::ComputeDexRegisterMapsSize() const { - size_t size = 0; - for (const DexRegisterMapEntry& entry : dex_register_entries_) { - size += entry.ComputeSize(location_catalog_entries_.size()); - } - return size; -} - -void StackMapStream::ComputeInvokeInfoEncoding(CodeInfoEncoding* encoding) { - DCHECK(encoding != nullptr); - uint32_t native_pc_max = 0; - uint16_t method_index_max = 0; - size_t invoke_infos_count = 0; - size_t invoke_type_max = 0; - for (const StackMapEntry& entry : stack_maps_) { - if (entry.dex_method_index != dex::kDexNoIndex) { - native_pc_max = std::max(native_pc_max, entry.native_pc_code_offset.CompressedValue()); - method_index_max = std::max(method_index_max, static_cast<uint16_t>(entry.dex_method_index)); - invoke_type_max = std::max(invoke_type_max, static_cast<size_t>(entry.invoke_type)); - ++invoke_infos_count; - } - } - encoding->invoke_info.num_entries = invoke_infos_count; - encoding->invoke_info.encoding.SetFromSizes(native_pc_max, invoke_type_max, method_index_max); -} - -void StackMapStream::ComputeInlineInfoEncoding(InlineInfoEncoding* encoding, - size_t dex_register_maps_bytes) { - uint32_t method_index_max = 0; - uint32_t dex_pc_max = dex::kDexNoIndex; - uint32_t extra_data_max = 0; - - uint32_t inline_info_index = 0; - for (const StackMapEntry& entry : stack_maps_) { - for (size_t j = 0; j < entry.inlining_depth; ++j) { - InlineInfoEntry inline_entry = inline_infos_[inline_info_index++]; - if (inline_entry.method == nullptr) { - method_index_max = std::max(method_index_max, inline_entry.dex_method_index_idx); - extra_data_max = std::max(extra_data_max, 1u); - } else { - method_index_max = std::max( - method_index_max, High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method))); - extra_data_max = std::max( - extra_data_max, Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method))); - } - if (inline_entry.dex_pc != dex::kDexNoIndex && - (dex_pc_max == dex::kDexNoIndex || dex_pc_max < inline_entry.dex_pc)) { - dex_pc_max = inline_entry.dex_pc; - } - } - } - DCHECK_EQ(inline_info_index, inline_infos_.size()); - - encoding->SetFromSizes(method_index_max, dex_pc_max, extra_data_max, dex_register_maps_bytes); -} - -size_t StackMapStream::MaybeCopyDexRegisterMap(DexRegisterMapEntry& entry, - size_t* current_offset, - MemoryRegion dex_register_locations_region) { - DCHECK(current_offset != nullptr); - if ((entry.num_dex_registers == 0) || (entry.live_dex_registers_mask->NumSetBits() == 0)) { - // No dex register map needed. - return StackMap::kNoDexRegisterMap; - } - if (entry.offset == DexRegisterMapEntry::kOffsetUnassigned) { - // Not already copied, need to copy and and assign an offset. - entry.offset = *current_offset; - const size_t entry_size = entry.ComputeSize(location_catalog_entries_.size()); - DexRegisterMap dex_register_map( - dex_register_locations_region.Subregion(entry.offset, entry_size)); - *current_offset += entry_size; - // Fill in the map since it was just added. - FillInDexRegisterMap(dex_register_map, - entry.num_dex_registers, - *entry.live_dex_registers_mask, - entry.locations_start_index); - } - return entry.offset; -} - void StackMapStream::FillInMethodInfo(MemoryRegion region) { { MethodInfo info(region.begin(), method_indices_.size()); @@ -318,30 +188,64 @@ void StackMapStream::FillInMethodInfo(MemoryRegion region) { } } -void StackMapStream::FillInCodeInfo(MemoryRegion region) { - DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; - DCHECK_NE(0u, needed_size_) << "PrepareForFillIn not called before FillIn"; +template<typename Vector> +static MemoryRegion EncodeMemoryRegion(Vector* out, size_t* bit_offset, uint32_t bit_length) { + uint32_t byte_length = BitsToBytesRoundUp(bit_length); + EncodeVarintBits(out, bit_offset, byte_length); + *bit_offset = RoundUp(*bit_offset, kBitsPerByte); + out->resize(out->size() + byte_length); + MemoryRegion region(out->data() + *bit_offset / kBitsPerByte, byte_length); + *bit_offset += kBitsPerByte * byte_length; + return region; +} - DCHECK_EQ(region.size(), needed_size_); +template<uint32_t NumColumns> +using ScopedBitTableBuilder = BitTableBuilder<NumColumns, ScopedArenaAllocatorAdapter<uint32_t>>; - // Note that the memory region does not have to be zeroed when we JIT code - // because we do not use the arena allocator there. +size_t StackMapStream::PrepareForFillIn() { + size_t bit_offset = 0; + out_.clear(); - // Write the CodeInfo header. - region.CopyFrom(0, MemoryRegion(code_info_encoding_.data(), code_info_encoding_.size())); + // Decide the offsets of dex register map entries, but do not write them out yet. + // Needs to be done first as it modifies the stack map entry. + size_t dex_register_map_bytes = 0; + for (DexRegisterMapEntry& entry : dex_register_entries_) { + size_t size = entry.ComputeSize(location_catalog_entries_.size()); + entry.offset = size == 0 ? DexRegisterMapEntry::kOffsetUnassigned : dex_register_map_bytes; + dex_register_map_bytes += size; + } - CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - DCHECK_EQ(encoding.stack_map.num_entries, stack_maps_.size()); + // Must be done before calling ComputeInlineInfoEncoding since ComputeInlineInfoEncoding requires + // dex_method_index_idx to be filled in. + PrepareMethodIndices(); - MemoryRegion dex_register_locations_region = region.Subregion( - encoding.dex_register_map.byte_offset, - encoding.dex_register_map.num_bytes); + // Dedup stack masks. Needs to be done first as it modifies the stack map entry. + size_t stack_mask_bits = stack_mask_max_ + 1; // Need room for max element too. + size_t num_stack_masks = PrepareStackMasks(stack_mask_bits); + + // Dedup register masks. Needs to be done first as it modifies the stack map entry. + size_t num_register_masks = PrepareRegisterMasks(); + + // Write dex register maps. + MemoryRegion dex_register_map_region = + EncodeMemoryRegion(&out_, &bit_offset, dex_register_map_bytes * kBitsPerByte); + for (DexRegisterMapEntry& entry : dex_register_entries_) { + size_t entry_size = entry.ComputeSize(location_catalog_entries_.size()); + if (entry_size != 0) { + DexRegisterMap dex_register_map( + dex_register_map_region.Subregion(entry.offset, entry_size)); + FillInDexRegisterMap(dex_register_map, + entry.num_dex_registers, + *entry.live_dex_registers_mask, + entry.locations_start_index); + } + } - // Set the Dex register location catalog. - MemoryRegion dex_register_location_catalog_region = region.Subregion( - encoding.location_catalog.byte_offset, - encoding.location_catalog.num_bytes); + // Write dex register catalog. + EncodeVarintBits(&out_, &bit_offset, location_catalog_entries_.size()); + size_t location_catalog_bytes = ComputeDexRegisterLocationCatalogSize(); + MemoryRegion dex_register_location_catalog_region = + EncodeMemoryRegion(&out_, &bit_offset, location_catalog_bytes * kBitsPerByte); DexRegisterLocationCatalog dex_register_location_catalog(dex_register_location_catalog_region); // Offset in `dex_register_location_catalog` where to store the next // register location. @@ -353,93 +257,87 @@ void StackMapStream::FillInCodeInfo(MemoryRegion region) { // Ensure we reached the end of the Dex registers location_catalog. DCHECK_EQ(location_catalog_offset, dex_register_location_catalog_region.size()); - ArenaBitVector empty_bitmask(allocator_, 0, /* expandable */ false, kArenaAllocStackMapStream); - uintptr_t next_dex_register_map_offset = 0; - uintptr_t next_inline_info_index = 0; - size_t invoke_info_idx = 0; - for (size_t i = 0, e = stack_maps_.size(); i < e; ++i) { - StackMap stack_map = code_info.GetStackMapAt(i, encoding); - StackMapEntry entry = stack_maps_[i]; - - stack_map.SetDexPc(encoding.stack_map.encoding, entry.dex_pc); - stack_map.SetNativePcCodeOffset(encoding.stack_map.encoding, entry.native_pc_code_offset); - stack_map.SetRegisterMaskIndex(encoding.stack_map.encoding, entry.register_mask_index); - stack_map.SetStackMaskIndex(encoding.stack_map.encoding, entry.stack_mask_index); - - size_t offset = MaybeCopyDexRegisterMap(dex_register_entries_[entry.dex_register_map_index], - &next_dex_register_map_offset, - dex_register_locations_region); - stack_map.SetDexRegisterMapOffset(encoding.stack_map.encoding, offset); - + // Write stack maps. + ScopedArenaAllocatorAdapter<void> adapter = allocator_->Adapter(kArenaAllocStackMapStream); + ScopedBitTableBuilder<StackMap::Field::kCount> stack_map_builder((adapter)); + ScopedBitTableBuilder<InvokeInfo::Field::kCount> invoke_info_builder((adapter)); + ScopedBitTableBuilder<InlineInfo::Field::kCount> inline_info_builder((adapter)); + for (const StackMapEntry& entry : stack_maps_) { if (entry.dex_method_index != dex::kDexNoIndex) { - InvokeInfo invoke_info(code_info.GetInvokeInfo(encoding, invoke_info_idx)); - invoke_info.SetNativePcCodeOffset(encoding.invoke_info.encoding, entry.native_pc_code_offset); - invoke_info.SetInvokeType(encoding.invoke_info.encoding, entry.invoke_type); - invoke_info.SetMethodIndexIdx(encoding.invoke_info.encoding, entry.dex_method_index_idx); - ++invoke_info_idx; + invoke_info_builder.AddRow( + entry.native_pc_code_offset.CompressedValue(), + entry.invoke_type, + entry.dex_method_index_idx); } // Set the inlining info. - if (entry.inlining_depth != 0) { - InlineInfo inline_info = code_info.GetInlineInfo(next_inline_info_index, encoding); - - // Fill in the index. - stack_map.SetInlineInfoIndex(encoding.stack_map.encoding, next_inline_info_index); - DCHECK_EQ(next_inline_info_index, entry.inline_infos_start_index); - next_inline_info_index += entry.inlining_depth; - - inline_info.SetDepth(encoding.inline_info.encoding, entry.inlining_depth); - DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size()); - - for (size_t depth = 0; depth < entry.inlining_depth; ++depth) { - InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index]; - if (inline_entry.method != nullptr) { - inline_info.SetMethodIndexIdxAtDepth( - encoding.inline_info.encoding, - depth, - High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method))); - inline_info.SetExtraDataAtDepth( - encoding.inline_info.encoding, - depth, - Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method))); - } else { - inline_info.SetMethodIndexIdxAtDepth(encoding.inline_info.encoding, - depth, - inline_entry.dex_method_index_idx); - inline_info.SetExtraDataAtDepth(encoding.inline_info.encoding, depth, 1); - } - inline_info.SetDexPcAtDepth(encoding.inline_info.encoding, depth, inline_entry.dex_pc); - size_t dex_register_map_offset = MaybeCopyDexRegisterMap( - dex_register_entries_[inline_entry.dex_register_map_index], - &next_dex_register_map_offset, - dex_register_locations_region); - inline_info.SetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding, - depth, - dex_register_map_offset); + uint32_t inline_info_index = StackMap::kNoValue; + DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size()); + for (size_t depth = 0; depth < entry.inlining_depth; ++depth) { + InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index]; + uint32_t method_index_idx = inline_entry.dex_method_index_idx; + uint32_t extra_data = 1; + if (inline_entry.method != nullptr) { + method_index_idx = High32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)); + extra_data = Low32Bits(reinterpret_cast<uintptr_t>(inline_entry.method)); + } + uint32_t index = inline_info_builder.AddRow( + (depth == entry.inlining_depth - 1) ? InlineInfo::kLast : InlineInfo::kMore, + method_index_idx, + inline_entry.dex_pc, + extra_data, + dex_register_entries_[inline_entry.dex_register_map_index].offset); + if (depth == 0) { + inline_info_index = index; } - } else if (encoding.stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { - stack_map.SetInlineInfoIndex(encoding.stack_map.encoding, StackMap::kNoInlineInfo); } + stack_map_builder.AddRow( + entry.native_pc_code_offset.CompressedValue(), + entry.dex_pc, + dex_register_entries_[entry.dex_register_map_index].offset, + inline_info_index, + entry.register_mask_index, + entry.stack_mask_index); + } + stack_map_builder.Encode(&out_, &bit_offset); + invoke_info_builder.Encode(&out_, &bit_offset); + inline_info_builder.Encode(&out_, &bit_offset); + + // Write register masks table. + ScopedBitTableBuilder<1> register_mask_builder((adapter)); + for (size_t i = 0; i < num_register_masks; ++i) { + register_mask_builder.AddRow(register_masks_[i]); } + register_mask_builder.Encode(&out_, &bit_offset); // Write stack masks table. - const size_t stack_mask_bits = encoding.stack_mask.encoding.BitSize(); + EncodeVarintBits(&out_, &bit_offset, stack_mask_bits); + out_.resize(BitsToBytesRoundUp(bit_offset + stack_mask_bits * num_stack_masks)); + BitMemoryRegion stack_mask_region(MemoryRegion(out_.data(), out_.size()), + bit_offset, + stack_mask_bits * num_stack_masks); if (stack_mask_bits > 0) { - size_t stack_mask_bytes = RoundUp(stack_mask_bits, kBitsPerByte) / kBitsPerByte; - for (size_t i = 0; i < encoding.stack_mask.num_entries; ++i) { - MemoryRegion source(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes); - BitMemoryRegion stack_mask = code_info.GetStackMask(i, encoding); - for (size_t bit_index = 0; bit_index < stack_mask_bits; ++bit_index) { - stack_mask.StoreBit(bit_index, source.LoadBit(bit_index)); + for (size_t i = 0; i < num_stack_masks; ++i) { + size_t stack_mask_bytes = BitsToBytesRoundUp(stack_mask_bits); + BitMemoryRegion src(MemoryRegion(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes)); + BitMemoryRegion dst = stack_mask_region.Subregion(i * stack_mask_bits, stack_mask_bits); + for (size_t bit_index = 0; bit_index < stack_mask_bits; bit_index += BitSizeOf<uint32_t>()) { + size_t num_bits = std::min<size_t>(stack_mask_bits - bit_index, BitSizeOf<uint32_t>()); + dst.StoreBits(bit_index, src.LoadBits(bit_index, num_bits), num_bits); } } } - // Write register masks table. - for (size_t i = 0; i < encoding.register_mask.num_entries; ++i) { - BitMemoryRegion register_mask = code_info.GetRegisterMask(i, encoding); - register_mask.StoreBits(0, register_masks_[i], encoding.register_mask.encoding.BitSize()); - } + return UnsignedLeb128Size(out_.size()) + out_.size(); +} + +void StackMapStream::FillInCodeInfo(MemoryRegion region) { + DCHECK_EQ(0u, current_entry_.dex_pc) << "EndStackMapEntry not called after BeginStackMapEntry"; + DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before FillIn"; + DCHECK_EQ(region.size(), UnsignedLeb128Size(out_.size()) + out_.size()); + + uint8_t* ptr = EncodeUnsignedLeb128(region.begin(), out_.size()); + region.CopyFromVector(ptr - region.begin(), out_); // Verify all written data in debug build. if (kIsDebugBuild) { @@ -527,7 +425,6 @@ void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info, size_t num_dex_registers, BitVector* live_dex_registers_mask, size_t dex_register_locations_index) const { - CodeInfoEncoding encoding = code_info.ExtractEncoding(); for (size_t reg = 0; reg < num_dex_registers; reg++) { // Find the location we tried to encode. DexRegisterLocation expected = DexRegisterLocation::None(); @@ -542,7 +439,7 @@ void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info, } else { DCHECK(dex_register_map.IsDexRegisterLive(reg)); DexRegisterLocation seen = dex_register_map.GetDexRegisterLocation( - reg, num_dex_registers, code_info, encoding); + reg, num_dex_registers, code_info); DCHECK_EQ(expected.GetKind(), seen.GetKind()); DCHECK_EQ(expected.GetValue(), seen.GetValue()); } @@ -600,8 +497,9 @@ size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) { for (StackMapEntry& stack_map : stack_maps_) { size_t index = dedup.size(); MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size); + BitMemoryRegion stack_mask_bits(stack_mask); for (size_t i = 0; i < entry_size_in_bits; i++) { - stack_mask.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i)); + stack_mask_bits.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i)); } stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second; } @@ -611,23 +509,23 @@ size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) { // Check that all StackMapStream inputs are correctly encoded by trying to read them back. void StackMapStream::CheckCodeInfo(MemoryRegion region) const { CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - DCHECK_EQ(code_info.GetNumberOfStackMaps(encoding), stack_maps_.size()); + DCHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); + DCHECK_EQ(code_info.GetNumberOfStackMaskBits(), static_cast<uint32_t>(stack_mask_max_ + 1)); + DCHECK_EQ(code_info.GetNumberOfLocationCatalogEntries(), location_catalog_entries_.size()); size_t invoke_info_index = 0; for (size_t s = 0; s < stack_maps_.size(); ++s) { - const StackMap stack_map = code_info.GetStackMapAt(s, encoding); - const StackMapEncoding& stack_map_encoding = encoding.stack_map.encoding; + const StackMap stack_map = code_info.GetStackMapAt(s); StackMapEntry entry = stack_maps_[s]; // Check main stack map fields. - DCHECK_EQ(stack_map.GetNativePcOffset(stack_map_encoding, instruction_set_), + DCHECK_EQ(stack_map.GetNativePcOffset(instruction_set_), entry.native_pc_code_offset.Uint32Value(instruction_set_)); - DCHECK_EQ(stack_map.GetDexPc(stack_map_encoding), entry.dex_pc); - DCHECK_EQ(stack_map.GetRegisterMaskIndex(stack_map_encoding), entry.register_mask_index); - DCHECK_EQ(code_info.GetRegisterMaskOf(encoding, stack_map), entry.register_mask); - const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits(encoding); - DCHECK_EQ(stack_map.GetStackMaskIndex(stack_map_encoding), entry.stack_mask_index); - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); + DCHECK_EQ(stack_map.GetDexPc(), entry.dex_pc); + DCHECK_EQ(stack_map.GetRegisterMaskIndex(), entry.register_mask_index); + DCHECK_EQ(code_info.GetRegisterMaskOf(stack_map), entry.register_mask); + const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits(); + DCHECK_EQ(stack_map.GetStackMaskIndex(), entry.stack_mask_index); + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); if (entry.sp_mask != nullptr) { DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits()); for (size_t b = 0; b < num_stack_mask_bits; b++) { @@ -639,38 +537,36 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const { } } if (entry.dex_method_index != dex::kDexNoIndex) { - InvokeInfo invoke_info = code_info.GetInvokeInfo(encoding, invoke_info_index); - DCHECK_EQ(invoke_info.GetNativePcOffset(encoding.invoke_info.encoding, instruction_set_), + InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index); + DCHECK_EQ(invoke_info.GetNativePcOffset(instruction_set_), entry.native_pc_code_offset.Uint32Value(instruction_set_)); - DCHECK_EQ(invoke_info.GetInvokeType(encoding.invoke_info.encoding), entry.invoke_type); - DCHECK_EQ(invoke_info.GetMethodIndexIdx(encoding.invoke_info.encoding), - entry.dex_method_index_idx); + DCHECK_EQ(invoke_info.GetInvokeType(), entry.invoke_type); + DCHECK_EQ(invoke_info.GetMethodIndexIdx(), entry.dex_method_index_idx); invoke_info_index++; } CheckDexRegisterMap(code_info, code_info.GetDexRegisterMapOf( - stack_map, encoding, entry.dex_register_entry.num_dex_registers), + stack_map, entry.dex_register_entry.num_dex_registers), entry.dex_register_entry.num_dex_registers, entry.dex_register_entry.live_dex_registers_mask, entry.dex_register_entry.locations_start_index); // Check inline info. - DCHECK_EQ(stack_map.HasInlineInfo(stack_map_encoding), (entry.inlining_depth != 0)); + DCHECK_EQ(stack_map.HasInlineInfo(), (entry.inlining_depth != 0)); if (entry.inlining_depth != 0) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - DCHECK_EQ(inline_info.GetDepth(encoding.inline_info.encoding), entry.inlining_depth); + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + DCHECK_EQ(inline_info.GetDepth(), entry.inlining_depth); for (size_t d = 0; d < entry.inlining_depth; ++d) { size_t inline_info_index = entry.inline_infos_start_index + d; DCHECK_LT(inline_info_index, inline_infos_.size()); InlineInfoEntry inline_entry = inline_infos_[inline_info_index]; - DCHECK_EQ(inline_info.GetDexPcAtDepth(encoding.inline_info.encoding, d), - inline_entry.dex_pc); - if (inline_info.EncodesArtMethodAtDepth(encoding.inline_info.encoding, d)) { - DCHECK_EQ(inline_info.GetArtMethodAtDepth(encoding.inline_info.encoding, d), + DCHECK_EQ(inline_info.GetDexPcAtDepth(d), inline_entry.dex_pc); + if (inline_info.EncodesArtMethodAtDepth(d)) { + DCHECK_EQ(inline_info.GetArtMethodAtDepth(d), inline_entry.method); } else { const size_t method_index_idx = - inline_info.GetMethodIndexIdxAtDepth(encoding.inline_info.encoding, d); + inline_info.GetMethodIndexIdxAtDepth(d); DCHECK_EQ(method_index_idx, inline_entry.dex_method_index_idx); DCHECK_EQ(method_indices_[method_index_idx], inline_entry.method_index); } @@ -679,7 +575,6 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const { code_info.GetDexRegisterMapAtDepth( d, inline_info, - encoding, inline_entry.dex_register_entry.num_dex_registers), inline_entry.dex_register_entry.num_dex_registers, inline_entry.dex_register_entry.live_dex_registers_mask, @@ -690,7 +585,7 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const { } size_t StackMapStream::ComputeMethodInfoSize() const { - DCHECK_NE(0u, needed_size_) << "PrepareForFillIn not called before " << __FUNCTION__; + DCHECK_NE(0u, out_.size()) << "PrepareForFillIn not called before " << __FUNCTION__; return MethodInfo::ComputeSize(method_indices_.size()); } diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index 268e9bd6e0..ea97cf6530 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -73,36 +73,32 @@ class StackMapStream : public ValueObject { method_indices_(allocator->Adapter(kArenaAllocStackMapStream)), dex_register_entries_(allocator->Adapter(kArenaAllocStackMapStream)), stack_mask_max_(-1), - dex_pc_max_(kNoDexPc), - register_mask_max_(0), - number_of_stack_maps_with_inline_info_(0), + out_(allocator->Adapter(kArenaAllocStackMapStream)), dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter(kArenaAllocStackMapStream)), current_entry_(), current_inline_info_(), - code_info_encoding_(allocator->Adapter(kArenaAllocStackMapStream)), - needed_size_(0), current_dex_register_(0), in_inline_frame_(false) { stack_maps_.reserve(10); + out_.reserve(64); location_catalog_entries_.reserve(4); dex_register_locations_.reserve(10 * 4); inline_infos_.reserve(2); - code_info_encoding_.reserve(16); } // A dex register map entry for a single stack map entry, contains what registers are live as // well as indices into the location catalog. class DexRegisterMapEntry { public: - static const size_t kOffsetUnassigned = -1; + static const uint32_t kOffsetUnassigned = -1; BitVector* live_dex_registers_mask; uint32_t num_dex_registers; size_t locations_start_index; // Computed fields size_t hash = 0; - size_t offset = kOffsetUnassigned; + uint32_t offset = kOffsetUnassigned; size_t ComputeSize(size_t catalog_size) const; }; @@ -113,7 +109,7 @@ class StackMapStream : public ValueObject { CodeOffset native_pc_code_offset; uint32_t register_mask; BitVector* sp_mask; - uint8_t inlining_depth; + uint32_t inlining_depth; size_t inline_infos_start_index; uint32_t stack_mask_index; uint32_t register_mask_index; @@ -174,11 +170,6 @@ class StackMapStream : public ValueObject { private: size_t ComputeDexRegisterLocationCatalogSize() const; - size_t ComputeDexRegisterMapsSize() const; - void ComputeInlineInfoEncoding(InlineInfoEncoding* encoding, - size_t dex_register_maps_bytes); - - CodeOffset ComputeMaxNativePcCodeOffset() const; // Returns the number of unique stack masks. size_t PrepareStackMasks(size_t entry_size_in_bits); @@ -197,24 +188,11 @@ class StackMapStream : public ValueObject { bool DexRegisterMapEntryEquals(const DexRegisterMapEntry& a, const DexRegisterMapEntry& b) const; // Fill in the corresponding entries of a register map. - void ComputeInvokeInfoEncoding(CodeInfoEncoding* encoding); - - // Returns the index of an entry with the same dex register map as the current_entry, - // or kNoSameDexMapFound if no such entry exists. - size_t FindEntryWithTheSameDexMap(); - bool HaveTheSameDexMaps(const StackMapEntry& a, const StackMapEntry& b) const; - - // Fill in the corresponding entries of a register map. void FillInDexRegisterMap(DexRegisterMap dex_register_map, uint32_t num_dex_registers, const BitVector& live_dex_registers_mask, uint32_t start_index_in_dex_register_locations) const; - // Returns the offset for the dex register inside of the dex register location region. See FillIn. - // Only copies the dex register map if the offset for the entry is not already assigned. - size_t MaybeCopyDexRegisterMap(DexRegisterMapEntry& entry, - size_t* current_offset, - MemoryRegion dex_register_locations_region); void CheckDexRegisterMap(const CodeInfo& code_info, const DexRegisterMap& dex_register_map, size_t num_dex_registers, @@ -244,21 +222,16 @@ class StackMapStream : public ValueObject { ScopedArenaVector<uint32_t> method_indices_; ScopedArenaVector<DexRegisterMapEntry> dex_register_entries_; int stack_mask_max_; - uint32_t dex_pc_max_; - uint32_t register_mask_max_; - size_t number_of_stack_maps_with_inline_info_; + + ScopedArenaVector<uint8_t> out_; ScopedArenaSafeMap<uint32_t, ScopedArenaVector<uint32_t>> dex_map_hash_to_stack_map_indices_; StackMapEntry current_entry_; InlineInfoEntry current_inline_info_; - ScopedArenaVector<uint8_t> code_info_encoding_; - size_t needed_size_; uint32_t current_dex_register_; bool in_inline_frame_; - static constexpr uint32_t kNoSameDexMapFound = -1; - DISALLOW_COPY_AND_ASSIGN(StackMapStream); }; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index e36c592662..9db7588b3a 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -29,14 +29,13 @@ namespace art { // to the given bit vector. Returns true if they are same. static bool CheckStackMask( const CodeInfo& code_info, - const CodeInfoEncoding& encoding, const StackMap& stack_map, const BitVector& bit_vector) { - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); - if (bit_vector.GetNumberOfBits() > encoding.stack_mask.encoding.BitSize()) { + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); + if (bit_vector.GetNumberOfBits() > code_info.GetNumberOfStackMaskBits()) { return false; } - for (size_t i = 0; i < encoding.stack_mask.encoding.BitSize(); ++i) { + for (size_t i = 0; i < code_info.GetNumberOfStackMaskBits(); ++i) { if (stack_mask.LoadBit(i) != bit_vector.IsBitSet(i)) { return false; } @@ -65,30 +64,29 @@ TEST(StackMapTest, Test1) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(1u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(1u, code_info.GetNumberOfStackMaps()); - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(2u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding); + DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); // The Dex register location catalog contains: // - one 1-byte short Dex register location, and // - one 5-byte large Dex register location. size_t expected_location_catalog_size = 1u + 5u; ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); - StackMap stack_map = code_info.GetStackMapAt(0, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); - ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -99,16 +97,16 @@ TEST(StackMapTest, Test1) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes( - 0, number_of_dex_registers, code_info, encoding)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -125,7 +123,7 @@ TEST(StackMapTest, Test1) { ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_FALSE(stack_map.HasInlineInfo()); } TEST(StackMapTest, Test2) { @@ -179,12 +177,11 @@ TEST(StackMapTest, Test2) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(4u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(4u, code_info.GetNumberOfStackMaps()); - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(7u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding); + DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); // The Dex register location catalog contains: // - six 1-byte short Dex register locations, and // - one 5-byte large Dex register location. @@ -193,18 +190,18 @@ TEST(StackMapTest, Test2) { // First stack map. { - StackMap stack_map = code_info.GetStackMapAt(0, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); - ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask1)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -215,16 +212,16 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInStack, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(0, dex_register_map.GetStackOffsetInBytes( - 0, number_of_dex_registers, code_info, encoding)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -241,29 +238,29 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); - ASSERT_TRUE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - ASSERT_EQ(2u, inline_info.GetDepth(encoding.inline_info.encoding)); - ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 1)); + ASSERT_TRUE(stack_map.HasInlineInfo()); + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + ASSERT_EQ(2u, inline_info.GetDepth()); + ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0)); + ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1)); + ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(0)); + ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(1)); } // Second stack map. { - StackMap stack_map = code_info.GetStackMapAt(1, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u, encoding))); - ASSERT_EQ(1u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(128u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0xFFu, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(1); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(128u))); + ASSERT_EQ(1u, stack_map.GetDexPc()); + ASSERT_EQ(128u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0xFFu, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask2)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask2)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -274,17 +271,17 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(18, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(3, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -301,23 +298,23 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(18, location0.GetValue()); ASSERT_EQ(3, location1.GetValue()); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_FALSE(stack_map.HasInlineInfo()); } // Third stack map. { - StackMap stack_map = code_info.GetStackMapAt(2, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u, encoding))); - ASSERT_EQ(2u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(192u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0xABu, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(2); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(2u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(192u))); + ASSERT_EQ(2u, stack_map.GetDexPc()); + ASSERT_EQ(192u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0xABu, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask3)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask3)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -328,17 +325,17 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInRegisterHigh, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(6, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(8, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -355,23 +352,23 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(6, location0.GetValue()); ASSERT_EQ(8, location1.GetValue()); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_FALSE(stack_map.HasInlineInfo()); } // Fourth stack map. { - StackMap stack_map = code_info.GetStackMapAt(3, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u, encoding))); - ASSERT_EQ(3u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(256u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0xCDu, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(3); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(3u))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(256u))); + ASSERT_EQ(3u, stack_map.GetDexPc()); + ASSERT_EQ(256u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0xCDu, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask4)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask4)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(2u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -382,17 +379,17 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInFpuRegister, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInFpuRegisterHigh, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(3, dex_register_map.GetMachineRegister( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(1, dex_register_map.GetMachineRegister( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -409,7 +406,7 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(3, location0.GetValue()); ASSERT_EQ(1, location1.GetValue()); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_FALSE(stack_map.HasInlineInfo()); } } @@ -440,12 +437,11 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(1u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(1u, code_info.GetNumberOfStackMaps()); - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(2u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding); + DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); // The Dex register location catalog contains: // - one 1-byte short Dex register locations, and // - one 5-byte large Dex register location. @@ -454,17 +450,17 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { // First stack map. { - StackMap stack_map = code_info.GetStackMapAt(0, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); - ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(CheckStackMask(code_info, encoding, stack_map, sp_mask1)); + ASSERT_TRUE(CheckStackMask(code_info, stack_map, sp_mask1)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); - DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); + DexRegisterMap map(code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers)); ASSERT_TRUE(map.IsDexRegisterLive(0)); ASSERT_TRUE(map.IsDexRegisterLive(1)); ASSERT_EQ(2u, map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -474,15 +470,15 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { size_t expected_map_size = 1u + 1u; ASSERT_EQ(expected_map_size, map.Size()); - ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0, number_of_dex_registers, code_info, encoding)); + ASSERT_EQ(Kind::kInStack, map.GetLocationKind(0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstant, - map.GetLocationKind(1, number_of_dex_registers, code_info, encoding)); + map.GetLocationKind(1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kInStack, - map.GetLocationInternalKind(0, number_of_dex_registers, code_info, encoding)); + map.GetLocationInternalKind(0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstantLargeValue, - map.GetLocationInternalKind(1, number_of_dex_registers, code_info, encoding)); - ASSERT_EQ(0, map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info, encoding)); - ASSERT_EQ(-2, map.GetConstant(1, number_of_dex_registers, code_info, encoding)); + map.GetLocationInternalKind(1, number_of_dex_registers, code_info)); + ASSERT_EQ(0, map.GetStackOffsetInBytes(0, number_of_dex_registers, code_info)); + ASSERT_EQ(-2, map.GetConstant(1, number_of_dex_registers, code_info)); const size_t index0 = map.GetLocationCatalogEntryIndex(0, number_of_dex_registers, number_of_catalog_entries); @@ -501,10 +497,10 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { // Test that the inline info dex register map deduplicated to the same offset as the stack map // one. - ASSERT_TRUE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - EXPECT_EQ(inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding, 0), - stack_map.GetDexRegisterMapOffset(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasInlineInfo()); + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + EXPECT_EQ(inline_info.GetDexRegisterMapOffsetAtDepth(0), + stack_map.GetDexRegisterMapOffset()); } } @@ -527,27 +523,26 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(1u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(1u, code_info.GetNumberOfStackMaps()); - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(1u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding); + DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); // The Dex register location catalog contains: // - one 5-byte large Dex register location. size_t expected_location_catalog_size = 5u; ASSERT_EQ(expected_location_catalog_size, location_catalog.Size()); - StackMap stack_map = code_info.GetStackMapAt(0, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); - ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map)); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); - ASSERT_TRUE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); + ASSERT_TRUE(stack_map.HasDexRegisterMap()); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); ASSERT_FALSE(dex_register_map.IsDexRegisterLive(0)); ASSERT_TRUE(dex_register_map.IsDexRegisterLive(1)); ASSERT_EQ(1u, dex_register_map.GetNumberOfLiveDexRegisters(number_of_dex_registers)); @@ -558,14 +553,14 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ASSERT_EQ(expected_dex_register_map_size, dex_register_map.Size()); ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstant, dex_register_map.GetLocationKind( - 1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kNone, dex_register_map.GetLocationInternalKind( - 0, number_of_dex_registers, code_info, encoding)); + 0, number_of_dex_registers, code_info)); ASSERT_EQ(Kind::kConstantLargeValue, dex_register_map.GetLocationInternalKind( - 1, number_of_dex_registers, code_info, encoding)); - ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info, encoding)); + 1, number_of_dex_registers, code_info)); + ASSERT_EQ(-2, dex_register_map.GetConstant(1, number_of_dex_registers, code_info)); size_t index0 = dex_register_map.GetLocationCatalogEntryIndex( 0, number_of_dex_registers, number_of_catalog_entries); @@ -582,7 +577,7 @@ TEST(StackMapTest, TestNonLiveDexRegisters) { ASSERT_EQ(0, location0.GetValue()); ASSERT_EQ(-2, location1.GetValue()); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_FALSE(stack_map.HasInlineInfo()); } // Generate a stack map whose dex register offset is @@ -620,11 +615,10 @@ TEST(StackMapTest, DexRegisterMapOffsetOverflow) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); // The location catalog contains two entries (DexRegisterLocation(kConstant, 0) // and DexRegisterLocation(kConstant, 1)), therefore the location catalog index // has a size of 1 bit. - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(2u, number_of_catalog_entries); ASSERT_EQ(1u, DexRegisterMap::SingleEntrySizeInBits(number_of_catalog_entries)); @@ -635,21 +629,21 @@ TEST(StackMapTest, DexRegisterMapOffsetOverflow) { // locations (that is, 127 bytes of data). // Hence it has a size of 255 bytes, and therefore... ASSERT_EQ(128u, DexRegisterMap::GetLiveBitMaskSize(number_of_dex_registers)); - StackMap stack_map0 = code_info.GetStackMapAt(0, encoding); + StackMap stack_map0 = code_info.GetStackMapAt(0); DexRegisterMap dex_register_map0 = - code_info.GetDexRegisterMapOf(stack_map0, encoding, number_of_dex_registers); + code_info.GetDexRegisterMapOf(stack_map0, number_of_dex_registers); ASSERT_EQ(127u, dex_register_map0.GetLocationMappingDataSize(number_of_dex_registers, number_of_catalog_entries)); ASSERT_EQ(255u, dex_register_map0.Size()); - StackMap stack_map1 = code_info.GetStackMapAt(1, encoding); - ASSERT_TRUE(stack_map1.HasDexRegisterMap(encoding.stack_map.encoding)); + StackMap stack_map1 = code_info.GetStackMapAt(1); + ASSERT_TRUE(stack_map1.HasDexRegisterMap()); // ...the offset of the second Dex register map (relative to the // beginning of the Dex register maps region) is 255 (i.e., // kNoDexRegisterMapSmallEncoding). - ASSERT_NE(stack_map1.GetDexRegisterMapOffset(encoding.stack_map.encoding), - StackMap::kNoDexRegisterMap); - ASSERT_EQ(stack_map1.GetDexRegisterMapOffset(encoding.stack_map.encoding), 0xFFu); + ASSERT_NE(stack_map1.GetDexRegisterMapOffset(), + StackMap::kNoValue); + ASSERT_EQ(stack_map1.GetDexRegisterMapOffset(), 0xFFu); } TEST(StackMapTest, TestShareDexRegisterMap) { @@ -682,33 +676,32 @@ TEST(StackMapTest, TestShareDexRegisterMap) { stream.FillInCodeInfo(region); CodeInfo ci(region); - CodeInfoEncoding encoding = ci.ExtractEncoding(); // Verify first stack map. - StackMap sm0 = ci.GetStackMapAt(0, encoding); - DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, encoding, number_of_dex_registers); - ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers, ci, encoding)); - ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers, ci, encoding)); + StackMap sm0 = ci.GetStackMapAt(0); + DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, number_of_dex_registers); + ASSERT_EQ(0, dex_registers0.GetMachineRegister(0, number_of_dex_registers, ci)); + ASSERT_EQ(-2, dex_registers0.GetConstant(1, number_of_dex_registers, ci)); // Verify second stack map. - StackMap sm1 = ci.GetStackMapAt(1, encoding); - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, encoding, number_of_dex_registers); - ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers, ci, encoding)); - ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers, ci, encoding)); + StackMap sm1 = ci.GetStackMapAt(1); + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapOf(sm1, number_of_dex_registers); + ASSERT_EQ(0, dex_registers1.GetMachineRegister(0, number_of_dex_registers, ci)); + ASSERT_EQ(-2, dex_registers1.GetConstant(1, number_of_dex_registers, ci)); // Verify third stack map. - StackMap sm2 = ci.GetStackMapAt(2, encoding); - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, encoding, number_of_dex_registers); - ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers, ci, encoding)); - ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers, ci, encoding)); + StackMap sm2 = ci.GetStackMapAt(2); + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapOf(sm2, number_of_dex_registers); + ASSERT_EQ(2, dex_registers2.GetMachineRegister(0, number_of_dex_registers, ci)); + ASSERT_EQ(-2, dex_registers2.GetConstant(1, number_of_dex_registers, ci)); // Verify dex register map offsets. - ASSERT_EQ(sm0.GetDexRegisterMapOffset(encoding.stack_map.encoding), - sm1.GetDexRegisterMapOffset(encoding.stack_map.encoding)); - ASSERT_NE(sm0.GetDexRegisterMapOffset(encoding.stack_map.encoding), - sm2.GetDexRegisterMapOffset(encoding.stack_map.encoding)); - ASSERT_NE(sm1.GetDexRegisterMapOffset(encoding.stack_map.encoding), - sm2.GetDexRegisterMapOffset(encoding.stack_map.encoding)); + ASSERT_EQ(sm0.GetDexRegisterMapOffset(), + sm1.GetDexRegisterMapOffset()); + ASSERT_NE(sm0.GetDexRegisterMapOffset(), + sm2.GetDexRegisterMapOffset()); + ASSERT_NE(sm1.GetDexRegisterMapOffset(), + sm2.GetDexRegisterMapOffset()); } TEST(StackMapTest, TestNoDexRegisterMap) { @@ -732,33 +725,32 @@ TEST(StackMapTest, TestNoDexRegisterMap) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(2u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(2u, code_info.GetNumberOfStackMaps()); - uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + uint32_t number_of_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); ASSERT_EQ(0u, number_of_catalog_entries); - DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(encoding); + DexRegisterLocationCatalog location_catalog = code_info.GetDexRegisterLocationCatalog(); ASSERT_EQ(0u, location_catalog.Size()); - StackMap stack_map = code_info.GetStackMapAt(0, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64, encoding))); - ASSERT_EQ(0u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(64u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(encoding, stack_map)); - - ASSERT_FALSE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); - - stack_map = code_info.GetStackMapAt(1, encoding); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1, encoding))); - ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68, encoding))); - ASSERT_EQ(1u, stack_map.GetDexPc(encoding.stack_map.encoding)); - ASSERT_EQ(68u, stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA)); - ASSERT_EQ(0x4u, code_info.GetRegisterMaskOf(encoding, stack_map)); - - ASSERT_FALSE(stack_map.HasDexRegisterMap(encoding.stack_map.encoding)); - ASSERT_FALSE(stack_map.HasInlineInfo(encoding.stack_map.encoding)); + StackMap stack_map = code_info.GetStackMapAt(0); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(0))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(64))); + ASSERT_EQ(0u, stack_map.GetDexPc()); + ASSERT_EQ(64u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x3u, code_info.GetRegisterMaskOf(stack_map)); + + ASSERT_FALSE(stack_map.HasDexRegisterMap()); + ASSERT_FALSE(stack_map.HasInlineInfo()); + + stack_map = code_info.GetStackMapAt(1); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForDexPc(1))); + ASSERT_TRUE(stack_map.Equals(code_info.GetStackMapForNativePcOffset(68))); + ASSERT_EQ(1u, stack_map.GetDexPc()); + ASSERT_EQ(68u, stack_map.GetNativePcOffset(kRuntimeISA)); + ASSERT_EQ(0x4u, code_info.GetRegisterMaskOf(stack_map)); + + ASSERT_FALSE(stack_map.HasDexRegisterMap()); + ASSERT_FALSE(stack_map.HasInlineInfo()); } TEST(StackMapTest, InlineTest) { @@ -835,100 +827,99 @@ TEST(StackMapTest, InlineTest) { stream.FillInCodeInfo(region); CodeInfo ci(region); - CodeInfoEncoding encoding = ci.ExtractEncoding(); { // Verify first stack map. - StackMap sm0 = ci.GetStackMapAt(0, encoding); - - DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, encoding, 2); - ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding)); - ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci, encoding)); - - InlineInfo if0 = ci.GetInlineInfoOf(sm0, encoding); - ASSERT_EQ(2u, if0.GetDepth(encoding.inline_info.encoding)); - ASSERT_EQ(2u, if0.GetDexPcAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_TRUE(if0.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_EQ(3u, if0.GetDexPcAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_TRUE(if0.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 1)); - - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, encoding, 1); - ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding)); - - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, encoding, 3); - ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci, encoding)); - ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci, encoding)); - ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci, encoding)); + StackMap sm0 = ci.GetStackMapAt(0); + + DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm0, 2); + ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); + ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci)); + + InlineInfo if0 = ci.GetInlineInfoOf(sm0); + ASSERT_EQ(2u, if0.GetDepth()); + ASSERT_EQ(2u, if0.GetDexPcAtDepth(0)); + ASSERT_TRUE(if0.EncodesArtMethodAtDepth(0)); + ASSERT_EQ(3u, if0.GetDexPcAtDepth(1)); + ASSERT_TRUE(if0.EncodesArtMethodAtDepth(1)); + + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, 1); + ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci)); + + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, 3); + ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0, 3, ci)); + ASSERT_EQ(20, dex_registers2.GetConstant(1, 3, ci)); + ASSERT_EQ(15, dex_registers2.GetMachineRegister(2, 3, ci)); } { // Verify second stack map. - StackMap sm1 = ci.GetStackMapAt(1, encoding); - - DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, encoding, 2); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding)); - ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding)); - - InlineInfo if1 = ci.GetInlineInfoOf(sm1, encoding); - ASSERT_EQ(3u, if1.GetDepth(encoding.inline_info.encoding)); - ASSERT_EQ(2u, if1.GetDexPcAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_EQ(3u, if1.GetDexPcAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_EQ(5u, if1.GetDexPcAtDepth(encoding.inline_info.encoding, 2)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 2)); - - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, encoding, 1); - ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding)); - - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, encoding, 3); - ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci, encoding)); - ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci, encoding)); - ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci, encoding)); - - ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(encoding.inline_info.encoding, 2)); + StackMap sm1 = ci.GetStackMapAt(1); + + DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm1, 2); + ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); + ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci)); + + InlineInfo if1 = ci.GetInlineInfoOf(sm1); + ASSERT_EQ(3u, if1.GetDepth()); + ASSERT_EQ(2u, if1.GetDexPcAtDepth(0)); + ASSERT_TRUE(if1.EncodesArtMethodAtDepth(0)); + ASSERT_EQ(3u, if1.GetDexPcAtDepth(1)); + ASSERT_TRUE(if1.EncodesArtMethodAtDepth(1)); + ASSERT_EQ(5u, if1.GetDexPcAtDepth(2)); + ASSERT_TRUE(if1.EncodesArtMethodAtDepth(2)); + + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, 1); + ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci)); + + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, 3); + ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0, 3, ci)); + ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci)); + ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci)); + + ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2)); } { // Verify third stack map. - StackMap sm2 = ci.GetStackMapAt(2, encoding); + StackMap sm2 = ci.GetStackMapAt(2); - DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, encoding, 2); + DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm2, 2); ASSERT_FALSE(dex_registers0.IsDexRegisterLive(0)); - ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci, encoding)); - ASSERT_FALSE(sm2.HasInlineInfo(encoding.stack_map.encoding)); + ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci)); + ASSERT_FALSE(sm2.HasInlineInfo()); } { // Verify fourth stack map. - StackMap sm3 = ci.GetStackMapAt(3, encoding); + StackMap sm3 = ci.GetStackMapAt(3); - DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, encoding, 2); - ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci, encoding)); - ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding)); + DexRegisterMap dex_registers0 = ci.GetDexRegisterMapOf(sm3, 2); + ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0, 2, ci)); + ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci)); - InlineInfo if2 = ci.GetInlineInfoOf(sm3, encoding); - ASSERT_EQ(3u, if2.GetDepth(encoding.inline_info.encoding)); - ASSERT_EQ(2u, if2.GetDexPcAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 0)); - ASSERT_EQ(5u, if2.GetDexPcAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 1)); - ASSERT_EQ(10u, if2.GetDexPcAtDepth(encoding.inline_info.encoding, 2)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(encoding.inline_info.encoding, 2)); + InlineInfo if2 = ci.GetInlineInfoOf(sm3); + ASSERT_EQ(3u, if2.GetDepth()); + ASSERT_EQ(2u, if2.GetDexPcAtDepth(0)); + ASSERT_TRUE(if2.EncodesArtMethodAtDepth(0)); + ASSERT_EQ(5u, if2.GetDexPcAtDepth(1)); + ASSERT_TRUE(if2.EncodesArtMethodAtDepth(1)); + ASSERT_EQ(10u, if2.GetDexPcAtDepth(2)); + ASSERT_TRUE(if2.EncodesArtMethodAtDepth(2)); - ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(encoding.inline_info.encoding, 0)); + ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0)); - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, encoding, 1); - ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci, encoding)); + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, 1); + ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci)); - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, encoding, 2); + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, 2); ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0)); - ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci, encoding)); + ASSERT_EQ(3, dex_registers2.GetMachineRegister(1, 2, ci)); } } TEST(StackMapTest, CodeOffsetTest) { - // Test minimum alignments, encoding, and decoding. + // Test minimum alignments, and decoding. CodeOffset offset_thumb2 = CodeOffset::FromOffset(kThumb2InstructionAlignment, InstructionSet::kThumb2); CodeOffset offset_arm64 = @@ -969,13 +960,12 @@ TEST(StackMapTest, TestDeduplicateStackMask) { stream.FillInCodeInfo(region); CodeInfo code_info(region); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(2u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(2u, code_info.GetNumberOfStackMaps()); - StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4, encoding); - StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8, encoding); - EXPECT_EQ(stack_map1.GetStackMaskIndex(encoding.stack_map.encoding), - stack_map2.GetStackMaskIndex(encoding.stack_map.encoding)); + StackMap stack_map1 = code_info.GetStackMapForNativePcOffset(4); + StackMap stack_map2 = code_info.GetStackMapForNativePcOffset(8); + EXPECT_EQ(stack_map1.GetStackMaskIndex(), + stack_map2.GetStackMaskIndex()); } TEST(StackMapTest, TestInvokeInfo) { @@ -1007,26 +997,25 @@ TEST(StackMapTest, TestInvokeInfo) { CodeInfo code_info(code_info_region); MethodInfo method_info(method_info_region.begin()); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - ASSERT_EQ(3u, code_info.GetNumberOfStackMaps(encoding)); + ASSERT_EQ(3u, code_info.GetNumberOfStackMaps()); - InvokeInfo invoke1(code_info.GetInvokeInfoForNativePcOffset(4, encoding)); - InvokeInfo invoke2(code_info.GetInvokeInfoForNativePcOffset(8, encoding)); - InvokeInfo invoke3(code_info.GetInvokeInfoForNativePcOffset(16, encoding)); - InvokeInfo invoke_invalid(code_info.GetInvokeInfoForNativePcOffset(12, encoding)); + InvokeInfo invoke1(code_info.GetInvokeInfoForNativePcOffset(4)); + InvokeInfo invoke2(code_info.GetInvokeInfoForNativePcOffset(8)); + InvokeInfo invoke3(code_info.GetInvokeInfoForNativePcOffset(16)); + InvokeInfo invoke_invalid(code_info.GetInvokeInfoForNativePcOffset(12)); EXPECT_FALSE(invoke_invalid.IsValid()); // No entry for that index. EXPECT_TRUE(invoke1.IsValid()); EXPECT_TRUE(invoke2.IsValid()); EXPECT_TRUE(invoke3.IsValid()); - EXPECT_EQ(invoke1.GetInvokeType(encoding.invoke_info.encoding), kSuper); - EXPECT_EQ(invoke1.GetMethodIndex(encoding.invoke_info.encoding, method_info), 1u); - EXPECT_EQ(invoke1.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 4u); - EXPECT_EQ(invoke2.GetInvokeType(encoding.invoke_info.encoding), kStatic); - EXPECT_EQ(invoke2.GetMethodIndex(encoding.invoke_info.encoding, method_info), 3u); - EXPECT_EQ(invoke2.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 8u); - EXPECT_EQ(invoke3.GetInvokeType(encoding.invoke_info.encoding), kDirect); - EXPECT_EQ(invoke3.GetMethodIndex(encoding.invoke_info.encoding, method_info), 65535u); - EXPECT_EQ(invoke3.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA), 16u); + EXPECT_EQ(invoke1.GetInvokeType(), kSuper); + EXPECT_EQ(invoke1.GetMethodIndex(method_info), 1u); + EXPECT_EQ(invoke1.GetNativePcOffset(kRuntimeISA), 4u); + EXPECT_EQ(invoke2.GetInvokeType(), kStatic); + EXPECT_EQ(invoke2.GetMethodIndex(method_info), 3u); + EXPECT_EQ(invoke2.GetNativePcOffset(kRuntimeISA), 8u); + EXPECT_EQ(invoke3.GetInvokeType(), kDirect); + EXPECT_EQ(invoke3.GetMethodIndex(method_info), 65535u); + EXPECT_EQ(invoke3.GetNativePcOffset(kRuntimeISA), 16u); } } // namespace art diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index 18548baf7f..e74947ad6a 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -202,6 +202,7 @@ art_cc_binary { "libart-dexlayout", "libart", "libdexfile", + "libartbase", "libbase", "liblz4", "libsigchain", @@ -239,6 +240,7 @@ art_cc_binary { "libartd-dexlayout", "libartd", "libdexfiled", + "libartbased", "libbase", "liblz4", "libsigchain", @@ -267,12 +269,13 @@ art_cc_binary { "-z muldefs", ], static_libs: [ - "libprofile", "libart-dex2oat", "libart-compiler", "libart-dexlayout", "libart", + "libartbase", "libdexfile", + "libprofile", "libvixl-arm", "libvixl-arm64", ] + art_static_dependencies, @@ -309,6 +312,7 @@ art_cc_binary { "libartd-compiler", "libartd-dexlayout", "libartd", + "libartbased", "libprofiled", "libdexfiled", "libvixld-arm", diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 9e5cd8035c..01726af1d6 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -248,7 +248,6 @@ bool ImageWriter::Write(int image_fd, CHECK_EQ(image_header->storage_mode_, image_storage_mode_); switch (image_storage_mode_) { - case ImageHeader::kStorageModeLZ4HC: // Fall-through. case ImageHeader::kStorageModeLZ4: { const size_t compressed_max_size = LZ4_compressBound(image_data_size); compressed_data.reset(new char[compressed_max_size]); @@ -257,22 +256,20 @@ bool ImageWriter::Write(int image_fd, &compressed_data[0], image_data_size, compressed_max_size); - break; } - /* - * Disabled due to image_test64 flakyness. Both use same decompression. b/27560444 case ImageHeader::kStorageModeLZ4HC: { // Bound is same as non HC. const size_t compressed_max_size = LZ4_compressBound(image_data_size); compressed_data.reset(new char[compressed_max_size]); - data_size = LZ4_compressHC( + data_size = LZ4_compress_HC( reinterpret_cast<char*>(image_info.image_->Begin()) + sizeof(ImageHeader), &compressed_data[0], - image_data_size); + image_data_size, + compressed_max_size, + LZ4HC_CLEVEL_MAX); break; } - */ case ImageHeader::kStorageModeUncompressed: { data_size = image_data_size; image_data_to_write = image_data; @@ -1067,18 +1064,12 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache, } if (method == nullptr || i < stored_index) { if (last_class != nullptr) { - const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - Signature signature = dex_file.GetMethodSignature(method_id); - if (last_class->IsInterface()) { - method = last_class->FindInterfaceMethod(name, signature, target_ptr_size_); - } else { - method = last_class->FindClassMethod(name, signature, target_ptr_size_); - } - if (method != nullptr) { - // If the referenced class is in the image, the defining class must also be there. - DCHECK(KeepClass(method->GetDeclaringClass())); - dex_cache->SetResolvedMethod(i, method, target_ptr_size_); - } + // Try to resolve the method with the class linker, which will insert + // it into the dex cache if successful. + method = class_linker->FindResolvedMethod(last_class, dex_cache, class_loader, i); + // If the referenced class is in the image, the defining class must also be there. + DCHECK(method == nullptr || KeepClass(method->GetDeclaringClass())); + DCHECK(method == nullptr || dex_cache->GetResolvedMethod(i, target_ptr_size_) == method); } } else { DCHECK_EQ(i, stored_index); @@ -1112,14 +1103,10 @@ void ImageWriter::PruneAndPreloadDexCache(ObjPtr<mirror::DexCache> dex_cache, } if (field == nullptr || i < stored_index) { if (last_class != nullptr) { - const char* name = dex_file.StringDataByIdx(field_id.name_idx_); - const char* type = dex_file.StringByTypeIdx(field_id.type_idx_); - field = mirror::Class::FindField(Thread::Current(), last_class, name, type); - if (field != nullptr) { - // If the referenced class is in the image, the defining class must also be there. - DCHECK(KeepClass(field->GetDeclaringClass())); - dex_cache->SetResolvedField(i, field, target_ptr_size_); - } + field = class_linker->FindResolvedFieldJLS(last_class, dex_cache, class_loader, i); + // If the referenced class is in the image, the defining class must also be there. + DCHECK(field == nullptr || KeepClass(field->GetDeclaringClass())); + DCHECK(field == nullptr || dex_cache->GetResolvedField(i, target_ptr_size_) == field); } } else { DCHECK_EQ(i, stored_index); @@ -1208,7 +1195,9 @@ void ImageWriter::PruneNonImageClasses() { } } for (ObjPtr<mirror::DexCache> dex_cache : dex_caches) { - PruneAndPreloadDexCache(dex_cache, class_loader); + // Pass the class loader associated with the DexCache. This can either be + // the app's `class_loader` or `nullptr` if boot class loader. + PruneAndPreloadDexCache(dex_cache, IsInBootImage(dex_cache.Ptr()) ? nullptr : class_loader); } // Drop the array class cache in the ClassLinker, as these are roots holding those classes live. diff --git a/dexdump/Android.bp b/dexdump/Android.bp index c63d6c319e..2f0962c19a 100644 --- a/dexdump/Android.bp +++ b/dexdump/Android.bp @@ -35,6 +35,7 @@ art_cc_binary { host_supported: true, shared_libs: [ "libdexfile", + "libartbase", "libbase", ], } @@ -46,6 +47,7 @@ art_cc_binary { device_supported: false, static_libs: [ "libdexfile", + "libartbase", ] + art_static_dependencies, target: { darwin: { diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 9536381ed0..e72d49e05f 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -786,11 +786,10 @@ static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) { static std::unique_ptr<char[]> indexString(const DexFile* pDexFile, const Instruction* pDecInsn, size_t bufSize) { - static const u4 kInvalidIndex = std::numeric_limits<u4>::max(); std::unique_ptr<char[]> buf(new char[bufSize]); // Determine index and width of the string. u4 index = 0; - u4 secondary_index = kInvalidIndex; + u2 secondary_index = 0; u4 width = 4; switch (Instruction::FormatOf(pDecInsn->Opcode())) { // SOME NOT SUPPORTED: @@ -898,7 +897,7 @@ static std::unique_ptr<char[]> indexString(const DexFile* pDexFile, signature.ToString().c_str()); } if (secondary_index < pDexFile->GetHeader().proto_ids_size_) { - const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index); + const DexFile::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(secondary_index)); const Signature signature = pDexFile->GetProtoSignature(protoId); proto = signature.ToString(); } @@ -916,7 +915,7 @@ static std::unique_ptr<char[]> indexString(const DexFile* pDexFile, break; case Instruction::kIndexProtoRef: if (index < pDexFile->GetHeader().proto_ids_size_) { - const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index); + const DexFile::ProtoId& protoId = pDexFile->GetProtoId(dex::ProtoIndex(index)); const Signature signature = pDexFile->GetProtoSignature(protoId); const std::string& proto = signature.ToString(); outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index); @@ -1705,7 +1704,7 @@ static void dumpCallSite(const DexFile* pDexFile, u4 idx) { dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i); const char* method_name = pDexFile->StringDataByIdx(method_name_idx); it.Next(); - uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i); + dex::ProtoIndex method_type_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i); const DexFile::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx); std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString(); it.Next(); @@ -1763,7 +1762,7 @@ static void dumpCallSite(const DexFile* pDexFile, u4 idx) { break; case EncodedArrayValueIterator::ValueType::kMethodType: { type = "MethodType"; - uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i); + dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(it.GetJavaValue().i); const DexFile::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx); value = pDexFile->GetProtoSignature(proto_id).ToString(); break; diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index b009774582..147af0c6a9 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -39,8 +39,8 @@ art_cc_library { "dex2oat-pgo-defaults", ], shared_libs: [ - "libart", "libdexfile", + "libartbase", "libprofile", ], @@ -60,8 +60,8 @@ art_cc_library { "art_debug_defaults", ], shared_libs: [ - "libartd", "libdexfiled", + "libartbased", "libprofiled", ], } @@ -70,7 +70,6 @@ cc_defaults { name: "dexlayout-defaults", defaults: ["art_defaults"], host_supported: true, - srcs: ["dexlayout_main.cc"], shared_libs: [ "libbase", ], @@ -79,9 +78,11 @@ cc_defaults { art_cc_binary { name: "dexlayout", defaults: ["dexlayout-defaults"], + srcs: ["dexlayout_main.cc"], shared_libs: [ + "libdexfile", "libprofile", - "libart", + "libartbase", "libart-dexlayout", ], } @@ -92,9 +93,11 @@ art_cc_binary { "art_debug_defaults", "dexlayout-defaults", ], + srcs: ["dexlayout_main.cc"], shared_libs: [ + "libdexfiled", "libprofiled", - "libartd", + "libartbased", "libartd-dexlayout", ], } @@ -117,6 +120,8 @@ art_cc_binary { cflags: ["-Wall"], shared_libs: [ "libart", + "libdexfile", + "libartbase", "libart-dexlayout", "libbase", ], diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 1525d537b7..b7d9db6da5 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -332,7 +332,7 @@ void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) { } void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) { - const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i); + const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i)); const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id); TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_); @@ -353,7 +353,7 @@ void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) { void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) { const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i); MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_), - GetProtoId(disk_method_id.proto_idx_), + GetProtoId(disk_method_id.proto_idx_.index_), GetStringId(disk_method_id.name_idx_.index_)); AddIndexedItem(method_ids_, method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i); } diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc index 6cb141f688..aa4e6d031e 100644 --- a/dexlayout/dexdiag.cc +++ b/dexlayout/dexdiag.cc @@ -27,7 +27,6 @@ #include "android-base/stringprintf.h" #include "base/logging.h" // For InitLogging. -#include "base/mutex.h" #include "base/stringpiece.h" #include "dexlayout.h" @@ -37,7 +36,6 @@ #ifdef ART_TARGET_ANDROID #include "pagemap/pagemap.h" #endif -#include "runtime.h" #include "vdex_file.h" namespace art { @@ -446,6 +444,11 @@ static void Usage(const char* cmd) { PrintLetterKey(); } +NO_RETURN static void Abort(const char* msg) { + std::cerr << msg; + exit(1); +} + static int DexDiagMain(int argc, char* argv[]) { if (argc < 2) { Usage(argv[0]); @@ -471,8 +474,7 @@ static int DexDiagMain(int argc, char* argv[]) { } // Art specific set up. - Locks::Init(); - InitLogging(argv, Runtime::Abort); + InitLogging(argv, Abort); MemMap::Init(); #ifdef ART_TARGET_ANDROID diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 185c1420ab..71e56d19ea 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -34,7 +34,6 @@ #include "base/logging.h" // For InitLogging. #include "base/mem_map.h" #include "profile/profile_compilation_info.h" -#include "runtime.h" namespace art { @@ -66,12 +65,17 @@ static void Usage(void) { LOG(ERROR) << " -x : compact dex generation level, either 'none' or 'fast'"; } +NO_RETURN static void Abort(const char* msg) { + LOG(ERROR) << msg; + exit(1); +} + /* * Main driver of the dexlayout utility. */ int DexlayoutDriver(int argc, char** argv) { // Art specific set up. - InitLogging(argv, Runtime::Abort); + InitLogging(argv, Abort); MemMap::Init(); Options options; diff --git a/dexlist/Android.bp b/dexlist/Android.bp index 2703732db6..bd521acbc0 100644 --- a/dexlist/Android.bp +++ b/dexlist/Android.bp @@ -17,7 +17,11 @@ art_cc_binary { host_supported: true, srcs: ["dexlist.cc"], cflags: ["-Wall", "-Werror"], - shared_libs: ["libdexfile", "libbase"], + shared_libs: [ + "libdexfile", + "libartbase", + "libbase" + ], // TODO: fix b/72216369 and remove the need for this. include_dirs: [ "art/runtime" // dex utils. diff --git a/dexoptanalyzer/Android.bp b/dexoptanalyzer/Android.bp index 33366ad371..99a11cd59b 100644 --- a/dexoptanalyzer/Android.bp +++ b/dexoptanalyzer/Android.bp @@ -38,6 +38,7 @@ art_cc_binary { defaults: ["dexoptanalyzer-defaults"], shared_libs: [ "libart", + "libartbase", ], } @@ -49,6 +50,7 @@ art_cc_binary { ], shared_libs: [ "libartd", + "libartbased", ], } diff --git a/imgdiag/Android.bp b/imgdiag/Android.bp index 2b89497e8e..972c8f7189 100644 --- a/imgdiag/Android.bp +++ b/imgdiag/Android.bp @@ -57,6 +57,7 @@ art_cc_binary { defaults: ["imgdiag-defaults"], shared_libs: [ "libart", + "libartbase", "libart-compiler", ], } @@ -69,6 +70,7 @@ art_cc_binary { ], shared_libs: [ "libartd", + "libartbased", "libartd-compiler", ], } diff --git a/libartbase/Android.bp b/libartbase/Android.bp index 50abdd36af..adf0ad6376 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -19,11 +19,13 @@ cc_defaults { defaults: ["art_defaults"], host_supported: true, srcs: [ + "arch/instruction_set.cc", "base/allocator.cc", "base/arena_allocator.cc", "base/arena_bit_vector.cc", "base/bit_vector.cc", "base/file_magic.cc", + "base/file_utils.cc", "base/hex_dump.cc", "base/logging.cc", "base/malloc_arena_pool.cc", @@ -62,7 +64,6 @@ cc_defaults { generated_sources: ["art_libartbase_operator_srcs"], cflags: ["-DBUILDING_LIBART=1"], shared_libs: [ - "libbacktrace", "liblog", // For ashmem. "libcutils", @@ -81,6 +82,7 @@ gensrcs { cmd: "$(location generate_operator_out) art/libartbase $(in) > $(out)", tools: ["generate_operator_out"], srcs: [ + "arch/instruction_set.h", "base/allocator.h", "base/callee_save_type.h", "base/unix_file/fd_file.h", @@ -142,12 +144,16 @@ art_cc_test { "art_gtest_defaults", ], srcs: [ + "arch/instruction_set_test.cc", "base/arena_allocator_test.cc", "base/bit_field_test.cc", + "base/bit_memory_region_test.cc", "base/bit_string_test.cc", "base/bit_struct_test.cc", + "base/bit_table_test.cc", "base/bit_utils_test.cc", "base/bit_vector_test.cc", + "base/file_utils_test.cc", "base/hash_set_test.cc", "base/hex_dump_test.cc", "base/histogram_test.cc", diff --git a/runtime/arch/instruction_set.cc b/libartbase/arch/instruction_set.cc index b848eb27fc..a187663062 100644 --- a/runtime/arch/instruction_set.cc +++ b/libartbase/arch/instruction_set.cc @@ -16,8 +16,6 @@ #include "instruction_set.h" -// Explicitly include our own elf.h to avoid Linux and other dependencies. -#include "../elf.h" #include "android-base/logging.h" #include "base/bit_utils.h" #include "base/globals.h" @@ -83,29 +81,6 @@ InstructionSet GetInstructionSetFromString(const char* isa_str) { return InstructionSet::kNone; } -InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) { - switch (e_machine) { - case EM_ARM: - return InstructionSet::kArm; - case EM_AARCH64: - return InstructionSet::kArm64; - case EM_386: - return InstructionSet::kX86; - case EM_X86_64: - return InstructionSet::kX86_64; - case EM_MIPS: { - if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 || - (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) { - return InstructionSet::kMips; - } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) { - return InstructionSet::kMips64; - } - break; - } - } - return InstructionSet::kNone; -} - size_t GetInstructionSetAlignment(InstructionSet isa) { switch (isa) { case InstructionSet::kArm: diff --git a/runtime/arch/instruction_set.h b/libartbase/arch/instruction_set.h index 6434005dda..06bd53a6a9 100644 --- a/runtime/arch/instruction_set.h +++ b/libartbase/arch/instruction_set.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_H_ -#define ART_RUNTIME_ARCH_INSTRUCTION_SET_H_ +#ifndef ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_ +#define ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_ #include <iosfwd> #include <string> @@ -89,8 +89,6 @@ const char* GetInstructionSetString(InstructionSet isa); // Note: Returns kNone when the string cannot be parsed to a known value. InstructionSet GetInstructionSetFromString(const char* instruction_set); -InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags); - // Fatal logging out of line to keep the header clean of logging.h. NO_RETURN void InstructionSetAbort(InstructionSet isa); @@ -299,4 +297,4 @@ static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) { } // namespace art -#endif // ART_RUNTIME_ARCH_INSTRUCTION_SET_H_ +#endif // ART_LIBARTBASE_ARCH_INSTRUCTION_SET_H_ diff --git a/runtime/arch/instruction_set_test.cc b/libartbase/arch/instruction_set_test.cc index 12a117d7a1..12a117d7a1 100644 --- a/runtime/arch/instruction_set_test.cc +++ b/libartbase/arch/instruction_set_test.cc diff --git a/libartbase/base/bit_memory_region.h b/libartbase/base/bit_memory_region.h index f3926bc9d8..3f4d0ba55b 100644 --- a/libartbase/base/bit_memory_region.h +++ b/libartbase/base/bit_memory_region.h @@ -19,6 +19,9 @@ #include "memory_region.h" +#include "bit_utils.h" +#include "memory_tool.h" + namespace art { // Bit memory region is a bit offset subregion of a normal memoryregion. This is useful for @@ -26,46 +29,126 @@ namespace art { class BitMemoryRegion FINAL : public ValueObject { public: BitMemoryRegion() = default; - ALWAYS_INLINE BitMemoryRegion(MemoryRegion region, size_t bit_offset, size_t bit_size) { - bit_start_ = bit_offset % kBitsPerByte; - const size_t start = bit_offset / kBitsPerByte; - const size_t end = (bit_offset + bit_size + kBitsPerByte - 1) / kBitsPerByte; - region_ = region.Subregion(start, end - start); + ALWAYS_INLINE explicit BitMemoryRegion(MemoryRegion region) + : data_(reinterpret_cast<uintptr_t*>(AlignDown(region.pointer(), sizeof(uintptr_t)))), + bit_start_(8 * (reinterpret_cast<uintptr_t>(region.pointer()) % sizeof(uintptr_t))), + bit_size_(region.size_in_bits()) { + } + ALWAYS_INLINE BitMemoryRegion(MemoryRegion region, size_t bit_offset, size_t bit_length) + : BitMemoryRegion(region) { + DCHECK_LE(bit_offset, bit_size_); + DCHECK_LE(bit_length, bit_size_ - bit_offset); + bit_start_ += bit_offset; + bit_size_ = bit_length; } - void* pointer() const { return region_.pointer(); } - size_t size() const { return region_.size(); } - size_t BitOffset() const { return bit_start_; } + ALWAYS_INLINE bool IsValid() const { return data_ != nullptr; } + size_t size_in_bits() const { - return region_.size_in_bits(); + return bit_size_; } - ALWAYS_INLINE BitMemoryRegion Subregion(size_t bit_offset, size_t bit_size) const { - return BitMemoryRegion(region_, bit_start_ + bit_offset, bit_size); + ALWAYS_INLINE BitMemoryRegion Subregion(size_t bit_offset, size_t bit_length) const { + DCHECK_LE(bit_offset, bit_size_); + DCHECK_LE(bit_length, bit_size_ - bit_offset); + BitMemoryRegion result = *this; + result.bit_start_ += bit_offset; + result.bit_size_ = bit_length; + return result; } // Load a single bit in the region. The bit at offset 0 is the least // significant bit in the first byte. + ATTRIBUTE_NO_SANITIZE_ADDRESS // We might touch extra bytes due to the alignment. ALWAYS_INLINE bool LoadBit(uintptr_t bit_offset) const { - return region_.LoadBit(bit_offset + bit_start_); + DCHECK_LT(bit_offset, bit_size_); + size_t index = (bit_start_ + bit_offset) / kBitsPerIntPtrT; + size_t shift = (bit_start_ + bit_offset) % kBitsPerIntPtrT; + return ((data_[index] >> shift) & 1) != 0; } ALWAYS_INLINE void StoreBit(uintptr_t bit_offset, bool value) const { - region_.StoreBit(bit_offset + bit_start_, value); + DCHECK_LT(bit_offset, bit_size_); + uint8_t* data = reinterpret_cast<uint8_t*>(data_); + size_t index = (bit_start_ + bit_offset) / kBitsPerByte; + size_t shift = (bit_start_ + bit_offset) % kBitsPerByte; + data[index] &= ~(1 << shift); // Clear bit. + data[index] |= (value ? 1 : 0) << shift; // Set bit. + DCHECK_EQ(value, LoadBit(bit_offset)); + } + + // Load `bit_length` bits from `data` starting at given `bit_offset`. + // The least significant bit is stored in the smallest memory offset. + ATTRIBUTE_NO_SANITIZE_ADDRESS // We might touch extra bytes due to the alignment. + ALWAYS_INLINE uint32_t LoadBits(size_t bit_offset, size_t bit_length) const { + DCHECK(IsAligned<sizeof(uintptr_t)>(data_)); + DCHECK_LE(bit_offset, bit_size_); + DCHECK_LE(bit_length, bit_size_ - bit_offset); + DCHECK_LE(bit_length, BitSizeOf<uint32_t>()); + if (bit_length == 0) { + return 0; + } + uintptr_t mask = std::numeric_limits<uintptr_t>::max() >> (kBitsPerIntPtrT - bit_length); + size_t index = (bit_start_ + bit_offset) / kBitsPerIntPtrT; + size_t shift = (bit_start_ + bit_offset) % kBitsPerIntPtrT; + uintptr_t value = data_[index] >> shift; + size_t finished_bits = kBitsPerIntPtrT - shift; + if (finished_bits < bit_length) { + value |= data_[index + 1] << finished_bits; + } + return value & mask; + } + + // Load bits starting at given `bit_offset`, and advance the `bit_offset`. + ALWAYS_INLINE uint32_t LoadBitsAndAdvance(size_t* bit_offset, size_t bit_length) const { + uint32_t result = LoadBits(*bit_offset, bit_length); + *bit_offset += bit_length; + return result; + } + + // Store `bit_length` bits in `data` starting at given `bit_offset`. + // The least significant bit is stored in the smallest memory offset. + ALWAYS_INLINE void StoreBits(size_t bit_offset, uint32_t value, size_t bit_length) { + DCHECK_LE(bit_offset, bit_size_); + DCHECK_LE(bit_length, bit_size_ - bit_offset); + DCHECK_LE(bit_length, BitSizeOf<uint32_t>()); + DCHECK_LE(value, MaxInt<uint32_t>(bit_length)); + if (bit_length == 0) { + return; + } + // Write data byte by byte to avoid races with other threads + // on bytes that do not overlap with this region. + uint8_t* data = reinterpret_cast<uint8_t*>(data_); + uint32_t mask = std::numeric_limits<uint32_t>::max() >> (BitSizeOf<uint32_t>() - bit_length); + size_t index = (bit_start_ + bit_offset) / kBitsPerByte; + size_t shift = (bit_start_ + bit_offset) % kBitsPerByte; + data[index] &= ~(mask << shift); // Clear bits. + data[index] |= (value << shift); // Set bits. + size_t finished_bits = kBitsPerByte - shift; + for (int i = 1; finished_bits < bit_length; i++, finished_bits += kBitsPerByte) { + data[index + i] &= ~(mask >> finished_bits); // Clear bits. + data[index + i] |= (value >> finished_bits); // Set bits. + } + DCHECK_EQ(value, LoadBits(bit_offset, bit_length)); } - ALWAYS_INLINE uint32_t LoadBits(uintptr_t bit_offset, size_t length) const { - return region_.LoadBits(bit_offset + bit_start_, length); + // Store bits starting at given `bit_offset`, and advance the `bit_offset`. + ALWAYS_INLINE void StoreBitsAndAdvance(size_t* bit_offset, uint32_t value, size_t bit_length) { + StoreBits(*bit_offset, value, bit_length); + *bit_offset += bit_length; } - // Store at a bit offset from inside the bit memory region. - ALWAYS_INLINE void StoreBits(uintptr_t bit_offset, uint32_t value, size_t length) { - region_.StoreBits(bit_offset + bit_start_, value, length); + ALWAYS_INLINE bool Equals(const BitMemoryRegion& other) const { + return data_ == other.data_ && + bit_start_ == other.bit_start_ && + bit_size_ == other.bit_size_; } private: - MemoryRegion region_; + // The data pointer must be naturally aligned. This makes loading code faster. + uintptr_t* data_ = nullptr; size_t bit_start_ = 0; + size_t bit_size_ = 0; }; } // namespace art diff --git a/libartbase/base/bit_memory_region_test.cc b/libartbase/base/bit_memory_region_test.cc new file mode 100644 index 0000000000..b7546985a9 --- /dev/null +++ b/libartbase/base/bit_memory_region_test.cc @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 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 "bit_memory_region.h" + +#include "gtest/gtest.h" + +namespace art { + +static void CheckBits(uint8_t* data, + size_t size, + uint32_t init, + size_t offset, + size_t length, + uint32_t value) { + for (size_t i = 0; i < size * kBitsPerByte; i++) { + uint8_t expected = (offset <= i && i < offset + length) ? value >> (i - offset) : init; + uint8_t actual = data[i / kBitsPerByte] >> (i % kBitsPerByte); + EXPECT_EQ(expected & 1, actual & 1); + } +} + +TEST(BitMemoryRegion, TestBit) { + uint8_t data[sizeof(uint32_t) * 2]; + for (size_t bit_offset = 0; bit_offset < 2 * sizeof(uint32_t) * kBitsPerByte; ++bit_offset) { + for (uint32_t initial_value = 0; initial_value <= 1; initial_value++) { + for (uint32_t value = 0; value <= 1; value++) { + // Check Store and Load with bit_offset set on the region. + std::fill_n(data, sizeof(data), initial_value * 0xFF); + BitMemoryRegion bmr1(MemoryRegion(&data, sizeof(data)), bit_offset, 1); + bmr1.StoreBit(0, value); + EXPECT_EQ(bmr1.LoadBit(0), value); + CheckBits(data, sizeof(data), initial_value, bit_offset, 1, value); + // Check Store and Load with bit_offset set on the methods. + std::fill_n(data, sizeof(data), initial_value * 0xFF); + BitMemoryRegion bmr2(MemoryRegion(&data, sizeof(data))); + bmr2.StoreBit(bit_offset, value); + EXPECT_EQ(bmr2.LoadBit(bit_offset), value); + CheckBits(data, sizeof(data), initial_value, bit_offset, 1, value); + } + } + } +} + +TEST(BitMemoryRegion, TestBits) { + uint8_t data[sizeof(uint32_t) * 4]; + for (size_t bit_offset = 0; bit_offset < 3 * sizeof(uint32_t) * kBitsPerByte; ++bit_offset) { + uint32_t mask = 0; + for (size_t bit_length = 0; bit_length < sizeof(uint32_t) * kBitsPerByte; ++bit_length) { + const uint32_t value = 0xDEADBEEF & mask; + for (uint32_t initial_value = 0; initial_value <= 1; initial_value++) { + // Check Store and Load with bit_offset set on the region. + std::fill_n(data, sizeof(data), initial_value * 0xFF); + BitMemoryRegion bmr1(MemoryRegion(&data, sizeof(data)), bit_offset, bit_length); + bmr1.StoreBits(0, value, bit_length); + EXPECT_EQ(bmr1.LoadBits(0, bit_length), value); + CheckBits(data, sizeof(data), initial_value, bit_offset, bit_length, value); + // Check Store and Load with bit_offset set on the methods. + std::fill_n(data, sizeof(data), initial_value * 0xFF); + BitMemoryRegion bmr2(MemoryRegion(&data, sizeof(data))); + bmr2.StoreBits(bit_offset, value, bit_length); + EXPECT_EQ(bmr2.LoadBits(bit_offset, bit_length), value); + CheckBits(data, sizeof(data), initial_value, bit_offset, bit_length, value); + } + mask = (mask << 1) | 1; + } + } +} + +} // namespace art diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h new file mode 100644 index 0000000000..24bdd13324 --- /dev/null +++ b/libartbase/base/bit_table.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2018 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_LIBARTBASE_BASE_BIT_TABLE_H_ +#define ART_LIBARTBASE_BASE_BIT_TABLE_H_ + +#include <vector> + +#include "base/bit_memory_region.h" +#include "base/bit_utils.h" +#include "base/memory_region.h" + +namespace art { + +constexpr uint32_t kVarintHeaderBits = 4; +constexpr uint32_t kVarintSmallValue = 11; // Maximum value which is stored as-is. + +// Load variable-length bit-packed integer from `data` starting at `bit_offset`. +// The first four bits determine the variable length of the encoded integer: +// Values 0..11 represent the result as-is, with no further following bits. +// Values 12..15 mean the result is in the next 8/16/24/32-bits respectively. +ALWAYS_INLINE static inline uint32_t DecodeVarintBits(BitMemoryRegion region, size_t* bit_offset) { + uint32_t x = region.LoadBitsAndAdvance(bit_offset, kVarintHeaderBits); + if (x > kVarintSmallValue) { + x = region.LoadBitsAndAdvance(bit_offset, (x - kVarintSmallValue) * kBitsPerByte); + } + return x; +} + +// Store variable-length bit-packed integer from `data` starting at `bit_offset`. +template<typename Vector> +ALWAYS_INLINE static inline void EncodeVarintBits(Vector* out, size_t* bit_offset, uint32_t value) { + if (value <= kVarintSmallValue) { + out->resize(BitsToBytesRoundUp(*bit_offset + kVarintHeaderBits)); + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + region.StoreBitsAndAdvance(bit_offset, value, kVarintHeaderBits); + } else { + uint32_t num_bits = RoundUp(MinimumBitsToStore(value), kBitsPerByte); + out->resize(BitsToBytesRoundUp(*bit_offset + kVarintHeaderBits + num_bits)); + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + uint32_t header = kVarintSmallValue + num_bits / kBitsPerByte; + region.StoreBitsAndAdvance(bit_offset, header, kVarintHeaderBits); + region.StoreBitsAndAdvance(bit_offset, value, num_bits); + } +} + +template<uint32_t kNumColumns> +class BitTable { + public: + class Accessor { + public: + static constexpr uint32_t kNoValue = std::numeric_limits<uint32_t>::max(); + + Accessor(const BitTable* table, uint32_t row) : table_(table), row_(row) {} + + ALWAYS_INLINE uint32_t Row() const { return row_; } + + ALWAYS_INLINE bool IsValid() const { return table_ != nullptr && row_ < table_->NumRows(); } + + template<uint32_t Column> + ALWAYS_INLINE uint32_t Get() const { + static_assert(Column < kNumColumns, "Column out of bounds"); + return table_->Get(row_, Column); + } + + ALWAYS_INLINE bool Equals(const Accessor& other) { + return this->table_ == other.table_ && this->row_ == other.row_; + } + + Accessor& operator++() { + row_++; + return *this; + } + + protected: + const BitTable* table_; + uint32_t row_; + }; + + static constexpr uint32_t kValueBias = -1; + + BitTable() {} + BitTable(void* data, size_t size, size_t* bit_offset = 0) { + Decode(BitMemoryRegion(MemoryRegion(data, size)), bit_offset); + } + + ALWAYS_INLINE void Decode(BitMemoryRegion region, size_t* bit_offset) { + // Decode row count and column sizes from the table header. + num_rows_ = DecodeVarintBits(region, bit_offset); + if (num_rows_ != 0) { + column_offset_[0] = 0; + for (uint32_t i = 0; i < kNumColumns; i++) { + size_t column_end = column_offset_[i] + DecodeVarintBits(region, bit_offset); + column_offset_[i + 1] = column_end; + DCHECK_EQ(column_offset_[i + 1], column_end) << "Overflow"; + } + } + + // Record the region which contains the table data and skip past it. + table_data_ = region.Subregion(*bit_offset, num_rows_ * NumRowBits()); + *bit_offset += table_data_.size_in_bits(); + } + + ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column = 0) const { + DCHECK_LT(row, num_rows_); + DCHECK_LT(column, kNumColumns); + size_t offset = row * NumRowBits() + column_offset_[column]; + return table_data_.LoadBits(offset, NumColumnBits(column)) + kValueBias; + } + + size_t NumRows() const { return num_rows_; } + + uint32_t NumRowBits() const { return column_offset_[kNumColumns]; } + + constexpr size_t NumColumns() const { return kNumColumns; } + + uint32_t NumColumnBits(uint32_t column) const { + return column_offset_[column + 1] - column_offset_[column]; + } + + size_t DataBitSize() const { return num_rows_ * column_offset_[kNumColumns]; } + + protected: + BitMemoryRegion table_data_; + size_t num_rows_ = 0; + + uint16_t column_offset_[kNumColumns + 1] = {}; +}; + +template<uint32_t kNumColumns> +constexpr uint32_t BitTable<kNumColumns>::Accessor::kNoValue; + +template<uint32_t kNumColumns> +constexpr uint32_t BitTable<kNumColumns>::kValueBias; + +template<uint32_t kNumColumns, typename Alloc = std::allocator<uint32_t>> +class BitTableBuilder { + public: + explicit BitTableBuilder(Alloc alloc = Alloc()) : buffer_(alloc) {} + + template<typename ... T> + uint32_t AddRow(T ... values) { + constexpr size_t count = sizeof...(values); + static_assert(count == kNumColumns, "Incorrect argument count"); + uint32_t data[count] = { values... }; + buffer_.insert(buffer_.end(), data, data + count); + return num_rows_++; + } + + ALWAYS_INLINE uint32_t Get(uint32_t row, uint32_t column) const { + return buffer_[row * kNumColumns + column]; + } + + template<typename Vector> + void Encode(Vector* out, size_t* bit_offset) { + constexpr uint32_t bias = BitTable<kNumColumns>::kValueBias; + size_t initial_bit_offset = *bit_offset; + // Measure data size. + uint32_t max_column_value[kNumColumns] = {}; + for (uint32_t r = 0; r < num_rows_; r++) { + for (uint32_t c = 0; c < kNumColumns; c++) { + max_column_value[c] |= Get(r, c) - bias; + } + } + // Write table header. + uint32_t table_data_bits = 0; + uint32_t column_bits[kNumColumns] = {}; + EncodeVarintBits(out, bit_offset, num_rows_); + if (num_rows_ != 0) { + for (uint32_t c = 0; c < kNumColumns; c++) { + column_bits[c] = MinimumBitsToStore(max_column_value[c]); + EncodeVarintBits(out, bit_offset, column_bits[c]); + table_data_bits += num_rows_ * column_bits[c]; + } + } + // Write table data. + out->resize(BitsToBytesRoundUp(*bit_offset + table_data_bits)); + BitMemoryRegion region(MemoryRegion(out->data(), out->size())); + for (uint32_t r = 0; r < num_rows_; r++) { + for (uint32_t c = 0; c < kNumColumns; c++) { + region.StoreBitsAndAdvance(bit_offset, Get(r, c) - bias, column_bits[c]); + } + } + // Verify the written data. + if (kIsDebugBuild) { + BitTable<kNumColumns> table; + table.Decode(region, &initial_bit_offset); + DCHECK_EQ(this->num_rows_, table.NumRows()); + for (uint32_t c = 0; c < kNumColumns; c++) { + DCHECK_EQ(column_bits[c], table.NumColumnBits(c)); + } + for (uint32_t r = 0; r < num_rows_; r++) { + for (uint32_t c = 0; c < kNumColumns; c++) { + DCHECK_EQ(this->Get(r, c), table.Get(r, c)) << " (" << r << ", " << c << ")"; + } + } + } + } + + protected: + std::vector<uint32_t, Alloc> buffer_; + uint32_t num_rows_ = 0; +}; + +} // namespace art + +#endif // ART_LIBARTBASE_BASE_BIT_TABLE_H_ diff --git a/libartbase/base/bit_table_test.cc b/libartbase/base/bit_table_test.cc new file mode 100644 index 0000000000..25bfcf095e --- /dev/null +++ b/libartbase/base/bit_table_test.cc @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018 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 "bit_table.h" + +#include "gtest/gtest.h" + +namespace art { + +TEST(BitTableTest, TestVarint) { + for (size_t start_bit_offset = 0; start_bit_offset <= 32; start_bit_offset++) { + uint32_t values[] = { 0, 1, 11, 12, 15, 16, 255, 256, ~1u, ~0u }; + for (uint32_t value : values) { + std::vector<uint8_t> buffer; + size_t encode_bit_offset = start_bit_offset; + EncodeVarintBits(&buffer, &encode_bit_offset, value); + + size_t decode_bit_offset = start_bit_offset; + BitMemoryRegion region(MemoryRegion(buffer.data(), buffer.size())); + uint32_t result = DecodeVarintBits(region, &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset); + EXPECT_EQ(value, result); + } + } +} + +TEST(BitTableTest, TestEmptyTable) { + std::vector<uint8_t> buffer; + size_t encode_bit_offset = 0; + BitTableBuilder<1> builder; + builder.Encode(&buffer, &encode_bit_offset); + + size_t decode_bit_offset = 0; + BitTable<1> table(buffer.data(), buffer.size(), &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset); + EXPECT_EQ(0u, table.NumRows()); +} + +TEST(BitTableTest, TestSingleColumnTable) { + constexpr uint32_t kNoValue = -1; + std::vector<uint8_t> buffer; + size_t encode_bit_offset = 0; + BitTableBuilder<1> builder; + builder.AddRow(42u); + builder.AddRow(kNoValue); + builder.AddRow(1000u); + builder.AddRow(kNoValue); + builder.Encode(&buffer, &encode_bit_offset); + + size_t decode_bit_offset = 0; + BitTable<1> table(buffer.data(), buffer.size(), &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset); + EXPECT_EQ(4u, table.NumRows()); + EXPECT_EQ(42u, table.Get(0)); + EXPECT_EQ(kNoValue, table.Get(1)); + EXPECT_EQ(1000u, table.Get(2)); + EXPECT_EQ(kNoValue, table.Get(3)); + EXPECT_EQ(10u, table.NumColumnBits(0)); +} + +TEST(BitTableTest, TestUnalignedTable) { + for (size_t start_bit_offset = 0; start_bit_offset <= 32; start_bit_offset++) { + std::vector<uint8_t> buffer; + size_t encode_bit_offset = start_bit_offset; + BitTableBuilder<1> builder; + builder.AddRow(42u); + builder.Encode(&buffer, &encode_bit_offset); + + size_t decode_bit_offset = start_bit_offset; + BitTable<1> table(buffer.data(), buffer.size(), &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset) << " start_bit_offset=" << start_bit_offset; + EXPECT_EQ(1u, table.NumRows()); + EXPECT_EQ(42u, table.Get(0)); + } +} + +TEST(BitTableTest, TestBigTable) { + constexpr uint32_t kNoValue = -1; + std::vector<uint8_t> buffer; + size_t encode_bit_offset = 0; + BitTableBuilder<4> builder; + builder.AddRow(42u, kNoValue, 0u, static_cast<uint32_t>(-2)); + builder.AddRow(62u, kNoValue, 63u, static_cast<uint32_t>(-3)); + builder.Encode(&buffer, &encode_bit_offset); + + size_t decode_bit_offset = 0; + BitTable<4> table(buffer.data(), buffer.size(), &decode_bit_offset); + EXPECT_EQ(encode_bit_offset, decode_bit_offset); + EXPECT_EQ(2u, table.NumRows()); + EXPECT_EQ(42u, table.Get(0, 0)); + EXPECT_EQ(kNoValue, table.Get(0, 1)); + EXPECT_EQ(0u, table.Get(0, 2)); + EXPECT_EQ(static_cast<uint32_t>(-2), table.Get(0, 3)); + EXPECT_EQ(62u, table.Get(1, 0)); + EXPECT_EQ(kNoValue, table.Get(1, 1)); + EXPECT_EQ(63u, table.Get(1, 2)); + EXPECT_EQ(static_cast<uint32_t>(-3), table.Get(1, 3)); + EXPECT_EQ(6u, table.NumColumnBits(0)); + EXPECT_EQ(0u, table.NumColumnBits(1)); + EXPECT_EQ(7u, table.NumColumnBits(2)); + EXPECT_EQ(32u, table.NumColumnBits(3)); +} + +} // namespace art diff --git a/libartbase/base/bit_utils.h b/libartbase/base/bit_utils.h index 04f0e8518c..58cc78ccca 100644 --- a/libartbase/base/bit_utils.h +++ b/libartbase/base/bit_utils.h @@ -22,6 +22,7 @@ #include <android-base/logging.h> +#include "globals.h" #include "stl_util_identity.h" namespace art { @@ -499,6 +500,10 @@ inline static constexpr T BitFieldExtract(T value, size_t lsb, size_t width) { return bitfield_unsigned; } +inline static constexpr size_t BitsToBytesRoundUp(size_t num_bits) { + return RoundUp(num_bits, kBitsPerByte) / kBitsPerByte; +} + } // namespace art #endif // ART_LIBARTBASE_BASE_BIT_UTILS_H_ diff --git a/runtime/base/file_utils.cc b/libartbase/base/file_utils.cc index 537216c198..56934aca1f 100644 --- a/runtime/base/file_utils.cc +++ b/libartbase/base/file_utils.cc @@ -47,7 +47,6 @@ #include "base/os.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" -#include "dex/dex_file_loader.h" #if defined(__APPLE__) #include <crt_externs.h> @@ -64,6 +63,8 @@ namespace art { using android::base::StringAppendF; using android::base::StringPrintf; +static constexpr const char* kClassesDex = "classes.dex"; + bool ReadFileToString(const std::string& file_name, std::string* result) { File file(file_name, O_RDONLY, false); if (!file.IsOpened()) { @@ -224,7 +225,7 @@ bool GetDalvikCacheFilename(const char* location, const char* cache_location, !android::base::EndsWith(location, ".art") && !android::base::EndsWith(location, ".oat")) { cache_file += "/"; - cache_file += DexFileLoader::kClassesDex; + cache_file += kClassesDex; } std::replace(cache_file.begin(), cache_file.end(), '/', '@'); *filename = StringPrintf("%s/%s", cache_location, cache_file.c_str()); @@ -263,7 +264,8 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string& bool LocationIsOnSystem(const char* path) { UniqueCPtr<const char[]> full_path(realpath(path, nullptr)); - return path != nullptr && android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str()); + return full_path != nullptr && + android::base::StartsWith(full_path.get(), GetAndroidRoot().c_str()); } bool LocationIsOnSystemFramework(const char* full_path) { diff --git a/runtime/base/file_utils.h b/libartbase/base/file_utils.h index d4f6c576c0..063393bd3b 100644 --- a/runtime/base/file_utils.h +++ b/libartbase/base/file_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_FILE_UTILS_H_ -#define ART_RUNTIME_BASE_FILE_UTILS_H_ +#ifndef ART_LIBARTBASE_BASE_FILE_UTILS_H_ +#define ART_LIBARTBASE_BASE_FILE_UTILS_H_ #include <stdlib.h> @@ -46,6 +46,7 @@ std::string GetDefaultBootImageLocation(std::string* error_msg); // Returns the dalvik-cache location, with subdir appended. Returns the empty string if the cache // could not be found. std::string GetDalvikCache(const char* subdir); + // Return true if we found the dalvik cache and stored it in the dalvik_cache argument. // have_android_data will be set to true if we have an ANDROID_DATA that exists, // dalvik_cache_exists will be true if there is a dalvik-cache directory that is present. @@ -79,4 +80,4 @@ bool LocationIsOnSystemFramework(const char* location); } // namespace art -#endif // ART_RUNTIME_BASE_FILE_UTILS_H_ +#endif // ART_LIBARTBASE_BASE_FILE_UTILS_H_ diff --git a/runtime/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc index e74dfe5e64..e74dfe5e64 100644 --- a/runtime/base/file_utils_test.cc +++ b/libartbase/base/file_utils_test.cc diff --git a/libartbase/base/globals.h b/libartbase/base/globals.h index 69d1a64a3b..39e0c509cd 100644 --- a/libartbase/base/globals.h +++ b/libartbase/base/globals.h @@ -38,6 +38,9 @@ static constexpr size_t kStackAlignment = 16; // compile-time constant so the compiler can generate better code. static constexpr int kPageSize = 4096; +// Size of Dex virtual registers. +static constexpr size_t kVRegSize = 4; + // Returns whether the given memory offset can be used for generating // an implicit null check. static inline bool CanDoImplicitNullCheckOn(uintptr_t offset) { diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc index 9a1392ceee..c455fed829 100644 --- a/libartbase/base/mem_map.cc +++ b/libartbase/base/mem_map.cc @@ -29,7 +29,6 @@ #include "android-base/stringprintf.h" #include "android-base/unique_fd.h" -#include "backtrace/BacktraceMap.h" #include "cutils/ashmem.h" #include "allocator.h" @@ -57,21 +56,6 @@ using Maps = AllocationTrackingMultiMap<void*, MemMap*, kAllocatorTagMaps>; // All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()). static Maps* gMaps GUARDED_BY(MemMap::GetMemMapsLock()) = nullptr; -static std::ostream& operator<<( - std::ostream& os, - std::pair<BacktraceMap::iterator, BacktraceMap::iterator> iters) { - for (BacktraceMap::iterator it = iters.first; it != iters.second; ++it) { - const backtrace_map_t* entry = *it; - os << StringPrintf("0x%08x-0x%08x %c%c%c %s\n", - static_cast<uint32_t>(entry->start), - static_cast<uint32_t>(entry->end), - (entry->flags & PROT_READ) ? 'r' : '-', - (entry->flags & PROT_WRITE) ? 'w' : '-', - (entry->flags & PROT_EXEC) ? 'x' : '-', entry->name.c_str()); - } - return os; -} - std::ostream& operator<<(std::ostream& os, const Maps& mem_maps) { os << "MemMap:" << std::endl; for (auto it = mem_maps.begin(); it != mem_maps.end(); ++it) { @@ -149,8 +133,6 @@ bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* uintptr_t begin = reinterpret_cast<uintptr_t>(ptr); uintptr_t end = begin + size; - // There is a suspicion that BacktraceMap::Create is occasionally missing maps. TODO: Investigate - // further. { std::lock_guard<std::mutex> mu(*mem_maps_lock_); for (auto& pair : *gMaps) { @@ -162,22 +144,6 @@ bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* } } - std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true)); - if (map == nullptr) { - if (error_msg != nullptr) { - *error_msg = StringPrintf("Failed to build process map"); - } - return false; - } - - ScopedBacktraceMapIteratorLock lock(map.get()); - for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) { - const backtrace_map_t* entry = *it; - if ((begin >= entry->start && begin < entry->end) // start of new within old - && (end > entry->start && end <= entry->end)) { // end of new within old - return true; - } - } if (error_msg != nullptr) { PrintFileToLog("/proc/self/maps", LogSeverity::ERROR); *error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " does not overlap " @@ -186,36 +152,6 @@ bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* return false; } -// Return true if the address range does not conflict with any /proc/self/maps entry. -static bool CheckNonOverlapping(uintptr_t begin, - uintptr_t end, - std::string* error_msg) { - std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid(), true)); - if (map.get() == nullptr) { - *error_msg = StringPrintf("Failed to build process map"); - return false; - } - ScopedBacktraceMapIteratorLock lock(map.get()); - for (BacktraceMap::iterator it = map->begin(); it != map->end(); ++it) { - const backtrace_map_t* entry = *it; - if ((begin >= entry->start && begin < entry->end) // start of new within old - || (end > entry->start && end < entry->end) // end of new within old - || (begin <= entry->start && end > entry->end)) { // start/end of new includes all of old - std::ostringstream map_info; - map_info << std::make_pair(it, map->end()); - *error_msg = StringPrintf("Requested region 0x%08" PRIxPTR "-0x%08" PRIxPTR " overlaps with " - "existing map 0x%08" PRIxPTR "-0x%08" PRIxPTR " (%s)\n%s", - begin, end, - static_cast<uintptr_t>(entry->start), - static_cast<uintptr_t>(entry->end), - entry->name.c_str(), - map_info.str().c_str()); - return false; - } - } - return true; -} - // CheckMapRequest to validate a non-MAP_FAILED mmap result based on // the expected value, calling munmap if validation fails, giving the // reason in error_msg. @@ -236,7 +172,6 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte uintptr_t actual = reinterpret_cast<uintptr_t>(actual_ptr); uintptr_t expected = reinterpret_cast<uintptr_t>(expected_ptr); - uintptr_t limit = expected + byte_count; if (expected_ptr == actual_ptr) { return true; @@ -256,15 +191,16 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte // true, even if there is no overlap // - There might have been an overlap at the point of mmap, but the // overlapping region has since been unmapped. - std::string error_detail; - CheckNonOverlapping(expected, limit, &error_detail); + + // Tell the client the mappings that were in place at the time. + if (kIsDebugBuild) { + PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); + } + std::ostringstream os; os << StringPrintf("Failed to mmap at expected address, mapped at " "0x%08" PRIxPTR " instead of 0x%08" PRIxPTR, actual, expected); - if (!error_detail.empty()) { - os << " : " << error_detail; - } *error_msg = os.str(); } return false; diff --git a/libartbase/base/memory_region.cc b/libartbase/base/memory_region.cc index 862ff73639..d207872487 100644 --- a/libartbase/base/memory_region.cc +++ b/libartbase/base/memory_region.cc @@ -29,36 +29,4 @@ void MemoryRegion::CopyFrom(size_t offset, const MemoryRegion& from) const { memmove(reinterpret_cast<void*>(begin() + offset), from.pointer(), from.size()); } -void MemoryRegion::StoreBits(uintptr_t bit_offset, uint32_t value, size_t length) { - DCHECK_LE(value, MaxInt<uint32_t>(length)); - DCHECK_LE(length, BitSizeOf<uint32_t>()); - DCHECK_LE(bit_offset + length, size_in_bits()); - if (length == 0) { - return; - } - // Bits are stored in this order {7 6 5 4 3 2 1 0}. - // How many remaining bits in current byte is (bit_offset % kBitsPerByte) + 1. - uint8_t* out = ComputeInternalPointer<uint8_t>(bit_offset >> kBitsPerByteLog2); - size_t orig_len = length; - uint32_t orig_value = value; - uintptr_t bit_remainder = bit_offset % kBitsPerByte; - while (true) { - const uintptr_t remaining_bits = kBitsPerByte - bit_remainder; - if (length <= remaining_bits) { - // Length is smaller than all of remainder bits. - size_t mask = ((1 << length) - 1) << bit_remainder; - *out = (*out & ~mask) | (value << bit_remainder); - break; - } - // Copy remaining bits in current byte. - size_t value_mask = (1 << remaining_bits) - 1; - *out = (*out & ~(value_mask << bit_remainder)) | ((value & value_mask) << bit_remainder); - value >>= remaining_bits; - bit_remainder = 0; - length -= remaining_bits; - ++out; - } - DCHECK_EQ(LoadBits(bit_offset, orig_len), orig_value) << bit_offset << " " << orig_len; -} - } // namespace art diff --git a/libartbase/base/memory_region.h b/libartbase/base/memory_region.h index 3d00f5b939..206032923f 100644 --- a/libartbase/base/memory_region.h +++ b/libartbase/base/memory_region.h @@ -109,67 +109,6 @@ class MemoryRegion FINAL : public ValueObject { return ComputeInternalPointer<T>(offset); } - // Load a single bit in the region. The bit at offset 0 is the least - // significant bit in the first byte. - ALWAYS_INLINE bool LoadBit(uintptr_t bit_offset) const { - uint8_t bit_mask; - uint8_t byte = *ComputeBitPointer(bit_offset, &bit_mask); - return byte & bit_mask; - } - - ALWAYS_INLINE void StoreBit(uintptr_t bit_offset, bool value) const { - uint8_t bit_mask; - uint8_t* byte = ComputeBitPointer(bit_offset, &bit_mask); - if (value) { - *byte |= bit_mask; - } else { - *byte &= ~bit_mask; - } - } - - // Load `length` bits from the region starting at bit offset `bit_offset`. - // The bit at the smallest offset is the least significant bit in the - // loaded value. `length` must not be larger than the number of bits - // contained in the return value (32). - ALWAYS_INLINE uint32_t LoadBits(uintptr_t bit_offset, size_t length) const { - DCHECK_LE(length, BitSizeOf<uint32_t>()); - DCHECK_LE(bit_offset + length, size_in_bits()); - if (UNLIKELY(length == 0)) { - // Do not touch any memory if the range is empty. - return 0; - } - const uint8_t* address = begin() + bit_offset / kBitsPerByte; - const uint32_t shift = bit_offset & (kBitsPerByte - 1); - // Load the value (reading only the strictly needed bytes). - const uint32_t load_bit_count = shift + length; - uint32_t value = address[0] >> shift; - if (load_bit_count > 8) { - value |= static_cast<uint32_t>(address[1]) << (8 - shift); - if (load_bit_count > 16) { - value |= static_cast<uint32_t>(address[2]) << (16 - shift); - if (load_bit_count > 24) { - value |= static_cast<uint32_t>(address[3]) << (24 - shift); - if (load_bit_count > 32) { - value |= static_cast<uint32_t>(address[4]) << (32 - shift); - } - } - } - } - // Clear unwanted most significant bits. - uint32_t clear_bit_count = BitSizeOf(value) - length; - value = (value << clear_bit_count) >> clear_bit_count; - for (size_t i = 0; i < length; ++i) { - DCHECK_EQ((value >> i) & 1, LoadBit(bit_offset + i)); - } - return value; - } - - // Store `value` on `length` bits in the region starting at bit offset - // `bit_offset`. The bit at the smallest offset is the least significant - // bit of the stored `value`. `value` must not be larger than `length` - // bits. - void StoreBits(uintptr_t bit_offset, uint32_t value, size_t length); - void CopyFrom(size_t offset, const MemoryRegion& from) const; template<class Vector> diff --git a/libartbase/base/memory_region_test.cc b/libartbase/base/memory_region_test.cc index e3aead47fa..72e03a485a 100644 --- a/libartbase/base/memory_region_test.cc +++ b/libartbase/base/memory_region_test.cc @@ -18,8 +18,6 @@ #include "gtest/gtest.h" -#include "bit_memory_region.h" - namespace art { TEST(MemoryRegion, LoadUnaligned) { @@ -57,35 +55,4 @@ TEST(MemoryRegion, StoreUnaligned) { } } -TEST(MemoryRegion, TestBits) { - const size_t n = 8; - uint8_t data[n] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - MemoryRegion region(&data, n); - uint32_t value = 0xDEADBEEF; - // Try various offsets and lengths. - for (size_t bit_offset = 0; bit_offset < 2 * kBitsPerByte; ++bit_offset) { - for (size_t length = 0; length < 2 * kBitsPerByte; ++length) { - const uint32_t length_mask = (1 << length) - 1; - uint32_t masked_value = value & length_mask; - BitMemoryRegion bmr(region, bit_offset, length); - region.StoreBits(bit_offset, masked_value, length); - EXPECT_EQ(region.LoadBits(bit_offset, length), masked_value); - EXPECT_EQ(bmr.LoadBits(0, length), masked_value); - // Check adjacent bits to make sure they were not incorrectly cleared. - EXPECT_EQ(region.LoadBits(0, bit_offset), (1u << bit_offset) - 1); - EXPECT_EQ(region.LoadBits(bit_offset + length, length), length_mask); - region.StoreBits(bit_offset, length_mask, length); - // Store with bit memory region. - bmr.StoreBits(0, masked_value, length); - EXPECT_EQ(bmr.LoadBits(0, length), masked_value); - // Check adjacent bits to make sure they were not incorrectly cleared. - EXPECT_EQ(region.LoadBits(0, bit_offset), (1u << bit_offset) - 1); - EXPECT_EQ(region.LoadBits(bit_offset + length, length), length_mask); - region.StoreBits(bit_offset, length_mask, length); - // Flip the value to try different edge bit combinations. - value = ~value; - } - } -} - } // namespace art diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index b2c041c81f..3818624d7a 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -19,6 +19,7 @@ cc_defaults { defaults: ["art_defaults"], host_supported: true, srcs: [ + "dex/art_dex_file_loader.cc", "dex/compact_dex_file.cc", "dex/compact_offset_table.cc", "dex/descriptors_names.cc", @@ -55,24 +56,20 @@ cc_defaults { }, generated_sources: ["dexfile_operator_srcs"], shared_libs: [ - // Important note: relying on libartbase's header_lib is perfectly acceptable. - // However, relying on the libartbase shared library introduces further, possibly cyclic, - // dependencies for clients outside of ART. + // For MemMap. + "libartbase", "liblog", + // For atrace. + "libcutils", // For common macros. "libbase", "libz", ], - header_libs: [ - "art_libartbase_headers", - ], export_include_dirs: ["."], export_shared_lib_headers: [ + "libartbase", "libbase", ], - export_header_lib_headers: [ - "art_libartbase_headers", - ], } gensrcs { @@ -114,6 +111,7 @@ art_cc_test { "art_gtest_defaults", ], srcs: [ + "dex/art_dex_file_loader_test.cc", "dex/code_item_accessors_test.cc", "dex/compact_dex_file_test.cc", "dex/compact_offset_table_test.cc", diff --git a/runtime/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc index 392ce1e7f5..392ce1e7f5 100644 --- a/runtime/dex/art_dex_file_loader.cc +++ b/libdexfile/dex/art_dex_file_loader.cc diff --git a/runtime/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h index 7577945632..a460aee60f 100644 --- a/runtime/dex/art_dex_file_loader.h +++ b/libdexfile/dex/art_dex_file_loader.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ -#define ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ +#ifndef ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_ +#define ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_ #include <cstdint> #include <memory> @@ -137,4 +137,4 @@ class ArtDexFileLoader : public DexFileLoader { } // namespace art -#endif // ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ +#endif // ART_LIBDEXFILE_DEX_ART_DEX_FILE_LOADER_H_ diff --git a/runtime/dex/art_dex_file_loader_test.cc b/libdexfile/dex/art_dex_file_loader_test.cc index 274a6df702..d353c26b35 100644 --- a/runtime/dex/art_dex_file_loader_test.cc +++ b/libdexfile/dex/art_dex_file_loader_test.cc @@ -43,48 +43,7 @@ static void Copy(const std::string& src, const std::string& dst) { dst_stream << src_stream.rdbuf(); } -class ArtDexFileLoaderTest : public CommonRuntimeTest { - public: - virtual void SetUp() { - CommonRuntimeTest::SetUp(); - - std::string dex_location = GetTestDexFileName("Main"); - std::string multidex_location = GetTestDexFileName("MultiDex"); - - data_location_path_ = android_data_ + "/foo.jar"; - system_location_path_ = GetAndroidRoot() + "/foo.jar"; - system_framework_location_path_ = GetAndroidRoot() + "/framework/foo.jar"; - data_multi_location_path_ = android_data_ + "/multifoo.jar"; - system_multi_location_path_ = GetAndroidRoot() + "/multifoo.jar"; - system_framework_multi_location_path_ = GetAndroidRoot() + "/framework/multifoo.jar"; - - Copy(dex_location, data_location_path_); - Copy(dex_location, system_location_path_); - Copy(dex_location, system_framework_location_path_); - - Copy(multidex_location, data_multi_location_path_); - Copy(multidex_location, system_multi_location_path_); - Copy(multidex_location, system_framework_multi_location_path_); - } - - virtual void TearDown() { - remove(data_location_path_.c_str()); - remove(system_location_path_.c_str()); - remove(system_framework_location_path_.c_str()); - remove(data_multi_location_path_.c_str()); - remove(system_multi_location_path_.c_str()); - remove(system_framework_multi_location_path_.c_str()); - CommonRuntimeTest::TearDown(); - } - - protected: - std::string data_location_path_; - std::string system_location_path_; - std::string system_framework_location_path_; - std::string data_multi_location_path_; - std::string system_multi_location_path_; - std::string system_framework_multi_location_path_; -}; +class ArtDexFileLoaderTest : public CommonRuntimeTest {}; // TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and // the tests that depend upon them should be moved to dex_file_loader_test.cc @@ -286,7 +245,7 @@ TEST_F(ArtDexFileLoaderTest, FindTypeId) { TEST_F(ArtDexFileLoaderTest, FindProtoId) { for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { - const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); + const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(dex::ProtoIndex(i)); const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); std::vector<dex::TypeIndex> to_find_types; if (to_find_tl != nullptr) { @@ -297,7 +256,7 @@ TEST_F(ArtDexFileLoaderTest, FindProtoId) { const DexFile::ProtoId* found = java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); ASSERT_TRUE(found != nullptr); - EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); + EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), dex::ProtoIndex(i)); } } @@ -353,21 +312,24 @@ TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) { ASSERT_EQ(0, unlink(dex_location_sym.c_str())); } -TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_DataDir) { + // Load file from a non-system directory and check that it is not flagged as framework. + std::string data_location_path = android_data_ + "/foo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path.c_str())); + + Copy(GetTestDexFileName("Main"), data_location_path); + ArtDexFileLoader loader; - bool success; - std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - - // Load file from a non-system directory and check that it is not flagged as framework. - ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path_.c_str())); - success = loader.Open(data_location_path_.c_str(), - data_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); + std::string error_msg; + bool success = loader.Open(data_location_path.c_str(), + data_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); ASSERT_TRUE(success) << error_msg; + ASSERT_GE(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_FALSE(dex_file->IsPlatformDexFile()); @@ -375,15 +337,27 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { dex_files.clear(); + ASSERT_EQ(0, remove(data_location_path.c_str())); +} + +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemDir) { // Load file from a system, non-framework directory and check that it is not flagged as framework. - ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path_.c_str())); - success = loader.Open(system_location_path_.c_str(), - system_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); - ASSERT_TRUE(success); + std::string system_location_path = GetAndroidRoot() + "/foo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path.c_str())); + + Copy(GetTestDexFileName("Main"), system_location_path); + + ArtDexFileLoader loader; + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + bool success = loader.Open(system_location_path.c_str(), + system_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); + ASSERT_TRUE(success) << error_msg; + ASSERT_GE(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_FALSE(dex_file->IsPlatformDexFile()); @@ -391,15 +365,27 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { dex_files.clear(); + ASSERT_EQ(0, remove(system_location_path.c_str())); +} + +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemFrameworkDir) { // Load file from a system/framework directory and check that it is flagged as a framework dex. - ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path_.c_str())); - success = loader.Open(system_framework_location_path_.c_str(), - system_framework_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); - ASSERT_TRUE(success); + std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar"; + ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path.c_str())); + + Copy(GetTestDexFileName("Main"), system_framework_location_path); + + ArtDexFileLoader loader; + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + bool success = loader.Open(system_framework_location_path.c_str(), + system_framework_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); + ASSERT_TRUE(success) << error_msg; + ASSERT_GE(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_TRUE(dex_file->IsPlatformDexFile()); @@ -407,14 +393,27 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { dex_files.clear(); + ASSERT_EQ(0, remove(system_framework_location_path.c_str())); +} + +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_DataDir_MultiDex) { // Load multidex file from a non-system directory and check that it is not flagged as framework. - success = loader.Open(data_multi_location_path_.c_str(), - data_multi_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); + std::string data_multi_location_path = android_data_ + "/multifoo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(data_multi_location_path.c_str())); + + Copy(GetTestDexFileName("MultiDex"), data_multi_location_path); + + ArtDexFileLoader loader; + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + bool success = loader.Open(data_multi_location_path.c_str(), + data_multi_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); ASSERT_TRUE(success) << error_msg; + ASSERT_GT(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_FALSE(dex_file->IsPlatformDexFile()); @@ -422,15 +421,28 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { dex_files.clear(); + ASSERT_EQ(0, remove(data_multi_location_path.c_str())); +} + +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemDir_MultiDex) { // Load multidex file from a system, non-framework directory and check that it is not flagged // as framework. - success = loader.Open(system_multi_location_path_.c_str(), - system_multi_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); - ASSERT_TRUE(success); + std::string system_multi_location_path = GetAndroidRoot() + "/multifoo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(system_multi_location_path.c_str())); + + Copy(GetTestDexFileName("MultiDex"), system_multi_location_path); + + ArtDexFileLoader loader; + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + bool success = loader.Open(system_multi_location_path.c_str(), + system_multi_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); + ASSERT_TRUE(success) << error_msg; + ASSERT_GT(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_FALSE(dex_file->IsPlatformDexFile()); @@ -438,19 +450,36 @@ TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile) { dex_files.clear(); + ASSERT_EQ(0, remove(system_multi_location_path.c_str())); +} + +TEST_F(ArtDexFileLoaderTest, IsPlatformDexFile_SystemFrameworkDir_MultiDex) { // Load multidex file from a system/framework directory and check that it is flagged as a // framework dex. - success = loader.Open(system_framework_multi_location_path_.c_str(), - system_framework_multi_location_path_, - /* verify */ false, - /* verify_checksum */ false, - &error_msg, - &dex_files); - ASSERT_TRUE(success); + std::string system_framework_multi_location_path = GetAndroidRoot() + "/framework/multifoo.jar"; + ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_multi_location_path.c_str())); + + Copy(GetTestDexFileName("MultiDex"), system_framework_multi_location_path); + + ArtDexFileLoader loader; + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + bool success = loader.Open(system_framework_multi_location_path.c_str(), + system_framework_multi_location_path, + /* verify */ false, + /* verify_checksum */ false, + &error_msg, + &dex_files); + ASSERT_TRUE(success) << error_msg; + ASSERT_GT(dex_files.size(), 1u); for (std::unique_ptr<const DexFile>& dex_file : dex_files) { ASSERT_TRUE(dex_file->IsPlatformDexFile()); } + + dex_files.clear(); + + ASSERT_EQ(0, remove(system_framework_multi_location_path.c_str())); } } // namespace art diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h index d1b32007c3..e78e8d7a44 100644 --- a/libdexfile/dex/dex_file-inl.h +++ b/libdexfile/dex/dex_file-inl.h @@ -127,7 +127,7 @@ inline const char* DexFile::GetReturnTypeDescriptor(const ProtoId& proto_id) con return StringByTypeIdx(proto_id.return_type_idx_); } -inline const char* DexFile::GetShorty(uint32_t proto_idx) const { +inline const char* DexFile::GetShorty(dex::ProtoIndex proto_idx) const { const ProtoId& proto_id = GetProtoId(proto_idx); return StringDataByIdx(proto_id.shorty_idx_); } diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 8cfee6655e..9de260c862 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -281,7 +281,7 @@ const DexFile::MethodId* DexFile::FindMethodId(const DexFile::TypeId& declaring_ // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass); const dex::StringIndex name_idx = GetIndexForStringId(name); - const uint16_t proto_idx = GetIndexForProtoId(signature); + const dex::ProtoIndex proto_idx = GetIndexForProtoId(signature); int32_t lo = 0; int32_t hi = NumMethodIds() - 1; while (hi >= lo) { @@ -373,7 +373,8 @@ const DexFile::ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx, int32_t hi = NumProtoIds() - 1; while (hi >= lo) { int32_t mid = (hi + lo) / 2; - const DexFile::ProtoId& proto = GetProtoId(mid); + const dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(mid); + const DexFile::ProtoId& proto = GetProtoId(proto_idx); int compare = return_type_idx.index_ - proto.return_type_idx_.index_; if (compare == 0) { DexFileParameterIterator it(*this, proto); @@ -777,6 +778,11 @@ void EncodedArrayValueIterator::Next() { namespace dex { +std::ostream& operator<<(std::ostream& os, const ProtoIndex& index) { + os << "ProtoIndex[" << index.index_ << "]"; + return os; +} + std::ostream& operator<<(std::ostream& os, const StringIndex& index) { os << "StringIndex[" << index.index_ << "]"; return os; diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index 4ca735ad66..87d2c48ff1 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -189,7 +189,7 @@ class DexFile { // Raw method_id_item. struct MethodId { dex::TypeIndex class_idx_; // index into type_ids_ array for defining class - uint16_t proto_idx_; // index into proto_ids_ array for method prototype + dex::ProtoIndex proto_idx_; // index into proto_ids_ array for method prototype dex::StringIndex name_idx_; // index into string_ids_ array for method name private: @@ -692,15 +692,15 @@ class DexFile { } // Returns the ProtoId at the specified index. - const ProtoId& GetProtoId(uint16_t idx) const { - DCHECK_LT(idx, NumProtoIds()) << GetLocation(); - return proto_ids_[idx]; + const ProtoId& GetProtoId(dex::ProtoIndex idx) const { + DCHECK_LT(idx.index_, NumProtoIds()) << GetLocation(); + return proto_ids_[idx.index_]; } - uint16_t GetIndexForProtoId(const ProtoId& proto_id) const { + dex::ProtoIndex GetIndexForProtoId(const ProtoId& proto_id) const { CHECK_GE(&proto_id, proto_ids_) << GetLocation(); CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_) << GetLocation(); - return &proto_id - proto_ids_; + return dex::ProtoIndex(&proto_id - proto_ids_); } // Looks up a proto id for a given return type and signature type list @@ -722,7 +722,7 @@ class DexFile { const Signature CreateSignature(const StringPiece& signature) const; // Returns the short form method descriptor for the given prototype. - const char* GetShorty(uint32_t proto_idx) const; + const char* GetShorty(dex::ProtoIndex proto_idx) const; const TypeList* GetProtoParameters(const ProtoId& proto_id) const { return DataPointer<TypeList>(proto_id.parameters_off_); diff --git a/libdexfile/dex/dex_file_types.h b/libdexfile/dex/dex_file_types.h index 2bb70ff261..d4fb3de504 100644 --- a/libdexfile/dex/dex_file_types.h +++ b/libdexfile/dex/dex_file_types.h @@ -25,72 +25,66 @@ namespace dex { constexpr uint32_t kDexNoIndex = 0xFFFFFFFF; -class StringIndex { +template<typename T> +class DexIndex { public: - uint32_t index_; + T index_; - constexpr StringIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {} - explicit constexpr StringIndex(uint32_t idx) : index_(idx) {} + constexpr DexIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {} + explicit constexpr DexIndex(T idx) : index_(idx) {} bool IsValid() const { return index_ != std::numeric_limits<decltype(index_)>::max(); } - static StringIndex Invalid() { - return StringIndex(std::numeric_limits<decltype(index_)>::max()); + static constexpr DexIndex Invalid() { + return DexIndex(std::numeric_limits<decltype(index_)>::max()); } - - bool operator==(const StringIndex& other) const { + bool operator==(const DexIndex& other) const { return index_ == other.index_; } - bool operator!=(const StringIndex& other) const { + bool operator!=(const DexIndex& other) const { return index_ != other.index_; } - bool operator<(const StringIndex& other) const { + bool operator<(const DexIndex& other) const { return index_ < other.index_; } - bool operator<=(const StringIndex& other) const { + bool operator<=(const DexIndex& other) const { return index_ <= other.index_; } - bool operator>(const StringIndex& other) const { + bool operator>(const DexIndex& other) const { return index_ > other.index_; } - bool operator>=(const StringIndex& other) const { + bool operator>=(const DexIndex& other) const { return index_ >= other.index_; } }; -std::ostream& operator<<(std::ostream& os, const StringIndex& index); -class TypeIndex { +class ProtoIndex : public DexIndex<uint16_t> { public: - uint16_t index_; - - constexpr TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {} - explicit constexpr TypeIndex(uint16_t idx) : index_(idx) {} - - bool IsValid() const { - return index_ != std::numeric_limits<decltype(index_)>::max(); - } - static TypeIndex Invalid() { - return TypeIndex(std::numeric_limits<decltype(index_)>::max()); + ProtoIndex() {} + explicit constexpr ProtoIndex(uint16_t index) : DexIndex<decltype(index_)>(index) {} + static constexpr ProtoIndex Invalid() { + return ProtoIndex(std::numeric_limits<decltype(index_)>::max()); } +}; +std::ostream& operator<<(std::ostream& os, const ProtoIndex& index); - bool operator==(const TypeIndex& other) const { - return index_ == other.index_; - } - bool operator!=(const TypeIndex& other) const { - return index_ != other.index_; - } - bool operator<(const TypeIndex& other) const { - return index_ < other.index_; - } - bool operator<=(const TypeIndex& other) const { - return index_ <= other.index_; - } - bool operator>(const TypeIndex& other) const { - return index_ > other.index_; +class StringIndex : public DexIndex<uint32_t> { + public: + StringIndex() {} + explicit constexpr StringIndex(uint32_t index) : DexIndex<decltype(index_)>(index) {} + static constexpr StringIndex Invalid() { + return StringIndex(std::numeric_limits<decltype(index_)>::max()); } - bool operator>=(const TypeIndex& other) const { - return index_ >= other.index_; +}; +std::ostream& operator<<(std::ostream& os, const StringIndex& index); + +class TypeIndex : public DexIndex<uint16_t> { + public: + TypeIndex() {} + explicit constexpr TypeIndex(uint16_t index) : DexIndex<uint16_t>(index) {} + static constexpr TypeIndex Invalid() { + return TypeIndex(std::numeric_limits<decltype(index_)>::max()); } }; std::ostream& operator<<(std::ostream& os, const TypeIndex& index); @@ -100,15 +94,21 @@ std::ostream& operator<<(std::ostream& os, const TypeIndex& index); namespace std { +template<> struct hash<art::dex::ProtoIndex> { + size_t operator()(const art::dex::ProtoIndex& index) const { + return hash<decltype(index.index_)>()(index.index_); + } +}; + template<> struct hash<art::dex::StringIndex> { size_t operator()(const art::dex::StringIndex& index) const { - return hash<uint32_t>()(index.index_); + return hash<decltype(index.index_)>()(index.index_); } }; template<> struct hash<art::dex::TypeIndex> { size_t operator()(const art::dex::TypeIndex& index) const { - return hash<uint16_t>()(index.index_); + return hash<decltype(index.index_)>()(index.index_); } }; diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc index a32f64e49f..78db8b9a35 100644 --- a/libdexfile/dex/dex_file_verifier.cc +++ b/libdexfile/dex/dex_file_verifier.cc @@ -127,8 +127,9 @@ const DexFile::MethodId* DexFileVerifier::CheckLoadMethodId(uint32_t idx, const return &dex_file_->GetMethodId(idx); } -const DexFile::ProtoId* DexFileVerifier::CheckLoadProtoId(uint32_t idx, const char* err_string) { - if (UNLIKELY(!CheckIndex(idx, dex_file_->NumProtoIds(), err_string))) { +const DexFile::ProtoId* DexFileVerifier::CheckLoadProtoId(dex::ProtoIndex idx, + const char* err_string) { + if (UNLIKELY(!CheckIndex(idx.index_, dex_file_->NumProtoIds(), err_string))) { return nullptr; } return &dex_file_->GetProtoId(idx); @@ -2208,7 +2209,7 @@ bool DexFileVerifier::CheckInterMethodIdItem() { } // Check that the proto id is valid. - if (UNLIKELY(!CheckIndex(item->proto_idx_, dex_file_->NumProtoIds(), + if (UNLIKELY(!CheckIndex(item->proto_idx_.index_, dex_file_->NumProtoIds(), "inter_method_id_item proto_idx"))) { return false; } diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h index 04d8d71fa8..43d1093809 100644 --- a/libdexfile/dex/dex_file_verifier.h +++ b/libdexfile/dex/dex_file_verifier.h @@ -164,7 +164,7 @@ class DexFileVerifier { // error if not. If there is an error, null is returned. const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt); const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt); - const DexFile::ProtoId* CheckLoadProtoId(uint32_t idx, const char* error_fmt); + const DexFile::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt); void ErrorStringPrintf(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc index f82081f8ee..c9bac0fef2 100644 --- a/libdexfile/dex/dex_file_verifier_test.cc +++ b/libdexfile/dex/dex_file_verifier_test.cc @@ -161,7 +161,7 @@ TEST_F(DexFileVerifierTest, MethodId) { "method_id_proto_idx", [](DexFile* dex_file) { DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0)); - method_id->proto_idx_ = 0xFF; + method_id->proto_idx_ = dex::ProtoIndex(0xFF); }, "inter_method_id_item proto_idx"); @@ -1425,12 +1425,13 @@ TEST_F(DexFileVerifierTest, ProtoOrdering) { CHECK_LT(method_idx + 1u, dex_file->NumMethodIds()); CHECK_EQ(dex_file->GetMethodId(method_idx).name_idx_, dex_file->GetMethodId(method_idx + 1).name_idx_); - CHECK_EQ(dex_file->GetMethodId(method_idx).proto_idx_ + 1u, - dex_file->GetMethodId(method_idx + 1).proto_idx_); + CHECK_EQ(dex_file->GetMethodId(method_idx).proto_idx_.index_ + 1u, + dex_file->GetMethodId(method_idx + 1).proto_idx_.index_); // Their return types should be the same. - uint32_t proto1_idx = dex_file->GetMethodId(method_idx).proto_idx_; + dex::ProtoIndex proto1_idx = dex_file->GetMethodId(method_idx).proto_idx_; const DexFile::ProtoId& proto1 = dex_file->GetProtoId(proto1_idx); - const DexFile::ProtoId& proto2 = dex_file->GetProtoId(proto1_idx + 1u); + dex::ProtoIndex proto2_idx(proto1_idx.index_ + 1u); + const DexFile::ProtoId& proto2 = dex_file->GetProtoId(proto2_idx); CHECK_EQ(proto1.return_type_idx_, proto2.return_type_idx_); // And the first should not have any parameters while the second should have some. CHECK(!DexFileParameterIterator(*dex_file, proto1).HasNext()); diff --git a/libdexfile/dex/dex_instruction-inl.h b/libdexfile/dex/dex_instruction-inl.h index 6bef18c85f..e0cffdd2f4 100644 --- a/libdexfile/dex/dex_instruction-inl.h +++ b/libdexfile/dex/dex_instruction-inl.h @@ -508,7 +508,7 @@ inline bool Instruction::HasVarArgs() const { return (FormatOf(Opcode()) == k35c) || (FormatOf(Opcode()) == k45cc); } -inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const { +inline uint32_t Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const { DCHECK(HasVarArgs()); /* @@ -551,6 +551,7 @@ inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_ default: // case 0 break; // Valid, but no need to do anything. } + return count; } } // namespace art diff --git a/libdexfile/dex/dex_instruction.cc b/libdexfile/dex/dex_instruction.cc index 886218129e..8378211c43 100644 --- a/libdexfile/dex/dex_instruction.cc +++ b/libdexfile/dex/dex_instruction.cc @@ -467,10 +467,10 @@ std::string Instruction::DumpString(const DexFile* file) const { case k45cc: { uint32_t arg[kMaxVarArgRegs]; GetVarArgs(arg); - uint32_t method_idx = VRegB_45cc(); - uint32_t proto_idx = VRegH_45cc(); + uint16_t method_idx = VRegB_45cc(); + dex::ProtoIndex proto_idx(VRegH_45cc()); os << opcode << " {"; - for (int i = 0; i < VRegA_45cc(); ++i) { + for (uint32_t i = 0; i < VRegA_45cc(); ++i) { if (i != 0) { os << ", "; } @@ -478,7 +478,8 @@ std::string Instruction::DumpString(const DexFile* file) const { } os << "}"; if (file != nullptr) { - os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) + os << ", " << file->PrettyMethod(method_idx) + << ", " << file->GetShorty(proto_idx) << " // "; } else { os << ", "; @@ -490,18 +491,19 @@ std::string Instruction::DumpString(const DexFile* file) const { switch (Opcode()) { case INVOKE_POLYMORPHIC_RANGE: { if (file != nullptr) { - uint32_t method_idx = VRegB_4rcc(); - uint32_t proto_idx = VRegH_4rcc(); + uint16_t method_idx = VRegB_4rcc(); + dex::ProtoIndex proto_idx(VRegH_4rcc()); os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) - << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) + << "}, " << file->PrettyMethod(method_idx) + << ", " << file->GetShorty(dex::ProtoIndex(proto_idx)) << " // method@" << method_idx << ", proto@" << proto_idx; break; } } FALLTHROUGH_INTENDED; default: { - uint32_t method_idx = VRegB_4rcc(); - uint32_t proto_idx = VRegH_4rcc(); + uint16_t method_idx = VRegB_4rcc(); + dex::ProtoIndex proto_idx(VRegH_4rcc()); os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) << "}, method@" << method_idx << ", proto@" << proto_idx; } diff --git a/libdexfile/dex/dex_instruction.h b/libdexfile/dex/dex_instruction.h index bf5083622b..6807025e13 100644 --- a/libdexfile/dex/dex_instruction.h +++ b/libdexfile/dex/dex_instruction.h @@ -462,8 +462,8 @@ class Instruction { // Fills the given array with the 'arg' array of the instruction. bool HasVarArgs() const; - void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const; - void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const { + uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const; + uint32_t GetVarArgs(uint32_t args[kMaxVarArgRegs]) const { return GetVarArgs(args, Fetch16(0)); } diff --git a/libprofile/Android.bp b/libprofile/Android.bp index bcb90cb680..b9883f658d 100644 --- a/libprofile/Android.bp +++ b/libprofile/Android.bp @@ -45,6 +45,7 @@ cc_defaults { shared_libs: [ "libartbase", "libdexfile", + "libartbase", // For atrace. "libcutils", ], @@ -97,6 +98,7 @@ art_cc_test { shared_libs: [ "libartbased", "libdexfiled", + "libartbased", "libziparchive", ], } diff --git a/oatdump/Android.bp b/oatdump/Android.bp index 535acdff62..77dede3e10 100644 --- a/oatdump/Android.bp +++ b/oatdump/Android.bp @@ -39,6 +39,7 @@ art_cc_binary { "libart-compiler", "libart-disassembler", "libdexfile", + "libartbase", "libprofile", "libbase", ], @@ -55,6 +56,7 @@ art_cc_binary { "libartd-compiler", "libartd-disassembler", "libdexfiled", + "libartbased", "libprofiled", "libbase", ], @@ -82,6 +84,7 @@ art_cc_binary { "libart", "libdexfile", "libprofile", + "libartbase", "libart-compiler", "libart-disassembler", "libvixl-arm", @@ -117,6 +120,7 @@ art_cc_binary { "libartd", "libdexfiled", "libprofiled", + "libartbased", "libartd-compiler", "libartd-disassembler", "libvixld-arm", diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 44050ff8ed..5c20efa3f7 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -753,7 +753,7 @@ class OatDumper { kByteKindQuickMethodHeader, kByteKindCodeInfoLocationCatalog, kByteKindCodeInfoDexRegisterMap, - kByteKindCodeInfoEncoding, + kByteKindCodeInfo, kByteKindCodeInfoInvokeInfo, kByteKindCodeInfoStackMasks, kByteKindCodeInfoRegisterMasks, @@ -800,7 +800,7 @@ class OatDumper { if (sum > 0) { Dump(os, "Code ", bits[kByteKindCode], sum); Dump(os, "QuickMethodHeader ", bits[kByteKindQuickMethodHeader], sum); - Dump(os, "CodeInfoEncoding ", bits[kByteKindCodeInfoEncoding], sum); + Dump(os, "CodeInfo ", bits[kByteKindCodeInfo], sum); Dump(os, "CodeInfoLocationCatalog ", bits[kByteKindCodeInfoLocationCatalog], sum); Dump(os, "CodeInfoDexRegisterMap ", bits[kByteKindCodeInfoDexRegisterMap], sum); Dump(os, "CodeInfoStackMasks ", bits[kByteKindCodeInfoStackMasks], sum); @@ -819,7 +819,7 @@ class OatDumper { stack_map_bits, "stack map"); Dump(os, - "StackMapDexPcEncoding ", + "StackMapDexPc ", bits[kByteKindStackMapDexPc], stack_map_bits, "stack map"); @@ -1732,8 +1732,7 @@ class OatDumper { public: explicit StackMapsHelper(const uint8_t* raw_code_info, InstructionSet instruction_set) : code_info_(raw_code_info), - encoding_(code_info_.ExtractEncoding()), - number_of_stack_maps_(code_info_.GetNumberOfStackMaps(encoding_)), + number_of_stack_maps_(code_info_.GetNumberOfStackMaps()), indexes_(), offset_(static_cast<uint32_t>(-1)), stack_map_index_(0u), @@ -1741,11 +1740,11 @@ class OatDumper { if (number_of_stack_maps_ != 0u) { // Check if native PCs are ordered. bool ordered = true; - StackMap last = code_info_.GetStackMapAt(0u, encoding_); + StackMap last = code_info_.GetStackMapAt(0u); for (size_t i = 1; i != number_of_stack_maps_; ++i) { - StackMap current = code_info_.GetStackMapAt(i, encoding_); - if (last.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set) > - current.GetNativePcOffset(encoding_.stack_map.encoding, instruction_set)) { + StackMap current = code_info_.GetStackMapAt(i); + if (last.GetNativePcOffset(instruction_set) > + current.GetNativePcOffset(instruction_set)) { ordered = false; break; } @@ -1760,18 +1759,15 @@ class OatDumper { std::sort(indexes_.begin(), indexes_.end(), [this](size_t lhs, size_t rhs) { - StackMap left = code_info_.GetStackMapAt(lhs, encoding_); - uint32_t left_pc = left.GetNativePcOffset(encoding_.stack_map.encoding, - instruction_set_); - StackMap right = code_info_.GetStackMapAt(rhs, encoding_); - uint32_t right_pc = right.GetNativePcOffset(encoding_.stack_map.encoding, - instruction_set_); + StackMap left = code_info_.GetStackMapAt(lhs); + uint32_t left_pc = left.GetNativePcOffset(instruction_set_); + StackMap right = code_info_.GetStackMapAt(rhs); + uint32_t right_pc = right.GetNativePcOffset(instruction_set_); // If the PCs are the same, compare indexes to preserve the original order. return (left_pc < right_pc) || (left_pc == right_pc && lhs < rhs); }); } - offset_ = GetStackMapAt(0).GetNativePcOffset(encoding_.stack_map.encoding, - instruction_set_); + offset_ = GetStackMapAt(0).GetNativePcOffset(instruction_set_); } } @@ -1779,10 +1775,6 @@ class OatDumper { return code_info_; } - const CodeInfoEncoding& GetEncoding() const { - return encoding_; - } - uint32_t GetOffset() const { return offset_; } @@ -1795,8 +1787,7 @@ class OatDumper { ++stack_map_index_; offset_ = (stack_map_index_ == number_of_stack_maps_) ? static_cast<uint32_t>(-1) - : GetStackMapAt(stack_map_index_).GetNativePcOffset(encoding_.stack_map.encoding, - instruction_set_); + : GetStackMapAt(stack_map_index_).GetNativePcOffset(instruction_set_); } private: @@ -1805,11 +1796,10 @@ class OatDumper { i = indexes_[i]; } DCHECK_LT(i, number_of_stack_maps_); - return code_info_.GetStackMapAt(i, encoding_); + return code_info_.GetStackMapAt(i); } const CodeInfo code_info_; - const CodeInfoEncoding encoding_; const size_t number_of_stack_maps_; dchecked_vector<size_t> indexes_; // Used if stack map native PCs are not ordered. uint32_t offset_; @@ -1835,79 +1825,75 @@ class OatDumper { StackMapsHelper helper(oat_method.GetVmapTable(), instruction_set_); MethodInfo method_info(oat_method.GetOatQuickMethodHeader()->GetOptimizedMethodInfo()); { - CodeInfoEncoding encoding(helper.GetEncoding()); - StackMapEncoding stack_map_encoding(encoding.stack_map.encoding); - const size_t num_stack_maps = encoding.stack_map.num_entries; - if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfoEncoding, - encoding.HeaderSize() * kBitsPerByte, + const CodeInfo code_info = helper.GetCodeInfo(); + const BitTable<StackMap::kCount>& stack_maps = code_info.stack_maps_; + const size_t num_stack_maps = stack_maps.NumRows(); + if (stats_.AddBitsIfUnique(Stats::kByteKindCodeInfo, + code_info.size_ * kBitsPerByte, oat_method.GetVmapTable())) { // Stack maps stats_.AddBits( Stats::kByteKindStackMapNativePc, - stack_map_encoding.GetNativePcEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kNativePcOffset) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapDexPc, - stack_map_encoding.GetDexPcEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kDexPc) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapDexRegisterMap, - stack_map_encoding.GetDexRegisterMapEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kDexRegisterMapOffset) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapInlineInfoIndex, - stack_map_encoding.GetInlineInfoEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kInlineInfoIndex) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapRegisterMaskIndex, - stack_map_encoding.GetRegisterMaskIndexEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kRegisterMaskIndex) * num_stack_maps); stats_.AddBits( Stats::kByteKindStackMapStackMaskIndex, - stack_map_encoding.GetStackMaskIndexEncoding().BitSize() * num_stack_maps); + stack_maps.NumColumnBits(StackMap::kStackMaskIndex) * num_stack_maps); // Stack masks stats_.AddBits( Stats::kByteKindCodeInfoStackMasks, - encoding.stack_mask.encoding.BitSize() * encoding.stack_mask.num_entries); + code_info.stack_masks_.size_in_bits()); // Register masks stats_.AddBits( Stats::kByteKindCodeInfoRegisterMasks, - encoding.register_mask.encoding.BitSize() * encoding.register_mask.num_entries); + code_info.register_masks_.DataBitSize()); // Invoke infos - if (encoding.invoke_info.num_entries > 0u) { - stats_.AddBits( - Stats::kByteKindCodeInfoInvokeInfo, - encoding.invoke_info.encoding.BitSize() * encoding.invoke_info.num_entries); - } + stats_.AddBits( + Stats::kByteKindCodeInfoInvokeInfo, + code_info.invoke_infos_.DataBitSize()); // Location catalog const size_t location_catalog_bytes = - helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(encoding); + helper.GetCodeInfo().GetDexRegisterLocationCatalogSize(); stats_.AddBits(Stats::kByteKindCodeInfoLocationCatalog, kBitsPerByte * location_catalog_bytes); // Dex register bytes. const size_t dex_register_bytes = - helper.GetCodeInfo().GetDexRegisterMapsSize(encoding, - code_item_accessor.RegistersSize()); + helper.GetCodeInfo().GetDexRegisterMapsSize(code_item_accessor.RegistersSize()); stats_.AddBits( Stats::kByteKindCodeInfoDexRegisterMap, kBitsPerByte * dex_register_bytes); // Inline infos. - const size_t num_inline_infos = encoding.inline_info.num_entries; + const BitTable<InlineInfo::kCount>& inline_infos = code_info.inline_infos_; + const size_t num_inline_infos = inline_infos.NumRows(); if (num_inline_infos > 0u) { stats_.AddBits( Stats::kByteKindInlineInfoMethodIndexIdx, - encoding.inline_info.encoding.GetMethodIndexIdxEncoding().BitSize() * - num_inline_infos); + inline_infos.NumColumnBits(InlineInfo::kMethodIndexIdx) * num_inline_infos); stats_.AddBits( Stats::kByteKindInlineInfoDexPc, - encoding.inline_info.encoding.GetDexPcEncoding().BitSize() * num_inline_infos); + inline_infos.NumColumnBits(InlineInfo::kDexPc) * num_inline_infos); stats_.AddBits( Stats::kByteKindInlineInfoExtraData, - encoding.inline_info.encoding.GetExtraDataEncoding().BitSize() * num_inline_infos); + inline_infos.NumColumnBits(InlineInfo::kExtraData) * num_inline_infos); stats_.AddBits( Stats::kByteKindInlineInfoDexRegisterMap, - encoding.inline_info.encoding.GetDexRegisterMapEncoding().BitSize() * - num_inline_infos); + inline_infos.NumColumnBits(InlineInfo::kDexRegisterMapOffset) * num_inline_infos); stats_.AddBits(Stats::kByteKindInlineInfoIsLast, num_inline_infos); } } @@ -1922,7 +1908,6 @@ class OatDumper { DCHECK(stack_map.IsValid()); stack_map.Dump(vios, helper.GetCodeInfo(), - helper.GetEncoding(), method_info, oat_method.GetCodeOffset(), code_item_accessor.RegistersSize(), diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index b85730d25e..bbe89ca33c 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -162,7 +162,6 @@ class OatDumpTest : public CommonRuntimeTest { // Code and dex code do not show up if list only. expected_prefixes.push_back("DEX CODE:"); expected_prefixes.push_back("CODE:"); - expected_prefixes.push_back("CodeInfoEncoding"); expected_prefixes.push_back("CodeInfoInlineInfo"); } if (mode == kModeArt) { diff --git a/openjdkjvm/Android.bp b/openjdkjvm/Android.bp index a17899358c..907315e4e0 100644 --- a/openjdkjvm/Android.bp +++ b/openjdkjvm/Android.bp @@ -29,7 +29,10 @@ cc_defaults { art_cc_library { name: "libopenjdkjvm", defaults: ["libopenjdkjvm_defaults"], - shared_libs: ["libart"], + shared_libs: [ + "libart", + "libartbase", + ], } art_cc_library { @@ -38,5 +41,8 @@ art_cc_library { "art_debug_defaults", "libopenjdkjvm_defaults", ], - shared_libs: ["libartd"], + shared_libs: [ + "libartd", + "libartbased", + ], } diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp index 81b69e8c95..d8902d60d1 100644 --- a/openjdkjvmti/Android.bp +++ b/openjdkjvmti/Android.bp @@ -71,6 +71,7 @@ art_cc_library { "libart-compiler", "libart-dexlayout", "libdexfile", + "libartbase", ], } @@ -85,5 +86,6 @@ art_cc_library { "libartd-compiler", "libartd-dexlayout", "libdexfiled", + "libartbased", ], } diff --git a/patchoat/Android.bp b/patchoat/Android.bp index 0e8e517cd4..13c8f475f5 100644 --- a/patchoat/Android.bp +++ b/patchoat/Android.bp @@ -25,6 +25,7 @@ cc_defaults { }, }, shared_libs: [ + "libartbase", "libbase", "libcrypto", // For computing the digest of image file ], @@ -58,7 +59,6 @@ art_cc_test { "patchoat_test.cc", ], shared_libs: [ - "libartd", "libcrypto", // For computing the digest of image file ], } diff --git a/profman/Android.bp b/profman/Android.bp index 3c8c72c34a..5aaccb0cef 100644 --- a/profman/Android.bp +++ b/profman/Android.bp @@ -42,6 +42,7 @@ art_cc_binary { "libart", "libprofile", "libdexfile", + "libartbase", ], } @@ -55,6 +56,7 @@ art_cc_binary { "libartd", "libprofiled", "libdexfiled", + "libartbased", ], } diff --git a/profman/profman.cc b/profman/profman.cc index cd88d03929..1f7723946c 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -33,6 +33,7 @@ #include "base/dumpable.h" #include "base/logging.h" // For InitLogging. +#include "base/mem_map.h" #include "base/scoped_flock.h" #include "base/stringpiece.h" #include "base/time_utils.h" @@ -49,7 +50,6 @@ #include "dex/type_reference.h" #include "profile/profile_compilation_info.h" #include "profile_assistant.h" -#include "runtime.h" namespace art { @@ -177,6 +177,11 @@ static constexpr char kMethodFlagStringHot = 'H'; static constexpr char kMethodFlagStringStartup = 'S'; static constexpr char kMethodFlagStringPostStartup = 'P'; +NO_RETURN static void Abort(const char* msg) { + LOG(ERROR) << msg; + exit(1); +} + // TODO(calin): This class has grown too much from its initial design. Split the functionality // into smaller, more contained pieces. class ProfMan FINAL { @@ -202,8 +207,8 @@ class ProfMan FINAL { original_argc = argc; original_argv = argv; - Locks::Init(); - InitLogging(argv, Runtime::Abort); + MemMap::Init(); + InitLogging(argv, Abort); // Skip over the command name. argv++; diff --git a/runtime/Android.bp b/runtime/Android.bp index 64e6796ba0..92607f51a0 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -23,7 +23,7 @@ JIT_DEBUG_REGISTER_CODE_LDFLAGS = [ "-Wl,--keep-unique,__dex_debug_register_code" ] -cc_defaults { +libart_cc_defaults { name: "libart_defaults", defaults: ["art_defaults"], host_supported: true, @@ -32,7 +32,6 @@ cc_defaults { "art_field.cc", "art_method.cc", "barrier.cc", - "base/file_utils.cc", "base/mem_map_arena_pool.cc", "base/mutex.cc", "base/quasi_atomic.cc", @@ -46,7 +45,6 @@ cc_defaults { "compiler_filter.cc", "debug_print.cc", "debugger.cc", - "dex/art_dex_file_loader.cc", "dex/dex_file_annotations.cc", "dex_to_dex_decompiler.cc", "elf_file.cc", @@ -196,6 +194,7 @@ cc_defaults { "ti/agent.cc", "trace.cc", "transaction.cc", + "var_handles.cc", "vdex_file.cc", "verifier/instruction_flags.cc", "verifier/method_verifier.cc", @@ -207,7 +206,6 @@ cc_defaults { "well_known_classes.cc", "arch/context.cc", - "arch/instruction_set.cc", "arch/instruction_set_features.cc", "arch/memcmp16.cc", "arch/arm/instruction_set_features_arm.cc", @@ -396,7 +394,6 @@ cc_defaults { "libbacktrace", "liblz4", "liblog", - "libmetricslogger", // For atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted. "libcutils", // For common macros. @@ -420,7 +417,6 @@ gensrcs { cmd: "$(location generate_operator_out) art/runtime $(in) > $(out)", tools: ["generate_operator_out"], srcs: [ - "arch/instruction_set.h", "base/mutex.h", "class_loader_context.h", "class_status.h", @@ -467,9 +463,9 @@ art_cc_library { keep_symbols: true, }, whole_static_libs: [ - "libartbase", ], shared_libs: [ + "libartbase", "libdexfile", "libprofile", ], @@ -492,9 +488,9 @@ art_cc_library { "libart_defaults", ], whole_static_libs: [ - "libartbased", ], shared_libs: [ + "libartbased", "libdexfiled", "libprofiled", ], @@ -531,7 +527,6 @@ art_cc_test { ], srcs: [ "arch/arch_test.cc", - "arch/instruction_set_test.cc", "arch/instruction_set_features_test.cc", "arch/memcmp16_test.cc", "arch/stub_test.cc", @@ -542,7 +537,6 @@ art_cc_test { "arch/x86/instruction_set_features_x86_test.cc", "arch/x86_64/instruction_set_features_x86_64_test.cc", "barrier_test.cc", - "base/file_utils_test.cc", "base/mutex_test.cc", "base/timing_logger_test.cc", "cha_test.cc", @@ -550,7 +544,6 @@ art_cc_test { "class_loader_context_test.cc", "class_table_test.cc", "compiler_filter_test.cc", - "dex/art_dex_file_loader_test.cc", "entrypoints/math_entrypoints_test.cc", "entrypoints/quick/quick_trampoline_entrypoints_test.cc", "entrypoints_order_test.cc", diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index cd00125de5..311e838fb3 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -55,7 +55,7 @@ @ Load kSaveAllCalleeSaves Method* into rTemp. ldr \rTemp, [\rTemp, #RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET] str \rTemp, [sp, #0] @ Place Method* at bottom of stack. - str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. + str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. // Ugly compile-time check, but we only have the preprocessor. #if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 36 + 64 + 12) @@ -86,7 +86,7 @@ @ Load kSaveRefsOnly Method* into rTemp. ldr \rTemp, [\rTemp, #RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET] str \rTemp, [sp, #0] @ Place Method* at bottom of stack. - str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. + str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. // Ugly compile-time check, but we only have the preprocessor. #if (FRAME_SIZE_SAVE_REFS_ONLY != 28 + 4) @@ -147,13 +147,13 @@ @ Load kSaveRefsAndArgs Method* into rTemp. ldr \rTemp, [\rTemp, #RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET] str \rTemp, [sp, #0] @ Place Method* at bottom of stack. - str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. + str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. .endm .macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_R0 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY str r0, [sp, #0] @ Store ArtMethod* to bottom of stack. - str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. + str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. .endm .macro RESTORE_SAVE_REFS_AND_ARGS_FRAME @@ -193,7 +193,7 @@ @ Load kSaveEverything Method* into rTemp. ldr \rTemp, [\rTemp, #\runtime_method_offset] str \rTemp, [sp, #0] @ Place Method* at bottom of stack. - str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. + str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. // Ugly compile-time check, but we only have the preprocessor. #if (FRAME_SIZE_SAVE_EVERYTHING != 56 + 128 + 8) @@ -301,7 +301,7 @@ * exception is Thread::Current()->exception_ when the runtime method frame is ready. */ .macro DELIVER_PENDING_EXCEPTION_FRAME_READY - mov r0, r9 @ pass Thread::Current + mov r0, rSELF @ pass Thread::Current bl artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*) .endm @@ -318,7 +318,7 @@ .extern \cxx_name ENTRY \c_name SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0 @ save all registers as basis for long jump context - mov r0, r9 @ pass Thread::Current + mov r0, rSELF @ pass Thread::Current bl \cxx_name @ \cxx_name(Thread*) END \c_name .endm @@ -327,7 +327,7 @@ END \c_name .extern \cxx_name ENTRY \c_name SETUP_SAVE_EVERYTHING_FRAME r0 @ save all registers as basis for long jump context - mov r0, r9 @ pass Thread::Current + mov r0, rSELF @ pass Thread::Current bl \cxx_name @ \cxx_name(Thread*) END \c_name .endm @@ -336,7 +336,7 @@ END \c_name .extern \cxx_name ENTRY \c_name SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r1 @ save all registers as basis for long jump context - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl \cxx_name @ \cxx_name(Thread*) END \c_name .endm @@ -345,13 +345,13 @@ END \c_name .extern \cxx_name ENTRY \c_name SETUP_SAVE_EVERYTHING_FRAME r2 @ save all registers as basis for long jump context - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current bl \cxx_name @ \cxx_name(Thread*) END \c_name .endm .macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg - ldr \reg, [r9, #THREAD_EXCEPTION_OFFSET] // Get exception field. + ldr \reg, [rSELF, #THREAD_EXCEPTION_OFFSET] @ Get exception field. cbnz \reg, 1f bx lr 1: @@ -377,7 +377,7 @@ END \c_name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r1 @ save callee saves in case of GC - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl \entrypoint @ (uint32_t field_idx, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -389,7 +389,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current bl \entrypoint @ (field_idx, Object*, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -401,7 +401,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r3 @ save callee saves in case of GC - mov r3, r9 @ pass Thread::Current + mov r3, rSELF @ pass Thread::Current bl \entrypoint @ (field_idx, Object*, new_val, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME @ TODO: we can clearly save an add here REFRESH_MARKING_REGISTER @@ -448,7 +448,7 @@ ENTRY art_quick_throw_null_pointer_exception_from_signal @ save all registers as basis for long jump context SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED r1 mov r0, lr @ pass the fault address stored in LR by the fault handler. - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl artThrowNullPointerExceptionFromSignal @ (Thread*) END art_quick_throw_null_pointer_exception_from_signal @@ -494,7 +494,7 @@ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFr .macro INVOKE_TRAMPOLINE_BODY cxx_name .extern \cxx_name SETUP_SAVE_REFS_AND_ARGS_FRAME r2 @ save callee saves in case allocation triggers GC - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current mov r3, sp bl \cxx_name @ (method_idx, this, Thread*, SP) mov r12, r1 @ save Method*->code_ @@ -682,50 +682,48 @@ TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, */ .extern artLockObjectFromCode ENTRY art_quick_lock_object + ldr r1, [rSELF, #THREAD_ID_OFFSET] cbz r0, .Lslow_lock .Lretry_lock: - ldr r2, [r9, #THREAD_ID_OFFSET] - ldrex r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] - mov r3, r1 - and r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ zero the gc bits - cbnz r3, .Lnot_unlocked @ already thin locked - @ unlocked case - r1: original lock word that's zero except for the read barrier bits. - orr r2, r1, r2 @ r2 holds thread id with count of 0 with preserved read barrier bits - strex r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] - cbnz r3, .Llock_strex_fail @ store failed, retry - dmb ish @ full (LoadLoad|LoadStore) memory barrier + ldrex r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] + eor r3, r2, r1 @ Prepare the value to store if unlocked + @ (thread id, count of 0 and preserved read barrier bits), + @ or prepare to compare thread id for recursive lock check + @ (lock_word.ThreadId() ^ self->ThreadId()). + ands ip, r2, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ Test the non-gc bits. + bne .Lnot_unlocked @ Check if unlocked. + @ unlocked case - store r3: original lock word plus thread id, preserved read barrier bits. + strex r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] + cbnz r2, .Llock_strex_fail @ If store failed, retry. + dmb ish @ Full (LoadLoad|LoadStore) memory barrier. bx lr -.Lnot_unlocked: @ r1: original lock word, r2: thread_id with count of 0 and zero read barrier bits - lsr r3, r1, LOCK_WORD_STATE_SHIFT - cbnz r3, .Lslow_lock @ if either of the top two bits are set, go slow path - eor r2, r1, r2 @ lock_word.ThreadId() ^ self->ThreadId() - uxth r2, r2 @ zero top 16 bits - cbnz r2, .Lslow_lock @ lock word and self thread id's match -> recursive lock - @ else contention, go to slow path - mov r3, r1 @ copy the lock word to check count overflow. - and r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ zero the gc bits. - add r2, r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ increment count in lock word placing in r2 to check overflow - lsr r3, r2, #LOCK_WORD_GC_STATE_SHIFT @ if the first gc state bit is set, we overflowed. - cbnz r3, .Lslow_lock @ if we overflow the count go slow path - add r2, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ increment count for real - strex r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits - cbnz r3, .Llock_strex_fail @ strex failed, retry +.Lnot_unlocked: @ r2: original lock word, r1: thread_id, r3: r2 ^ r1 +#if LOCK_WORD_THIN_LOCK_COUNT_SHIFT + LOCK_WORD_THIN_LOCK_COUNT_SIZE != LOCK_WORD_GC_STATE_SHIFT +#error "Expecting thin lock count and gc state in consecutive bits." +#endif + @ Check lock word state and thread id together, + bfc r3, #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, #(LOCK_WORD_THIN_LOCK_COUNT_SIZE + LOCK_WORD_GC_STATE_SIZE) + cbnz r3, .Lslow_lock @ if either of the top two bits are set, or the lock word's + @ thread id did not match, go slow path. + add r3, r2, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ Increment the recursive lock count. + @ Extract the new thin lock count for overflow check. + ubfx r2, r3, #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, #LOCK_WORD_THIN_LOCK_COUNT_SIZE + cbz r2, .Lslow_lock @ Zero as the new count indicates overflow, go slow path. + strex r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits. + cbnz r2, .Llock_strex_fail @ If strex failed, retry. bx lr .Llock_strex_fail: b .Lretry_lock @ retry -.Lslow_lock: - SETUP_SAVE_REFS_ONLY_FRAME r1 @ save callee saves in case we block - mov r1, r9 @ pass Thread::Current - bl artLockObjectFromCode @ (Object* obj, Thread*) - RESTORE_SAVE_REFS_ONLY_FRAME - REFRESH_MARKING_REGISTER - RETURN_IF_RESULT_IS_ZERO - DELIVER_PENDING_EXCEPTION +// Note: the slow path is actually the art_quick_lock_object_no_inline (tail call). END art_quick_lock_object ENTRY art_quick_lock_object_no_inline + // This is also the slow path for art_quick_lock_object. Note that we + // need a local label, the assembler complains about target being out of + // range if we try to jump to `art_quick_lock_object_no_inline`. +.Lslow_lock: SETUP_SAVE_REFS_ONLY_FRAME r1 @ save callee saves in case we block - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl artLockObjectFromCode @ (Object* obj, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -739,62 +737,59 @@ END art_quick_lock_object_no_inline */ .extern artUnlockObjectFromCode ENTRY art_quick_unlock_object + ldr r1, [rSELF, #THREAD_ID_OFFSET] cbz r0, .Lslow_unlock .Lretry_unlock: #ifndef USE_READ_BARRIER - ldr r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] + ldr r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] #else - ldrex r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ Need to use atomic instructions for read barrier + @ Need to use atomic instructions for read barrier. + ldrex r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] #endif - lsr r2, r1, #LOCK_WORD_STATE_SHIFT - cbnz r2, .Lslow_unlock @ if either of the top two bits are set, go slow path - ldr r2, [r9, #THREAD_ID_OFFSET] - mov r3, r1 @ copy lock word to check thread id equality - and r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ zero the gc bits - eor r3, r3, r2 @ lock_word.ThreadId() ^ self->ThreadId() - uxth r3, r3 @ zero top 16 bits - cbnz r3, .Lslow_unlock @ do lock word and self thread id's match? - mov r3, r1 @ copy lock word to detect transition to unlocked - and r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ zero the gc bits - cmp r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE - bpl .Lrecursive_thin_unlock - @ transition to unlocked - mov r3, r1 - and r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED @ r3: zero except for the preserved gc bits - dmb ish @ full (LoadStore|StoreStore) memory barrier + eor r3, r2, r1 @ Prepare the value to store if simply locked + @ (mostly 0s, and preserved read barrier bits), + @ or prepare to compare thread id for recursive lock check + @ (lock_word.ThreadId() ^ self->ThreadId()). + ands ip, r3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ Test the non-gc bits. + bne .Lnot_simply_locked @ Locked recursively or by other thread? + @ Transition to unlocked. + dmb ish @ Full (LoadStore|StoreStore) memory barrier. #ifndef USE_READ_BARRIER str r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] #else strex r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits - cbnz r2, .Lunlock_strex_fail @ store failed, retry + cbnz r2, .Lunlock_strex_fail @ If the store failed, retry. #endif bx lr -.Lrecursive_thin_unlock: @ r1: original lock word - sub r1, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ decrement count +.Lnot_simply_locked: @ r2: original lock word, r1: thread_id, r3: r2 ^ r1 +#if LOCK_WORD_THIN_LOCK_COUNT_SHIFT + LOCK_WORD_THIN_LOCK_COUNT_SIZE != LOCK_WORD_GC_STATE_SHIFT +#error "Expecting thin lock count and gc state in consecutive bits." +#endif + @ Check lock word state and thread id together, + bfc r3, #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, #(LOCK_WORD_THIN_LOCK_COUNT_SIZE + LOCK_WORD_GC_STATE_SIZE) + cbnz r3, .Lslow_unlock @ if either of the top two bits are set, or the lock word's + @ thread id did not match, go slow path. + sub r3, r2, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ Decrement recursive lock count. #ifndef USE_READ_BARRIER - str r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] + str r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] #else - strex r2, r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits - cbnz r2, .Lunlock_strex_fail @ store failed, retry + strex r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits. + cbnz r2, .Lunlock_strex_fail @ If the store failed, retry. #endif bx lr .Lunlock_strex_fail: b .Lretry_unlock @ retry -.Lslow_unlock: - @ save callee saves in case exception allocation triggers GC - SETUP_SAVE_REFS_ONLY_FRAME r1 - mov r1, r9 @ pass Thread::Current - bl artUnlockObjectFromCode @ (Object* obj, Thread*) - RESTORE_SAVE_REFS_ONLY_FRAME - REFRESH_MARKING_REGISTER - RETURN_IF_RESULT_IS_ZERO - DELIVER_PENDING_EXCEPTION +// Note: the slow path is actually the art_quick_unlock_object_no_inline (tail call). END art_quick_unlock_object ENTRY art_quick_unlock_object_no_inline + // This is also the slow path for art_quick_unlock_object. Note that we + // need a local label, the assembler complains about target being out of + // range if we try to jump to `art_quick_unlock_object_no_inline`. +.Lslow_unlock: @ save callee saves in case exception allocation triggers GC SETUP_SAVE_REFS_ONLY_FRAME r1 - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl artUnlockObjectFromCode @ (Object* obj, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -832,7 +827,7 @@ ENTRY art_quick_check_instance_of .Lthrow_class_cast_exception_for_bitstring_check: SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r2 @ save all registers as basis for long jump context - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current bl artThrowClassCastExceptionForObject @ (Object*, Class*, Thread*) bkpt END art_quick_check_instance_of @@ -917,7 +912,7 @@ ENTRY art_quick_aput_obj add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET POISON_HEAP_REF r2 str r2, [r3, r1, lsl #2] - ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET] + ldr r3, [rSELF, #THREAD_CARD_TABLE_OFFSET] lsr r0, r0, #CARD_TABLE_CARD_SHIFT strb r3, [r3, r0] blx lr @@ -945,7 +940,7 @@ ENTRY art_quick_aput_obj add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET POISON_HEAP_REF r2 str r2, [r3, r1, lsl #2] - ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET] + ldr r3, [rSELF, #THREAD_CARD_TABLE_OFFSET] lsr r0, r0, #CARD_TABLE_CARD_SHIFT strb r3, [r3, r0] blx lr @@ -954,7 +949,7 @@ ENTRY art_quick_aput_obj /* No need to repeat restore cfi directives, the ones above apply here. */ SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r3 mov r1, r2 - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current bl artThrowArrayStoreException @ (Class*, Class*, Thread*) bkpt @ unreached END art_quick_aput_obj @@ -964,7 +959,7 @@ END art_quick_aput_obj .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r1 @ save callee saves in case of GC - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl \entrypoint @ (uint32_t type_idx, Method* method, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -977,7 +972,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current bl \entrypoint @ (uint32_t type_idx, Method* method, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -990,7 +985,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r3 @ save callee saves in case of GC - mov r3, r9 @ pass Thread::Current + mov r3, rSELF @ pass Thread::Current @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*) bl \entrypoint RESTORE_SAVE_REFS_ONLY_FRAME @@ -1004,7 +999,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_REFS_ONLY_FRAME r12 @ save callee saves in case of GC - str r9, [sp, #-16]! @ expand the frame and pass Thread::Current + str rSELF, [sp, #-16]! @ expand the frame and pass Thread::Current .cfi_adjust_cfa_offset 16 bl \entrypoint add sp, #16 @ strip the extra frame @@ -1023,7 +1018,7 @@ END \name .extern \entrypoint ENTRY \name SETUP_SAVE_EVERYTHING_FRAME r1, \runtime_method_offset @ save everything in case of GC - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl \entrypoint @ (uint32_t index, Thread*) cbz r0, 1f @ If result is null, deliver the OOME. .cfi_remember_state @@ -1065,9 +1060,9 @@ ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCompiledCode, .extern artGet64StaticFromCompiledCode ENTRY art_quick_get64_static SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC - mov r1, r9 @ pass Thread::Current - bl artGet64StaticFromCompiledCode @ (uint32_t field_idx, Thread*) - ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + mov r1, rSELF @ pass Thread::Current + bl artGet64StaticFromCompiledCode @ (uint32_t field_idx, Thread*) + ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER cbnz r2, 1f @ success if no exception pending @@ -1091,9 +1086,9 @@ TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCompiledCo .extern artGet64InstanceFromCompiledCode ENTRY art_quick_get64_instance SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC - mov r2, r9 @ pass Thread::Current - bl artGet64InstanceFromCompiledCode @ (field_idx, Object*, Thread*) - ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + mov r2, rSELF @ pass Thread::Current + bl artGet64InstanceFromCompiledCode @ (field_idx, Object*, Thread*) + ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER cbnz r2, 1f @ success if no exception pending @@ -1125,7 +1120,7 @@ THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCompiled ENTRY art_quick_set64_instance SETUP_SAVE_REFS_ONLY_FRAME r12 @ save callee saves in case of GC @ r2:r3 contain the wide argument - str r9, [sp, #-16]! @ expand the frame and pass Thread::Current + str rSELF, [sp, #-16]! @ expand the frame and pass Thread::Current .cfi_adjust_cfa_offset 16 bl artSet64InstanceFromCompiledCode @ (field_idx, Object*, new_val, Thread*) add sp, #16 @ release out args @@ -1140,7 +1135,7 @@ END art_quick_set64_instance ENTRY art_quick_set64_static SETUP_SAVE_REFS_ONLY_FRAME r12 @ save callee saves in case of GC @ r2:r3 contain the wide argument - str r9, [sp, #-16]! @ expand the frame and pass Thread::Current + str rSELF, [sp, #-16]! @ expand the frame and pass Thread::Current .cfi_adjust_cfa_offset 16 bl artSet64StaticFromCompiledCode @ (field_idx, new_val, Thread*) add sp, #16 @ release out args @@ -1185,12 +1180,12 @@ GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB) .macro ART_QUICK_ALLOC_OBJECT_ROSALLOC c_name, cxx_name, isInitialized ENTRY \c_name // Fast path rosalloc allocation. - // r0: type/return value, r9: Thread::Current + // r0: type/return value, rSELF (r9): Thread::Current // r1, r2, r3, r12: free. - ldr r3, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] // Check if the thread local + ldr r3, [rSELF, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] // Check if the thread local // allocation stack has room. // TODO: consider using ldrd. - ldr r12, [r9, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET] + ldr r12, [rSELF, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET] cmp r3, r12 bhs .Lslow_path\c_name @@ -1208,7 +1203,7 @@ ENTRY \c_name // from the size. Since the size is // already aligned we can combine the // two shifts together. - add r12, r9, r3, lsr #(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT) + add r12, rSELF, r3, lsr #(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT) // Subtract pointer size since ther // are no runs for 0 byte allocations // and the size is already aligned. @@ -1236,9 +1231,9 @@ ENTRY \c_name // local allocation stack and // increment the thread local // allocation stack top. - ldr r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] + ldr r1, [rSELF, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] str r3, [r1], #COMPRESSED_REFERENCE_SIZE // (Increment r1 as a side effect.) - str r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] + str r1, [rSELF, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET] // Decrement the size of the free list // After this "STR" the object is published to the thread local allocation stack, @@ -1287,7 +1282,7 @@ ENTRY \c_name .Lslow_path\c_name: SETUP_SAVE_REFS_ONLY_FRAME r2 @ save callee saves in case of GC - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current bl \cxx_name @ (mirror::Class* cls, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -1301,7 +1296,7 @@ ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, art // The common fast path code for art_quick_alloc_object_resolved/initialized_tlab // and art_quick_alloc_object_resolved/initialized_region_tlab. // -// r0: type r9: Thread::Current, r1, r2, r3, r12: free. +// r0: type, rSELF (r9): Thread::Current, r1, r2, r3, r12: free. // Need to preserve r0 to the slow path. // // If isInitialized=1 then the compiler assumes the object's class has already been initialized. @@ -1313,7 +1308,7 @@ ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, art #if !((THREAD_LOCAL_POS_OFFSET + 4 == THREAD_LOCAL_END_OFFSET) && (THREAD_LOCAL_POS_OFFSET % 8 == 0)) #error "Thread::thread_local_pos/end must be consecutive and are 8 byte aligned for performance" #endif - ldrd r12, r3, [r9, #THREAD_LOCAL_POS_OFFSET] + ldrd r12, r3, [rSELF, #THREAD_LOCAL_POS_OFFSET] sub r12, r3, r12 // Compute the remaining buf size. ldr r3, [r0, #MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET] // Load the object size (r3). cmp r3, r12 // Check if it fits. @@ -1326,9 +1321,9 @@ ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, art // "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1. // Reload old thread_local_pos (r0) // for the return value. - ldr r2, [r9, #THREAD_LOCAL_POS_OFFSET] + ldr r2, [rSELF, #THREAD_LOCAL_POS_OFFSET] add r1, r2, r3 - str r1, [r9, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos. + str r1, [rSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos. // After this "STR" the object is published to the thread local allocation stack, // and it will be observable from a runtime internal (eg. Heap::VisitObjects) point of view. // It is not yet visible to the running (user) compiled code until after the return. @@ -1346,9 +1341,9 @@ ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, art // // (Note: The actual check is done by checking that the object's class pointer is non-null. // Also, unlike rosalloc, the object can never be observed as null). - ldr r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects. + ldr r1, [rSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects. add r1, r1, #1 - str r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET] + str r1, [rSELF, #THREAD_LOCAL_OBJECTS_OFFSET] POISON_HEAP_REF r0 str r0, [r2, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer. // Fence. This is "ish" not "ishst" so @@ -1375,12 +1370,12 @@ ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, art .macro GENERATE_ALLOC_OBJECT_RESOLVED_TLAB name, entrypoint, isInitialized ENTRY \name // Fast path tlab allocation. - // r0: type, r9: Thread::Current + // r0: type, rSELF (r9): Thread::Current // r1, r2, r3, r12: free. ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lslow_path\name, \isInitialized .Lslow_path\name: SETUP_SAVE_REFS_ONLY_FRAME r2 // Save callee saves in case of GC. - mov r1, r9 // Pass Thread::Current. + mov r1, rSELF // Pass Thread::Current. bl \entrypoint // (mirror::Class* klass, Thread*) RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -1397,7 +1392,7 @@ GENERATE_ALLOC_OBJECT_RESOLVED_TLAB art_quick_alloc_object_initialized_tlab, art // The common fast path code for art_quick_alloc_array_resolved/initialized_tlab // and art_quick_alloc_array_resolved/initialized_region_tlab. // -// r0: type r1: component_count r2: total_size r9: Thread::Current, r3, r12: free. +// r0: type, r1: component_count, r2: total_size, rSELF (r9): Thread::Current, r3, r12: free. // Need to preserve r0 and r1 to the slow path. .macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel and r2, r2, #OBJECT_ALIGNMENT_MASK_TOGGLED // Apply alignment mask @@ -1409,7 +1404,7 @@ GENERATE_ALLOC_OBJECT_RESOLVED_TLAB art_quick_alloc_object_initialized_tlab, art #if !((THREAD_LOCAL_POS_OFFSET + 4 == THREAD_LOCAL_END_OFFSET) && (THREAD_LOCAL_POS_OFFSET % 8 == 0)) #error "Thread::thread_local_pos/end must be consecutive and are 8 byte aligned for performance" #endif - ldrd r3, r12, [r9, #THREAD_LOCAL_POS_OFFSET] + ldrd r3, r12, [rSELF, #THREAD_LOCAL_POS_OFFSET] sub r12, r12, r3 // Compute the remaining buf size. cmp r2, r12 // Check if the total_size fits. // The array class is always initialized here. Unlike new-instance, @@ -1417,10 +1412,10 @@ GENERATE_ALLOC_OBJECT_RESOLVED_TLAB art_quick_alloc_object_initialized_tlab, art bhi \slowPathLabel // "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1. add r2, r2, r3 - str r2, [r9, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos. - ldr r2, [r9, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects. + str r2, [rSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos. + ldr r2, [rSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects. add r2, r2, #1 - str r2, [r9, #THREAD_LOCAL_OBJECTS_OFFSET] + str r2, [rSELF, #THREAD_LOCAL_OBJECTS_OFFSET] POISON_HEAP_REF r0 str r0, [r3, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer. str r1, [r3, #MIRROR_ARRAY_LENGTH_OFFSET] // Store the array length. @@ -1443,7 +1438,7 @@ ENTRY \name // Fast path array allocation for region tlab allocation. // r0: mirror::Class* type // r1: int32_t component_count - // r9: thread + // rSELF (r9): thread // r2, r3, r12: free. \size_setup .Lslow_path\name ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path\name @@ -1452,7 +1447,7 @@ ENTRY \name // r1: int32_t component_count // r2: Thread* self SETUP_SAVE_REFS_ONLY_FRAME r2 // save callee saves in case of GC - mov r2, r9 // pass Thread::Current + mov r2, rSELF // pass Thread::Current bl \entrypoint RESTORE_SAVE_REFS_ONLY_FRAME REFRESH_MARKING_REGISTER @@ -1575,10 +1570,10 @@ END art_quick_implicit_suspend .extern artQuickProxyInvokeHandler ENTRY art_quick_proxy_invoke_handler SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_R0 - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current mov r3, sp @ pass SP blx artQuickProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP) - ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ // Tear down the callee-save frame. Skip arg registers. add sp, #(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY) .cfi_adjust_cfa_offset -(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY) @@ -1706,7 +1701,7 @@ END art_quick_imt_conflict_trampoline .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline SETUP_SAVE_REFS_AND_ARGS_FRAME r2 - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current mov r3, sp @ pass SP blx artQuickResolutionTrampoline @ (Method* called, receiver, Thread*, SP) cbz r0, 1f @ is code pointer null? goto exception @@ -1780,10 +1775,10 @@ ENTRY art_quick_generic_jni_trampoline blx artQuickGenericJniEndTrampoline // Restore self pointer. - mov r9, r11 + mov rSELF, r11 // Pending exceptions possible. - ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ cbnz r2, .Lexception_in_native // Tear down the alloca. @@ -1804,7 +1799,7 @@ ENTRY art_quick_generic_jni_trampoline .cfi_adjust_cfa_offset FRAME_SIZE_SAVE_REFS_AND_ARGS-FRAME_SIZE_SAVE_REFS_ONLY .Lexception_in_native: - ldr ip, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] + ldr ip, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] add ip, ip, #-1 // Remove the GenericJNI tag. ADD/SUB writing directly to SP is UNPREDICTABLE. mov sp, ip .cfi_def_cfa_register sp @@ -1815,10 +1810,10 @@ END art_quick_generic_jni_trampoline .extern artQuickToInterpreterBridge ENTRY art_quick_to_interpreter_bridge SETUP_SAVE_REFS_AND_ARGS_FRAME r1 - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current mov r2, sp @ pass SP blx artQuickToInterpreterBridge @ (Method* method, Thread*, SP) - ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ + ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ // Tear down the callee-save frame. Skip arg registers. add sp, #(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY) .cfi_adjust_cfa_offset -(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY) @@ -1846,7 +1841,7 @@ ENTRY art_quick_instrumentation_entry SETUP_SAVE_REFS_AND_ARGS_FRAME r2 @ preserve r0 (not normally an arg) knowing there is a spare slot in kSaveRefsAndArgs. str r0, [sp, #4] - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current mov r3, sp @ pass SP blx artInstrumentationMethodEntryFromCode @ (Method*, Object*, Thread*, SP) cbz r0, .Ldeliver_instrumentation_entry_exception @@ -1872,7 +1867,7 @@ ENTRY art_quick_instrumentation_exit add r3, sp, #8 @ store fpr_res pointer, in kSaveEverything frame add r2, sp, #136 @ store gpr_res pointer, in kSaveEverything frame mov r1, sp @ pass SP - mov r0, r9 @ pass Thread::Current + mov r0, rSELF @ pass Thread::Current blx artInstrumentationMethodExitFromCode @ (Thread*, SP, gpr_res*, fpr_res*) cbz r0, .Ldo_deliver_instrumentation_exception @@ -1901,7 +1896,7 @@ END art_quick_instrumentation_exit .extern artDeoptimize ENTRY art_quick_deoptimize SETUP_SAVE_EVERYTHING_FRAME r0 - mov r0, r9 @ pass Thread::Current + mov r0, rSELF @ pass Thread::Current blx artDeoptimize @ (Thread*) END art_quick_deoptimize @@ -1912,7 +1907,7 @@ END art_quick_deoptimize .extern artDeoptimizeFromCompiledCode ENTRY art_quick_deoptimize_from_compiled_code SETUP_SAVE_EVERYTHING_FRAME r1 - mov r1, r9 @ pass Thread::Current + mov r1, rSELF @ pass Thread::Current blx artDeoptimizeFromCompiledCode @ (DeoptimizationKind, Thread*) END art_quick_deoptimize_from_compiled_code @@ -2691,7 +2686,7 @@ END art_quick_read_barrier_mark_introspection .extern artInvokePolymorphic ENTRY art_quick_invoke_polymorphic SETUP_SAVE_REFS_AND_ARGS_FRAME r2 - mov r2, r9 @ pass Thread::Current + mov r2, rSELF @ pass Thread::Current mov r3, sp @ pass SP mov r0, #0 @ initialize 64-bit JValue as zero. str r0, [sp, #-4]! diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index ac5b2b8b88..14d0cc7db4 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1151,45 +1151,36 @@ END art_quick_do_long_jump */ .extern artLockObjectFromCode ENTRY art_quick_lock_object - cbz w0, .Lslow_lock - add x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET // exclusive load/store has no immediate anymore + ldr w1, [xSELF, #THREAD_ID_OFFSET] + cbz w0, art_quick_lock_object_no_inline + // Exclusive load/store has no immediate anymore. + add x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET .Lretry_lock: - ldr w2, [xSELF, #THREAD_ID_OFFSET] // TODO: Can the thread ID really change during the loop? - ldaxr w1, [x4] // acquire needed only in most common case - and w3, w1, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // zero the gc bits - cbnz w3, .Lnot_unlocked // already thin locked - // unlocked case - x1: original lock word that's zero except for the read barrier bits. - orr x2, x1, x2 // x2 holds thread id with count of 0 with preserved read barrier bits - stxr w3, w2, [x4] - cbnz w3, .Llock_stxr_fail // store failed, retry + ldaxr w2, [x4] // Acquire needed only in most common case. + eor w3, w2, w1 // Prepare the value to store if unlocked + // (thread id, count of 0 and preserved read barrier bits), + // or prepare to compare thread id for recursive lock check + // (lock_word.ThreadId() ^ self->ThreadId()). + tst w2, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // Test the non-gc bits. + b.ne .Lnot_unlocked // Check if unlocked. + // unlocked case - store w3: original lock word plus thread id, preserved read barrier bits. + stxr w2, w3, [x4] + cbnz w2, .Lretry_lock // If the store failed, retry. ret -.Lnot_unlocked: // x1: original lock word - lsr w3, w1, LOCK_WORD_STATE_SHIFT - cbnz w3, .Lslow_lock // if either of the top two bits are set, go slow path - eor w2, w1, w2 // lock_word.ThreadId() ^ self->ThreadId() - uxth w2, w2 // zero top 16 bits - cbnz w2, .Lslow_lock // lock word and self thread id's match -> recursive lock - // else contention, go to slow path - and w3, w1, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // zero the gc bits. - add w2, w3, #LOCK_WORD_THIN_LOCK_COUNT_ONE // increment count in lock word placing in w2 to check overflow - lsr w3, w2, #LOCK_WORD_GC_STATE_SHIFT // if the first gc state bit is set, we overflowed. - cbnz w3, .Lslow_lock // if we overflow the count go slow path - add w2, w1, #LOCK_WORD_THIN_LOCK_COUNT_ONE // increment count for real - stxr w3, w2, [x4] - cbnz w3, .Llock_stxr_fail // store failed, retry +.Lnot_unlocked: // w2: original lock word, w1: thread id, w3: w2 ^ w1 + // Check lock word state and thread id together, + tst w3, #(LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED) + b.ne art_quick_lock_object_no_inline + add w3, w2, #LOCK_WORD_THIN_LOCK_COUNT_ONE // Increment the recursive lock count. + tst w3, #LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED // Test the new thin lock count. + b.eq art_quick_lock_object_no_inline // Zero as the new count indicates overflow, go slow path. + stxr w2, w3, [x4] + cbnz w2, .Lretry_lock // If the store failed, retry. ret -.Llock_stxr_fail: - b .Lretry_lock // retry -.Lslow_lock: - SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case we block - mov x1, xSELF // pass Thread::Current - bl artLockObjectFromCode // (Object* obj, Thread*) - RESTORE_SAVE_REFS_ONLY_FRAME - REFRESH_MARKING_REGISTER - RETURN_IF_W0_IS_ZERO_OR_DELIVER END art_quick_lock_object ENTRY art_quick_lock_object_no_inline + // This is also the slow path for art_quick_lock_object. SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case we block mov x1, xSELF // pass Thread::Current bl artLockObjectFromCode // (Object* obj, Thread*) @@ -1206,54 +1197,46 @@ END art_quick_lock_object_no_inline */ .extern artUnlockObjectFromCode ENTRY art_quick_unlock_object - cbz x0, .Lslow_unlock - add x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET // exclusive load/store has no immediate anymore + ldr w1, [xSELF, #THREAD_ID_OFFSET] + cbz x0, art_quick_unlock_object_no_inline + // Exclusive load/store has no immediate anymore. + add x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET .Lretry_unlock: #ifndef USE_READ_BARRIER - ldr w1, [x4] + ldr w2, [x4] #else - ldxr w1, [x4] // Need to use atomic instructions for read barrier + ldxr w2, [x4] // Need to use atomic instructions for read barrier. #endif - lsr w2, w1, LOCK_WORD_STATE_SHIFT - cbnz w2, .Lslow_unlock // if either of the top two bits are set, go slow path - ldr w2, [xSELF, #THREAD_ID_OFFSET] - and w3, w1, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // zero the gc bits - eor w3, w3, w2 // lock_word.ThreadId() ^ self->ThreadId() - uxth w3, w3 // zero top 16 bits - cbnz w3, .Lslow_unlock // do lock word and self thread id's match? - and w3, w1, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // zero the gc bits - cmp w3, #LOCK_WORD_THIN_LOCK_COUNT_ONE - bpl .Lrecursive_thin_unlock - // transition to unlocked - and w3, w1, #LOCK_WORD_GC_STATE_MASK_SHIFTED // w3: zero except for the preserved read barrier bits + eor w3, w2, w1 // Prepare the value to store if simply locked + // (mostly 0s, and preserved read barrier bits), + // or prepare to compare thread id for recursive lock check + // (lock_word.ThreadId() ^ self->ThreadId()). + tst w3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // Test the non-gc bits. + b.ne .Lnot_simply_locked // Locked recursively or by other thread? + // Transition to unlocked. #ifndef USE_READ_BARRIER stlr w3, [x4] #else - stlxr w2, w3, [x4] // Need to use atomic instructions for read barrier - cbnz w2, .Lunlock_stxr_fail // store failed, retry + stlxr w2, w3, [x4] // Need to use atomic instructions for read barrier. + cbnz w2, .Lretry_unlock // If the store failed, retry. #endif ret -.Lrecursive_thin_unlock: // w1: original lock word - sub w1, w1, #LOCK_WORD_THIN_LOCK_COUNT_ONE // decrement count +.Lnot_simply_locked: + // Check lock word state and thread id together, + tst w3, #(LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED) + b.ne art_quick_unlock_object_no_inline + sub w3, w2, #LOCK_WORD_THIN_LOCK_COUNT_ONE // decrement count #ifndef USE_READ_BARRIER - str w1, [x4] + str w3, [x4] #else - stxr w2, w1, [x4] // Need to use atomic instructions for read barrier - cbnz w2, .Lunlock_stxr_fail // store failed, retry + stxr w2, w3, [x4] // Need to use atomic instructions for read barrier. + cbnz w2, .Lretry_unlock // If the store failed, retry. #endif ret -.Lunlock_stxr_fail: - b .Lretry_unlock // retry -.Lslow_unlock: - SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case exception allocation triggers GC - mov x1, xSELF // pass Thread::Current - bl artUnlockObjectFromCode // (Object* obj, Thread*) - RESTORE_SAVE_REFS_ONLY_FRAME - REFRESH_MARKING_REGISTER - RETURN_IF_W0_IS_ZERO_OR_DELIVER END art_quick_unlock_object ENTRY art_quick_unlock_object_no_inline + // This is also the slow path for art_quick_unlock_object. SETUP_SAVE_REFS_ONLY_FRAME // save callee saves in case exception allocation triggers GC mov x1, xSELF // pass Thread::Current bl artUnlockObjectFromCode // (Object* obj, Thread*) diff --git a/runtime/arch/code_offset.h b/runtime/arch/code_offset.h index 8e8dde4c4c..f0c6d22ef2 100644 --- a/runtime/arch/code_offset.h +++ b/runtime/arch/code_offset.h @@ -21,9 +21,9 @@ #include <android-base/logging.h> +#include "arch/instruction_set.h" #include "base/bit_utils.h" #include "base/macros.h" -#include "instruction_set.h" namespace art { diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h index 5f1a507f7a..c31c927668 100644 --- a/runtime/arch/instruction_set_features.h +++ b/runtime/arch/instruction_set_features.h @@ -21,8 +21,8 @@ #include <ostream> #include <vector> +#include "arch/instruction_set.h" #include "base/macros.h" -#include "instruction_set.h" namespace art { diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 8ab4ce160f..b89d45f617 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -1292,7 +1292,7 @@ DEFINE_FUNCTION art_quick_lock_object jz .Lslow_lock .Lretry_lock: movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax), %ecx // ecx := lock word - test LITERAL(LOCK_WORD_STATE_MASK), %ecx // test the 2 high bits. + test LITERAL(LOCK_WORD_STATE_MASK_SHIFTED), %ecx // test the 2 high bits. jne .Lslow_lock // slow path if either of the two high bits are set. movl %ecx, %edx // save lock word (edx) to keep read barrier bits. andl LITERAL(LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED), %ecx // zero the gc bits. @@ -1362,7 +1362,7 @@ DEFINE_FUNCTION art_quick_unlock_object .Lretry_unlock: movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%eax), %ecx // ecx := lock word movl %fs:THREAD_ID_OFFSET, %edx // edx := thread id - test LITERAL(LOCK_WORD_STATE_MASK), %ecx + test LITERAL(LOCK_WORD_STATE_MASK_SHIFTED), %ecx jnz .Lslow_unlock // lock word contains a monitor cmpw %cx, %dx // does the thread id match? jne .Lslow_unlock diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index eb945ed366..c179033e6b 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -1312,7 +1312,7 @@ DEFINE_FUNCTION art_quick_lock_object jz .Lslow_lock .Lretry_lock: movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi), %ecx // ecx := lock word. - test LITERAL(LOCK_WORD_STATE_MASK), %ecx // Test the 2 high bits. + test LITERAL(LOCK_WORD_STATE_MASK_SHIFTED), %ecx // Test the 2 high bits. jne .Lslow_lock // Slow path if either of the two high bits are set. movl %ecx, %edx // save lock word (edx) to keep read barrier bits. andl LITERAL(LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED), %ecx // zero the gc bits. @@ -1362,7 +1362,7 @@ DEFINE_FUNCTION art_quick_unlock_object .Lretry_unlock: movl MIRROR_OBJECT_LOCK_WORD_OFFSET(%edi), %ecx // ecx := lock word movl %gs:THREAD_ID_OFFSET, %edx // edx := thread id - test LITERAL(LOCK_WORD_STATE_MASK), %ecx + test LITERAL(LOCK_WORD_STATE_MASK_SHIFTED), %ecx jnz .Lslow_unlock // lock word contains a monitor cmpw %cx, %dx // does the thread id match? jne .Lslow_unlock diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 87fcb20698..608e33cf65 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -710,6 +710,23 @@ bool ArtMethod::HasAnyCompiledCode() { return GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()) != nullptr; } +void ArtMethod::SetNotIntrinsic() { + if (!IsIntrinsic()) { + return; + } + + // Query the hidden API access flags of the intrinsic. + HiddenApiAccessFlags::ApiList intrinsic_api_list = GetHiddenApiAccessFlags(); + + // Clear intrinsic-related access flags. + ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits); + + // Re-apply hidden API access flags now that the method is not an intrinsic. + SetAccessFlags(HiddenApiAccessFlags::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list)); + DCHECK_EQ(GetHiddenApiAccessFlags(), intrinsic_api_list); +} + + void ArtMethod::CopyFrom(ArtMethod* src, PointerSize image_pointer_size) { memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src), Size(image_pointer_size)); diff --git a/runtime/art_method.h b/runtime/art_method.h index acaa4a68a1..012d706756 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -194,9 +194,7 @@ class ArtMethod FINAL { return (GetAccessFlags() & kAccIntrinsicBits) >> kAccFlagsShift; } - void SetNotIntrinsic() REQUIRES_SHARED(Locks::mutator_lock_) { - ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits); - } + void SetNotIntrinsic() REQUIRES_SHARED(Locks::mutator_lock_); bool IsCopied() { static_assert((kAccCopied & (kAccIntrinsic | kAccIntrinsicBits)) == 0, diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index e2ad7fd83f..6917899bff 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -64,20 +64,19 @@ class CheckReferenceMapVisitor : public StackVisitor { void CheckOptimizedMethod(int* registers, int number_of_references, uint32_t native_pc_offset) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* m = GetMethod(); - CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + CodeInfo code_info(GetCurrentOatQuickMethodHeader()); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); CodeItemDataAccessor accessor(m->DexInstructionData()); uint16_t number_of_dex_registers = accessor.RegistersSize(); DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); - uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map); - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); + code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); + uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map); + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); for (int i = 0; i < number_of_references; ++i) { int reg = registers[i]; CHECK_LT(reg, accessor.RegistersSize()); DexRegisterLocation location = dex_register_map.GetDexRegisterLocation( - reg, number_of_dex_registers, code_info, encoding); + reg, number_of_dex_registers, code_info); switch (location.GetKind()) { case DexRegisterLocation::Kind::kNone: // Not set, should not be a reference. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 4141a37366..b88aa5e07a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -828,9 +828,24 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b return true; } +static void CreateStringInitBindings(Thread* self, ClassLinker* class_linker) + REQUIRES_SHARED(Locks::mutator_lock_) { + // Find String.<init> -> StringFactory bindings. + ObjPtr<mirror::Class> string_factory_class = + class_linker->FindSystemClass(self, "Ljava/lang/StringFactory;"); + CHECK(string_factory_class != nullptr); + ObjPtr<mirror::Class> string_class = + class_linker->GetClassRoot(ClassLinker::ClassRoot::kJavaLangString); + WellKnownClasses::InitStringInit(string_class, string_factory_class); + // Update the primordial thread. + self->InitStringEntryPoints(); +} + void ClassLinker::FinishInit(Thread* self) { VLOG(startup) << "ClassLinker::FinishInit entering"; + CreateStringInitBindings(self, this); + // Let the heap know some key offsets into java.lang.ref instances // Note: we hard code the field indexes here rather than using FindInstanceField // as the types of the field can't be resolved prior to the runtime being @@ -4850,6 +4865,9 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, const uint32_t field_idx = field->GetDexFieldIndex(); ArtField* resolved_field = dex_cache->GetResolvedField(field_idx, image_pointer_size_); if (resolved_field == nullptr) { + // Populating cache of a dex file which defines `klass` should always be allowed. + DCHECK_EQ(hiddenapi::GetMemberAction( + field, class_loader.Get(), dex_cache.Get(), hiddenapi::kNone), hiddenapi::kAllow); dex_cache->SetResolvedField(field_idx, field, image_pointer_size_); } else { DCHECK_EQ(field, resolved_field); @@ -8053,26 +8071,8 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, return nullptr; } DCHECK(klass->IsResolved()); - Thread* self = is_static ? Thread::Current() : nullptr; - // First try to find a field declared directly by `klass` by the field index. - ArtField* resolved_field = is_static - ? mirror::Class::FindStaticField(self, klass, dex_cache, field_idx) - : klass->FindInstanceField(dex_cache, field_idx); - - if (resolved_field == nullptr) { - // If not found in `klass` by field index, search the class hierarchy using the name and type. - const char* name = dex_file.GetFieldName(field_id); - const char* type = dex_file.GetFieldTypeDescriptor(field_id); - resolved_field = is_static - ? mirror::Class::FindStaticField(self, klass, name, type) - : klass->FindInstanceField(name, type); - } - - if (resolved_field != nullptr) { - dex_cache->SetResolvedField(field_idx, resolved_field, image_pointer_size_); - } - return resolved_field; + return FindResolvedField(klass, dex_cache, class_loader, field_idx, is_static); } ArtField* ClassLinker::ResolveField(uint32_t field_idx, @@ -8087,39 +8087,18 @@ ArtField* ClassLinker::ResolveField(uint32_t field_idx, } const DexFile& dex_file = *dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); - Thread* const self = Thread::Current(); ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader); if (klass == nullptr) { DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; } - if (is_static) { - resolved = mirror::Class::FindStaticField(self, klass, dex_cache.Get(), field_idx); - } else { - resolved = klass->FindInstanceField(dex_cache.Get(), field_idx); - } - + resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static); if (resolved == nullptr) { const char* name = dex_file.GetFieldName(field_id); const char* type = dex_file.GetFieldTypeDescriptor(field_id); - if (is_static) { - resolved = mirror::Class::FindStaticField(self, klass, name, type); - } else { - resolved = klass->FindInstanceField(name, type); - } - } - - if (resolved == nullptr || - hiddenapi::GetMemberAction( - resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) { - const char* name = dex_file.GetFieldName(field_id); - const char* type = dex_file.GetFieldTypeDescriptor(field_id); ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name); - return nullptr; } - - dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_); return resolved; } @@ -8134,32 +8113,83 @@ ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx, } const DexFile& dex_file = *dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); - Thread* self = Thread::Current(); ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader); if (klass == nullptr) { DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; } - StringPiece name(dex_file.GetFieldName(field_id)); - StringPiece type(dex_file.GetFieldTypeDescriptor(field_id)); + resolved = FindResolvedFieldJLS(klass, dex_cache.Get(), class_loader.Get(), field_idx); + if (resolved == nullptr) { + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + ThrowNoSuchFieldError("", klass, type, name); + } + return resolved; +} + +ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t field_idx, + bool is_static) { + ArtField* resolved = nullptr; + Thread* self = is_static ? Thread::Current() : nullptr; + const DexFile& dex_file = *dex_cache->GetDexFile(); + + resolved = is_static ? mirror::Class::FindStaticField(self, klass, dex_cache, field_idx) + : klass->FindInstanceField(dex_cache, field_idx); + + if (resolved == nullptr) { + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + resolved = is_static ? mirror::Class::FindStaticField(self, klass, name, type) + : klass->FindInstanceField(name, type); + } + + if (resolved != nullptr && + hiddenapi::GetMemberAction( + resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) { + resolved = nullptr; + } + + if (resolved != nullptr) { + dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_); + } + + return resolved; +} + +ArtField* ClassLinker::FindResolvedFieldJLS(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t field_idx) { + ArtField* resolved = nullptr; + Thread* self = Thread::Current(); + const DexFile& dex_file = *dex_cache->GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); resolved = mirror::Class::FindField(self, klass, name, type); + if (resolved != nullptr && hiddenapi::GetMemberAction( - resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) { + resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) { resolved = nullptr; } + if (resolved != nullptr) { dex_cache->SetResolvedField(field_idx, resolved, image_pointer_size_); - } else { - ThrowNoSuchFieldError("", klass, type, name); } + return resolved; } ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType( Thread* self, - uint32_t proto_idx, + dex::ProtoIndex proto_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); @@ -8221,7 +8251,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType( } ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(Thread* self, - uint32_t proto_idx, + dex::ProtoIndex proto_idx, ArtMethod* referrer) { StackHandleScope<2> hs(self); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index e935d1dfb8..52ecf82c86 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -392,17 +392,38 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); + // Find a field with a given ID from the DexFile associated with the given DexCache + // and ClassLoader, storing the result in DexCache. The declaring class is assumed + // to have been already resolved into `klass`. The `is_static` argument is used to + // determine if we are resolving a static or non-static field. + ArtField* FindResolvedField(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t field_idx, + bool is_static) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Find a field with a given ID from the DexFile associated with the given DexCache + // and ClassLoader, storing the result in DexCache. The declaring class is assumed + // to have been already resolved into `klass`. No is_static argument is provided + // so that Java field resolution semantics are followed. + ArtField* FindResolvedFieldJLS(ObjPtr<mirror::Class> klass, + ObjPtr<mirror::DexCache> dex_cache, + ObjPtr<mirror::ClassLoader> class_loader, + uint32_t field_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a method type with a given ID from the DexFile associated with a given DexCache // and ClassLoader, storing the result in the DexCache. ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self, - uint32_t proto_idx, + dex::ProtoIndex proto_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self, - uint32_t proto_idx, + dex::ProtoIndex proto_idx, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 37e074d552..9c2a40b50d 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -29,6 +29,7 @@ #include "instrumentation.h" #include "interpreter/shadow_frame.h" #include "interpreter/unstarted_runtime.h" +#include "jvalue-inl.h" #include "mirror/class.h" #include "mirror/object.h" #include "obj_ptr-inl.h" diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 8fd95ed890..657a78bd2f 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -880,11 +880,14 @@ void ThrowVerifyError(ObjPtr<mirror::Class> referrer, const char* fmt, ...) { void ThrowWrongMethodTypeException(ObjPtr<mirror::MethodType> expected_type, ObjPtr<mirror::MethodType> actual_type) { - ThrowException("Ljava/lang/invoke/WrongMethodTypeException;", - nullptr, - StringPrintf("Expected %s but was %s", - expected_type->PrettyDescriptor().c_str(), - actual_type->PrettyDescriptor().c_str()).c_str()); + ThrowWrongMethodTypeException(expected_type->PrettyDescriptor(), actual_type->PrettyDescriptor()); +} + +void ThrowWrongMethodTypeException(const std::string& expected_descriptor, + const std::string& actual_descriptor) { + std::ostringstream msg; + msg << "Expected " << expected_descriptor << " but was " << actual_descriptor; + ThrowException("Ljava/lang/invoke/WrongMethodTypeException;", nullptr, msg.str().c_str()); } } // namespace art diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 29a056e9ea..6acff6f222 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -274,6 +274,10 @@ void ThrowWrongMethodTypeException(ObjPtr<mirror::MethodType> callee_type, ObjPtr<mirror::MethodType> callsite_type) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; +void ThrowWrongMethodTypeException(const std::string& expected_descriptor, + const std::string& actual_descriptor) + REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; + } // namespace art #endif // ART_RUNTIME_COMMON_THROWS_H_ diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index c399b1c7fe..95b42d27d2 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -29,6 +29,7 @@ #include "mirror/field.h" #include "mirror/method.h" #include "oat_file.h" +#include "obj_ptr-inl.h" #include "reflection.h" #include "thread.h" #include "well_known_classes.h" @@ -116,9 +117,9 @@ class ClassData { DISALLOW_COPY_AND_ASSIGN(ClassData); }; -mirror::Object* CreateAnnotationMember(const ClassData& klass, - Handle<mirror::Class> annotation_class, - const uint8_t** annotation) +ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass, + Handle<mirror::Class> annotation_class, + const uint8_t** annotation) REQUIRES_SHARED(Locks::mutator_lock_); bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) { @@ -333,7 +334,7 @@ const DexFile::AnnotationSetItem* FindAnnotationSetForClass(const ClassData& kla return dex_file.GetClassAnnotationSet(annotations_dir); } -mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** annotation) +ObjPtr<mirror::Object> ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** annotation) REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t type_index = DecodeUnsignedLeb128(annotation); uint32_t size = DecodeUnsignedLeb128(annotation); @@ -355,13 +356,13 @@ mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** } ObjPtr<mirror::Class> annotation_member_class = - soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember).Ptr(); - mirror::Class* annotation_member_array_class = + soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember); + ObjPtr<mirror::Class> annotation_member_array_class = class_linker->FindArrayClass(self, &annotation_member_class); if (annotation_member_array_class == nullptr) { return nullptr; } - mirror::ObjectArray<mirror::Object>* element_array = nullptr; + ObjPtr<mirror::ObjectArray<mirror::Object>> element_array = nullptr; if (size > 0) { element_array = mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_member_array_class, size); @@ -373,7 +374,7 @@ mirror::Object* ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** Handle<mirror::ObjectArray<mirror::Object>> h_element_array(hs.NewHandle(element_array)); for (uint32_t i = 0; i < size; ++i) { - mirror::Object* new_member = CreateAnnotationMember(klass, annotation_class, annotation); + ObjPtr<mirror::Object> new_member = CreateAnnotationMember(klass, annotation_class, annotation); if (new_member == nullptr) { return nullptr; } @@ -605,7 +606,7 @@ bool ProcessAnnotationValue(const ClassData& klass, return false; } if (!component_type->IsPrimitive()) { - mirror::Object* obj = new_annotation_value.value_.GetL(); + ObjPtr<mirror::Object> obj = new_annotation_value.value_.GetL(); new_array->AsObjectArray<mirror::Object>()-> SetWithoutChecks<kTransactionActive>(i, obj); } else { @@ -682,20 +683,20 @@ bool ProcessAnnotationValue(const ClassData& klass, *annotation_ptr = annotation; if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) { - element_object = BoxPrimitive(primitive_type, annotation_value->value_).Ptr(); + element_object = BoxPrimitive(primitive_type, annotation_value->value_); set_object = true; } if (set_object) { - annotation_value->value_.SetL(element_object.Ptr()); + annotation_value->value_.SetL(element_object); } return true; } -mirror::Object* CreateAnnotationMember(const ClassData& klass, - Handle<mirror::Class> annotation_class, - const uint8_t** annotation) { +ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass, + Handle<mirror::Class> annotation_class, + const uint8_t** annotation) { const DexFile& dex_file = klass.GetDexFile(); Thread* self = Thread::Current(); ScopedObjectAccessUnchecked soa(self); @@ -799,7 +800,7 @@ const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet( return nullptr; } -mirror::Object* GetAnnotationObjectFromAnnotationSet( +ObjPtr<mirror::Object> GetAnnotationObjectFromAnnotationSet( const ClassData& klass, const DexFile::AnnotationSetItem* annotation_set, uint32_t visibility, @@ -814,11 +815,11 @@ mirror::Object* GetAnnotationObjectFromAnnotationSet( return ProcessEncodedAnnotation(klass, &annotation); } -mirror::Object* GetAnnotationValue(const ClassData& klass, - const DexFile::AnnotationItem* annotation_item, - const char* annotation_name, - Handle<mirror::Class> array_class, - uint32_t expected_type) +ObjPtr<mirror::Object> GetAnnotationValue(const ClassData& klass, + const DexFile::AnnotationItem* annotation_item, + const char* annotation_name, + Handle<mirror::Class> array_class, + uint32_t expected_type) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); const uint8_t* annotation = @@ -864,7 +865,7 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, if (string_array_class == nullptr) { return nullptr; } - mirror::Object* obj = + ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", string_array_class, DexFile::kDexAnnotationArray); if (obj == nullptr) { @@ -873,8 +874,9 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, return obj->AsObjectArray<mirror::String>(); } -mirror::ObjectArray<mirror::Class>* GetThrowsValue(const ClassData& klass, - const DexFile::AnnotationSetItem* annotation_set) +ObjPtr<mirror::ObjectArray<mirror::Class>> GetThrowsValue( + const ClassData& klass, + const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); StackHandleScope<1> hs(Thread::Current()); @@ -890,7 +892,7 @@ mirror::ObjectArray<mirror::Class>* GetThrowsValue(const ClassData& klass, if (class_array_class == nullptr) { return nullptr; } - mirror::Object* obj = + ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); if (obj == nullptr) { @@ -899,7 +901,7 @@ mirror::ObjectArray<mirror::Class>* GetThrowsValue(const ClassData& klass, return obj->AsObjectArray<mirror::Class>(); } -mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet( +ObjPtr<mirror::ObjectArray<mirror::Object>> ProcessAnnotationSet( const ClassData& klass, const DexFile::AnnotationSetItem* annotation_set, uint32_t visibility) @@ -930,7 +932,7 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet( continue; } const uint8_t* annotation = annotation_item->annotation_; - mirror::Object* annotation_obj = ProcessEncodedAnnotation(klass, &annotation); + ObjPtr<mirror::Object> annotation_obj = ProcessEncodedAnnotation(klass, &annotation); if (annotation_obj != nullptr) { result->SetWithoutChecks<false>(dest_index, annotation_obj); ++dest_index; @@ -943,21 +945,21 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet( return result.Get(); } - mirror::ObjectArray<mirror::Object>* trimmed_result = + ObjPtr<mirror::ObjectArray<mirror::Object>> trimmed_result = mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), dest_index); if (trimmed_result == nullptr) { return nullptr; } for (uint32_t i = 0; i < dest_index; ++i) { - mirror::Object* obj = result->GetWithoutChecks(i); + ObjPtr<mirror::Object> obj = result->GetWithoutChecks(i); trimmed_result->SetWithoutChecks<false>(i, obj); } return trimmed_result; } -mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList( +ObjPtr<mirror::ObjectArray<mirror::Object>> ProcessAnnotationSetRefList( const ClassData& klass, const DexFile::AnnotationSetRefList* set_ref_list, uint32_t size) @@ -968,7 +970,7 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList( StackHandleScope<1> hs(self); ObjPtr<mirror::Class> annotation_array_class = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); - mirror::Class* annotation_array_array_class = + ObjPtr<mirror::Class> annotation_array_array_class = Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class); if (annotation_array_array_class == nullptr) { return nullptr; @@ -982,8 +984,9 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList( for (uint32_t index = 0; index < size; ++index) { const DexFile::AnnotationSetRefItem* set_ref_item = &set_ref_list->list_[index]; const DexFile::AnnotationSetItem* set_item = dex_file.GetSetRefItemItem(set_ref_item); - mirror::Object* annotation_set = ProcessAnnotationSet(klass, set_item, - DexFile::kDexVisibilityRuntime); + ObjPtr<mirror::Object> annotation_set = ProcessAnnotationSet(klass, + set_item, + DexFile::kDexVisibilityRuntime); if (annotation_set == nullptr) { return nullptr; } @@ -995,7 +998,8 @@ mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList( namespace annotations { -mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class) { +ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, + Handle<mirror::Class> annotation_class) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); if (annotation_set == nullptr) { return nullptr; @@ -1008,7 +1012,7 @@ mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> ann annotation_class); } -mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) { +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); StackHandleScope<1> hs(Thread::Current()); const ClassData field_class(hs, field); @@ -1037,7 +1041,7 @@ bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_ return annotation_item != nullptr; } -mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) { +ObjPtr<mirror::Object> GetAnnotationDefaultValue(ArtMethod* method) { const ClassData klass(method); const DexFile* dex_file = &klass.GetDexFile(); const DexFile::AnnotationsDirectoryItem* annotations_dir = @@ -1081,7 +1085,8 @@ mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) { return annotation_value.value_.GetL(); } -mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class) { +ObjPtr<mirror::Object> GetAnnotationForMethod(ArtMethod* method, + Handle<mirror::Class> annotation_class) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { return nullptr; @@ -1090,14 +1095,14 @@ mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> DexFile::kDexVisibilityRuntime, annotation_class); } -mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); return ProcessAnnotationSet(ClassData(method), annotation_set, DexFile::kDexVisibilityRuntime); } -mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::Class>> GetExceptionTypesForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { return nullptr; @@ -1105,7 +1110,7 @@ mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method return GetThrowsValue(ClassData(method), annotation_set); } -mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::Object>> GetParameterAnnotations(ArtMethod* method) { const DexFile* dex_file = method->GetDexFile(); const DexFile::ParameterAnnotationsItem* parameter_annotations = FindAnnotationsItemForMethod(method); @@ -1136,9 +1141,9 @@ uint32_t GetNumberOfAnnotatedMethodParameters(ArtMethod* method) { return set_ref_list->size_; } -mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, - uint32_t parameter_idx, - Handle<mirror::Class> annotation_class) { +ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, + uint32_t parameter_idx, + Handle<mirror::Class> annotation_class) { const DexFile* dex_file = method->GetDexFile(); const DexFile::ParameterAnnotationsItem* parameter_annotations = FindAnnotationsItemForMethod(method); @@ -1307,8 +1312,8 @@ uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file, return access_flags; } -mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass, - Handle<mirror::Class> annotation_class) { +ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass, + Handle<mirror::Class> annotation_class) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1320,13 +1325,13 @@ mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass, annotation_class); } -mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) { +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForClass(Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); return ProcessAnnotationSet(data, annotation_set, DexFile::kDexVisibilityRuntime); } -mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) { +ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1345,7 +1350,7 @@ mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> kla if (class_array_class == nullptr) { return nullptr; } - mirror::Object* obj = + ObjPtr<mirror::Object> obj = GetAnnotationValue(data, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); if (obj == nullptr) { @@ -1354,7 +1359,7 @@ mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> kla return obj->AsObjectArray<mirror::Class>(); } -mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) { +ObjPtr<mirror::Class> GetDeclaringClass(Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1366,17 +1371,19 @@ mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) { if (annotation_item == nullptr) { return nullptr; } - mirror::Object* obj = GetAnnotationValue(data, annotation_item, "value", - ScopedNullHandle<mirror::Class>(), - DexFile::kDexAnnotationType); + ObjPtr<mirror::Object> obj = GetAnnotationValue(data, + annotation_item, + "value", + ScopedNullHandle<mirror::Class>(), + DexFile::kDexAnnotationType); if (obj == nullptr) { return nullptr; } return obj->AsClass(); } -mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) { - mirror::Class* declaring_class = GetDeclaringClass(klass); +ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) { + ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(klass); if (declaring_class != nullptr) { return declaring_class; } @@ -1420,7 +1427,7 @@ mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) { return method->GetDeclaringClass(); } -mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) { +ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1438,7 +1445,7 @@ mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) { DexFile::kDexAnnotationMethod); } -bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) { +bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index 4bb0d75a57..9645a7febd 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -22,6 +22,7 @@ #include "handle.h" #include "mirror/dex_cache.h" #include "mirror/object_array.h" +#include "obj_ptr.h" namespace art { @@ -35,9 +36,10 @@ class ClassLinker; namespace annotations { // Field annotations. -mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class) +ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, + Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); @@ -45,21 +47,22 @@ bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_ REQUIRES_SHARED(Locks::mutator_lock_); // Method annotations. -mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) +ObjPtr<mirror::Object> GetAnnotationDefaultValue(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class) +ObjPtr<mirror::Object> GetAnnotationForMethod(ArtMethod* method, + Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) +ObjPtr<mirror::ObjectArray<mirror::Class>> GetExceptionTypesForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) +ObjPtr<mirror::ObjectArray<mirror::Object>> GetParameterAnnotations(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); uint32_t GetNumberOfAnnotatedMethodParameters(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, - uint32_t parameter_idx, - Handle<mirror::Class> annotation_class) +ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, + uint32_t parameter_idx, + Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); bool GetParametersMetadataForMethod(ArtMethod* method, MutableHandle<mirror::ObjectArray<mirror::String>>* names, @@ -85,20 +88,20 @@ uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file, uint32_t method_index); // Class annotations. -mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass, +ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) +ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) +ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) +ObjPtr<mirror::Class> GetDeclaringClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) +ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) +ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) +bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) REQUIRES_SHARED(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 719b4af293..026b5da748 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1073,6 +1073,29 @@ bool ElfFileImpl<ElfTypes>::GetLoadedSize(size_t* size, std::string* error_msg) return true; } +static InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) { + switch (e_machine) { + case EM_ARM: + return InstructionSet::kArm; + case EM_AARCH64: + return InstructionSet::kArm64; + case EM_386: + return InstructionSet::kX86; + case EM_X86_64: + return InstructionSet::kX86_64; + case EM_MIPS: { + if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 || + (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) { + return InstructionSet::kMips; + } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) { + return InstructionSet::kMips64; + } + break; + } + } + return InstructionSet::kNone; +} + template <typename ElfTypes> bool ElfFileImpl<ElfTypes>::Load(File* file, bool executable, diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index d4e7492f00..f6b1c73230 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -47,7 +47,6 @@ namespace art { inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, const MethodInfo& method_info, const InlineInfo& inline_info, - const InlineInfoEncoding& encoding, uint8_t inlining_depth) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!outer_method->IsObsolete()); @@ -57,12 +56,12 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, // suspended while executing it. ScopedAssertNoThreadSuspension sants(__FUNCTION__); - if (inline_info.EncodesArtMethodAtDepth(encoding, inlining_depth)) { - return inline_info.GetArtMethodAtDepth(encoding, inlining_depth); + if (inline_info.EncodesArtMethodAtDepth(inlining_depth)) { + return inline_info.GetArtMethodAtDepth(inlining_depth); } - uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, method_info, inlining_depth); - if (inline_info.GetDexPcAtDepth(encoding, inlining_depth) == static_cast<uint32_t>(-1)) { + uint32_t method_index = inline_info.GetMethodIndexAtDepth(method_info, inlining_depth); + if (inline_info.GetDexPcAtDepth(inlining_depth) == static_cast<uint32_t>(-1)) { // "charAt" special case. It is the only non-leaf method we inline across dex files. ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index); @@ -73,9 +72,9 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ArtMethod* method = outer_method; for (uint32_t depth = 0, end = inlining_depth + 1u; depth != end; ++depth) { - DCHECK(!inline_info.EncodesArtMethodAtDepth(encoding, depth)); - DCHECK_NE(inline_info.GetDexPcAtDepth(encoding, depth), static_cast<uint32_t>(-1)); - method_index = inline_info.GetMethodIndexAtDepth(encoding, method_info, depth); + DCHECK(!inline_info.EncodesArtMethodAtDepth(depth)); + DCHECK_NE(inline_info.GetDexPcAtDepth(depth), static_cast<uint32_t>(-1)); + method_index = inline_info.GetMethodIndexAtDepth(method_info, depth); ArtMethod* inlined_method = class_linker->LookupResolvedMethod(method_index, method->GetDexCache(), method->GetClassLoader()); diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 7536910cee..7f9b385a0a 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -201,18 +201,16 @@ static inline ArtMethod* DoGetCalleeSaveMethodCaller(ArtMethod* outer_method, DCHECK(current_code != nullptr); DCHECK(current_code->IsOptimized()); uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc); - CodeInfo code_info = current_code->GetOptimizedCodeInfo(); + CodeInfo code_info(current_code); MethodInfo method_info = current_code->GetOptimizedMethodInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo(encoding.stack_map.encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); + if (stack_map.HasInlineInfo()) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); caller = GetResolvedMethod(outer_method, method_info, inline_info, - encoding.inline_info.encoding, - inline_info.GetDepth(encoding.inline_info.encoding) - 1); + inline_info.GetDepth() - 1); } } if (kIsDebugBuild && do_caller_check) { @@ -268,7 +266,7 @@ ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer, } ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, - uint32_t proto_idx) { + dex::ProtoIndex proto_idx) { Thread::PoisonObjectPointersIfDebug(); ObjPtr<mirror::MethodType> method_type = referrer->GetDexCache()->GetResolvedMethodType(proto_idx); diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 0a3b5dfc93..e33de9c45a 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -158,7 +158,7 @@ ObjPtr<mirror::MethodHandle> ResolveMethodHandleFromCode(ArtMethod* referrer, REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); -ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, uint32_t proto_idx) +ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index cf9ddd8aa8..fa536c77a9 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -200,7 +200,7 @@ extern "C" mirror::MethodType* artResolveMethodTypeFromCode(uint32_t proto_idx, auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveEverything); ArtMethod* caller = caller_and_outer.caller; - ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, proto_idx); + ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, dex::ProtoIndex(proto_idx)); return result.Ptr(); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index d0aec0309d..ff85f477ec 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -43,6 +43,7 @@ #include "mirror/method_handle_impl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "mirror/var_handle.h" #include "oat_file.h" #include "oat_quick_method_header.h" #include "quick_exception_handler.h" @@ -50,6 +51,7 @@ #include "scoped_thread_state_change-inl.h" #include "stack.h" #include "thread-inl.h" +#include "var_handles.h" #include "well_known_classes.h" namespace art { @@ -337,16 +339,14 @@ class QuickArgumentVisitor { uintptr_t outer_pc_offset = current_code->NativeQuickPcOffset(outer_pc); if (current_code->IsOptimized()) { - CodeInfo code_info = current_code->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset, encoding); + CodeInfo code_info(current_code); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset); DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo(encoding.stack_map.encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - return inline_info.GetDexPcAtDepth(encoding.inline_info.encoding, - inline_info.GetDepth(encoding.inline_info.encoding)-1); + if (stack_map.HasInlineInfo()) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + return inline_info.GetDexPcAtDepth(inline_info.GetDepth()-1); } else { - return stack_map.GetDexPc(encoding.stack_map.encoding); + return stack_map.GetDexPc(); } } else { return current_code->ToDexPc(*caller_sp, outer_pc); @@ -366,13 +366,12 @@ class QuickArgumentVisitor { return false; } uintptr_t outer_pc_offset = current_code->NativeQuickPcOffset(outer_pc); - CodeInfo code_info = current_code->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(current_code); MethodInfo method_info = current_code->GetOptimizedMethodInfo(); - InvokeInfo invoke(code_info.GetInvokeInfoForNativePcOffset(outer_pc_offset, encoding)); + InvokeInfo invoke(code_info.GetInvokeInfoForNativePcOffset(outer_pc_offset)); if (invoke.IsValid()) { - *invoke_type = static_cast<InvokeType>(invoke.GetInvokeType(encoding.invoke_info.encoding)); - *dex_method_index = invoke.GetMethodIndex(encoding.invoke_info.encoding, method_info); + *invoke_type = static_cast<InvokeType>(invoke.GetInvokeType()); + *dex_method_index = invoke.GetMethodIndex(method_info); return true; } return false; @@ -1212,12 +1211,11 @@ static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutato CHECK(current_code != nullptr); CHECK(current_code->IsOptimized()); uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc); - CodeInfo code_info = current_code->GetOptimizedCodeInfo(); + CodeInfo code_info(current_code); MethodInfo method_info = current_code->GetOptimizedMethodInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); CHECK(stack_map.IsValid()); - uint32_t dex_pc = stack_map.GetDexPc(encoding.stack_map.encoding); + uint32_t dex_pc = stack_map.GetDexPc(); // Log the outer method and its associated dex file and class table pointer which can be used // to find out if the inlined methods were defined by other dex file(s) or class loader(s). @@ -1231,20 +1229,17 @@ static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutato LOG(FATAL_WITHOUT_ABORT) << " instruction: " << DumpInstruction(outer_method, dex_pc); ArtMethod* caller = outer_method; - if (stack_map.HasInlineInfo(encoding.stack_map.encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - const InlineInfoEncoding& inline_info_encoding = encoding.inline_info.encoding; - size_t depth = inline_info.GetDepth(inline_info_encoding); + if (stack_map.HasInlineInfo()) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); + size_t depth = inline_info.GetDepth(); for (size_t d = 0; d < depth; ++d) { const char* tag = ""; - dex_pc = inline_info.GetDexPcAtDepth(inline_info_encoding, d); - if (inline_info.EncodesArtMethodAtDepth(inline_info_encoding, d)) { + dex_pc = inline_info.GetDexPcAtDepth(d); + if (inline_info.EncodesArtMethodAtDepth(d)) { tag = "encoded "; - caller = inline_info.GetArtMethodAtDepth(inline_info_encoding, d); + caller = inline_info.GetArtMethodAtDepth(d); } else { - uint32_t method_index = inline_info.GetMethodIndexAtDepth(inline_info_encoding, - method_info, - d); + uint32_t method_index = inline_info.GetMethodIndexAtDepth(method_info, d); if (dex_pc == static_cast<uint32_t>(-1)) { tag = "special "; CHECK_EQ(d + 1u, depth); @@ -2750,7 +2745,7 @@ extern "C" uintptr_t artInvokePolymorphic( const Instruction& inst = caller_method->DexInstructions().InstructionAt(dex_pc); DCHECK(inst.Opcode() == Instruction::INVOKE_POLYMORPHIC || inst.Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE); - const uint32_t proto_idx = inst.VRegH(); + const dex::ProtoIndex proto_idx(inst.VRegH()); const char* shorty = caller_method->GetDexFile()->GetShorty(proto_idx); const size_t shorty_length = strlen(shorty); static const bool kMethodIsStatic = false; // invoke() and invokeExact() are not static. @@ -2773,13 +2768,6 @@ extern "C" uintptr_t artInvokePolymorphic( return static_cast<uintptr_t>('V'); } - // TODO(oth): Ensure this path isn't taken for VarHandle accessors (b/65872996). - DCHECK_EQ(resolved_method->GetDeclaringClass(), - WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_MethodHandle)); - - Handle<mirror::MethodHandle> method_handle(hs.NewHandle( - ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get())))); - Handle<mirror::MethodType> method_type( hs.NewHandle(linker->ResolveMethodType(self, proto_idx, caller_method))); @@ -2819,24 +2807,43 @@ extern "C" uintptr_t artInvokePolymorphic( // Call DoInvokePolymorphic with |is_range| = true, as shadow frame has argument registers in // consecutive order. RangeInstructionOperands operands(first_arg + 1, num_vregs - 1); - bool isExact = (jni::EncodeArtMethod(resolved_method) == - WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact); + Intrinsics intrinsic = static_cast<Intrinsics>(resolved_method->GetIntrinsic()); bool success = false; - if (isExact) { - success = MethodHandleInvokeExact(self, + if (resolved_method->GetDeclaringClass() == mirror::MethodHandle::StaticClass()) { + Handle<mirror::MethodHandle> method_handle(hs.NewHandle( + ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get())))); + if (intrinsic == Intrinsics::kMethodHandleInvokeExact) { + success = MethodHandleInvokeExact(self, + *shadow_frame, + method_handle, + method_type, + &operands, + result); + } else { + DCHECK_EQ(static_cast<uint32_t>(intrinsic), + static_cast<uint32_t>(Intrinsics::kMethodHandleInvoke)); + success = MethodHandleInvoke(self, + *shadow_frame, + method_handle, + method_type, + &operands, + result); + } + } else { + DCHECK_EQ(mirror::VarHandle::StaticClass(), resolved_method->GetDeclaringClass()); + Handle<mirror::VarHandle> var_handle(hs.NewHandle( + ObjPtr<mirror::VarHandle>::DownCast(MakeObjPtr(receiver_handle.Get())))); + mirror::VarHandle::AccessMode access_mode = + mirror::VarHandle::GetAccessModeByIntrinsic(intrinsic); + success = VarHandleInvokeAccessor(self, *shadow_frame, - method_handle, + var_handle, method_type, + access_mode, &operands, result); - } else { - success = MethodHandleInvoke(self, - *shadow_frame, - method_handle, - method_type, - &operands, - result); } + DCHECK(success || self->IsExceptionPending()); // Pop transition record. diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h index 46630dbeef..464c2b749f 100644 --- a/runtime/generated/asm_support_gen.h +++ b/runtime/generated/asm_support_gen.h @@ -90,16 +90,24 @@ DEFINE_CHECK_EQ(static_cast<size_t>(CARD_TABLE_CARD_SHIFT), (static_cast<size_t> DEFINE_CHECK_EQ(static_cast<size_t>(MIN_LARGE_OBJECT_THRESHOLD), (static_cast<size_t>(art::gc::Heap::kMinLargeObjectThreshold))) #define LOCK_WORD_STATE_SHIFT 30 DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_STATE_SHIFT), (static_cast<int32_t>(art::LockWord::kStateShift))) -#define LOCK_WORD_STATE_MASK 0xc0000000 -DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_MASK), (static_cast<uint32_t>(art::LockWord::kStateMaskShifted))) +#define LOCK_WORD_STATE_MASK_SHIFTED 0xc0000000 +DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_MASK_SHIFTED), (static_cast<uint32_t>(art::LockWord::kStateMaskShifted))) #define LOCK_WORD_READ_BARRIER_STATE_SHIFT 28 DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_READ_BARRIER_STATE_SHIFT), (static_cast<int32_t>(art::LockWord::kReadBarrierStateShift))) #define LOCK_WORD_READ_BARRIER_STATE_MASK 0x10000000 DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_READ_BARRIER_STATE_MASK), (static_cast<uint32_t>(art::LockWord::kReadBarrierStateMaskShifted))) #define LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED 0xefffffff DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED), (static_cast<uint32_t>(art::LockWord::kReadBarrierStateMaskShiftedToggled))) -#define LOCK_WORD_THIN_LOCK_COUNT_ONE 65536 -DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_THIN_LOCK_COUNT_ONE), (static_cast<int32_t>(art::LockWord::kThinLockCountOne))) +#define LOCK_WORD_THIN_LOCK_COUNT_SIZE 12 +DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_THIN_LOCK_COUNT_SIZE), (static_cast<int32_t>(art::LockWord::kThinLockCountSize))) +#define LOCK_WORD_THIN_LOCK_COUNT_SHIFT 16 +DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_THIN_LOCK_COUNT_SHIFT), (static_cast<int32_t>(art::LockWord::kThinLockCountShift))) +#define LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED 0xfff0000 +DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED), (static_cast<uint32_t>(art::LockWord::kThinLockCountMaskShifted))) +#define LOCK_WORD_THIN_LOCK_COUNT_ONE 0x10000 +DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_THIN_LOCK_COUNT_ONE), (static_cast<uint32_t>(art::LockWord::kThinLockCountOne))) +#define LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED 0xffff +DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED), (static_cast<uint32_t>(art::LockWord::kThinLockOwnerMaskShifted))) #define LOCK_WORD_STATE_FORWARDING_ADDRESS 0x3 DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_FORWARDING_ADDRESS), (static_cast<uint32_t>(art::LockWord::kStateForwardingAddress))) #define LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW 0x40000000 @@ -110,6 +118,8 @@ DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT), DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_GC_STATE_MASK_SHIFTED), (static_cast<uint32_t>(art::LockWord::kGCStateMaskShifted))) #define LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED 0xcfffffff DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED), (static_cast<uint32_t>(art::LockWord::kGCStateMaskShiftedToggled))) +#define LOCK_WORD_GC_STATE_SIZE 2 +DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_GC_STATE_SIZE), (static_cast<int32_t>(art::LockWord::kGCStateSize))) #define LOCK_WORD_GC_STATE_SHIFT 28 DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_GC_STATE_SHIFT), (static_cast<int32_t>(art::LockWord::kGCStateShift))) #define LOCK_WORD_MARK_BIT_SHIFT 29 diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc index 9445ae0c8e..e41d1d3eb9 100644 --- a/runtime/hidden_api.cc +++ b/runtime/hidden_api.cc @@ -14,8 +14,6 @@ * limitations under the License. */ -#include <metricslogger/metrics_logger.h> - #include "hidden_api.h" #include <nativehelper/scoped_local_ref.h> @@ -24,11 +22,14 @@ #include "thread-current-inl.h" #include "well_known_classes.h" +#ifdef ART_TARGET_ANDROID +#include <metricslogger/metrics_logger.h> using android::metricslogger::ComplexEventLogger; using android::metricslogger::ACTION_HIDDEN_API_ACCESSED; using android::metricslogger::FIELD_HIDDEN_API_ACCESS_METHOD; using android::metricslogger::FIELD_HIDDEN_API_ACCESS_DENIED; using android::metricslogger::FIELD_HIDDEN_API_SIGNATURE; +#endif namespace art { namespace hiddenapi { @@ -39,7 +40,7 @@ namespace hiddenapi { // Note that when flipping this flag, you must also update the expectations of test 674-hiddenapi // as it affects whether or not we warn for light grey APIs that have been added to the exemptions // list. -static constexpr bool kLogAllAccesses = true; +static constexpr bool kLogAllAccesses = false; static inline std::ostream& operator<<(std::ostream& os, AccessMethod value) { switch (value) { @@ -137,6 +138,7 @@ void MemberSignature::WarnAboutAccess(AccessMethod access_method, LOG(WARNING) << "Accessing hidden " << (type_ == kField ? "field " : "method ") << Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")"; } +#ifdef ART_TARGET_ANDROID // Convert an AccessMethod enum to a value for logging from the proto enum. // This method may look odd (the enum values are current the same), but it // prevents coupling the internal enum to the proto enum (which should never @@ -156,12 +158,15 @@ inline static int32_t GetEnumValueForLog(AccessMethod access_method) { DCHECK(false); } } +#endif void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action action_taken) { - if (access_method == kLinking) { +#ifdef ART_TARGET_ANDROID + if (access_method == kLinking || access_method == kNone) { // Linking warnings come from static analysis/compilation of the bytecode // and can contain false positives (i.e. code that is never run). We choose // not to log these in the event log. + // None does not correspond to actual access, so should also be ignored. return; } ComplexEventLogger log_maker(ACTION_HIDDEN_API_ACCESSED); @@ -173,6 +178,10 @@ void MemberSignature::LogAccessToEventLog(AccessMethod access_method, Action act Dump(signature_str); log_maker.AddTaggedData(FIELD_HIDDEN_API_SIGNATURE, signature_str.str()); log_maker.Record(); +#else + UNUSED(access_method); + UNUSED(action_taken); +#endif } static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtField*) { @@ -210,7 +219,8 @@ Action GetMemberActionImpl(T* member, // - for non-debuggable apps, there is no distinction between light grey & whitelisted APIs. // - we want to avoid the overhead of checking for exemptions for light greylisted APIs whenever // possible. - if (kLogAllAccesses || action == kDeny || runtime->IsJavaDebuggable()) { + const bool shouldWarn = kLogAllAccesses || runtime->IsJavaDebuggable(); + if (shouldWarn || action == kDeny) { if (member_signature.IsExempted(runtime->GetHiddenApiExemptions())) { action = kAllow; // Avoid re-examining the exemption list next time. @@ -227,7 +237,7 @@ Action GetMemberActionImpl(T* member, } } - if (kIsTargetBuild) { + if (kIsTargetBuild && !kIsTargetLinux) { uint32_t eventLogSampleRate = runtime->GetHiddenApiEventLogSampleRate(); // Assert that RAND_MAX is big enough, to ensure sampling below works as expected. static_assert(RAND_MAX >= 0xffff, "RAND_MAX too small"); @@ -251,7 +261,8 @@ Action GetMemberActionImpl(T* member, MaybeWhitelistMember(runtime, member); // If this action requires a UI warning, set the appropriate flag. - if (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag()) { + if (shouldWarn && + (action == kAllowButWarnAndToast || runtime->ShouldAlwaysSetHiddenApiWarningFlag())) { runtime->SetPendingHiddenApiWarning(true); } } diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index 8e21fd3b8f..580224e439 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -95,6 +95,22 @@ inline Action GetActionFromAccessFlags(HiddenApiAccessFlags::ApiList api_list) { } } +class ScopedHiddenApiEnforcementPolicySetting { + public: + explicit ScopedHiddenApiEnforcementPolicySetting(EnforcementPolicy new_policy) + : initial_policy_(Runtime::Current()->GetHiddenApiEnforcementPolicy()) { + Runtime::Current()->SetHiddenApiEnforcementPolicy(new_policy); + } + + ~ScopedHiddenApiEnforcementPolicySetting() { + Runtime::Current()->SetHiddenApiEnforcementPolicy(initial_policy_); + } + + private: + const EnforcementPolicy initial_policy_; + DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiEnforcementPolicySetting); +}; + // Implementation details. DO NOT ACCESS DIRECTLY. namespace detail { diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 8a85ee41f8..5a50ec5586 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -24,7 +24,7 @@ #include "entrypoints/runtime_asm_entrypoints.h" #include "intrinsics_enum.h" #include "jit/jit.h" -#include "jvalue.h" +#include "jvalue-inl.h" #include "method_handles-inl.h" #include "method_handles.h" #include "mirror/array-inl.h" @@ -37,6 +37,7 @@ #include "stack.h" #include "thread-inl.h" #include "transaction.h" +#include "var_handles.h" #include "well_known_classes.h" namespace art { @@ -626,7 +627,8 @@ static bool DoMethodHandleInvokeCommon(Thread* self, // The vRegH value gives the index of the proto_id associated with this // signature polymorphic call site. - const uint32_t callsite_proto_id = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); + const uint16_t vRegH = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); + const dex::ProtoIndex callsite_proto_id(vRegH); // Call through to the classlinker and ask it to resolve the static type associated // with the callsite. This information is stored in the dex cache so it's @@ -724,38 +726,6 @@ bool DoMethodHandleInvoke(Thread* self, } } -static bool DoVarHandleInvokeChecked(Thread* self, - Handle<mirror::VarHandle> var_handle, - Handle<mirror::MethodType> callsite_type, - mirror::VarHandle::AccessMode access_mode, - ShadowFrame& shadow_frame, - InstructionOperands* operands, - JValue* result) - REQUIRES_SHARED(Locks::mutator_lock_) { - // TODO(oth): GetMethodTypeForAccessMode() allocates a MethodType() - // which is only required if we need to convert argument and/or - // return types. - StackHandleScope<1> hs(self); - Handle<mirror::MethodType> accessor_type(hs.NewHandle( - var_handle->GetMethodTypeForAccessMode(self, access_mode))); - const size_t num_vregs = accessor_type->NumberOfVRegs(); - const int num_params = accessor_type->GetPTypes()->GetLength(); - ShadowFrameAllocaUniquePtr accessor_frame = - CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC()); - ShadowFrameGetter getter(shadow_frame, operands); - static const uint32_t kFirstDestinationReg = 0; - ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg); - if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) { - return false; - } - RangeInstructionOperands accessor_operands(kFirstDestinationReg, - kFirstDestinationReg + num_vregs); - if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) { - return false; - } - return ConvertReturnValue(callsite_type, accessor_type, result); -} - static bool DoVarHandleInvokeCommon(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, @@ -768,59 +738,43 @@ static bool DoVarHandleInvokeCommon(Thread* self, return false; } - bool is_var_args = inst->HasVarArgs(); - const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc(); - ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC)); - if (receiver.IsNull()) { - ThrowNullPointerExceptionFromDexPC(); - return false; - } - StackHandleScope<2> hs(self); - Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr()))); - if (!var_handle->IsAccessModeSupported(access_mode)) { - ThrowUnsupportedOperationException(); - return false; - } - - const uint32_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc(); + bool is_var_args = inst->HasVarArgs(); + const uint16_t vRegH = is_var_args ? inst->VRegH_45cc() : inst->VRegH_4rcc(); ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); Handle<mirror::MethodType> callsite_type(hs.NewHandle( - class_linker->ResolveMethodType(self, vRegH, shadow_frame.GetMethod()))); + class_linker->ResolveMethodType(self, dex::ProtoIndex(vRegH), shadow_frame.GetMethod()))); // This implies we couldn't resolve one or more types in this VarHandle. if (UNLIKELY(callsite_type == nullptr)) { CHECK(self->IsExceptionPending()); return false; } - if (!var_handle->IsMethodTypeCompatible(access_mode, callsite_type.Get())) { - ThrowWrongMethodTypeException(var_handle->GetMethodTypeForAccessMode(self, access_mode), - callsite_type.Get()); - return false; - } - + const uint32_t vRegC = is_var_args ? inst->VRegC_45cc() : inst->VRegC_4rcc(); + ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(vRegC)); + Handle<mirror::VarHandle> var_handle(hs.NewHandle(down_cast<mirror::VarHandle*>(receiver.Ptr()))); if (is_var_args) { uint32_t args[Instruction::kMaxVarArgRegs]; inst->GetVarArgs(args, inst_data); VarArgsInstructionOperands all_operands(args, inst->VRegA_45cc()); NoReceiverInstructionOperands operands(&all_operands); - return DoVarHandleInvokeChecked(self, - var_handle, - callsite_type, - access_mode, - shadow_frame, - &operands, - result); + return VarHandleInvokeAccessor(self, + shadow_frame, + var_handle, + callsite_type, + access_mode, + &operands, + result); } else { RangeInstructionOperands all_operands(inst->VRegC_4rcc(), inst->VRegA_4rcc()); NoReceiverInstructionOperands operands(&all_operands); - return DoVarHandleInvokeChecked(self, - var_handle, - callsite_type, - access_mode, - shadow_frame, - &operands, - result); + return VarHandleInvokeAccessor(self, + shadow_frame, + var_handle, + callsite_type, + access_mode, + &operands, + result); } } @@ -965,9 +919,10 @@ static bool GetArgumentForBootstrapMethod(Thread* self, StackHandleScope<2> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - uint32_t index = static_cast<uint32_t>(encoded_value->GetI()); + dex::ProtoIndex proto_idx(encoded_value->GetC()); ClassLinker* cl = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::MethodType> o = cl->ResolveMethodType(self, index, dex_cache, class_loader); + ObjPtr<mirror::MethodType> o = + cl->ResolveMethodType(self, proto_idx, dex_cache, class_loader); if (UNLIKELY(o.IsNull())) { DCHECK(self->IsExceptionPending()); return false; diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 0818e06675..67a0349d7a 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -217,7 +217,7 @@ static inline ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self, } static inline ObjPtr<mirror::MethodType> ResolveMethodType(Thread* self, - uint32_t method_type_index, + dex::ProtoIndex method_type_index, ArtMethod* referrer) REQUIRES_SHARED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 283885e522..5c7838cd66 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -565,7 +565,7 @@ void ExecuteSwitchImplCpp(SwitchImplContext* ctx) { PREAMBLE(); ClassLinker* cl = Runtime::Current()->GetClassLinker(); ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self, - inst->VRegB_21c(), + dex::ProtoIndex(inst->VRegB_21c()), shadow_frame.GetMethod()); if (UNLIKELY(mt == nullptr)) { HANDLE_PENDING_EXCEPTION(); diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index 2a9ef2ce98..1b39a7422d 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -408,7 +408,8 @@ extern "C" size_t MterpConstMethodType(uint32_t index, ShadowFrame* shadow_frame, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::MethodType> mt = ResolveMethodType(self, index, shadow_frame->GetMethod()); + ObjPtr<mirror::MethodType> mt = + ResolveMethodType(self, dex::ProtoIndex(index), shadow_frame->GetMethod()); if (UNLIKELY(mt == nullptr)) { return true; } diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 791ebf09b7..0e429a63f6 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -510,7 +510,7 @@ void UnstartedRuntime::UnstartedClassIsAnonymousClass( result->SetZ(false); return; } - mirror::String* class_name = nullptr; + ObjPtr<mirror::String> class_name = nullptr; if (!annotations::GetInnerClass(klass, &class_name)) { result->SetZ(false); return; diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 0684b461ae..5d4b9e8cc9 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -46,8 +46,6 @@ namespace art { namespace jit { static constexpr bool kEnableOnStackReplacement = true; -// At what priority to schedule jit threads. 9 is the lowest foreground priority on device. -static constexpr int kJitPoolThreadPthreadPriority = 9; // Different compilation threshold constants. These can be overridden on the command line. static constexpr size_t kJitDefaultCompileThreshold = 10000; // Non-debug default. @@ -80,6 +78,8 @@ JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& opt options.Exists(RuntimeArgumentMap::DumpJITInfoOnShutdown); jit_options->profile_saver_options_ = options.GetOrDefault(RuntimeArgumentMap::ProfileSaverOpts); + jit_options->thread_pool_pthread_priority_ = + options.GetOrDefault(RuntimeArgumentMap::JITPoolThreadPthreadPriority); if (options.Exists(RuntimeArgumentMap::JITCompileThreshold)) { jit_options->compile_threshold_ = *options.Get(RuntimeArgumentMap::JITCompileThreshold); @@ -167,21 +167,14 @@ void Jit::AddTimingLogger(const TimingLogger& logger) { cumulative_timings_.AddLogger(logger); } -Jit::Jit() : dump_info_on_shutdown_(false), - cumulative_timings_("JIT timings"), - memory_use_("Memory used for compilation", 16), - lock_("JIT memory use lock"), - use_jit_compilation_(true), - hot_method_threshold_(0), - warm_method_threshold_(0), - osr_method_threshold_(0), - priority_thread_weight_(0), - invoke_transition_weight_(0) {} +Jit::Jit(JitOptions* options) : options_(options), + cumulative_timings_("JIT timings"), + memory_use_("Memory used for compilation", 16), + lock_("JIT memory use lock") {} Jit* Jit::Create(JitOptions* options, std::string* error_msg) { DCHECK(options->UseJitCompilation() || options->GetProfileSaverOptions().IsEnabled()); - std::unique_ptr<Jit> jit(new Jit); - jit->dump_info_on_shutdown_ = options->DumpJitInfoOnShutdown(); + std::unique_ptr<Jit> jit(new Jit(options)); if (jit_compiler_handle_ == nullptr && !LoadCompiler(error_msg)) { return nullptr; } @@ -195,8 +188,6 @@ Jit* Jit::Create(JitOptions* options, std::string* error_msg) { if (jit->GetCodeCache() == nullptr) { return nullptr; } - jit->use_jit_compilation_ = options->UseJitCompilation(); - jit->profile_saver_options_ = options->GetProfileSaverOptions(); VLOG(jit) << "JIT created with initial_capacity=" << PrettySize(options->GetCodeCacheInitialCapacity()) << ", max_capacity=" << PrettySize(options->GetCodeCacheMaxCapacity()) @@ -204,12 +195,6 @@ Jit* Jit::Create(JitOptions* options, std::string* error_msg) { << ", profile_saver_options=" << options->GetProfileSaverOptions(); - jit->hot_method_threshold_ = options->GetCompileThreshold(); - jit->warm_method_threshold_ = options->GetWarmupThreshold(); - jit->osr_method_threshold_ = options->GetOsrThreshold(); - jit->priority_thread_weight_ = options->GetPriorityThreadWeight(); - jit->invoke_transition_weight_ = options->GetInvokeTransitionWeight(); - jit->CreateThreadPool(); // Notify native debugger about the classes already loaded before the creation of the jit. @@ -330,7 +315,7 @@ void Jit::CreateThreadPool() { constexpr bool kJitPoolNeedsPeers = true; thread_pool_.reset(new ThreadPool("Jit thread pool", 1, kJitPoolNeedsPeers)); - thread_pool_->SetPthreadPriority(kJitPoolThreadPthreadPriority); + thread_pool_->SetPthreadPriority(options_->GetThreadPoolPthreadPriority()); Start(); } @@ -360,8 +345,8 @@ void Jit::DeleteThreadPool() { void Jit::StartProfileSaver(const std::string& filename, const std::vector<std::string>& code_paths) { - if (profile_saver_options_.IsEnabled()) { - ProfileSaver::Start(profile_saver_options_, + if (options_->GetSaveProfilingInfo()) { + ProfileSaver::Start(options_->GetProfileSaverOptions(), filename, code_cache_.get(), code_paths); @@ -369,8 +354,8 @@ void Jit::StartProfileSaver(const std::string& filename, } void Jit::StopProfileSaver() { - if (profile_saver_options_.IsEnabled() && ProfileSaver::IsStarted()) { - ProfileSaver::Stop(dump_info_on_shutdown_); + if (options_->GetSaveProfilingInfo() && ProfileSaver::IsStarted()) { + ProfileSaver::Stop(options_->DumpJitInfoOnShutdown()); } } @@ -383,8 +368,8 @@ bool Jit::CanInvokeCompiledCode(ArtMethod* method) { } Jit::~Jit() { - DCHECK(!profile_saver_options_.IsEnabled() || !ProfileSaver::IsStarted()); - if (dump_info_on_shutdown_) { + DCHECK(!options_->GetSaveProfilingInfo() || !ProfileSaver::IsStarted()); + if (options_->DumpJitInfoOnShutdown()) { DumpInfo(LOG_STREAM(INFO)); Runtime::Current()->DumpDeoptimizations(LOG_STREAM(INFO)); } @@ -488,11 +473,10 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, return false; } - CodeInfo code_info = osr_method->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(osr_method); // Find stack map starting at the target dex_pc. - StackMap stack_map = code_info.GetOsrStackMapForDexPc(dex_pc + dex_pc_offset, encoding); + StackMap stack_map = code_info.GetOsrStackMapForDexPc(dex_pc + dex_pc_offset); if (!stack_map.IsValid()) { // There is no OSR stack map for this dex pc offset. Just return to the interpreter in the // hope that the next branch has one. @@ -509,7 +493,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, // We found a stack map, now fill the frame with dex register values from the interpreter's // shadow frame. DexRegisterMap vreg_map = - code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_vregs); + code_info.GetDexRegisterMapOf(stack_map, number_of_vregs); frame_size = osr_method->GetFrameSizeInBytes(); @@ -531,7 +515,7 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, } else { for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { DexRegisterLocation::Kind location = - vreg_map.GetLocationKind(vreg, number_of_vregs, code_info, encoding); + vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); if (location == DexRegisterLocation::Kind::kNone) { // Dex register is dead or uninitialized. continue; @@ -547,15 +531,14 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, int32_t vreg_value = shadow_frame->GetVReg(vreg); int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg, number_of_vregs, - code_info, - encoding); + code_info); DCHECK_LT(slot_offset, static_cast<int32_t>(frame_size)); DCHECK_GT(slot_offset, 0); (reinterpret_cast<int32_t*>(memory))[slot_offset / sizeof(int32_t)] = vreg_value; } } - native_pc = stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA) + + native_pc = stack_map.GetNativePcOffset(kRuntimeISA) + osr_method->GetEntryPoint(); VLOG(jit) << "Jumping to " << method_name @@ -671,25 +654,25 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_ if (IgnoreSamplesForMethod(method)) { return; } - if (hot_method_threshold_ == 0) { + if (HotMethodThreshold() == 0) { // Tests might request JIT on first use (compiled synchronously in the interpreter). return; } DCHECK(thread_pool_ != nullptr); - DCHECK_GT(warm_method_threshold_, 0); - DCHECK_GT(hot_method_threshold_, warm_method_threshold_); - DCHECK_GT(osr_method_threshold_, hot_method_threshold_); - DCHECK_GE(priority_thread_weight_, 1); - DCHECK_LE(priority_thread_weight_, hot_method_threshold_); + DCHECK_GT(WarmMethodThreshold(), 0); + DCHECK_GT(HotMethodThreshold(), WarmMethodThreshold()); + DCHECK_GT(OSRMethodThreshold(), HotMethodThreshold()); + DCHECK_GE(PriorityThreadWeight(), 1); + DCHECK_LE(PriorityThreadWeight(), HotMethodThreshold()); - int32_t starting_count = method->GetCounter(); + uint16_t starting_count = method->GetCounter(); if (Jit::ShouldUsePriorityThreadWeight(self)) { - count *= priority_thread_weight_; + count *= PriorityThreadWeight(); } - int32_t new_count = starting_count + count; // int32 here to avoid wrap-around; + uint32_t new_count = starting_count + count; // Note: Native method have no "warm" state or profiling info. - if (LIKELY(!method->IsNative()) && starting_count < warm_method_threshold_) { - if ((new_count >= warm_method_threshold_) && + if (LIKELY(!method->IsNative()) && starting_count < WarmMethodThreshold()) { + if ((new_count >= WarmMethodThreshold()) && (method->GetProfilingInfo(kRuntimePointerSize) == nullptr)) { bool success = ProfilingInfo::Create(self, method, /* retry_allocation */ false); if (success) { @@ -710,23 +693,23 @@ void Jit::AddSamples(Thread* self, ArtMethod* method, uint16_t count, bool with_ } } // Avoid jumping more than one state at a time. - new_count = std::min(new_count, hot_method_threshold_ - 1); - } else if (use_jit_compilation_) { - if (starting_count < hot_method_threshold_) { - if ((new_count >= hot_method_threshold_) && + new_count = std::min(new_count, static_cast<uint32_t>(HotMethodThreshold() - 1)); + } else if (UseJitCompilation()) { + if (starting_count < HotMethodThreshold()) { + if ((new_count >= HotMethodThreshold()) && !code_cache_->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) { DCHECK(thread_pool_ != nullptr); thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile)); } // Avoid jumping more than one state at a time. - new_count = std::min(new_count, osr_method_threshold_ - 1); - } else if (starting_count < osr_method_threshold_) { + new_count = std::min(new_count, static_cast<uint32_t>(OSRMethodThreshold() - 1)); + } else if (starting_count < OSRMethodThreshold()) { if (!with_backedges) { // If the samples don't contain any back edge, we don't increment the hotness. return; } DCHECK(!method->IsNative()); // No back edges reported for native methods. - if ((new_count >= osr_method_threshold_) && !code_cache_->IsOsrCompiled(method)) { + if ((new_count >= OSRMethodThreshold()) && !code_cache_->IsOsrCompiled(method)) { DCHECK(thread_pool_ != nullptr); thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr)); } diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 4b8b8919d1..edaf348cc4 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -44,6 +44,110 @@ class JitOptions; static constexpr int16_t kJitCheckForOSR = -1; static constexpr int16_t kJitHotnessDisabled = -2; +// At what priority to schedule jit threads. 9 is the lowest foreground priority on device. +// See android/os/Process.java. +static constexpr int kJitPoolThreadPthreadDefaultPriority = 9; + +class JitOptions { + public: + static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options); + + uint16_t GetCompileThreshold() const { + return compile_threshold_; + } + + uint16_t GetWarmupThreshold() const { + return warmup_threshold_; + } + + uint16_t GetOsrThreshold() const { + return osr_threshold_; + } + + uint16_t GetPriorityThreadWeight() const { + return priority_thread_weight_; + } + + uint16_t GetInvokeTransitionWeight() const { + return invoke_transition_weight_; + } + + size_t GetCodeCacheInitialCapacity() const { + return code_cache_initial_capacity_; + } + + size_t GetCodeCacheMaxCapacity() const { + return code_cache_max_capacity_; + } + + bool DumpJitInfoOnShutdown() const { + return dump_info_on_shutdown_; + } + + const ProfileSaverOptions& GetProfileSaverOptions() const { + return profile_saver_options_; + } + + bool GetSaveProfilingInfo() const { + return profile_saver_options_.IsEnabled(); + } + + int GetThreadPoolPthreadPriority() const { + return thread_pool_pthread_priority_; + } + + bool UseJitCompilation() const { + return use_jit_compilation_; + } + + void SetUseJitCompilation(bool b) { + use_jit_compilation_ = b; + } + + void SetSaveProfilingInfo(bool save_profiling_info) { + profile_saver_options_.SetEnabled(save_profiling_info); + } + + void SetWaitForJitNotificationsToSaveProfile(bool value) { + profile_saver_options_.SetWaitForJitNotificationsToSave(value); + } + + void SetProfileAOTCode(bool value) { + profile_saver_options_.SetProfileAOTCode(value); + } + + void SetJitAtFirstUse() { + use_jit_compilation_ = true; + compile_threshold_ = 0; + } + + private: + bool use_jit_compilation_; + size_t code_cache_initial_capacity_; + size_t code_cache_max_capacity_; + uint16_t compile_threshold_; + uint16_t warmup_threshold_; + uint16_t osr_threshold_; + uint16_t priority_thread_weight_; + uint16_t invoke_transition_weight_; + bool dump_info_on_shutdown_; + int thread_pool_pthread_priority_; + ProfileSaverOptions profile_saver_options_; + + JitOptions() + : use_jit_compilation_(false), + code_cache_initial_capacity_(0), + code_cache_max_capacity_(0), + compile_threshold_(0), + warmup_threshold_(0), + osr_threshold_(0), + priority_thread_weight_(0), + invoke_transition_weight_(0), + dump_info_on_shutdown_(false), + thread_pool_pthread_priority_(kJitPoolThreadPthreadDefaultPriority) {} + + DISALLOW_COPY_AND_ASSIGN(JitOptions); +}; class Jit { public: @@ -77,29 +181,29 @@ class Jit { REQUIRES(!lock_) REQUIRES_SHARED(Locks::mutator_lock_); - size_t OSRMethodThreshold() const { - return osr_method_threshold_; + uint16_t OSRMethodThreshold() const { + return options_->GetOsrThreshold(); } - size_t HotMethodThreshold() const { - return hot_method_threshold_; + uint16_t HotMethodThreshold() const { + return options_->GetCompileThreshold(); } - size_t WarmMethodThreshold() const { - return warm_method_threshold_; + uint16_t WarmMethodThreshold() const { + return options_->GetWarmupThreshold(); } uint16_t PriorityThreadWeight() const { - return priority_thread_weight_; + return options_->GetPriorityThreadWeight(); } // Returns false if we only need to save profile information and not compile methods. bool UseJitCompilation() const { - return use_jit_compilation_; + return options_->UseJitCompilation(); } bool GetSaveProfilingInfo() const { - return profile_saver_options_.IsEnabled(); + return options_->GetSaveProfilingInfo(); } // Wait until there is no more pending compilation tasks. @@ -120,12 +224,12 @@ class Jit { void NotifyInterpreterToCompiledCodeTransition(Thread* self, ArtMethod* caller) REQUIRES_SHARED(Locks::mutator_lock_) { - AddSamples(self, caller, invoke_transition_weight_, false); + AddSamples(self, caller, options_->GetInvokeTransitionWeight(), false); } void NotifyCompiledCodeToInterpreterTransition(Thread* self, ArtMethod* callee) REQUIRES_SHARED(Locks::mutator_lock_) { - AddSamples(self, callee, invoke_transition_weight_, false); + AddSamples(self, callee, options_->GetInvokeTransitionWeight(), false); } // Starts the profile saver if the config options allow profile recording. @@ -177,7 +281,7 @@ class Jit { void Start(); private: - Jit(); + explicit Jit(JitOptions* options); static bool LoadCompiler(std::string* error_msg); @@ -189,107 +293,22 @@ class Jit { static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool); static void (*jit_types_loaded_)(void*, mirror::Class**, size_t count); + // We make this static to simplify the interaction with libart-compiler.so. + static bool generate_debug_info_; + + const JitOptions* const options_; + + std::unique_ptr<jit::JitCodeCache> code_cache_; + std::unique_ptr<ThreadPool> thread_pool_; + // Performance monitoring. - bool dump_info_on_shutdown_; CumulativeLogger cumulative_timings_; Histogram<uint64_t> memory_use_ GUARDED_BY(lock_); Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - std::unique_ptr<jit::JitCodeCache> code_cache_; - - bool use_jit_compilation_; - ProfileSaverOptions profile_saver_options_; - static bool generate_debug_info_; - uint16_t hot_method_threshold_; - uint16_t warm_method_threshold_; - uint16_t osr_method_threshold_; - uint16_t priority_thread_weight_; - uint16_t invoke_transition_weight_; - std::unique_ptr<ThreadPool> thread_pool_; - DISALLOW_COPY_AND_ASSIGN(Jit); }; -class JitOptions { - public: - static JitOptions* CreateFromRuntimeArguments(const RuntimeArgumentMap& options); - size_t GetCompileThreshold() const { - return compile_threshold_; - } - size_t GetWarmupThreshold() const { - return warmup_threshold_; - } - size_t GetOsrThreshold() const { - return osr_threshold_; - } - uint16_t GetPriorityThreadWeight() const { - return priority_thread_weight_; - } - size_t GetInvokeTransitionWeight() const { - return invoke_transition_weight_; - } - size_t GetCodeCacheInitialCapacity() const { - return code_cache_initial_capacity_; - } - size_t GetCodeCacheMaxCapacity() const { - return code_cache_max_capacity_; - } - bool DumpJitInfoOnShutdown() const { - return dump_info_on_shutdown_; - } - const ProfileSaverOptions& GetProfileSaverOptions() const { - return profile_saver_options_; - } - bool GetSaveProfilingInfo() const { - return profile_saver_options_.IsEnabled(); - } - bool UseJitCompilation() const { - return use_jit_compilation_; - } - void SetUseJitCompilation(bool b) { - use_jit_compilation_ = b; - } - void SetSaveProfilingInfo(bool save_profiling_info) { - profile_saver_options_.SetEnabled(save_profiling_info); - } - void SetWaitForJitNotificationsToSaveProfile(bool value) { - profile_saver_options_.SetWaitForJitNotificationsToSave(value); - } - void SetProfileAOTCode(bool value) { - profile_saver_options_.SetProfileAOTCode(value); - } - - void SetJitAtFirstUse() { - use_jit_compilation_ = true; - compile_threshold_ = 0; - } - - private: - bool use_jit_compilation_; - size_t code_cache_initial_capacity_; - size_t code_cache_max_capacity_; - size_t compile_threshold_; - size_t warmup_threshold_; - size_t osr_threshold_; - uint16_t priority_thread_weight_; - size_t invoke_transition_weight_; - bool dump_info_on_shutdown_; - ProfileSaverOptions profile_saver_options_; - - JitOptions() - : use_jit_compilation_(false), - code_cache_initial_capacity_(0), - code_cache_max_capacity_(0), - compile_threshold_(0), - warmup_threshold_(0), - osr_threshold_(0), - priority_thread_weight_(0), - invoke_transition_weight_(0), - dump_info_on_shutdown_(false) {} - - DISALLOW_COPY_AND_ASSIGN(JitOptions); -}; - // Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce. class ScopedJitSuspend { public: diff --git a/runtime/jvalue-inl.h b/runtime/jvalue-inl.h index 25e34b2a74..5bd4f176f6 100644 --- a/runtime/jvalue-inl.h +++ b/runtime/jvalue-inl.h @@ -19,7 +19,7 @@ #include "jvalue.h" -#include "obj_ptr.h" +#include "obj_ptr-inl.h" namespace art { diff --git a/runtime/jvalue.h b/runtime/jvalue.h index 266abcf399..b42d995d5c 100644 --- a/runtime/jvalue.h +++ b/runtime/jvalue.h @@ -33,7 +33,7 @@ union PACKED(alignof(mirror::Object*)) JValue { // We default initialize JValue instances to all-zeros. JValue() : j(0) {} - template<typename T> static JValue FromPrimitive(T v); + template<typename T> ALWAYS_INLINE static JValue FromPrimitive(T v); int8_t GetB() const { return b; } void SetB(int8_t new_b) { @@ -62,6 +62,7 @@ union PACKED(alignof(mirror::Object*)) JValue { mirror::Object* GetL() const REQUIRES_SHARED(Locks::mutator_lock_) { return l; } + ALWAYS_INLINE void SetL(ObjPtr<mirror::Object> new_l) REQUIRES_SHARED(Locks::mutator_lock_); int16_t GetS() const { return s; } diff --git a/runtime/lock_word.h b/runtime/lock_word.h index 09d856f89b..ce7fe34b22 100644 --- a/runtime/lock_word.h +++ b/runtime/lock_word.h @@ -75,16 +75,18 @@ class LockWord { // Remaining bits are the recursive lock count. kThinLockCountSize = 32 - kThinLockOwnerSize - kStateSize - kReadBarrierStateSize - kMarkBitStateSize, - // Thin lock bits. Owner in lowest bits. + // Thin lock bits. Owner in lowest bits. kThinLockOwnerShift = 0, kThinLockOwnerMask = (1 << kThinLockOwnerSize) - 1, + kThinLockOwnerMaskShifted = kThinLockOwnerMask << kThinLockOwnerShift, kThinLockMaxOwner = kThinLockOwnerMask, // Count in higher bits. kThinLockCountShift = kThinLockOwnerSize + kThinLockOwnerShift, kThinLockCountMask = (1 << kThinLockCountSize) - 1, kThinLockMaxCount = kThinLockCountMask, kThinLockCountOne = 1 << kThinLockCountShift, // == 65536 (0x10000) + kThinLockCountMaskShifted = kThinLockCountMask << kThinLockCountShift, // State in the highest bits. kStateShift = kReadBarrierStateSize + kThinLockCountSize + kThinLockCountShift + diff --git a/runtime/method_handles-inl.h b/runtime/method_handles-inl.h index 41c8384e0d..00a8c00880 100644 --- a/runtime/method_handles-inl.h +++ b/runtime/method_handles-inl.h @@ -22,7 +22,7 @@ #include "common_throws.h" #include "dex/dex_instruction.h" #include "interpreter/interpreter_common.h" -#include "jvalue.h" +#include "jvalue-inl.h" #include "mirror/class.h" #include "mirror/method_type.h" #include "mirror/object.h" diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 64ab78997f..1d45aaeb2e 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -20,7 +20,6 @@ #include "common_dex_operations.h" #include "jvalue-inl.h" -#include "jvalue.h" #include "mirror/emulated_stack_frame.h" #include "mirror/method_handle_impl-inl.h" #include "mirror/method_type.h" diff --git a/runtime/method_info.h b/runtime/method_info.h index b00ddc660f..6f74678e42 100644 --- a/runtime/method_info.h +++ b/runtime/method_info.h @@ -21,7 +21,7 @@ #include "base/leb128.h" #include "base/macros.h" -#include "base/memory_region.h" +#include "base/bit_memory_region.h" namespace art { @@ -35,8 +35,8 @@ class MethodInfo { explicit MethodInfo(const uint8_t* ptr) { if (ptr != nullptr) { num_method_indices_ = DecodeUnsignedLeb128(&ptr); - region_ = MemoryRegion(const_cast<uint8_t*>(ptr), - num_method_indices_ * sizeof(MethodIndexType)); + region_ = BitMemoryRegion( + MemoryRegion(const_cast<uint8_t*>(ptr), num_method_indices_ * sizeof(MethodIndexType))); } } @@ -44,7 +44,7 @@ class MethodInfo { MethodInfo(uint8_t* ptr, size_t num_method_indices) : num_method_indices_(num_method_indices) { DCHECK(ptr != nullptr); ptr = EncodeUnsignedLeb128(ptr, num_method_indices_); - region_ = MemoryRegion(ptr, num_method_indices_ * sizeof(MethodIndexType)); + region_ = BitMemoryRegion(MemoryRegion(ptr, num_method_indices_ * sizeof(MethodIndexType))); } static size_t ComputeSize(size_t num_method_indices) { @@ -71,7 +71,7 @@ class MethodInfo { private: size_t num_method_indices_ = 0u; - MemoryRegion region_; + BitMemoryRegion region_; }; } // namespace art diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h index 7a4876c412..72f1443dfa 100644 --- a/runtime/mirror/dex_cache-inl.h +++ b/runtime/mirror/dex_cache-inl.h @@ -127,23 +127,23 @@ inline void DexCache::ClearResolvedType(dex::TypeIndex type_idx) { } } -inline uint32_t DexCache::MethodTypeSlotIndex(uint32_t proto_idx) { +inline uint32_t DexCache::MethodTypeSlotIndex(dex::ProtoIndex proto_idx) { DCHECK(Runtime::Current()->IsMethodHandlesEnabled()); - DCHECK_LT(proto_idx, GetDexFile()->NumProtoIds()); - const uint32_t slot_idx = proto_idx % kDexCacheMethodTypeCacheSize; + DCHECK_LT(proto_idx.index_, GetDexFile()->NumProtoIds()); + const uint32_t slot_idx = proto_idx.index_ % kDexCacheMethodTypeCacheSize; DCHECK_LT(slot_idx, NumResolvedMethodTypes()); return slot_idx; } -inline MethodType* DexCache::GetResolvedMethodType(uint32_t proto_idx) { +inline MethodType* DexCache::GetResolvedMethodType(dex::ProtoIndex proto_idx) { return GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].load( - std::memory_order_relaxed).GetObjectForIndex(proto_idx); + std::memory_order_relaxed).GetObjectForIndex(proto_idx.index_); } -inline void DexCache::SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved) { +inline void DexCache::SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodType* resolved) { DCHECK(resolved != nullptr); GetResolvedMethodTypes()[MethodTypeSlotIndex(proto_idx)].store( - MethodTypeDexCachePair(resolved, proto_idx), std::memory_order_relaxed); + MethodTypeDexCachePair(resolved, proto_idx.index_), std::memory_order_relaxed); // TODO: Fine-grained marking, so that we don't need to go through all arrays in full. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this); } diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index d940964edb..9aff9ec49a 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -307,9 +307,9 @@ class MANAGED DexCache FINAL : public Object { ALWAYS_INLINE void ClearResolvedField(uint32_t idx, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_); - MethodType* GetResolvedMethodType(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_); + MethodType* GetResolvedMethodType(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_); - void SetResolvedMethodType(uint32_t proto_idx, MethodType* resolved) + void SetResolvedMethodType(dex::ProtoIndex proto_idx, MethodType* resolved) REQUIRES_SHARED(Locks::mutator_lock_); CallSite* GetResolvedCallSite(uint32_t call_site_idx) REQUIRES_SHARED(Locks::mutator_lock_); @@ -432,7 +432,7 @@ class MANAGED DexCache FINAL : public Object { uint32_t TypeSlotIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_); uint32_t FieldSlotIndex(uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_); uint32_t MethodSlotIndex(uint32_t method_idx) REQUIRES_SHARED(Locks::mutator_lock_); - uint32_t MethodTypeSlotIndex(uint32_t proto_idx) REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t MethodTypeSlotIndex(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_); private: void Init(const DexFile* dex_file, diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc index d2bff2c19a..97e0ce6684 100644 --- a/runtime/mirror/dex_cache_test.cc +++ b/runtime/mirror/dex_cache_test.cc @@ -169,9 +169,9 @@ TEST_F(DexCacheMethodHandlesTest, TestResolvedMethodTypes) { for (size_t i = 0; i < dex_file.NumProtoIds(); ++i) { const MethodTypeDexCachePair pair = method_types_cache[i].load(std::memory_order_relaxed); - if (pair.index == method1_id.proto_idx_) { + if (dex::ProtoIndex(pair.index) == method1_id.proto_idx_) { ASSERT_EQ(method1_type.Get(), pair.object.Read()); - } else if (pair.index == method2_id.proto_idx_) { + } else if (dex::ProtoIndex(pair.index) == method2_id.proto_idx_) { ASSERT_EQ(method2_type.Get(), pair.object.Read()); } else { ASSERT_TRUE(false); diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc index b309f596fd..44c819aaf7 100644 --- a/runtime/mirror/var_handle.cc +++ b/runtime/mirror/var_handle.cc @@ -1425,21 +1425,24 @@ int32_t VarHandle::GetAccessModesBitMask() { return GetField32(AccessModesBitMaskOffset()); } -bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) { - StackHandleScope<3> hs(Thread::Current()); - Handle<Class> mt_rtype(hs.NewHandle(method_type->GetRType())); - Handle<VarHandle> vh(hs.NewHandle(this)); - Handle<Class> var_type(hs.NewHandle(vh->GetVarType())); +VarHandle::MatchKind VarHandle::GetMethodTypeMatchForAccessMode(AccessMode access_mode, + MethodType* method_type) { + MatchKind match = MatchKind::kExact; + + ObjPtr<VarHandle> vh = this; + ObjPtr<Class> var_type = vh->GetVarType(); + ObjPtr<Class> mt_rtype = method_type->GetRType(); AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); - // Check return type first. - if (mt_rtype->GetPrimitiveType() == Primitive::Type::kPrimVoid) { - // The result of the operation will be discarded. The return type - // of the VarHandle is immaterial. - } else { - ObjPtr<Class> vh_rtype(GetReturnType(access_mode_template, var_type.Get())); - if (!IsReturnTypeConvertible(vh_rtype, mt_rtype.Get())) { - return false; + // Check return type first. If the return type of the method + // of the VarHandle is immaterial. + if (mt_rtype->GetPrimitiveType() != Primitive::Type::kPrimVoid) { + ObjPtr<Class> vh_rtype = GetReturnType(access_mode_template, var_type.Ptr()); + if (vh_rtype != mt_rtype) { + if (!IsReturnTypeConvertible(vh_rtype, mt_rtype)) { + return MatchKind::kNone; + } + match = MatchKind::kWithConversions; } } @@ -1447,21 +1450,25 @@ bool VarHandle::IsMethodTypeCompatible(AccessMode access_mode, MethodType* metho ObjPtr<Class> vh_ptypes[VarHandle::kMaxAccessorParameters]; const int32_t vh_ptypes_count = BuildParameterArray(vh_ptypes, access_mode_template, - var_type.Get(), + var_type, GetCoordinateType0(), GetCoordinateType1()); if (vh_ptypes_count != method_type->GetPTypes()->GetLength()) { - return false; + return MatchKind::kNone; } // Check the parameter types are compatible. ObjPtr<ObjectArray<Class>> mt_ptypes = method_type->GetPTypes(); for (int32_t i = 0; i < vh_ptypes_count; ++i) { + if (mt_ptypes->Get(i) == vh_ptypes[i]) { + continue; + } if (!IsParameterTypeConvertible(mt_ptypes->Get(i), vh_ptypes[i])) { - return false; + return MatchKind::kNone; } + match = MatchKind::kWithConversions; } - return true; + return match; } bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode, @@ -1508,7 +1515,7 @@ bool VarHandle::IsInvokerMethodTypeCompatible(AccessMode access_mode, MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, ObjPtr<VarHandle> var_handle, AccessMode access_mode) { - // This is a static as the var_handle might be moved by the GC during it's execution. + // This is a static method as the var_handle might be moved by the GC during it's execution. AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); StackHandleScope<3> hs(self); @@ -1538,9 +1545,40 @@ MethodType* VarHandle::GetMethodTypeForAccessMode(Thread* self, AccessMode acces return GetMethodTypeForAccessMode(self, this, access_mode); } +std::string VarHandle::PrettyDescriptorForAccessMode(AccessMode access_mode) { + // Effect MethodType::PrettyDescriptor() without first creating a method type first. + std::ostringstream oss; + oss << '('; + + AccessModeTemplate access_mode_template = GetAccessModeTemplate(access_mode); + ObjPtr<Class> var_type = GetVarType(); + ObjPtr<Class> ctypes[2] = { GetCoordinateType0(), GetCoordinateType1() }; + const int32_t ptypes_count = GetNumberOfParameters(access_mode_template, ctypes[0], ctypes[1]); + int32_t ptypes_done = 0; + for (ObjPtr<Class> ctype : ctypes) { + if (!ctype.IsNull()) { + if (ptypes_done != 0) { + oss << ", "; + } + oss << ctype->PrettyDescriptor();; + ptypes_done++; + } + } + while (ptypes_done != ptypes_count) { + if (ptypes_done != 0) { + oss << ", "; + } + oss << var_type->PrettyDescriptor(); + ptypes_done++; + } + ObjPtr<Class> rtype = GetReturnType(access_mode_template, var_type); + oss << ')' << rtype->PrettyDescriptor(); + return oss.str(); +} + bool VarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) { Class* klass = GetClass(); if (klass == FieldVarHandle::StaticClass()) { @@ -1671,7 +1709,7 @@ ArtField* FieldVarHandle::GetField() { bool FieldVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); ArtField* field = GetField(); @@ -1743,7 +1781,7 @@ GcRoot<Class> FieldVarHandle::static_class_; bool ArrayElementVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); @@ -1856,7 +1894,7 @@ bool ByteArrayViewVarHandle::GetNativeByteOrder() { bool ByteArrayViewVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); @@ -1965,7 +2003,7 @@ bool ByteBufferViewVarHandle::GetNativeByteOrder() { bool ByteBufferViewVarHandle::Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) { ShadowFrameGetter getter(*shadow_frame, operands); diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h index d46d900a8d..5186d43830 100644 --- a/runtime/mirror/var_handle.h +++ b/runtime/mirror/var_handle.h @@ -99,14 +99,16 @@ class MANAGED VarHandle : public Object { return (GetAccessModesBitMask() & (1u << static_cast<uint32_t>(accessMode))) != 0; } - // Returns true if the MethodType specified is compatible with the - // method type associated with the specified AccessMode. The - // supplied MethodType is assumed to be from the point of invocation - // so it is valid for the supplied MethodType to have a void return - // value when the return value for the AccessMode is non-void. This - // corresponds to the result of the accessor being discarded. - bool IsMethodTypeCompatible(AccessMode access_mode, MethodType* method_type) - REQUIRES_SHARED(Locks::mutator_lock_); + enum MatchKind : uint8_t { + kNone, + kWithConversions, + kExact + }; + + // Returns match information on the compatability between the exact method type for + // 'access_mode' and the provided 'method_type'. + MatchKind GetMethodTypeMatchForAccessMode(AccessMode access_mode, MethodType* method_type) + REQUIRES_SHARED(Locks::mutator_lock_); // Returns true if the MethodType specified is compatible with the // specified access_mode if the first parameter of method_type is @@ -122,9 +124,14 @@ class MANAGED VarHandle : public Object { MethodType* GetMethodTypeForAccessMode(Thread* self, AccessMode accessMode) REQUIRES_SHARED(Locks::mutator_lock_); + // Returns a string representing the descriptor of the MethodType associated with + // this AccessMode. + std::string PrettyDescriptorForAccessMode(AccessMode access_mode) + REQUIRES_SHARED(Locks::mutator_lock_); + bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); @@ -192,7 +199,7 @@ class MANAGED FieldVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); @@ -225,7 +232,7 @@ class MANAGED ArrayElementVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); @@ -248,7 +255,7 @@ class MANAGED ByteArrayViewVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); @@ -281,7 +288,7 @@ class MANAGED ByteBufferViewVarHandle : public VarHandle { public: bool Access(AccessMode access_mode, ShadowFrame* shadow_frame, - InstructionOperands* operands, + const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc index d9fa07f207..005aba3edd 100644 --- a/runtime/mirror/var_handle_test.cc +++ b/runtime/mirror/var_handle_test.cc @@ -246,6 +246,47 @@ static MethodType* MethodTypeOf(const std::string& method_descriptor) { return MethodType::Create(self, rtype, ptypes); } +static bool AccessModeMatch(VarHandle* vh, + VarHandle::AccessMode access_mode, + MethodType* method_type, + VarHandle::MatchKind expected_match) + REQUIRES_SHARED(Locks::mutator_lock_) { + return vh->GetMethodTypeMatchForAccessMode(access_mode, method_type) == expected_match; +} + +template <typename VH> +static bool AccessModeExactMatch(Handle<VH> vh, + VarHandle::AccessMode access_mode, + const char* descriptor) + REQUIRES_SHARED(Locks::mutator_lock_) { + return AccessModeMatch(vh.Get(), + access_mode, + MethodTypeOf(descriptor), + VarHandle::MatchKind::kExact); +} + +template <typename VH> +static bool AccessModeWithConversionsMatch(Handle<VH> vh, + VarHandle::AccessMode access_mode, + const char* descriptor) + REQUIRES_SHARED(Locks::mutator_lock_) { + return AccessModeMatch(vh.Get(), + access_mode, + MethodTypeOf(descriptor), + VarHandle::MatchKind::kWithConversions); +} + +template <typename VH> +static bool AccessModeNoMatch(Handle<VH> vh, + VarHandle::AccessMode access_mode, + const char* descriptor) + REQUIRES_SHARED(Locks::mutator_lock_) { + return AccessModeMatch(vh.Get(), + access_mode, + MethodTypeOf(descriptor), + VarHandle::MatchKind::kNone); +} + TEST_F(VarHandleTest, InstanceFieldVarHandle) { Thread * const self = Thread::Current(); ScopedObjectAccess soa(self); @@ -296,47 +337,53 @@ TEST_F(VarHandleTest, InstanceFieldVarHandle) { // Check compatibility - "Get" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;)V")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;)D")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z")); } // Check compatibility - "Set" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;S)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndSet" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, - MethodTypeOf("(Ljava/lang/Integer;II)I"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Z")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)Ljava/lang/Boolean;")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;IB)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndExchange" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;II)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIII)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;II)V")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;II)J")); + EXPECT_TRUE(AccessModeWithConversionsMatch(fvh, access_mode, "(Ljava/lang/Integer;BS)F")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIII)V")); } // Check compatibility - "GetAndUpdate" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/lang/Integer;I)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(Ljava/lang/Integer;I)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Ljava/lang/Integer;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S")); } // Check synthesized method types match expected forms. @@ -430,48 +477,47 @@ TEST_F(VarHandleTest, StaticFieldVarHandle) { // Check compatibility - "Get" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "()V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)Z")); } // Check compatibility - "Set" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(F)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(F)V")); } // Check compatibility - "CompareAndSet" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, - MethodTypeOf("(II)Ljava/lang/String;"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("()Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)Ljava/lang/String;")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "()Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndExchange" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(ID)I"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)S"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(IIJ)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(II)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(ID)I")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)S")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(IIJ)V")); } // Check compatibility - "GetAndUpdate" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd; - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)I"))); - EXPECT_TRUE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)V"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(I)Z"))); - EXPECT_FALSE(fvh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)I")); + EXPECT_TRUE(AccessModeExactMatch(fvh, access_mode, "(I)V")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(I)Z")); + EXPECT_TRUE(AccessModeNoMatch(fvh, access_mode, "(II)V")); } // Check synthesized method types match expected forms. @@ -594,50 +640,46 @@ TEST_F(VarHandleTest, ArrayElementVarHandle) { // Check compatibility - "Get" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Ljava/lang/String;"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;Ljava/lang/String;)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)Ljava/lang/String;")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;I)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;Ljava/lang/String;)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z")); } // Check compatibility - "Set" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndSet" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet; - EXPECT_TRUE( - vh->IsMethodTypeCompatible( - access_mode, - MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, - MethodTypeOf("([Ljava/lang/String;III)I"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;I)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;III)I")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndExchange" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;II)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;II)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V")); } // Check compatibility - "GetAndUpdate" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([Ljava/lang/String;ILjava/lang/String;)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([Ljava/lang/String;ILjava/lang/String;)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V")); } // Check synthesized method types match expected forms. @@ -747,50 +789,46 @@ TEST_F(VarHandleTest, ByteArrayViewVarHandle) { // Check compatibility - "Get" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)C"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BC)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)C")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BI)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BC)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z")); } // Check compatibility - "Set" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndSet" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet; - EXPECT_TRUE( - vh->IsMethodTypeCompatible( - access_mode, - MethodTypeOf("([BICC)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, - MethodTypeOf("([BIII)I"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BI)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIII)I")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BI)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndExchange" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)C"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BICC)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BII)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)C")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BICC)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BII)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V")); } // Check compatibility - "GetAndUpdate" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)C"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("([BIC)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)C")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "([BIC)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "([BIC)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V")); } // Check synthesized method types match expected forms. @@ -900,50 +938,46 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) { // Check compatibility - "Get" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)D"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;D)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)Z"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)D")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;D)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)Z")); } // Check compatibility - "Set" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kSet; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndSet" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndSet; - EXPECT_TRUE( - vh->IsMethodTypeCompatible( - access_mode, - MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, - MethodTypeOf("(Ljava/nio/ByteBuffer;IDI)D"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;I)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Z)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDI)D")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;I)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Z)V")); } // Check compatibility - "CompareAndExchange" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kCompareAndExchange; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)D"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;IDD)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;II)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(III)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)D")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;IDD)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;II)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(III)V")); } // Check compatibility - "GetAndUpdate" pattern { const VarHandle::AccessMode access_mode = VarHandle::AccessMode::kGetAndAdd; - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)D"))); - EXPECT_TRUE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)V"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(Ljava/nio/ByteBuffer;ID)Z"))); - EXPECT_FALSE(vh->IsMethodTypeCompatible(access_mode, MethodTypeOf("(II)V"))); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)D")); + EXPECT_TRUE(AccessModeExactMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)V")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(Ljava/nio/ByteBuffer;ID)Z")); + EXPECT_TRUE(AccessModeNoMatch(vh, access_mode, "(II)V")); } // Check synthesized method types match expected forms. diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 7f7b524227..6c820190b4 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -185,6 +185,10 @@ static jboolean VMRuntime_isNativeDebuggable(JNIEnv*, jobject) { return Runtime::Current()->IsNativeDebuggable(); } +static jboolean VMRuntime_isJavaDebuggable(JNIEnv*, jobject) { + return Runtime::Current()->IsJavaDebuggable(); +} + static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) { DCHECK(WellKnownClasses::java_lang_String != nullptr); @@ -702,6 +706,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"), FAST_NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"), FAST_NATIVE_METHOD(VMRuntime, isNativeDebuggable, "()Z"), + NATIVE_METHOD(VMRuntime, isJavaDebuggable, "()Z"), NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"), FAST_NATIVE_METHOD(VMRuntime, newNonMovableArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"), FAST_NATIVE_METHOD(VMRuntime, newUnpaddedArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"), diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 68024cd1c2..9f595b1c29 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -648,7 +648,7 @@ static jobjectArray Class_getDeclaredAnnotations(JNIEnv* env, jobject javaThis) // Return an empty array instead of a null pointer. ObjPtr<mirror::Class> annotation_array_class = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array); - mirror::ObjectArray<mirror::Object>* empty_array = + ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array = mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Ptr(), 0); @@ -661,7 +661,7 @@ static jobjectArray Class_getDeclaredClasses(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis))); - mirror::ObjectArray<mirror::Class>* classes = nullptr; + ObjPtr<mirror::ObjectArray<mirror::Class>> classes = nullptr; if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) { classes = annotations::GetDeclaredClasses(klass); } @@ -738,7 +738,7 @@ static jstring Class_getInnerClassName(JNIEnv* env, jobject javaThis) { if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) { return nullptr; } - mirror::String* class_name = nullptr; + ObjPtr<mirror::String> class_name = nullptr; if (!annotations::GetInnerClass(klass, &class_name)) { return nullptr; } @@ -763,7 +763,7 @@ static jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) { if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) { return false; } - mirror::String* class_name = nullptr; + ObjPtr<mirror::String> class_name = nullptr; if (!annotations::GetInnerClass(klass, &class_name)) { return false; } diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index a5d6c9704d..13a8d28267 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -38,7 +38,7 @@ static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMetho ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod) ->GetInterfaceMethodIfProxy(kRuntimePointerSize); - mirror::ObjectArray<mirror::Class>* result_array = + ObjPtr<mirror::ObjectArray<mirror::Class>> result_array = annotations::GetExceptionTypesForMethod(method); if (result_array == nullptr) { // Return an empty array instead of a null pointer. diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index e0afbee845..25599843e9 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -27,6 +27,7 @@ #include "dex/dex_file-inl.h" #include "dex/dex_file_annotations.h" #include "jni/jni_internal.h" +#include "jvalue-inl.h" #include "mirror/class-inl.h" #include "mirror/field-inl.h" #include "native_util.h" diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index 2503b3cb44..52e04941c6 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -62,7 +62,7 @@ static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { klass->GetProxyThrows()->Get(throws_index); return soa.AddLocalReference<jobjectArray>(declared_exceptions->Clone(soa.Self())); } else { - mirror::ObjectArray<mirror::Class>* result_array = + ObjPtr<mirror::ObjectArray<mirror::Class>> result_array = annotations::GetExceptionTypesForMethod(method); if (result_array == nullptr) { // Return an empty array instead of a null pointer diff --git a/runtime/oat.h b/runtime/oat.h index 6c683f1541..7b8f71a3f3 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: compiler support const-method-handle - static constexpr uint8_t kOatVersion[] = { '1', '4', '3', '\0' }; + // Last oat version changed reason: Refactor stackmap encoding. + static constexpr uint8_t kOatVersion[] = { '1', '4', '4', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 371678d4d9..ffbc26c647 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -211,12 +211,12 @@ OatFileBase* OatFileBase::OpenOatFile(int zip_fd, return nullptr; } + ret->PreSetup(elf_filename); + if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) { return nullptr; } - ret->PreSetup(elf_filename); - if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) { return nullptr; } @@ -252,12 +252,12 @@ OatFileBase* OatFileBase::OpenOatFile(int zip_fd, return nullptr; } + ret->PreSetup(oat_location); + if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) { return nullptr; } - ret->PreSetup(oat_location); - if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) { return nullptr; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 7d69927ffb..6c869cada5 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -36,6 +36,7 @@ #include "exec_utils.h" #include "gc/heap.h" #include "gc/space/image_space.h" +#include "hidden_api.h" #include "image.h" #include "oat.h" #include "runtime.h" @@ -823,6 +824,11 @@ bool OatFileAssistant::Dex2Oat(const std::vector<std::string>& args, argv.push_back("--compiler-filter=verify-none"); } + if (runtime->GetHiddenApiEnforcementPolicy() != hiddenapi::EnforcementPolicy::kNoChecks) { + argv.push_back("--runtime-arg"); + argv.push_back("-Xhidden-api-checks"); + } + if (runtime->MustRelocateIfPossible()) { argv.push_back("--runtime-arg"); argv.push_back("-Xrelocate"); @@ -860,6 +866,13 @@ bool OatFileAssistant::DexLocationToOatFilename(const std::string& location, CHECK(oat_filename != nullptr); CHECK(error_msg != nullptr); + // If ANDROID_DATA is not set, return false instead of aborting. + // This can occur for preopt when using a class loader context. + if (GetAndroidDataSafe(error_msg) == nullptr) { + *error_msg = "GetAndroidDataSafe failed: " + *error_msg; + return false; + } + std::string cache_dir = GetDalvikCache(GetInstructionSetString(isa)); if (cache_dir.empty()) { *error_msg = "Dalvik cache directory does not exist"; diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 99bc0b2c6e..0b3c61d474 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -33,6 +33,7 @@ #include "class_loader_context.h" #include "common_runtime_test.h" #include "dexopt_test.h" +#include "hidden_api.h" #include "oat_file.h" #include "oat_file_manager.h" #include "scoped_thread_state_change-inl.h" @@ -43,6 +44,8 @@ namespace art { static const std::string kSpecialSharedLibrary = "&"; // NOLINT [runtime/string] [4] static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr; +static constexpr char kDex2oatCmdLineHiddenApiArg[] = " --runtime-arg -Xhidden-api-checks"; + class OatFileAssistantTest : public DexoptTest { public: void VerifyOptimizationStatus(const std::string& file, @@ -1413,6 +1416,46 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) { oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey)); } +TEST_F(OatFileAssistantTest, MakeUpToDateWithHiddenApiDisabled) { + hiddenapi::ScopedHiddenApiEnforcementPolicySetting hiddenapi_exemption( + hiddenapi::EnforcementPolicy::kNoChecks); + + std::string dex_location = GetScratchDir() + "/TestDexHiddenApiDisabled.jar"; + Copy(GetDexSrc1(), dex_location); + + OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + std::string error_msg; + int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; + + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); + EXPECT_NE(nullptr, oat_file.get()); + + const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey); + EXPECT_NE(nullptr, cmd_line); + EXPECT_EQ(nullptr, strstr(cmd_line, kDex2oatCmdLineHiddenApiArg)); +} + +TEST_F(OatFileAssistantTest, MakeUpToDateWithHiddenApiEnabled) { + hiddenapi::ScopedHiddenApiEnforcementPolicySetting hiddenapi_exemption( + hiddenapi::EnforcementPolicy::kBlacklistOnly); + + std::string dex_location = GetScratchDir() + "/TestDexHiddenApiEnabled.jar"; + Copy(GetDexSrc1(), dex_location); + + OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + std::string error_msg; + int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; + + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); + EXPECT_NE(nullptr, oat_file.get()); + + const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey); + EXPECT_NE(nullptr, cmd_line); + EXPECT_NE(nullptr, strstr(cmd_line, kDex2oatCmdLineHiddenApiArg)); +} + TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) { std::string dex_location = GetScratchDir() + "/TestDex.jar"; std::string context_location = GetScratchDir() + "/ContextDex.jar"; diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc index 98238e5600..aed6bc57b3 100644 --- a/runtime/oat_quick_method_header.cc +++ b/runtime/oat_quick_method_header.cc @@ -19,6 +19,7 @@ #include "art_method.h" #include "dex/dex_file_types.h" #include "scoped_thread_state_change-inl.h" +#include "stack_map.h" #include "thread.h" namespace art { @@ -42,11 +43,10 @@ uint32_t OatQuickMethodHeader::ToDexPc(ArtMethod* method, const void* entry_point = GetEntryPoint(); uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point); if (IsOptimized()) { - CodeInfo code_info = GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset, encoding); + CodeInfo code_info(this); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(sought_offset); if (stack_map.IsValid()) { - return stack_map.GetDexPc(encoding.stack_map.encoding); + return stack_map.GetDexPc(); } } else { DCHECK(method->IsNative()); @@ -71,18 +71,17 @@ uintptr_t OatQuickMethodHeader::ToNativeQuickPc(ArtMethod* method, DCHECK(!method->IsNative()); DCHECK(IsOptimized()); // Search for the dex-to-pc mapping in stack maps. - CodeInfo code_info = GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(this); // All stack maps are stored in the same CodeItem section, safepoint stack // maps first, then catch stack maps. We use `is_for_catch_handler` to select // the order of iteration. StackMap stack_map = - LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding) - : code_info.GetStackMapForDexPc(dex_pc, encoding); + LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc) + : code_info.GetStackMapForDexPc(dex_pc); if (stack_map.IsValid()) { return reinterpret_cast<uintptr_t>(entry_point) + - stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA); + stack_map.GetNativePcOffset(kRuntimeISA); } if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h index f0966b7bfa..d6762d6bc6 100644 --- a/runtime/oat_quick_method_header.h +++ b/runtime/oat_quick_method_header.h @@ -22,7 +22,6 @@ #include "base/utils.h" #include "method_info.h" #include "quick/quick_method_frame_info.h" -#include "stack_map.h" namespace art { @@ -75,10 +74,6 @@ class PACKED(4) OatQuickMethodHeader { return code_ - vmap_table_offset_; } - CodeInfo GetOptimizedCodeInfo() const { - return CodeInfo(GetOptimizedCodeInfoPtr()); - } - const void* GetOptimizedMethodInfoPtr() const { DCHECK(IsOptimized()); return reinterpret_cast<const void*>(code_ - method_info_offset_); diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 3aa481af8c..7383d477bb 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -194,6 +194,9 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .Define("-Xjittransitionweight:_") .WithType<unsigned int>() .IntoKey(M::JITInvokeTransitionWeight) + .Define("-Xjitpthreadpriority:_") + .WithType<int>() + .IntoKey(M::JITPoolThreadPthreadPriority) .Define("-Xjitsaveprofilinginfo") .WithType<ProfileSaverOptions>() .AppendValues() diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 077aa33925..c555fca23c 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -224,30 +224,29 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* CodeItemDataAccessor accessor(handler_method_->DexInstructionData()); const size_t number_of_vregs = accessor.RegistersSize(); - CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(handler_method_header_); // Find stack map of the catch block. - StackMap catch_stack_map = code_info.GetCatchStackMapForDexPc(GetHandlerDexPc(), encoding); + StackMap catch_stack_map = code_info.GetCatchStackMapForDexPc(GetHandlerDexPc()); DCHECK(catch_stack_map.IsValid()); DexRegisterMap catch_vreg_map = - code_info.GetDexRegisterMapOf(catch_stack_map, encoding, number_of_vregs); + code_info.GetDexRegisterMapOf(catch_stack_map, number_of_vregs); if (!catch_vreg_map.IsValid()) { return; } // Find stack map of the throwing instruction. StackMap throw_stack_map = - code_info.GetStackMapForNativePcOffset(stack_visitor->GetNativePcOffset(), encoding); + code_info.GetStackMapForNativePcOffset(stack_visitor->GetNativePcOffset()); DCHECK(throw_stack_map.IsValid()); DexRegisterMap throw_vreg_map = - code_info.GetDexRegisterMapOf(throw_stack_map, encoding, number_of_vregs); + code_info.GetDexRegisterMapOf(throw_stack_map, number_of_vregs); DCHECK(throw_vreg_map.IsValid()); // Copy values between them. for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) { DexRegisterLocation::Kind catch_location = - catch_vreg_map.GetLocationKind(vreg, number_of_vregs, code_info, encoding); + catch_vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); if (catch_location == DexRegisterLocation::Kind::kNone) { continue; } @@ -257,8 +256,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* uint32_t vreg_value; VRegKind vreg_kind = ToVRegKind(throw_vreg_map.GetLocationKind(vreg, number_of_vregs, - code_info, - encoding)); + code_info)); bool get_vreg_success = stack_visitor->GetVReg(stack_visitor->GetMethod(), vreg, vreg_kind, @@ -271,8 +269,7 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* // Copy value to the catch phi's stack slot. int32_t slot_offset = catch_vreg_map.GetStackOffsetInBytes(vreg, number_of_vregs, - code_info, - encoding); + code_info); ArtMethod** frame_top = stack_visitor->GetCurrentQuickFrame(); uint8_t* slot_address = reinterpret_cast<uint8_t*>(frame_top) + slot_offset; uint32_t* slot_ptr = reinterpret_cast<uint32_t*>(slot_address); @@ -404,20 +401,18 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { const bool* updated_vregs) REQUIRES_SHARED(Locks::mutator_lock_) { const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - CodeInfo code_info = method_header->GetOptimizedCodeInfo(); + CodeInfo code_info(method_header); uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); CodeItemDataAccessor accessor(m->DexInstructionData()); const size_t number_of_vregs = accessor.RegistersSize(); - uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map); - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); + uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map); + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); DexRegisterMap vreg_map = IsInInlinedFrame() ? code_info.GetDexRegisterMapAtDepth(GetCurrentInliningDepth() - 1, - code_info.GetInlineInfoOf(stack_map, encoding), - encoding, + code_info.GetInlineInfoOf(stack_map), number_of_vregs) - : code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_vregs); + : code_info.GetDexRegisterMapOf(stack_map, number_of_vregs); if (!vreg_map.IsValid()) { return; @@ -430,7 +425,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { } DexRegisterLocation::Kind location = - vreg_map.GetLocationKind(vreg, number_of_vregs, code_info, encoding); + vreg_map.GetLocationKind(vreg, number_of_vregs, code_info); static constexpr uint32_t kDeadValue = 0xEBADDE09; uint32_t value = kDeadValue; bool is_reference = false; @@ -439,12 +434,11 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { case DexRegisterLocation::Kind::kInStack: { const int32_t offset = vreg_map.GetStackOffsetInBytes(vreg, number_of_vregs, - code_info, - encoding); + code_info); const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset; value = *reinterpret_cast<const uint32_t*>(addr); uint32_t bit = (offset >> 2); - if (bit < encoding.stack_mask.encoding.BitSize() && stack_mask.LoadBit(bit)) { + if (bit < code_info.GetNumberOfStackMaskBits() && stack_mask.LoadBit(bit)) { is_reference = true; } break; @@ -453,7 +447,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { case DexRegisterLocation::Kind::kInRegisterHigh: case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { - uint32_t reg = vreg_map.GetMachineRegister(vreg, number_of_vregs, code_info, encoding); + uint32_t reg = vreg_map.GetMachineRegister(vreg, number_of_vregs, code_info); bool result = GetRegisterIfAccessible(reg, ToVRegKind(location), &value); CHECK(result); if (location == DexRegisterLocation::Kind::kInRegister) { @@ -464,7 +458,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { break; } case DexRegisterLocation::Kind::kConstant: { - value = vreg_map.GetConstant(vreg, number_of_vregs, code_info, encoding); + value = vreg_map.GetConstant(vreg, number_of_vregs, code_info); if (value == 0) { // Make it a reference for extra safety. is_reference = true; @@ -479,8 +473,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { << "Unexpected location kind " << vreg_map.GetLocationInternalKind(vreg, number_of_vregs, - code_info, - encoding); + code_info); UNREACHABLE(); } } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index dfa4b3daab..66eba1e1d4 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -25,6 +25,7 @@ #include "indirect_reference_table-inl.h" #include "jni/java_vm_ext.h" #include "jni/jni_internal.h" +#include "jvalue-inl.h" #include "mirror/class-inl.h" #include "mirror/executable.h" #include "mirror/object_array-inl.h" diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 5d974246ff..14027493d8 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1192,7 +1192,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // As is, we're encoding some logic here about which specific policy to use, which would be better // controlled by the framework. hidden_api_policy_ = do_hidden_api_checks - ? hiddenapi::EnforcementPolicy::kBlacklistOnly + ? hiddenapi::EnforcementPolicy::kDarkGreyAndBlackList : hiddenapi::EnforcementPolicy::kNoChecks; no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain); diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index 427385d914..e647423b9c 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -77,6 +77,7 @@ RUNTIME_OPTIONS_KEY (unsigned int, JITWarmupThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITOsrThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITPriorityThreadWeight) RUNTIME_OPTIONS_KEY (unsigned int, JITInvokeTransitionWeight) +RUNTIME_OPTIONS_KEY (int, JITPoolThreadPthreadPriority, jit::kJitPoolThreadPthreadDefaultPriority) RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheInitialCapacity, jit::JitCodeCache::kInitialCapacity) RUNTIME_OPTIONS_KEY (MemoryKiB, JITCodeCacheMaxCapacity, jit::JitCodeCache::kMaxCapacity) RUNTIME_OPTIONS_KEY (MillisecondsToNanoseconds, \ diff --git a/runtime/stack.cc b/runtime/stack.cc index c58380dee2..7d1cb5cc4b 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -76,15 +76,14 @@ StackVisitor::StackVisitor(Thread* thread, } } -static InlineInfo GetCurrentInlineInfo(const OatQuickMethodHeader* method_header, +static InlineInfo GetCurrentInlineInfo(CodeInfo& code_info, + const OatQuickMethodHeader* method_header, uintptr_t cur_quick_frame_pc) REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc); - CodeInfo code_info = method_header->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(stack_map.IsValid()); - return code_info.GetInlineInfoOf(stack_map, encoding); + return code_info.GetInlineInfoOf(stack_map); } ArtMethod* StackVisitor::GetMethod() const { @@ -93,16 +92,16 @@ ArtMethod* StackVisitor::GetMethod() const { } else if (cur_quick_frame_ != nullptr) { if (IsInInlinedFrame()) { size_t depth_in_stack_map = current_inlining_depth_ - 1; - InlineInfo inline_info = GetCurrentInlineInfo(GetCurrentOatQuickMethodHeader(), - cur_quick_frame_pc_); const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding(); + CodeInfo code_info(method_header); + InlineInfo inline_info = GetCurrentInlineInfo(code_info, + method_header, + cur_quick_frame_pc_); MethodInfo method_info = method_header->GetOptimizedMethodInfo(); DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames); return GetResolvedMethod(*GetCurrentQuickFrame(), method_info, inline_info, - encoding.inline_info.encoding, depth_in_stack_map); } else { return *cur_quick_frame_; @@ -116,11 +115,11 @@ uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const { return cur_shadow_frame_->GetDexPC(); } else if (cur_quick_frame_ != nullptr) { if (IsInInlinedFrame()) { - size_t depth_in_stack_map = current_inlining_depth_ - 1; const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding(); - return GetCurrentInlineInfo(GetCurrentOatQuickMethodHeader(), cur_quick_frame_pc_). - GetDexPcAtDepth(encoding.inline_info.encoding, depth_in_stack_map); + CodeInfo code_info(method_header); + size_t depth_in_stack_map = current_inlining_depth_ - 1; + return GetCurrentInlineInfo(code_info, method_header, cur_quick_frame_pc_). + GetDexPcAtDepth(depth_in_stack_map); } else if (cur_oat_quick_method_header_ == nullptr) { return dex::kDexNoIndex; } else { @@ -230,32 +229,29 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin uint16_t number_of_dex_registers = accessor.RegistersSize(); DCHECK_LT(vreg, number_of_dex_registers); const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - CodeInfo code_info = method_header->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(method_header); uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(stack_map.IsValid()); size_t depth_in_stack_map = current_inlining_depth_ - 1; DexRegisterMap dex_register_map = IsInInlinedFrame() ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map, - code_info.GetInlineInfoOf(stack_map, encoding), - encoding, + code_info.GetInlineInfoOf(stack_map), number_of_dex_registers) - : code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); + : code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); if (!dex_register_map.IsValid()) { return false; } DexRegisterLocation::Kind location_kind = - dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info, encoding); + dex_register_map.GetLocationKind(vreg, number_of_dex_registers, code_info); switch (location_kind) { case DexRegisterLocation::Kind::kInStack: { const int32_t offset = dex_register_map.GetStackOffsetInBytes(vreg, number_of_dex_registers, - code_info, - encoding); + code_info); const uint8_t* addr = reinterpret_cast<const uint8_t*>(cur_quick_frame_) + offset; *val = *reinterpret_cast<const uint32_t*>(addr); return true; @@ -265,11 +261,11 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin case DexRegisterLocation::Kind::kInFpuRegister: case DexRegisterLocation::Kind::kInFpuRegisterHigh: { uint32_t reg = - dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info, encoding); + dex_register_map.GetMachineRegister(vreg, number_of_dex_registers, code_info); return GetRegisterIfAccessible(reg, kind, val); } case DexRegisterLocation::Kind::kConstant: - *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info, encoding); + *val = dex_register_map.GetConstant(vreg, number_of_dex_registers, code_info); return true; case DexRegisterLocation::Kind::kNone: return false; @@ -278,8 +274,7 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin << "Unexpected location kind " << dex_register_map.GetLocationInternalKind(vreg, number_of_dex_registers, - code_info, - encoding); + code_info); UNREACHABLE(); } } @@ -831,15 +826,14 @@ void StackVisitor::WalkStack(bool include_transitions) { if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames) && (cur_oat_quick_method_header_ != nullptr) && cur_oat_quick_method_header_->IsOptimized()) { - CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + CodeInfo code_info(cur_oat_quick_method_header_); uint32_t native_pc_offset = cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding.stack_map.encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); + if (stack_map.IsValid() && stack_map.HasInlineInfo()) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); DCHECK_EQ(current_inlining_depth_, 0u); - for (current_inlining_depth_ = inline_info.GetDepth(encoding.inline_info.encoding); + for (current_inlining_depth_ = inline_info.GetDepth(); current_inlining_depth_ != 0; --current_inlining_depth_) { bool should_continue = VisitFrame(); diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 9c7b6875cf..2b7e8dd748 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -25,8 +25,6 @@ namespace art { constexpr size_t DexRegisterLocationCatalog::kNoLocationEntryIndex; -constexpr uint32_t StackMap::kNoDexRegisterMap; -constexpr uint32_t StackMap::kNoInlineInfo; std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& kind) { using Kind = DexRegisterLocation::Kind; @@ -56,27 +54,25 @@ std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation::Kind& DexRegisterLocation::Kind DexRegisterMap::GetLocationInternalKind( uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { DexRegisterLocationCatalog dex_register_location_catalog = - code_info.GetDexRegisterLocationCatalog(enc); + code_info.GetDexRegisterLocationCatalog(); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, - code_info.GetNumberOfLocationCatalogEntries(enc)); + code_info.GetNumberOfLocationCatalogEntries()); return dex_register_location_catalog.GetLocationInternalKind(location_catalog_entry_index); } DexRegisterLocation DexRegisterMap::GetDexRegisterLocation(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { DexRegisterLocationCatalog dex_register_location_catalog = - code_info.GetDexRegisterLocationCatalog(enc); + code_info.GetDexRegisterLocationCatalog(); size_t location_catalog_entry_index = GetLocationCatalogEntryIndex( dex_register_number, number_of_dex_registers, - code_info.GetNumberOfLocationCatalogEntries(enc)); + code_info.GetNumberOfLocationCatalogEntries()); return dex_register_location_catalog.GetDexRegisterLocation(location_catalog_entry_index); } @@ -90,27 +86,28 @@ static void DumpRegisterMapping(std::ostream& os, << " (" << location.GetValue() << ")" << suffix << '\n'; } -void StackMapEncoding::Dump(VariableIndentationOutputStream* vios) const { +void StackMap::DumpEncoding(const BitTable<6>& table, + VariableIndentationOutputStream* vios) { vios->Stream() << "StackMapEncoding" - << " (native_pc_bit_offset=" << static_cast<uint32_t>(kNativePcBitOffset) - << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_) - << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_) - << ", inline_info_bit_offset=" << static_cast<uint32_t>(inline_info_bit_offset_) - << ", register_mask_bit_offset=" << static_cast<uint32_t>(register_mask_index_bit_offset_) - << ", stack_mask_index_bit_offset=" << static_cast<uint32_t>(stack_mask_index_bit_offset_) - << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_) + << " (NativePcOffsetBits=" << table.NumColumnBits(kNativePcOffset) + << ", DexPcBits=" << table.NumColumnBits(kDexPc) + << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset) + << ", InlineInfoIndexBits=" << table.NumColumnBits(kInlineInfoIndex) + << ", RegisterMaskIndexBits=" << table.NumColumnBits(kRegisterMaskIndex) + << ", StackMaskIndexBits=" << table.NumColumnBits(kStackMaskIndex) << ")\n"; } -void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const { +void InlineInfo::DumpEncoding(const BitTable<5>& table, + VariableIndentationOutputStream* vios) { vios->Stream() << "InlineInfoEncoding" - << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset) - << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_) - << ", extra_data_bit_offset=" << static_cast<uint32_t>(extra_data_bit_offset_) - << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_) - << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_) + << " (IsLastBits=" << table.NumColumnBits(kIsLast) + << ", MethodIndexIdxBits=" << table.NumColumnBits(kMethodIndexIdx) + << ", DexPcBits=" << table.NumColumnBits(kDexPc) + << ", ExtraDataBits=" << table.NumColumnBits(kExtraData) + << ", DexRegisterMapOffsetBits=" << table.NumColumnBits(kDexRegisterMapOffset) << ")\n"; } @@ -120,26 +117,24 @@ void CodeInfo::Dump(VariableIndentationOutputStream* vios, bool dump_stack_maps, InstructionSet instruction_set, const MethodInfo& method_info) const { - CodeInfoEncoding encoding = ExtractEncoding(); - size_t number_of_stack_maps = GetNumberOfStackMaps(encoding); + size_t number_of_stack_maps = GetNumberOfStackMaps(); vios->Stream() << "Optimized CodeInfo (number_of_dex_registers=" << number_of_dex_registers << ", number_of_stack_maps=" << number_of_stack_maps << ")\n"; ScopedIndentation indent1(vios); - encoding.stack_map.encoding.Dump(vios); - if (HasInlineInfo(encoding)) { - encoding.inline_info.encoding.Dump(vios); + StackMap::DumpEncoding(stack_maps_, vios); + if (HasInlineInfo()) { + InlineInfo::DumpEncoding(inline_infos_, vios); } // Display the Dex register location catalog. - GetDexRegisterLocationCatalog(encoding).Dump(vios, *this); + GetDexRegisterLocationCatalog().Dump(vios, *this); // Display stack maps along with (live) Dex register maps. if (dump_stack_maps) { for (size_t i = 0; i < number_of_stack_maps; ++i) { - StackMap stack_map = GetStackMapAt(i, encoding); + StackMap stack_map = GetStackMapAt(i); stack_map.Dump(vios, *this, - encoding, method_info, code_offset, number_of_dex_registers, @@ -153,9 +148,8 @@ void CodeInfo::Dump(VariableIndentationOutputStream* vios, void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info) { - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); - size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(encoding); + size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); + size_t location_catalog_size_in_bytes = code_info.GetDexRegisterLocationCatalogSize(); vios->Stream() << "DexRegisterLocationCatalog (number_of_entries=" << number_of_location_catalog_entries << ", size_in_bytes=" << location_catalog_size_in_bytes << ")\n"; @@ -169,8 +163,7 @@ void DexRegisterLocationCatalog::Dump(VariableIndentationOutputStream* vios, void DexRegisterMap::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, uint16_t number_of_dex_registers) const { - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(encoding); + size_t number_of_location_catalog_entries = code_info.GetNumberOfLocationCatalogEntries(); // TODO: Display the bit mask of live Dex registers. for (size_t j = 0; j < number_of_dex_registers; ++j) { if (IsDexRegisterLive(j)) { @@ -178,8 +171,7 @@ void DexRegisterMap::Dump(VariableIndentationOutputStream* vios, j, number_of_dex_registers, number_of_location_catalog_entries); DexRegisterLocation location = GetDexRegisterLocation(j, number_of_dex_registers, - code_info, - encoding); + code_info); ScopedIndentation indent1(vios); DumpRegisterMapping( vios->Stream(), j, location, "v", @@ -190,38 +182,35 @@ void DexRegisterMap::Dump(VariableIndentationOutputStream* vios, void StackMap::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, - const CodeInfoEncoding& encoding, const MethodInfo& method_info, uint32_t code_offset, uint16_t number_of_dex_registers, InstructionSet instruction_set, const std::string& header_suffix) const { - StackMapEncoding stack_map_encoding = encoding.stack_map.encoding; - const uint32_t pc_offset = GetNativePcOffset(stack_map_encoding, instruction_set); + const uint32_t pc_offset = GetNativePcOffset(instruction_set); vios->Stream() << "StackMap" << header_suffix << std::hex << " [native_pc=0x" << code_offset + pc_offset << "]" - << " [entry_size=0x" << encoding.stack_map.encoding.BitSize() << " bits]" - << " (dex_pc=0x" << GetDexPc(stack_map_encoding) + << " (dex_pc=0x" << GetDexPc() << ", native_pc_offset=0x" << pc_offset - << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset(stack_map_encoding) - << ", inline_info_offset=0x" << GetInlineInfoIndex(stack_map_encoding) - << ", register_mask=0x" << code_info.GetRegisterMaskOf(encoding, *this) + << ", dex_register_map_offset=0x" << GetDexRegisterMapOffset() + << ", inline_info_offset=0x" << GetInlineInfoIndex() + << ", register_mask=0x" << code_info.GetRegisterMaskOf(*this) << std::dec << ", stack_mask=0b"; - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, *this); - for (size_t i = 0, e = encoding.stack_mask.encoding.BitSize(); i < e; ++i) { + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(*this); + for (size_t i = 0, e = code_info.GetNumberOfStackMaskBits(); i < e; ++i) { vios->Stream() << stack_mask.LoadBit(e - i - 1); } vios->Stream() << ")\n"; - if (HasDexRegisterMap(stack_map_encoding)) { + if (HasDexRegisterMap()) { DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf( - *this, encoding, number_of_dex_registers); + *this, number_of_dex_registers); dex_register_map.Dump(vios, code_info, number_of_dex_registers); } - if (HasInlineInfo(stack_map_encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(*this, encoding); + if (HasInlineInfo()) { + InlineInfo inline_info = code_info.GetInlineInfoOf(*this); // We do not know the length of the dex register maps of inlined frames // at this level, so we just pass null to `InlineInfo::Dump` to tell // it not to look at these maps. @@ -233,29 +222,27 @@ void InlineInfo::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, const MethodInfo& method_info, uint16_t number_of_dex_registers[]) const { - InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info.encoding; vios->Stream() << "InlineInfo with depth " - << static_cast<uint32_t>(GetDepth(inline_info_encoding)) + << static_cast<uint32_t>(GetDepth()) << "\n"; - for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) { + for (size_t i = 0; i < GetDepth(); ++i) { vios->Stream() << " At depth " << i << std::hex - << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i); - if (EncodesArtMethodAtDepth(inline_info_encoding, i)) { + << " (dex_pc=0x" << GetDexPcAtDepth(i); + if (EncodesArtMethodAtDepth(i)) { ScopedObjectAccess soa(Thread::Current()); - vios->Stream() << ", method=" << GetArtMethodAtDepth(inline_info_encoding, i)->PrettyMethod(); + vios->Stream() << ", method=" << GetArtMethodAtDepth(i)->PrettyMethod(); } else { vios->Stream() << std::dec - << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, method_info, i); + << ", method_index=" << GetMethodIndexAtDepth(method_info, i); } vios->Stream() << ")\n"; - if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) { - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) { DexRegisterMap dex_register_map = - code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]); + code_info.GetDexRegisterMapAtDepth(i, *this, number_of_dex_registers[i]); ScopedIndentation indent1(vios); dex_register_map.Dump(vios, code_info, number_of_dex_registers[i]); } diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 38397643b6..91cecf0690 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -21,12 +21,14 @@ #include "arch/code_offset.h" #include "base/bit_memory_region.h" +#include "base/bit_table.h" #include "base/bit_utils.h" #include "base/bit_vector.h" #include "base/leb128.h" #include "base/memory_region.h" #include "dex/dex_file_types.h" #include "method_info.h" +#include "oat_quick_method_header.h" namespace art { @@ -37,13 +39,8 @@ class VariableIndentationOutputStream; // (signed) values. static constexpr ssize_t kFrameSlotSize = 4; -// Size of Dex virtual registers. -static constexpr size_t kVRegSize = 4; - class ArtMethod; class CodeInfo; -class StackMapEncoding; -struct CodeInfoEncoding; /** * Classes in the following file are wrapper on stack map information backed @@ -452,35 +449,31 @@ class DexRegisterMap { explicit DexRegisterMap(MemoryRegion region) : region_(region) {} DexRegisterMap() {} - bool IsValid() const { return region_.pointer() != nullptr; } + bool IsValid() const { return region_.IsValid(); } // Get the surface kind of Dex register `dex_register_number`. DexRegisterLocation::Kind GetLocationKind(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { return DexRegisterLocation::ConvertToSurfaceKind( - GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info, enc)); + GetLocationInternalKind(dex_register_number, number_of_dex_registers, code_info)); } // Get the internal kind of Dex register `dex_register_number`. DexRegisterLocation::Kind GetLocationInternalKind(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const; + const CodeInfo& code_info) const; // Get the Dex register location `dex_register_number`. DexRegisterLocation GetDexRegisterLocation(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const; + const CodeInfo& code_info) const; int32_t GetStackOffsetInBytes(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); + GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); DCHECK(location.GetKind() == DexRegisterLocation::Kind::kInStack); // GetDexRegisterLocation returns the offset in bytes. return location.GetValue(); @@ -488,20 +481,18 @@ class DexRegisterMap { int32_t GetConstant(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); + GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); DCHECK_EQ(location.GetKind(), DexRegisterLocation::Kind::kConstant); return location.GetValue(); } int32_t GetMachineRegister(uint16_t dex_register_number, uint16_t number_of_dex_registers, - const CodeInfo& code_info, - const CodeInfoEncoding& enc) const { + const CodeInfo& code_info) const { DexRegisterLocation location = - GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info, enc); + GetDexRegisterLocation(dex_register_number, number_of_dex_registers, code_info); DCHECK(location.GetInternalKind() == DexRegisterLocation::Kind::kInRegister || location.GetInternalKind() == DexRegisterLocation::Kind::kInRegisterHigh || location.GetInternalKind() == DexRegisterLocation::Kind::kInFpuRegister || @@ -627,7 +618,7 @@ class DexRegisterMap { // Return the size of the DexRegisterMap object, in bytes. size_t Size() const { - return region_.size(); + return BitsToBytesRoundUp(region_.size_in_bits()); } void Dump(VariableIndentationOutputStream* vios, @@ -650,143 +641,12 @@ class DexRegisterMap { static constexpr int kFixedSize = 0; - MemoryRegion region_; + BitMemoryRegion region_; friend class CodeInfo; friend class StackMapStream; }; -// Represents bit range of bit-packed integer field. -// We reuse the idea from ULEB128p1 to support encoding of -1 (aka 0xFFFFFFFF). -// If min_value is set to -1, we implicitly subtract one from any loaded value, -// and add one to any stored value. This is generalized to any negative values. -// In other words, min_value acts as a base and the stored value is added to it. -struct FieldEncoding { - FieldEncoding(size_t start_offset, size_t end_offset, int32_t min_value = 0) - : start_offset_(start_offset), end_offset_(end_offset), min_value_(min_value) { - DCHECK_LE(start_offset_, end_offset_); - DCHECK_LE(BitSize(), 32u); - } - - ALWAYS_INLINE size_t BitSize() const { return end_offset_ - start_offset_; } - - template <typename Region> - ALWAYS_INLINE int32_t Load(const Region& region) const { - DCHECK_LE(end_offset_, region.size_in_bits()); - return static_cast<int32_t>(region.LoadBits(start_offset_, BitSize())) + min_value_; - } - - template <typename Region> - ALWAYS_INLINE void Store(Region region, int32_t value) const { - region.StoreBits(start_offset_, value - min_value_, BitSize()); - DCHECK_EQ(Load(region), value); - } - - private: - size_t start_offset_; - size_t end_offset_; - int32_t min_value_; -}; - -class StackMapEncoding { - public: - StackMapEncoding() - : dex_pc_bit_offset_(0), - dex_register_map_bit_offset_(0), - inline_info_bit_offset_(0), - register_mask_index_bit_offset_(0), - stack_mask_index_bit_offset_(0), - total_bit_size_(0) {} - - // Set stack map bit layout based on given sizes. - // Returns the size of stack map in bits. - size_t SetFromSizes(size_t native_pc_max, - size_t dex_pc_max, - size_t dex_register_map_size, - size_t number_of_inline_info, - size_t number_of_register_masks, - size_t number_of_stack_masks) { - total_bit_size_ = 0; - DCHECK_EQ(kNativePcBitOffset, total_bit_size_); - total_bit_size_ += MinimumBitsToStore(native_pc_max); - - dex_pc_bit_offset_ = total_bit_size_; - // Note: We're not encoding the dex pc if there is none. That's the case - // for an intrinsified native method, such as String.charAt(). - if (dex_pc_max != dex::kDexNoIndex) { - total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); - } - - // We also need +1 for kNoDexRegisterMap, but since the size is strictly - // greater than any offset we might try to encode, we already implicitly have it. - dex_register_map_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(dex_register_map_size); - - // We also need +1 for kNoInlineInfo, but since the inline_info_size is strictly - // greater than the offset we might try to encode, we already implicitly have it. - // If inline_info_size is zero, we can encode only kNoInlineInfo (in zero bits). - inline_info_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(number_of_inline_info); - - register_mask_index_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(number_of_register_masks); - - stack_mask_index_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(number_of_stack_masks); - - return total_bit_size_; - } - - ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { - return FieldEncoding(kNativePcBitOffset, dex_pc_bit_offset_); - } - ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { - return FieldEncoding(dex_pc_bit_offset_, dex_register_map_bit_offset_, -1 /* min_value */); - } - ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { - return FieldEncoding(dex_register_map_bit_offset_, inline_info_bit_offset_, -1 /* min_value */); - } - ALWAYS_INLINE FieldEncoding GetInlineInfoEncoding() const { - return FieldEncoding(inline_info_bit_offset_, - register_mask_index_bit_offset_, - -1 /* min_value */); - } - ALWAYS_INLINE FieldEncoding GetRegisterMaskIndexEncoding() const { - return FieldEncoding(register_mask_index_bit_offset_, stack_mask_index_bit_offset_); - } - ALWAYS_INLINE FieldEncoding GetStackMaskIndexEncoding() const { - return FieldEncoding(stack_mask_index_bit_offset_, total_bit_size_); - } - ALWAYS_INLINE size_t BitSize() const { - return total_bit_size_; - } - - // Encode the encoding into the vector. - template<typename Vector> - void Encode(Vector* dest) const { - static_assert(alignof(StackMapEncoding) == 1, "Should not require alignment"); - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); - dest->insert(dest->end(), ptr, ptr + sizeof(*this)); - } - - // Decode the encoding from a pointer, updates the pointer. - void Decode(const uint8_t** ptr) { - *this = *reinterpret_cast<const StackMapEncoding*>(*ptr); - *ptr += sizeof(*this); - } - - void Dump(VariableIndentationOutputStream* vios) const; - - private: - static constexpr size_t kNativePcBitOffset = 0; - uint8_t dex_pc_bit_offset_; - uint8_t dex_register_map_bit_offset_; - uint8_t inline_info_bit_offset_; - uint8_t register_mask_index_bit_offset_; - uint8_t stack_mask_index_bit_offset_; - uint8_t total_bit_size_; -}; - /** * A Stack Map holds compilation information for a specific PC necessary for: * - Mapping it to a dex PC, @@ -794,248 +654,101 @@ class StackMapEncoding { * - Knowing which registers hold objects, * - Knowing the inlining information, * - Knowing the values of dex registers. - * - * The information is of the form: - * - * [native_pc_offset, dex_pc, dex_register_map_offset, inlining_info_index, register_mask_index, - * stack_mask_index]. */ -class StackMap { +class StackMap : public BitTable<6>::Accessor { public: - StackMap() {} - explicit StackMap(BitMemoryRegion region) : region_(region) {} - - ALWAYS_INLINE bool IsValid() const { return region_.pointer() != nullptr; } - - ALWAYS_INLINE uint32_t GetDexPc(const StackMapEncoding& encoding) const { - return encoding.GetDexPcEncoding().Load(region_); - } + enum Field { + kNativePcOffset, + kDexPc, + kDexRegisterMapOffset, + kInlineInfoIndex, + kRegisterMaskIndex, + kStackMaskIndex, + kCount, + }; - ALWAYS_INLINE void SetDexPc(const StackMapEncoding& encoding, uint32_t dex_pc) { - encoding.GetDexPcEncoding().Store(region_, dex_pc); - } + StackMap() : BitTable<kCount>::Accessor(nullptr, -1) {} + StackMap(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} - ALWAYS_INLINE uint32_t GetNativePcOffset(const StackMapEncoding& encoding, - InstructionSet instruction_set) const { - CodeOffset offset( - CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); + ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const { + CodeOffset offset(CodeOffset::FromCompressedOffset(Get<kNativePcOffset>())); return offset.Uint32Value(instruction_set); } - ALWAYS_INLINE void SetNativePcCodeOffset(const StackMapEncoding& encoding, - CodeOffset native_pc_offset) { - encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); - } - - ALWAYS_INLINE uint32_t GetDexRegisterMapOffset(const StackMapEncoding& encoding) const { - return encoding.GetDexRegisterMapEncoding().Load(region_); - } - - ALWAYS_INLINE void SetDexRegisterMapOffset(const StackMapEncoding& encoding, uint32_t offset) { - encoding.GetDexRegisterMapEncoding().Store(region_, offset); - } - - ALWAYS_INLINE uint32_t GetInlineInfoIndex(const StackMapEncoding& encoding) const { - return encoding.GetInlineInfoEncoding().Load(region_); - } - - ALWAYS_INLINE void SetInlineInfoIndex(const StackMapEncoding& encoding, uint32_t index) { - encoding.GetInlineInfoEncoding().Store(region_, index); - } - - ALWAYS_INLINE uint32_t GetRegisterMaskIndex(const StackMapEncoding& encoding) const { - return encoding.GetRegisterMaskIndexEncoding().Load(region_); - } - - ALWAYS_INLINE void SetRegisterMaskIndex(const StackMapEncoding& encoding, uint32_t mask) { - encoding.GetRegisterMaskIndexEncoding().Store(region_, mask); - } + uint32_t GetDexPc() const { return Get<kDexPc>(); } - ALWAYS_INLINE uint32_t GetStackMaskIndex(const StackMapEncoding& encoding) const { - return encoding.GetStackMaskIndexEncoding().Load(region_); - } + uint32_t GetDexRegisterMapOffset() const { return Get<kDexRegisterMapOffset>(); } + bool HasDexRegisterMap() const { return GetDexRegisterMapOffset() != kNoValue; } - ALWAYS_INLINE void SetStackMaskIndex(const StackMapEncoding& encoding, uint32_t mask) { - encoding.GetStackMaskIndexEncoding().Store(region_, mask); - } + uint32_t GetInlineInfoIndex() const { return Get<kInlineInfoIndex>(); } + bool HasInlineInfo() const { return GetInlineInfoIndex() != kNoValue; } - ALWAYS_INLINE bool HasDexRegisterMap(const StackMapEncoding& encoding) const { - return GetDexRegisterMapOffset(encoding) != kNoDexRegisterMap; - } + uint32_t GetRegisterMaskIndex() const { return Get<kRegisterMaskIndex>(); } - ALWAYS_INLINE bool HasInlineInfo(const StackMapEncoding& encoding) const { - return GetInlineInfoIndex(encoding) != kNoInlineInfo; - } - - ALWAYS_INLINE bool Equals(const StackMap& other) const { - return region_.pointer() == other.region_.pointer() && - region_.size() == other.region_.size() && - region_.BitOffset() == other.region_.BitOffset(); - } + uint32_t GetStackMaskIndex() const { return Get<kStackMaskIndex>(); } + static void DumpEncoding(const BitTable<6>& table, VariableIndentationOutputStream* vios); void Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, - const CodeInfoEncoding& encoding, const MethodInfo& method_info, uint32_t code_offset, uint16_t number_of_dex_registers, InstructionSet instruction_set, const std::string& header_suffix = "") const; - - // Special (invalid) offset for the DexRegisterMapOffset field meaning - // that there is no Dex register map for this stack map. - static constexpr uint32_t kNoDexRegisterMap = -1; - - // Special (invalid) offset for the InlineDescriptorOffset field meaning - // that there is no inline info for this stack map. - static constexpr uint32_t kNoInlineInfo = -1; - - private: - static constexpr int kFixedSize = 0; - - BitMemoryRegion region_; - - friend class StackMapStream; -}; - -class InlineInfoEncoding { - public: - void SetFromSizes(size_t method_index_idx_max, - size_t dex_pc_max, - size_t extra_data_max, - size_t dex_register_map_size) { - total_bit_size_ = kMethodIndexBitOffset; - total_bit_size_ += MinimumBitsToStore(method_index_idx_max); - - dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); - // Note: We're not encoding the dex pc if there is none. That's the case - // for an intrinsified native method, such as String.charAt(). - if (dex_pc_max != dex::kDexNoIndex) { - total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max); - } - - extra_data_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); - total_bit_size_ += MinimumBitsToStore(extra_data_max); - - // We also need +1 for kNoDexRegisterMap, but since the size is strictly - // greater than any offset we might try to encode, we already implicitly have it. - dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_); - total_bit_size_ += MinimumBitsToStore(dex_register_map_size); - } - - ALWAYS_INLINE FieldEncoding GetMethodIndexIdxEncoding() const { - return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_); - } - ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const { - return FieldEncoding(dex_pc_bit_offset_, extra_data_bit_offset_, -1 /* min_value */); - } - ALWAYS_INLINE FieldEncoding GetExtraDataEncoding() const { - return FieldEncoding(extra_data_bit_offset_, dex_register_map_bit_offset_); - } - ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const { - return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */); - } - ALWAYS_INLINE size_t BitSize() const { - return total_bit_size_; - } - - void Dump(VariableIndentationOutputStream* vios) const; - - // Encode the encoding into the vector. - template<typename Vector> - void Encode(Vector* dest) const { - static_assert(alignof(InlineInfoEncoding) == 1, "Should not require alignment"); - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); - dest->insert(dest->end(), ptr, ptr + sizeof(*this)); - } - - // Decode the encoding from a pointer, updates the pointer. - void Decode(const uint8_t** ptr) { - *this = *reinterpret_cast<const InlineInfoEncoding*>(*ptr); - *ptr += sizeof(*this); - } - - private: - static constexpr uint8_t kIsLastBitOffset = 0; - static constexpr uint8_t kMethodIndexBitOffset = 1; - uint8_t dex_pc_bit_offset_; - uint8_t extra_data_bit_offset_; - uint8_t dex_register_map_bit_offset_; - uint8_t total_bit_size_; }; /** - * Inline information for a specific PC. The information is of the form: - * - * [is_last, - * method_index (or ArtMethod high bits), - * dex_pc, - * extra_data (ArtMethod low bits or 1), - * dex_register_map_offset]+. + * Inline information for a specific PC. + * The row referenced from the StackMap holds information at depth 0. + * Following rows hold information for further depths. */ -class InlineInfo { +class InlineInfo : public BitTable<5>::Accessor { public: - explicit InlineInfo(BitMemoryRegion region) : region_(region) {} - - ALWAYS_INLINE uint32_t GetDepth(const InlineInfoEncoding& encoding) const { - size_t depth = 0; - while (!GetRegionAtDepth(encoding, depth++).LoadBit(0)) { } // Check is_last bit. - return depth; - } - - ALWAYS_INLINE void SetDepth(const InlineInfoEncoding& encoding, uint32_t depth) { - DCHECK_GT(depth, 0u); - for (size_t d = 0; d < depth; ++d) { - GetRegionAtDepth(encoding, d).StoreBit(0, d == depth - 1); // Set is_last bit. - } - } + enum Field { + kIsLast, // Determines if there are further rows for further depths. + kMethodIndexIdx, // Method index or ArtMethod high bits. + kDexPc, + kExtraData, // ArtMethod low bits or 1. + kDexRegisterMapOffset, + kCount, + }; + static constexpr uint32_t kLast = -1; + static constexpr uint32_t kMore = 0; - ALWAYS_INLINE uint32_t GetMethodIndexIdxAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - DCHECK(!EncodesArtMethodAtDepth(encoding, depth)); - return encoding.GetMethodIndexIdxEncoding().Load(GetRegionAtDepth(encoding, depth)); - } + InlineInfo(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} - ALWAYS_INLINE void SetMethodIndexIdxAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth, - uint32_t index) { - encoding.GetMethodIndexIdxEncoding().Store(GetRegionAtDepth(encoding, depth), index); + ALWAYS_INLINE InlineInfo AtDepth(uint32_t depth) const { + return InlineInfo(table_, this->row_ + depth); } - - ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding, - const MethodInfo& method_info, - uint32_t depth) const { - return method_info.GetMethodIndex(GetMethodIndexIdxAtDepth(encoding, depth)); + uint32_t GetDepth() const { + size_t depth = 0; + while (AtDepth(depth++).Get<kIsLast>() == kMore) { } + return depth; } - ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth)); + uint32_t GetMethodIndexIdxAtDepth(uint32_t depth) const { + DCHECK(!EncodesArtMethodAtDepth(depth)); + return AtDepth(depth).Get<kMethodIndexIdx>(); } - ALWAYS_INLINE void SetDexPcAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth, - uint32_t dex_pc) { - encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc); + uint32_t GetMethodIndexAtDepth(const MethodInfo& method_info, uint32_t depth) const { + return method_info.GetMethodIndex(GetMethodIndexIdxAtDepth(depth)); } - ALWAYS_INLINE bool EncodesArtMethodAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - return (encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)) & 1) == 0; + uint32_t GetDexPcAtDepth(uint32_t depth) const { + return AtDepth(depth).Get<kDexPc>(); } - ALWAYS_INLINE void SetExtraDataAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth, - uint32_t extra_data) { - encoding.GetExtraDataEncoding().Store(GetRegionAtDepth(encoding, depth), extra_data); + bool EncodesArtMethodAtDepth(uint32_t depth) const { + return (AtDepth(depth).Get<kExtraData>() & 1) == 0; } - ALWAYS_INLINE ArtMethod* GetArtMethodAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - uint32_t low_bits = encoding.GetExtraDataEncoding().Load(GetRegionAtDepth(encoding, depth)); - uint32_t high_bits = encoding.GetMethodIndexIdxEncoding().Load( - GetRegionAtDepth(encoding, depth)); + ArtMethod* GetArtMethodAtDepth(uint32_t depth) const { + uint32_t low_bits = AtDepth(depth).Get<kExtraData>(); + uint32_t high_bits = AtDepth(depth).Get<kMethodIndexIdx>(); if (high_bits == 0) { return reinterpret_cast<ArtMethod*>(low_bits); } else { @@ -1045,411 +758,132 @@ class InlineInfo { } } - ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth)); - } - - ALWAYS_INLINE void SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth, - uint32_t offset) { - encoding.GetDexRegisterMapEncoding().Store(GetRegionAtDepth(encoding, depth), offset); + uint32_t GetDexRegisterMapOffsetAtDepth(uint32_t depth) const { + return AtDepth(depth).Get<kDexRegisterMapOffset>(); } - ALWAYS_INLINE bool HasDexRegisterMapAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - return GetDexRegisterMapOffsetAtDepth(encoding, depth) != StackMap::kNoDexRegisterMap; + bool HasDexRegisterMapAtDepth(uint32_t depth) const { + return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoValue; } + static void DumpEncoding(const BitTable<5>& table, VariableIndentationOutputStream* vios); void Dump(VariableIndentationOutputStream* vios, const CodeInfo& info, const MethodInfo& method_info, uint16_t* number_of_dex_registers) const; - - private: - ALWAYS_INLINE BitMemoryRegion GetRegionAtDepth(const InlineInfoEncoding& encoding, - uint32_t depth) const { - size_t entry_size = encoding.BitSize(); - DCHECK_GT(entry_size, 0u); - return region_.Subregion(depth * entry_size, entry_size); - } - - BitMemoryRegion region_; }; -// Bit sized region encoding, may be more than 255 bits. -class BitRegionEncoding { +class InvokeInfo : public BitTable<3>::Accessor { public: - uint32_t num_bits = 0; - - ALWAYS_INLINE size_t BitSize() const { - return num_bits; - } - - template<typename Vector> - void Encode(Vector* dest) const { - EncodeUnsignedLeb128(dest, num_bits); // Use leb in case num_bits is greater than 255. - } - - void Decode(const uint8_t** ptr) { - num_bits = DecodeUnsignedLeb128(ptr); - } -}; - -// A table of bit sized encodings. -template <typename Encoding> -struct BitEncodingTable { - static constexpr size_t kInvalidOffset = static_cast<size_t>(-1); - // How the encoding is laid out (serialized). - Encoding encoding; - - // Number of entries in the table (serialized). - size_t num_entries; - - // Bit offset for the base of the table (computed). - size_t bit_offset = kInvalidOffset; - - template<typename Vector> - void Encode(Vector* dest) const { - EncodeUnsignedLeb128(dest, num_entries); - encoding.Encode(dest); - } - - ALWAYS_INLINE void Decode(const uint8_t** ptr) { - num_entries = DecodeUnsignedLeb128(ptr); - encoding.Decode(ptr); - } - - // Set the bit offset in the table and adds the space used by the table to offset. - void UpdateBitOffset(size_t* offset) { - DCHECK(offset != nullptr); - bit_offset = *offset; - *offset += encoding.BitSize() * num_entries; - } - - // Return the bit region for the map at index i. - ALWAYS_INLINE BitMemoryRegion BitRegion(MemoryRegion region, size_t index) const { - DCHECK_NE(bit_offset, kInvalidOffset) << "Invalid table offset"; - DCHECK_LT(index, num_entries); - const size_t map_size = encoding.BitSize(); - return BitMemoryRegion(region, bit_offset + index * map_size, map_size); - } -}; - -// A byte sized table of possible variable sized encodings. -struct ByteSizedTable { - static constexpr size_t kInvalidOffset = static_cast<size_t>(-1); - - // Number of entries in the table (serialized). - size_t num_entries = 0; - - // Number of bytes of the table (serialized). - size_t num_bytes; - - // Bit offset for the base of the table (computed). - size_t byte_offset = kInvalidOffset; - - template<typename Vector> - void Encode(Vector* dest) const { - EncodeUnsignedLeb128(dest, num_entries); - EncodeUnsignedLeb128(dest, num_bytes); - } - - ALWAYS_INLINE void Decode(const uint8_t** ptr) { - num_entries = DecodeUnsignedLeb128(ptr); - num_bytes = DecodeUnsignedLeb128(ptr); - } - - // Set the bit offset of the table. Adds the total bit size of the table to offset. - void UpdateBitOffset(size_t* offset) { - DCHECK(offset != nullptr); - DCHECK_ALIGNED(*offset, kBitsPerByte); - byte_offset = *offset / kBitsPerByte; - *offset += num_bytes * kBitsPerByte; - } -}; - -// Format is [native pc, invoke type, method index]. -class InvokeInfoEncoding { - public: - void SetFromSizes(size_t native_pc_max, - size_t invoke_type_max, - size_t method_index_max) { - total_bit_size_ = 0; - DCHECK_EQ(kNativePcBitOffset, total_bit_size_); - total_bit_size_ += MinimumBitsToStore(native_pc_max); - invoke_type_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(invoke_type_max); - method_index_bit_offset_ = total_bit_size_; - total_bit_size_ += MinimumBitsToStore(method_index_max); - } - - ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { - return FieldEncoding(kNativePcBitOffset, invoke_type_bit_offset_); - } - - ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const { - return FieldEncoding(invoke_type_bit_offset_, method_index_bit_offset_); - } - - ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const { - return FieldEncoding(method_index_bit_offset_, total_bit_size_); - } - - ALWAYS_INLINE size_t BitSize() const { - return total_bit_size_; - } - - template<typename Vector> - void Encode(Vector* dest) const { - static_assert(alignof(InvokeInfoEncoding) == 1, "Should not require alignment"); - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(this); - dest->insert(dest->end(), ptr, ptr + sizeof(*this)); - } - - void Decode(const uint8_t** ptr) { - *this = *reinterpret_cast<const InvokeInfoEncoding*>(*ptr); - *ptr += sizeof(*this); - } - - private: - static constexpr uint8_t kNativePcBitOffset = 0; - uint8_t invoke_type_bit_offset_; - uint8_t method_index_bit_offset_; - uint8_t total_bit_size_; -}; + enum Field { + kNativePcOffset, + kInvokeType, + kMethodIndexIdx, + kCount, + }; -class InvokeInfo { - public: - explicit InvokeInfo(BitMemoryRegion region) : region_(region) {} + InvokeInfo(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} - ALWAYS_INLINE uint32_t GetNativePcOffset(const InvokeInfoEncoding& encoding, - InstructionSet instruction_set) const { - CodeOffset offset( - CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); + ALWAYS_INLINE uint32_t GetNativePcOffset(InstructionSet instruction_set) const { + CodeOffset offset(CodeOffset::FromCompressedOffset(Get<kNativePcOffset>())); return offset.Uint32Value(instruction_set); } - ALWAYS_INLINE void SetNativePcCodeOffset(const InvokeInfoEncoding& encoding, - CodeOffset native_pc_offset) { - encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); - } - - ALWAYS_INLINE uint32_t GetInvokeType(const InvokeInfoEncoding& encoding) const { - return encoding.GetInvokeTypeEncoding().Load(region_); - } - - ALWAYS_INLINE void SetInvokeType(const InvokeInfoEncoding& encoding, uint32_t invoke_type) { - encoding.GetInvokeTypeEncoding().Store(region_, invoke_type); - } - - ALWAYS_INLINE uint32_t GetMethodIndexIdx(const InvokeInfoEncoding& encoding) const { - return encoding.GetMethodIndexEncoding().Load(region_); - } - - ALWAYS_INLINE void SetMethodIndexIdx(const InvokeInfoEncoding& encoding, - uint32_t method_index_idx) { - encoding.GetMethodIndexEncoding().Store(region_, method_index_idx); - } - - ALWAYS_INLINE uint32_t GetMethodIndex(const InvokeInfoEncoding& encoding, - MethodInfo method_info) const { - return method_info.GetMethodIndex(GetMethodIndexIdx(encoding)); - } - - bool IsValid() const { return region_.pointer() != nullptr; } - - private: - BitMemoryRegion region_; -}; - -// Most of the fields are encoded as ULEB128 to save space. -struct CodeInfoEncoding { - using SizeType = uint32_t; - - static constexpr SizeType kInvalidSize = std::numeric_limits<SizeType>::max(); - - // Byte sized tables go first to avoid unnecessary alignment bits. - ByteSizedTable dex_register_map; - ByteSizedTable location_catalog; - BitEncodingTable<StackMapEncoding> stack_map; - BitEncodingTable<BitRegionEncoding> register_mask; - BitEncodingTable<BitRegionEncoding> stack_mask; - BitEncodingTable<InvokeInfoEncoding> invoke_info; - BitEncodingTable<InlineInfoEncoding> inline_info; - - CodeInfoEncoding() {} - - explicit CodeInfoEncoding(const void* data) { - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data); - dex_register_map.Decode(&ptr); - location_catalog.Decode(&ptr); - stack_map.Decode(&ptr); - register_mask.Decode(&ptr); - stack_mask.Decode(&ptr); - invoke_info.Decode(&ptr); - if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { - inline_info.Decode(&ptr); - } else { - inline_info = BitEncodingTable<InlineInfoEncoding>(); - } - cache_header_size = - dchecked_integral_cast<SizeType>(ptr - reinterpret_cast<const uint8_t*>(data)); - ComputeTableOffsets(); - } - - // Compress is not const since it calculates cache_header_size. This is used by PrepareForFillIn. - template<typename Vector> - void Compress(Vector* dest) { - dex_register_map.Encode(dest); - location_catalog.Encode(dest); - stack_map.Encode(dest); - register_mask.Encode(dest); - stack_mask.Encode(dest); - invoke_info.Encode(dest); - if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { - inline_info.Encode(dest); - } - cache_header_size = dest->size(); - } - - ALWAYS_INLINE void ComputeTableOffsets() { - // Skip the header. - size_t bit_offset = HeaderSize() * kBitsPerByte; - // The byte tables must be aligned so they must go first. - dex_register_map.UpdateBitOffset(&bit_offset); - location_catalog.UpdateBitOffset(&bit_offset); - // Other tables don't require alignment. - stack_map.UpdateBitOffset(&bit_offset); - register_mask.UpdateBitOffset(&bit_offset); - stack_mask.UpdateBitOffset(&bit_offset); - invoke_info.UpdateBitOffset(&bit_offset); - inline_info.UpdateBitOffset(&bit_offset); - cache_non_header_size = RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte - HeaderSize(); - } + uint32_t GetInvokeType() const { return Get<kInvokeType>(); } - ALWAYS_INLINE size_t HeaderSize() const { - DCHECK_NE(cache_header_size, kInvalidSize) << "Uninitialized"; - return cache_header_size; - } + uint32_t GetMethodIndexIdx() const { return Get<kMethodIndexIdx>(); } - ALWAYS_INLINE size_t NonHeaderSize() const { - DCHECK_NE(cache_non_header_size, kInvalidSize) << "Uninitialized"; - return cache_non_header_size; + uint32_t GetMethodIndex(MethodInfo method_info) const { + return method_info.GetMethodIndex(GetMethodIndexIdx()); } - - private: - // Computed fields (not serialized). - // Header size in bytes, cached to avoid needing to re-decoding the encoding in HeaderSize. - SizeType cache_header_size = kInvalidSize; - // Non header size in bytes, cached to avoid needing to re-decoding the encoding in NonHeaderSize. - SizeType cache_non_header_size = kInvalidSize; }; /** * Wrapper around all compiler information collected for a method. * The information is of the form: * - * [CodeInfoEncoding, DexRegisterMap+, DexLocationCatalog+, StackMap+, RegisterMask+, StackMask+, - * InlineInfo*] - * - * where CodeInfoEncoding is of the form: + * [BitTable<Header>, BitTable<StackMap>, BitTable<RegisterMask>, BitTable<InlineInfo>, + * BitTable<InvokeInfo>, BitTable<StackMask>, DexRegisterMap, DexLocationCatalog] * - * [ByteSizedTable(dex_register_map), ByteSizedTable(location_catalog), - * BitEncodingTable<StackMapEncoding>, BitEncodingTable<BitRegionEncoding>, - * BitEncodingTable<BitRegionEncoding>, BitEncodingTable<InlineInfoEncoding>] */ class CodeInfo { public: - explicit CodeInfo(MemoryRegion region) : region_(region) { - } - explicit CodeInfo(const void* data) { - CodeInfoEncoding encoding = CodeInfoEncoding(data); - region_ = MemoryRegion(const_cast<void*>(data), - encoding.HeaderSize() + encoding.NonHeaderSize()); + Decode(reinterpret_cast<const uint8_t*>(data)); } - CodeInfoEncoding ExtractEncoding() const { - CodeInfoEncoding encoding(region_.begin()); - AssertValidStackMap(encoding); - return encoding; + explicit CodeInfo(MemoryRegion region) : CodeInfo(region.begin()) { + DCHECK_EQ(size_, region.size()); } - bool HasInlineInfo(const CodeInfoEncoding& encoding) const { - return encoding.stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0; + explicit CodeInfo(const OatQuickMethodHeader* header) + : CodeInfo(header->GetOptimizedCodeInfoPtr()) { } - DexRegisterLocationCatalog GetDexRegisterLocationCatalog(const CodeInfoEncoding& encoding) const { - return DexRegisterLocationCatalog(region_.Subregion(encoding.location_catalog.byte_offset, - encoding.location_catalog.num_bytes)); + size_t Size() const { + return size_; } - ALWAYS_INLINE size_t GetNumberOfStackMaskBits(const CodeInfoEncoding& encoding) const { - return encoding.stack_mask.encoding.BitSize(); + bool HasInlineInfo() const { + return stack_maps_.NumColumnBits(StackMap::kInlineInfoIndex) != 0; } - ALWAYS_INLINE StackMap GetStackMapAt(size_t index, const CodeInfoEncoding& encoding) const { - return StackMap(encoding.stack_map.BitRegion(region_, index)); + DexRegisterLocationCatalog GetDexRegisterLocationCatalog() const { + return DexRegisterLocationCatalog(location_catalog_); } - BitMemoryRegion GetStackMask(size_t index, const CodeInfoEncoding& encoding) const { - return encoding.stack_mask.BitRegion(region_, index); + ALWAYS_INLINE size_t GetNumberOfStackMaskBits() const { + return stack_mask_bits_; } - BitMemoryRegion GetStackMaskOf(const CodeInfoEncoding& encoding, - const StackMap& stack_map) const { - return GetStackMask(stack_map.GetStackMaskIndex(encoding.stack_map.encoding), encoding); + ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const { + return StackMap(&stack_maps_, index); } - BitMemoryRegion GetRegisterMask(size_t index, const CodeInfoEncoding& encoding) const { - return encoding.register_mask.BitRegion(region_, index); + BitMemoryRegion GetStackMask(size_t index) const { + return stack_masks_.Subregion(index * stack_mask_bits_, stack_mask_bits_); } - uint32_t GetRegisterMaskOf(const CodeInfoEncoding& encoding, const StackMap& stack_map) const { - size_t index = stack_map.GetRegisterMaskIndex(encoding.stack_map.encoding); - return GetRegisterMask(index, encoding).LoadBits(0u, encoding.register_mask.encoding.BitSize()); + BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const { + return GetStackMask(stack_map.GetStackMaskIndex()); } - uint32_t GetNumberOfLocationCatalogEntries(const CodeInfoEncoding& encoding) const { - return encoding.location_catalog.num_entries; + uint32_t GetRegisterMaskOf(const StackMap& stack_map) const { + return register_masks_.Get(stack_map.GetRegisterMaskIndex()); } - uint32_t GetDexRegisterLocationCatalogSize(const CodeInfoEncoding& encoding) const { - return encoding.location_catalog.num_bytes; + uint32_t GetNumberOfLocationCatalogEntries() const { + return location_catalog_entries_; } - uint32_t GetNumberOfStackMaps(const CodeInfoEncoding& encoding) const { - return encoding.stack_map.num_entries; + uint32_t GetDexRegisterLocationCatalogSize() const { + return location_catalog_.size(); } - // Get the size of all the stack maps of this CodeInfo object, in bits. Not byte aligned. - ALWAYS_INLINE size_t GetStackMapsSizeInBits(const CodeInfoEncoding& encoding) const { - return encoding.stack_map.encoding.BitSize() * GetNumberOfStackMaps(encoding); + uint32_t GetNumberOfStackMaps() const { + return stack_maps_.NumRows(); } - InvokeInfo GetInvokeInfo(const CodeInfoEncoding& encoding, size_t index) const { - return InvokeInfo(encoding.invoke_info.BitRegion(region_, index)); + InvokeInfo GetInvokeInfo(size_t index) const { + return InvokeInfo(&invoke_infos_, index); } DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, - const CodeInfoEncoding& encoding, size_t number_of_dex_registers) const { - if (!stack_map.HasDexRegisterMap(encoding.stack_map.encoding)) { + if (!stack_map.HasDexRegisterMap()) { return DexRegisterMap(); } - const uint32_t offset = encoding.dex_register_map.byte_offset + - stack_map.GetDexRegisterMapOffset(encoding.stack_map.encoding); - size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers); - return DexRegisterMap(region_.Subregion(offset, size)); + const uint32_t offset = stack_map.GetDexRegisterMapOffset(); + size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers); + return DexRegisterMap(dex_register_maps_.Subregion(offset, size)); } - size_t GetDexRegisterMapsSize(const CodeInfoEncoding& encoding, - uint32_t number_of_dex_registers) const { + size_t GetDexRegisterMapsSize(uint32_t number_of_dex_registers) const { size_t total = 0; - for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { - StackMap stack_map = GetStackMapAt(i, encoding); - DexRegisterMap map(GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers)); + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { + StackMap stack_map = GetStackMapAt(i); + DexRegisterMap map(GetDexRegisterMapOf(stack_map, number_of_dex_registers)); total += map.Size(); } return total; @@ -1458,38 +892,30 @@ class CodeInfo { // Return the `DexRegisterMap` pointed by `inline_info` at depth `depth`. DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, InlineInfo inline_info, - const CodeInfoEncoding& encoding, uint32_t number_of_dex_registers) const { - if (!inline_info.HasDexRegisterMapAtDepth(encoding.inline_info.encoding, depth)) { + if (!inline_info.HasDexRegisterMapAtDepth(depth)) { return DexRegisterMap(); } else { - uint32_t offset = encoding.dex_register_map.byte_offset + - inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info.encoding, depth); - size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers); - return DexRegisterMap(region_.Subregion(offset, size)); + uint32_t offset = inline_info.GetDexRegisterMapOffsetAtDepth(depth); + size_t size = ComputeDexRegisterMapSizeOf(offset, number_of_dex_registers); + return DexRegisterMap(dex_register_maps_.Subregion(offset, size)); } } - InlineInfo GetInlineInfo(size_t index, const CodeInfoEncoding& encoding) const { - // Since we do not know the depth, we just return the whole remaining map. The caller may - // access the inline info for arbitrary depths. To return the precise inline info we would need - // to count the depth before returning. - // TODO: Clean this up. - const size_t bit_offset = encoding.inline_info.bit_offset + - index * encoding.inline_info.encoding.BitSize(); - return InlineInfo(BitMemoryRegion(region_, bit_offset, region_.size_in_bits() - bit_offset)); + InlineInfo GetInlineInfo(size_t index) const { + return InlineInfo(&inline_infos_, index); } - InlineInfo GetInlineInfoOf(StackMap stack_map, const CodeInfoEncoding& encoding) const { - DCHECK(stack_map.HasInlineInfo(encoding.stack_map.encoding)); - uint32_t index = stack_map.GetInlineInfoIndex(encoding.stack_map.encoding); - return GetInlineInfo(index, encoding); + InlineInfo GetInlineInfoOf(StackMap stack_map) const { + DCHECK(stack_map.HasInlineInfo()); + uint32_t index = stack_map.GetInlineInfoIndex(); + return GetInlineInfo(index); } - StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { - for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { - StackMap stack_map = GetStackMapAt(i, encoding); - if (stack_map.GetDexPc(encoding.stack_map.encoding) == dex_pc) { + StackMap GetStackMapForDexPc(uint32_t dex_pc) const { + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { + StackMap stack_map = GetStackMapAt(i); + if (stack_map.GetDexPc() == dex_pc) { return stack_map; } } @@ -1498,40 +924,39 @@ class CodeInfo { // Searches the stack map list backwards because catch stack maps are stored // at the end. - StackMap GetCatchStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { - for (size_t i = GetNumberOfStackMaps(encoding); i > 0; --i) { - StackMap stack_map = GetStackMapAt(i - 1, encoding); - if (stack_map.GetDexPc(encoding.stack_map.encoding) == dex_pc) { + StackMap GetCatchStackMapForDexPc(uint32_t dex_pc) const { + for (size_t i = GetNumberOfStackMaps(); i > 0; --i) { + StackMap stack_map = GetStackMapAt(i - 1); + if (stack_map.GetDexPc() == dex_pc) { return stack_map; } } return StackMap(); } - StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const { - size_t e = GetNumberOfStackMaps(encoding); + StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const { + size_t e = GetNumberOfStackMaps(); if (e == 0) { // There cannot be OSR stack map if there is no stack map. return StackMap(); } // Walk over all stack maps. If two consecutive stack maps are identical, then we // have found a stack map suitable for OSR. - const StackMapEncoding& stack_map_encoding = encoding.stack_map.encoding; for (size_t i = 0; i < e - 1; ++i) { - StackMap stack_map = GetStackMapAt(i, encoding); - if (stack_map.GetDexPc(stack_map_encoding) == dex_pc) { - StackMap other = GetStackMapAt(i + 1, encoding); - if (other.GetDexPc(stack_map_encoding) == dex_pc && - other.GetNativePcOffset(stack_map_encoding, kRuntimeISA) == - stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA)) { - DCHECK_EQ(other.GetDexRegisterMapOffset(stack_map_encoding), - stack_map.GetDexRegisterMapOffset(stack_map_encoding)); - DCHECK(!stack_map.HasInlineInfo(stack_map_encoding)); + StackMap stack_map = GetStackMapAt(i); + if (stack_map.GetDexPc() == dex_pc) { + StackMap other = GetStackMapAt(i + 1); + if (other.GetDexPc() == dex_pc && + other.GetNativePcOffset(kRuntimeISA) == + stack_map.GetNativePcOffset(kRuntimeISA)) { + DCHECK_EQ(other.GetDexRegisterMapOffset(), + stack_map.GetDexRegisterMapOffset()); + DCHECK(!stack_map.HasInlineInfo()); if (i < e - 2) { // Make sure there are not three identical stack maps following each other. DCHECK_NE( - stack_map.GetNativePcOffset(stack_map_encoding, kRuntimeISA), - GetStackMapAt(i + 2, encoding).GetNativePcOffset(stack_map_encoding, kRuntimeISA)); + stack_map.GetNativePcOffset(kRuntimeISA), + GetStackMapAt(i + 2).GetNativePcOffset(kRuntimeISA)); } return stack_map; } @@ -1540,30 +965,27 @@ class CodeInfo { return StackMap(); } - StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset, - const CodeInfoEncoding& encoding) const { + StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset) const { // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack // maps are not. If we knew that the method does not have try/catch, // we could do binary search. - for (size_t i = 0, e = GetNumberOfStackMaps(encoding); i < e; ++i) { - StackMap stack_map = GetStackMapAt(i, encoding); - if (stack_map.GetNativePcOffset(encoding.stack_map.encoding, kRuntimeISA) == - native_pc_offset) { + for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) { + StackMap stack_map = GetStackMapAt(i); + if (stack_map.GetNativePcOffset(kRuntimeISA) == native_pc_offset) { return stack_map; } } return StackMap(); } - InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset, - const CodeInfoEncoding& encoding) { - for (size_t index = 0; index < encoding.invoke_info.num_entries; index++) { - InvokeInfo item = GetInvokeInfo(encoding, index); - if (item.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA) == native_pc_offset) { + InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset) { + for (size_t index = 0; index < invoke_infos_.NumRows(); index++) { + InvokeInfo item = GetInvokeInfo(index); + if (item.GetNativePcOffset(kRuntimeISA) == native_pc_offset) { return item; } } - return InvokeInfo(BitMemoryRegion()); + return InvokeInfo(&invoke_infos_, -1); } // Dump this CodeInfo object on `os`. `code_offset` is the (absolute) @@ -1578,23 +1000,10 @@ class CodeInfo { InstructionSet instruction_set, const MethodInfo& method_info) const; - // Check that the code info has valid stack map and abort if it does not. - void AssertValidStackMap(const CodeInfoEncoding& encoding) const { - if (region_.size() != 0 && region_.size_in_bits() < GetStackMapsSizeInBits(encoding)) { - LOG(FATAL) << region_.size() << "\n" - << encoding.HeaderSize() << "\n" - << encoding.NonHeaderSize() << "\n" - << encoding.location_catalog.num_entries << "\n" - << encoding.stack_map.num_entries << "\n" - << encoding.stack_map.encoding.BitSize(); - } - } - private: // Compute the size of the Dex register map associated to the stack map at // `dex_register_map_offset_in_code_info`. - size_t ComputeDexRegisterMapSizeOf(const CodeInfoEncoding& encoding, - uint32_t dex_register_map_offset_in_code_info, + size_t ComputeDexRegisterMapSizeOf(uint32_t dex_register_map_offset, uint16_t number_of_dex_registers) const { // Offset where the actual mapping data starts within art::DexRegisterMap. size_t location_mapping_data_offset_in_dex_register_map = @@ -1602,12 +1011,12 @@ class CodeInfo { // Create a temporary art::DexRegisterMap to be able to call // art::DexRegisterMap::GetNumberOfLiveDexRegisters and DexRegisterMap dex_register_map_without_locations( - MemoryRegion(region_.Subregion(dex_register_map_offset_in_code_info, - location_mapping_data_offset_in_dex_register_map))); + MemoryRegion(dex_register_maps_.Subregion(dex_register_map_offset, + location_mapping_data_offset_in_dex_register_map))); size_t number_of_live_dex_registers = dex_register_map_without_locations.GetNumberOfLiveDexRegisters(number_of_dex_registers); size_t location_mapping_data_size_in_bits = - DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries(encoding)) + DexRegisterMap::SingleEntrySizeInBits(GetNumberOfLocationCatalogEntries()) * number_of_live_dex_registers; size_t location_mapping_data_size_in_bytes = RoundUp(location_mapping_data_size_in_bits, kBitsPerByte) / kBitsPerByte; @@ -1616,37 +1025,42 @@ class CodeInfo { return dex_register_map_size; } - // Compute the size of a Dex register location catalog starting at offset `origin` - // in `region_` and containing `number_of_dex_locations` entries. - size_t ComputeDexRegisterLocationCatalogSize(uint32_t origin, - uint32_t number_of_dex_locations) const { - // TODO: Ideally, we would like to use art::DexRegisterLocationCatalog::Size or - // art::DexRegisterLocationCatalog::FindLocationOffset, but the - // DexRegisterLocationCatalog is not yet built. Try to factor common code. - size_t offset = origin + DexRegisterLocationCatalog::kFixedSize; - - // Skip the first `number_of_dex_locations - 1` entries. - for (uint16_t i = 0; i < number_of_dex_locations; ++i) { - // Read the first next byte and inspect its first 3 bits to decide - // whether it is a short or a large location. - DexRegisterLocationCatalog::ShortLocation first_byte = - region_.LoadUnaligned<DexRegisterLocationCatalog::ShortLocation>(offset); - DexRegisterLocation::Kind kind = - DexRegisterLocationCatalog::ExtractKindFromShortLocation(first_byte); - if (DexRegisterLocation::IsShortLocationKind(kind)) { - // Short location. Skip the current byte. - offset += DexRegisterLocationCatalog::SingleShortEntrySize(); - } else { - // Large location. Skip the 5 next bytes. - offset += DexRegisterLocationCatalog::SingleLargeEntrySize(); - } - } - size_t size = offset - origin; - return size; - } - - MemoryRegion region_; - friend class StackMapStream; + MemoryRegion DecodeMemoryRegion(MemoryRegion& region, size_t* bit_offset) { + size_t length = DecodeVarintBits(BitMemoryRegion(region), bit_offset); + size_t offset = BitsToBytesRoundUp(*bit_offset);; + *bit_offset = (offset + length) * kBitsPerByte; + return region.Subregion(offset, length); + } + + void Decode(const uint8_t* data) { + size_t non_header_size = DecodeUnsignedLeb128(&data); + MemoryRegion region(const_cast<uint8_t*>(data), non_header_size); + BitMemoryRegion bit_region(region); + size_t bit_offset = 0; + size_ = UnsignedLeb128Size(non_header_size) + non_header_size; + dex_register_maps_ = DecodeMemoryRegion(region, &bit_offset); + location_catalog_entries_ = DecodeVarintBits(bit_region, &bit_offset); + location_catalog_ = DecodeMemoryRegion(region, &bit_offset); + stack_maps_.Decode(bit_region, &bit_offset); + invoke_infos_.Decode(bit_region, &bit_offset); + inline_infos_.Decode(bit_region, &bit_offset); + register_masks_.Decode(bit_region, &bit_offset); + stack_mask_bits_ = DecodeVarintBits(bit_region, &bit_offset); + stack_masks_ = bit_region.Subregion(bit_offset, non_header_size * kBitsPerByte - bit_offset); + } + + size_t size_; + MemoryRegion dex_register_maps_; + uint32_t location_catalog_entries_; + MemoryRegion location_catalog_; + BitTable<StackMap::Field::kCount> stack_maps_; + BitTable<InvokeInfo::Field::kCount> invoke_infos_; + BitTable<InlineInfo::Field::kCount> inline_infos_; + BitTable<1> register_masks_; + uint32_t stack_mask_bits_ = 0; + BitMemoryRegion stack_masks_; + + friend class OatDumper; }; #undef ELEMENT_BYTE_OFFSET_AFTER diff --git a/runtime/thread.cc b/runtime/thread.cc index eada24d257..81ed722fcc 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3559,16 +3559,15 @@ class ReferenceMapVisitor : public StackVisitor { StackReference<mirror::Object>* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( reinterpret_cast<uintptr_t>(cur_quick_frame)); uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); - CodeInfo code_info = method_header->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + CodeInfo code_info(method_header); + StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(map.IsValid()); - T vreg_info(m, code_info, encoding, map, visitor_); + T vreg_info(m, code_info, map, visitor_); // Visit stack entries that hold pointers. - const size_t number_of_bits = code_info.GetNumberOfStackMaskBits(encoding); - BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, map); + const size_t number_of_bits = code_info.GetNumberOfStackMaskBits(); + BitMemoryRegion stack_mask = code_info.GetStackMaskOf(map); for (size_t i = 0; i < number_of_bits; ++i) { if (stack_mask.LoadBit(i)) { StackReference<mirror::Object>* ref_addr = vreg_base + i; @@ -3583,7 +3582,7 @@ class ReferenceMapVisitor : public StackVisitor { } } // Visit callee-save registers that hold pointers. - uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, map); + uint32_t register_mask = code_info.GetRegisterMaskOf(map); for (size_t i = 0; i < BitSizeOf<uint32_t>(); ++i) { if (register_mask & (1 << i)) { mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(i)); @@ -3631,7 +3630,6 @@ class ReferenceMapVisitor : public StackVisitor { struct UndefinedVRegInfo { UndefinedVRegInfo(ArtMethod* method ATTRIBUTE_UNUSED, const CodeInfo& code_info ATTRIBUTE_UNUSED, - const CodeInfoEncoding& encoding ATTRIBUTE_UNUSED, const StackMap& map ATTRIBUTE_UNUSED, RootVisitor& _visitor) : visitor(_visitor) { @@ -3662,14 +3660,11 @@ class ReferenceMapVisitor : public StackVisitor { struct StackMapVRegInfo { StackMapVRegInfo(ArtMethod* method, const CodeInfo& _code_info, - const CodeInfoEncoding& _encoding, const StackMap& map, RootVisitor& _visitor) : number_of_dex_registers(method->DexInstructionData().RegistersSize()), code_info(_code_info), - encoding(_encoding), dex_register_map(code_info.GetDexRegisterMapOf(map, - encoding, number_of_dex_registers)), visitor(_visitor) { } @@ -3684,7 +3679,7 @@ class ReferenceMapVisitor : public StackVisitor { bool found = false; for (size_t dex_reg = 0; dex_reg != number_of_dex_registers; ++dex_reg) { DexRegisterLocation location = dex_register_map.GetDexRegisterLocation( - dex_reg, number_of_dex_registers, code_info, encoding); + dex_reg, number_of_dex_registers, code_info); if (location.GetKind() == kind && static_cast<size_t>(location.GetValue()) == index) { visitor(ref, dex_reg, stack_visitor); found = true; @@ -3718,7 +3713,6 @@ class ReferenceMapVisitor : public StackVisitor { size_t number_of_dex_registers; const CodeInfo& code_info; - const CodeInfoEncoding& encoding; DexRegisterMap dex_register_map; RootVisitor& visitor; }; diff --git a/runtime/var_handles.cc b/runtime/var_handles.cc new file mode 100644 index 0000000000..f08742fcd7 --- /dev/null +++ b/runtime/var_handles.cc @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 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 "var_handles.h" + +#include "common_throws.h" +#include "dex/dex_instruction.h" +#include "handle.h" +#include "method_handles-inl.h" +#include "mirror/method_type.h" +#include "mirror/var_handle.h" + +namespace art { + +namespace { + +bool VarHandleInvokeAccessorWithConversions(Thread* self, + ShadowFrame& shadow_frame, + Handle<mirror::VarHandle> var_handle, + Handle<mirror::MethodType> callsite_type, + const mirror::VarHandle::AccessMode access_mode, + const InstructionOperands* const operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_) { + StackHandleScope<1> hs(self); + Handle<mirror::MethodType> accessor_type(hs.NewHandle( + var_handle->GetMethodTypeForAccessMode(self, access_mode))); + const size_t num_vregs = accessor_type->NumberOfVRegs(); + const int num_params = accessor_type->GetPTypes()->GetLength(); + ShadowFrameAllocaUniquePtr accessor_frame = + CREATE_SHADOW_FRAME(num_vregs, nullptr, shadow_frame.GetMethod(), shadow_frame.GetDexPC()); + ShadowFrameGetter getter(shadow_frame, operands); + static const uint32_t kFirstDestinationReg = 0; + ShadowFrameSetter setter(accessor_frame.get(), kFirstDestinationReg); + if (!PerformConversions(self, callsite_type, accessor_type, &getter, &setter, num_params)) { + return false; + } + RangeInstructionOperands accessor_operands(kFirstDestinationReg, + kFirstDestinationReg + num_vregs); + if (!var_handle->Access(access_mode, accessor_frame.get(), &accessor_operands, result)) { + return false; + } + return ConvertReturnValue(callsite_type, accessor_type, result); +} + +} // namespace + +bool VarHandleInvokeAccessor(Thread* self, + ShadowFrame& shadow_frame, + Handle<mirror::VarHandle> var_handle, + Handle<mirror::MethodType> callsite_type, + const mirror::VarHandle::AccessMode access_mode, + const InstructionOperands* const operands, + JValue* result) { + if (var_handle.IsNull()) { + ThrowNullPointerExceptionFromDexPC(); + return false; + } + + if (!var_handle->IsAccessModeSupported(access_mode)) { + ThrowUnsupportedOperationException(); + return false; + } + + mirror::VarHandle::MatchKind match_kind = + var_handle->GetMethodTypeMatchForAccessMode(access_mode, callsite_type.Get()); + if (LIKELY(match_kind == mirror::VarHandle::MatchKind::kExact)) { + return var_handle->Access(access_mode, &shadow_frame, operands, result); + } else if (match_kind == mirror::VarHandle::MatchKind::kWithConversions) { + return VarHandleInvokeAccessorWithConversions(self, + shadow_frame, + var_handle, + callsite_type, + access_mode, + operands, + result); + } else { + DCHECK_EQ(match_kind, mirror::VarHandle::MatchKind::kNone); + ThrowWrongMethodTypeException(var_handle->PrettyDescriptorForAccessMode(access_mode), + callsite_type->PrettyDescriptor()); + return false; + } +} + +} // namespace art diff --git a/runtime/var_handles.h b/runtime/var_handles.h new file mode 100644 index 0000000000..2ff8405f03 --- /dev/null +++ b/runtime/var_handles.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 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_VAR_HANDLES_H_ +#define ART_RUNTIME_VAR_HANDLES_H_ + +#include "mirror/var_handle.h" + +namespace art { + +bool VarHandleInvokeAccessor(Thread* self, + ShadowFrame& shadow_frame, + Handle<mirror::VarHandle> var_handle, + Handle<mirror::MethodType> callsite_type, + const mirror::VarHandle::AccessMode access_mode, + const InstructionOperands* const operands, + JValue* result) + REQUIRES_SHARED(Locks::mutator_lock_); + +} // namespace art + +#endif // ART_RUNTIME_VAR_HANDLES_H_ diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 3518d2facd..91cec23dd5 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3086,7 +3086,8 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { DCHECK(HasFailures()); break; } - const uint32_t proto_idx = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); + const uint16_t vRegH = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc(); + const dex::ProtoIndex proto_idx(vRegH); const char* return_descriptor = dex_file_->GetReturnTypeDescriptor(dex_file_->GetProtoId(proto_idx)); const RegType& return_type = @@ -3117,7 +3118,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { CallSiteArrayValueIterator it(*dex_file_, dex_file_->GetCallSiteId(call_site_idx)); it.Next(); // Skip to name. it.Next(); // Skip to method type of the method handle - const uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i); + const dex::ProtoIndex proto_idx(it.GetJavaValue().c); const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(proto_idx); DexFileParameterIterator param_it(*dex_file_, proto_id); // Treat method as static as it has yet to be determined. @@ -4190,7 +4191,8 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs( if (UNLIKELY(method_type == METHOD_POLYMORPHIC)) { // Process the signature of the calling site that is invoking the method handle. - DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(inst->VRegH())); + dex::ProtoIndex proto_idx(inst->VRegH()); + DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(proto_idx)); return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method); } else { // Process the target method's signature. @@ -4208,8 +4210,6 @@ bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) { expected_return_descriptor = mirror::MethodHandle::GetReturnTypeDescriptor(method_name); } else if (klass == mirror::VarHandle::StaticClass()) { expected_return_descriptor = mirror::VarHandle::GetReturnTypeDescriptor(method_name); - // TODO: add compiler support for VarHandle accessor methods (b/71781600) - Fail(VERIFY_ERROR_FORCE_INTERPRETER); } else { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Signature polymorphic method in unsuppported class: " << klass->PrettyDescriptor(); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index b79334ac7f..f7cdf3920a 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -23,6 +23,8 @@ #include <android-base/logging.h> #include <android-base/stringprintf.h> +#include "base/enums.h" +#include "class_linker.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "hidden_api.h" #include "jni/jni_internal.h" @@ -30,6 +32,7 @@ #include "mirror/throwable.h" #include "nativehelper/scoped_local_ref.h" #include "obj_ptr-inl.h" +#include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" @@ -231,19 +234,28 @@ static jmethodID CachePrimitiveBoxingMethod(JNIEnv* env, char prim_name, const c V(java_lang_String_init_StringBuilder, "(Ljava/lang/StringBuilder;)V", newStringFromStringBuilder, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;", NewStringFromStringBuilder) \ #define STATIC_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, ...) \ - static ArtMethod* init_runtime_name; \ - static ArtMethod* new_runtime_name; + static ArtMethod* init_runtime_name = nullptr; \ + static ArtMethod* new_runtime_name = nullptr; STRING_INIT_LIST(STATIC_STRING_INIT) #undef STATIC_STRING_INIT -void WellKnownClasses::InitStringInit(JNIEnv* env) { - ScopedObjectAccess soa(Thread::Current()); - #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \ - new_java_name, new_signature, ...) \ - init_runtime_name = jni::DecodeArtMethod( \ - CacheMethod(env, java_lang_String, false, "<init>", init_signature)); \ - new_runtime_name = jni::DecodeArtMethod( \ - CacheMethod(env, java_lang_StringFactory, true, new_java_name, new_signature)); +void WellKnownClasses::InitStringInit(ObjPtr<mirror::Class> string_class, + ObjPtr<mirror::Class> string_builder_class) { + PointerSize p_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); + auto find_method = [p_size](ObjPtr<mirror::Class> klass, + const char* name, + const char* sig, + bool expext_static) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* ret = klass->FindClassMethod(name, sig, p_size); + CHECK(ret != nullptr); + CHECK_EQ(expext_static, ret->IsStatic()); + return ret; + }; + + #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \ + new_java_name, new_signature, ...) \ + init_runtime_name = find_method(string_class, "<init>", init_signature, false); \ + new_runtime_name = find_method(string_builder_class, new_java_name, new_signature, true); STRING_INIT_LIST(LOAD_STRING_INIT) #undef LOAD_STRING_INIT } @@ -252,6 +264,7 @@ void Thread::InitStringEntryPoints() { QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints; #define SET_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \ new_java_name, new_signature, entry_point_name) \ + DCHECK(!Runtime::Current()->IsStarted() || (new_runtime_name) != nullptr); \ qpoints->p ## entry_point_name = reinterpret_cast<void(*)()>(new_runtime_name); STRING_INIT_LIST(SET_ENTRY_POINT) #undef SET_ENTRY_POINT @@ -260,7 +273,9 @@ void Thread::InitStringEntryPoints() { ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) { #define TO_STRING_FACTORY(init_runtime_name, init_signature, new_runtime_name, \ new_java_name, new_signature, entry_point_name) \ + DCHECK((init_runtime_name) != nullptr); \ if (string_init == (init_runtime_name)) { \ + DCHECK((new_runtime_name) != nullptr); \ return (new_runtime_name); \ } STRING_INIT_LIST(TO_STRING_FACTORY) @@ -282,26 +297,9 @@ uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) { } #undef STRING_INIT_LIST -class ScopedHiddenApiExemption { - public: - explicit ScopedHiddenApiExemption(Runtime* runtime) - : runtime_(runtime), - initial_policy_(runtime_->GetHiddenApiEnforcementPolicy()) { - runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kNoChecks); - } - - ~ScopedHiddenApiExemption() { - runtime_->SetHiddenApiEnforcementPolicy(initial_policy_); - } - - private: - Runtime* runtime_; - const hiddenapi::EnforcementPolicy initial_policy_; - DISALLOW_COPY_AND_ASSIGN(ScopedHiddenApiExemption); -}; - void WellKnownClasses::Init(JNIEnv* env) { - ScopedHiddenApiExemption hiddenapi_exemption(Runtime::Current()); + hiddenapi::ScopedHiddenApiEnforcementPolicySetting hiddenapi_exemption( + hiddenapi::EnforcementPolicy::kNoChecks); dalvik_annotation_optimization_CriticalNative = CacheClass(env, "dalvik/annotation/optimization/CriticalNative"); @@ -427,9 +425,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Integer_valueOf = CachePrimitiveBoxingMethod(env, 'I', "java/lang/Integer"); java_lang_Long_valueOf = CachePrimitiveBoxingMethod(env, 'J', "java/lang/Long"); java_lang_Short_valueOf = CachePrimitiveBoxingMethod(env, 'S', "java/lang/Short"); - - InitStringInit(env); - Thread::Current()->InitStringEntryPoints(); } void WellKnownClasses::LateInit(JNIEnv* env) { diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 25c07b27de..c06e4a71ce 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -40,6 +40,9 @@ struct WellKnownClasses { static void Clear(); + static void InitStringInit(ObjPtr<mirror::Class> string_class, + ObjPtr<mirror::Class> string_builder_class) + REQUIRES_SHARED(Locks::mutator_lock_); static ArtMethod* StringInitToStringFactory(ArtMethod* method); static uint32_t StringInitToEntryPoint(ArtMethod* method); @@ -168,9 +171,6 @@ struct WellKnownClasses { static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset; static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_type; - - private: - static void InitStringInit(JNIEnv* env); }; } // namespace art diff --git a/simulator/Android.bp b/simulator/Android.bp index 74b5a900b4..8690426466 100644 --- a/simulator/Android.bp +++ b/simulator/Android.bp @@ -44,6 +44,7 @@ art_cc_library { defaults: ["libart_simulator_defaults"], shared_libs: [ "libart", + "libartbase", "libvixl-arm64", ], } @@ -56,6 +57,7 @@ art_cc_library { ], shared_libs: [ "libartd", + "libartbased", "libvixld-arm64", ], } @@ -80,6 +82,7 @@ art_cc_library { name: "libart-simulator-container", defaults: ["libart_simulator_container_defaults"], shared_libs: [ + "libartbase", "libart", ], } @@ -91,6 +94,7 @@ art_cc_library { "libart_simulator_container_defaults", ], shared_libs: [ + "libartbased", "libartd", ], } diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 6a9bf61d25..2b57824464 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -33,7 +33,7 @@ z (class java.lang.Character) 14 (class java.lang.Short) [java.lang.String(int,int,char[]), public java.lang.String(), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder)] [private final int java.lang.String.count, private int java.lang.String.hash, private static final java.io.ObjectStreamField[] java.lang.String.serialPersistentFields, private static final long java.lang.String.serialVersionUID, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER] -[native void java.lang.String.getCharsNoCheck(int,int,char[],int), private boolean java.lang.String.nonSyncContentEquals(java.lang.AbstractStringBuilder), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private native java.lang.String java.lang.String.doReplace(char,char), private native java.lang.String java.lang.String.fastSubstring(int,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public byte[] java.lang.String.getBytes(), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public native char java.lang.String.charAt(int), public native char[] java.lang.String.toCharArray(), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(java.lang.String,java.lang.String,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), static int java.lang.String.lastIndexOf(java.lang.String,java.lang.String,int), void java.lang.String.getChars(char[],int)] +[native void java.lang.String.getCharsNoCheck(int,int,char[],int), private boolean java.lang.String.nonSyncContentEquals(java.lang.AbstractStringBuilder), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private native java.lang.String java.lang.String.doReplace(char,char), private native java.lang.String java.lang.String.fastSubstring(int,int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int), private static int java.lang.String.lastIndexOf(java.lang.String,java.lang.String,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public byte[] java.lang.String.getBytes(), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public native char java.lang.String.charAt(int), public native char[] java.lang.String.toCharArray(), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.CharSequence[]), public static java.lang.String java.lang.String.join(java.lang.CharSequence,java.lang.Iterable), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(char[],int,int,java.lang.String,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), static int java.lang.String.lastIndexOf(char[],int,int,java.lang.String,int), void java.lang.String.getChars(char[],int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] 0 diff --git a/test/563-checker-fakestring/smali/TestCase.smali b/test/563-checker-fakestring/smali/TestCase.smali index adafb78bd7..8898c48ea1 100644 --- a/test/563-checker-fakestring/smali/TestCase.smali +++ b/test/563-checker-fakestring/smali/TestCase.smali @@ -133,17 +133,8 @@ .end method -# Test that the compiler does not assume that the first argument of String.<init> -# is a NewInstance by inserting an irreducible loop between them (b/26676472). - -# We verify the type of the input instruction (Phi) in debuggable mode, because -# it is eliminated by later stages of SsaBuilder otherwise. - -## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance1(byte[], boolean) register (after) -## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}} -## CHECK-DAG: <<Phi>> Phi - -.method public static thisNotNewInstance1([BZ)Ljava/lang/String; +# Test #1 for irreducible loops and String.<init>. +.method public static irreducibleLoopAndStringInit1([BZ)Ljava/lang/String; .registers 5 new-instance v0, Ljava/lang/String; @@ -164,11 +155,8 @@ .end method -## CHECK-START-DEBUGGABLE: java.lang.String TestCase.thisNotNewInstance2(byte[], boolean) register (after) -## CHECK-DAG: InvokeStaticOrDirect env:[[<<Phi:l\d+>>,{{.*]]}} -## CHECK-DAG: <<Phi>> Phi - -.method public static thisNotNewInstance2([BZ)Ljava/lang/String; +# Test #2 for irreducible loops and String.<init>. +.method public static irreducibleLoopAndStringInit2([BZ)Ljava/lang/String; .registers 5 new-instance v0, Ljava/lang/String; @@ -188,3 +176,26 @@ return-object v0 .end method + +# Test #3 for irreducible loops and String.<init> alias. +.method public static irreducibleLoopAndStringInit3([BZ)Ljava/lang/String; + .registers 5 + + new-instance v0, Ljava/lang/String; + move-object v2, v0 + + # Irreducible loop + if-eqz p1, :loop_entry + :loop_header + const v1, 0x1 + xor-int p1, p1, v1 + :loop_entry + if-eqz p1, :string_init + goto :loop_header + + :string_init + const-string v1, "UTF8" + invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V + return-object v2 + +.end method diff --git a/test/563-checker-fakestring/src/Main.java b/test/563-checker-fakestring/src/Main.java index 78cb37ae09..d38b7f4f23 100644 --- a/test/563-checker-fakestring/src/Main.java +++ b/test/563-checker-fakestring/src/Main.java @@ -65,14 +65,21 @@ public class Main { } { - Method m = c.getMethod("thisNotNewInstance1", byte[].class, boolean.class); + Method m = c.getMethod("irreducibleLoopAndStringInit1", byte[].class, boolean.class); String result = (String) m.invoke(null, new Object[] { testData, true }); assertEqual(testString, result); result = (String) m.invoke(null, new Object[] { testData, false }); assertEqual(testString, result); } { - Method m = c.getMethod("thisNotNewInstance2", byte[].class, boolean.class); + Method m = c.getMethod("irreducibleLoopAndStringInit2", byte[].class, boolean.class); + String result = (String) m.invoke(null, new Object[] { testData, true }); + assertEqual(testString, result); + result = (String) m.invoke(null, new Object[] { testData, false }); + assertEqual(testString, result); + } + { + Method m = c.getMethod("irreducibleLoopAndStringInit3", byte[].class, boolean.class); String result = (String) m.invoke(null, new Object[] { testData, true }); assertEqual(testString, result); result = (String) m.invoke(null, new Object[] { testData, false }); diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc index e2b8aa037f..7c1507fb5c 100644 --- a/test/566-polymorphic-inlining/polymorphic_inline.cc +++ b/test/566-polymorphic-inlining/polymorphic_inline.cc @@ -48,9 +48,8 @@ static void do_checks(jclass cls, const char* method_name) { } } - CodeInfo info = header->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = info.ExtractEncoding(); - CHECK(info.HasInlineInfo(encoding)); + CodeInfo info(header); + CHECK(info.HasInlineInfo()); } static void allocate_profiling_info(jclass cls, const char* method_name) { diff --git a/test/586-checker-null-array-get/src/Main.java b/test/586-checker-null-array-get/src/Main.java index de9429fd8b..ebe91cfe1e 100644 --- a/test/586-checker-null-array-get/src/Main.java +++ b/test/586-checker-null-array-get/src/Main.java @@ -107,9 +107,8 @@ public class Main { /// CHECK-DAG: <<GetJ3:j\d+>> ArrayGet [<<CheckJ>>,{{i\d+}}] public static void bar() { // We create multiple accesses that will lead the bounds check - // elimination pass to add a HDeoptimize. Not having the bounds check helped - // the load store elimination think it could merge two ArrayGet with different - // types. + // elimination pass to add a HDeoptimize. Not having the bounds check + // makes the ArrayGets look almost the same if it were not for the type! String[] array = (String[])getNull(); objectField = array[0]; objectField = array[1]; diff --git a/test/674-hiddenapi/src-ex/ChildClass.java b/test/674-hiddenapi/src-ex/ChildClass.java index 0349e8fe46..db3ba6d8bf 100644 --- a/test/674-hiddenapi/src-ex/ChildClass.java +++ b/test/674-hiddenapi/src-ex/ChildClass.java @@ -87,16 +87,21 @@ public class ChildClass { ChildClass.everythingWhitelisted = everythingWhitelisted; boolean isSameBoot = (isParentInBoot == isChildInBoot); + boolean isDebuggable = VMRuntime.getRuntime().isJavaDebuggable(); // Run meaningful combinations of access flags. for (Hiddenness hiddenness : Hiddenness.values()) { final Behaviour expected; - if (isSameBoot || hiddenness == Hiddenness.Whitelist || everythingWhitelisted) { + // Warnings are now disabled whenever access is granted, even for + // greylisted APIs. This is the behaviour for release builds. + if (isSameBoot || everythingWhitelisted || hiddenness == Hiddenness.Whitelist) { expected = Behaviour.Granted; } else if (hiddenness == Hiddenness.Blacklist) { expected = Behaviour.Denied; - } else { + } else if (isDebuggable) { expected = Behaviour.Warning; + } else { + expected = Behaviour.Granted; } for (boolean isStatic : booleanValues) { diff --git a/test/677-fsi2/expected.txt b/test/677-fsi2/expected.txt new file mode 100644 index 0000000000..de008470fe --- /dev/null +++ b/test/677-fsi2/expected.txt @@ -0,0 +1,4 @@ +Run default +Hello World +Run without dex2oat +Hello World diff --git a/test/677-fsi2/info.txt b/test/677-fsi2/info.txt new file mode 100644 index 0000000000..ed0a0f2388 --- /dev/null +++ b/test/677-fsi2/info.txt @@ -0,0 +1 @@ +Test that -Xonly-use-system-oat-files works. diff --git a/test/677-fsi2/run b/test/677-fsi2/run new file mode 100644 index 0000000000..039a6a78f0 --- /dev/null +++ b/test/677-fsi2/run @@ -0,0 +1,25 @@ +#!/bin/bash +# +# Copyright (C) 2018 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. + +echo "Run default" +${RUN} $@ --runtime-option -Xonly-use-system-oat-files +return_status1=$? + +echo "Run without dex2oat" +${RUN} $@ --no-dex2oat --runtime-option -Xonly-use-system-oat-files +return_status2=$? + +(exit $return_status1) && (exit $return_status2) diff --git a/test/677-fsi2/src/Main.java b/test/677-fsi2/src/Main.java new file mode 100644 index 0000000000..834075f67a --- /dev/null +++ b/test/677-fsi2/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2018 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. + */ + +public class Main { + public static void main(String[] args) { + System.out.println("Hello World"); + } +} diff --git a/test/712-varhandle-invocations/src/SampleValues.java b/test/712-varhandle-invocations/src/SampleValues.java new file mode 100644 index 0000000000..79f4f194bd --- /dev/null +++ b/test/712-varhandle-invocations/src/SampleValues.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 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. + */ + +/** Sample values for use in VarHandle tests. These are here to avoid repeatedly boxing which + * makes gcstress tests run slowly. */ +public class SampleValues { + public static final boolean[] PRIMITIVE_BOOLEANS = new boolean[] {true, false}; + + public static final Boolean[] BOOLEANS = new Boolean[] {true, false}; + + public static final byte[] PRIMITIVE_BYTES = + new byte[] {(byte) -128, (byte) -61, (byte) 7, (byte) 127, (byte) 33}; + + public static final Byte[] BYTES = + new Byte[] {(byte) -128, (byte) -61, (byte) 7, (byte) 127, (byte) 33}; + + public static final short[] PRIMITIVE_SHORTS = + new short[] {(short) -32768, (short) -384, (short) 32767, (short) 0xaa55}; + + public static final Short[] SHORTS = + new Short[] {(short) -32768, (short) -384, (short) 32767, (short) 0xaa55}; + + public static final char[] PRIMITIVE_CHARS = + new char[] {'A', '#', '$', 'Z', 't', 'c'}; + + public static final Character[] CHARACTERS = + new Character[] {'A', '#', '$', 'Z', 't', 'c'}; + + public static final int[] PRIMITIVE_INTS = + new int[] {-0x01234567, 0x7f6e5d4c, 0x12345678, 0x10215220, 42}; + + public static final Integer[] INTEGERS = + new Integer[] {-0x01234567, 0x7f6e5d4c, 0x12345678, 0x10215220, 42}; + + public static final long[] PRIMITIVE_LONGS = + new long[] {-0x0123456789abcdefl, 0x789abcdef0123456l, 0xfedcba9876543210l}; + + public static final Long[] LONGS = + new Long[] {-0x0123456789abcdefl, 0x789abcdef0123456l, 0xfedcba9876543210l}; + + public static final float[] PRIMITIVE_FLOATS = + new float[] {-7.77e23f, 1.234e-17f, 3.40e36f, -8.888e3f, 4.442e11f}; + + public static final Float[] FLOATS = + new Float[] {-7.77e23f, 1.234e-17f, 3.40e36f, -8.888e3f, 4.442e11f}; + + public static final double[] PRIMITIVE_DOUBLES = + new double[] {-1.0e-200, 1.11e200, 3.141, 1.1111, 6.022e23, 6.626e-34}; + + public static final Double[] DOUBLES = + new Double[] {-1.0e-200, 1.11e200, 3.141, 1.1111, 6.022e23, 6.626e-34}; + + public static boolean get_boolean(int index) { + return PRIMITIVE_BOOLEANS[index]; + } + + public static Boolean get_Boolean(int index) { + return BOOLEANS[index]; + } + + public static byte get_byte(int index) { + return PRIMITIVE_BYTES[index]; + } + + public static Byte get_Byte(int index) { + return BYTES[index]; + } + + public static short get_short(int index) { + return PRIMITIVE_SHORTS[index]; + } + + public static Short get_Short(int index) { + return SHORTS[index]; + } + + public static char get_char(int index) { + return PRIMITIVE_CHARS[index]; + } + + public static Character get_Character(int index) { + return CHARACTERS[index]; + } + + public static int get_int(int index) { + return PRIMITIVE_INTS[index]; + } + + public static Integer get_Integer(int index) { + return INTEGERS[index]; + } + + public static long get_long(int index) { + return PRIMITIVE_LONGS[index]; + } + + public static Long get_Long(int index) { + return LONGS[index]; + } + + public static float get_float(int index) { + return PRIMITIVE_FLOATS[index]; + } + + public static Float get_Float(int index) { + return FLOATS[index]; + } + + public static double get_double(int index) { + return PRIMITIVE_DOUBLES[index]; + } + + public static Double get_Double(int index) { + return DOUBLES[index]; + } +} + diff --git a/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java index bc64c0c8b1..5a69b549cf 100644 --- a/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java +++ b/test/712-varhandle-invocations/src/VarHandleUnitTestCollector.java @@ -19,30 +19,52 @@ import java.io.PrintStream; // Results collector for VarHandle Unit tests public final class VarHandleUnitTestCollector { private final PrintStream out = System.out; + private final boolean verbose = false; private int numberOfSuccesses; private int numberOfSkips; private int numberOfFailures; + private int consecutiveResults = 0; + private String current; + private long startMillis; public void start(String testName) { - out.print(testName); - out.print("..."); + out.append(testName) + .append("..."); + consecutiveResults = 0; + current = testName; + startMillis = System.currentTimeMillis(); + } + + private void printStatus(String status) { + out.print(status); + if (verbose) { + out.print('['); + out.print(System.currentTimeMillis() - startMillis); + out.print(']'); + } + out.println(); } public void skip() { numberOfSkips += 1; - out.println("SKIP"); + printStatus("SKIP"); + consecutiveResults++; } public void success() { numberOfSuccesses += 1; - out.println("OK"); + printStatus("OK"); + if (consecutiveResults++ > 1) { + throw new AssertionError("Oops: " + consecutiveResults); + } } public void fail(String errorMessage) { numberOfFailures += 1; - out.println("FAIL"); + printStatus("FAIL"); out.print(errorMessage); + consecutiveResults++; } public void printSummary() { diff --git a/test/712-varhandle-invocations/util-src/generate_java.py b/test/712-varhandle-invocations/util-src/generate_java.py index 9520b53844..f535b400f8 100644 --- a/test/712-varhandle-invocations/util-src/generate_java.py +++ b/test/712-varhandle-invocations/util-src/generate_java.py @@ -757,7 +757,9 @@ public class ${test_class} extends VarHandleUnitTest { """) with io.StringIO() as body_text: compatible_types = types_that_widen_to(var_type) - for value_type in VALUE_TYPES: + incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) } + test_types = compatible_types | incompatible_types + for value_type in test_types: print("try {", file=body_text) return_type = accessor.get_return_type(var_type) if return_type: @@ -765,7 +767,7 @@ public class ${test_class} extends VarHandleUnitTest { print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) num_args = accessor.get_number_of_var_type_arguments() for i in range(0, num_args): - print(", {0}({1})".format(value_type.boxing_method(), value_type.examples[i]), end="", file=body_text) + print(", SampleValues.get_{0}({1})".format(value_type.boxed_type, i), end="", file=body_text) print(");", file=body_text) if value_type in compatible_types: print(" assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.{0}));".format(accessor.access_mode), @@ -817,7 +819,9 @@ public class ${test_class} extends VarHandleUnitTest { with io.StringIO() as body_text: return_type = accessor.get_return_type(var_type) compatible_types = { return_type } - for value_type in VALUE_TYPES: + incompatible_types = { RANDOM.choice(list(VALUE_TYPES - compatible_types)) } + test_types = compatible_types | incompatible_types + for value_type in test_types: print("try {", file=body_text) print("{0} result = ({0}) ".format(value_type.boxed_type), end="", file=body_text) print("vh.{0}(this".format(accessor.method_name), end="", file=body_text) diff --git a/test/988-method-trace/expected.txt b/test/988-method-trace/expected.txt index 7f64e23a77..6e16722d53 100644 --- a/test/988-method-trace/expected.txt +++ b/test/988-method-trace/expected.txt @@ -130,8 +130,10 @@ fibonacci(5)=5 ....<= public java.lang.AbstractStringBuilder java.lang.AbstractStringBuilder.append(java.lang.String) -> <class java.lang.StringBuilder: Bad argument: -19 < 0> ...<= public java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String) -> <class java.lang.StringBuilder: Bad argument: -19 < 0> ...=> public java.lang.String java.lang.StringBuilder.toString() -....=> static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -....<= static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -> <class java.lang.String: Bad argument: -19 < 0> +....=> public static java.lang.String java.lang.StringFactory.newStringFromChars(char[],int,int) +.....=> static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) +.....<= static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -> <class java.lang.String: Bad argument: -19 < 0> +....<= public static java.lang.String java.lang.StringFactory.newStringFromChars(char[],int,int) -> <class java.lang.String: Bad argument: -19 < 0> ...<= public java.lang.String java.lang.StringBuilder.toString() -> <class java.lang.String: Bad argument: -19 < 0> ...=> public java.lang.Error(java.lang.String) ....=> public java.lang.Throwable(java.lang.String) @@ -231,8 +233,10 @@ fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0 ....<= public java.lang.AbstractStringBuilder java.lang.AbstractStringBuilder.append(java.lang.String) -> <class java.lang.StringBuilder: Bad argument: -19 < 0> ...<= public java.lang.StringBuilder java.lang.StringBuilder.append(java.lang.String) -> <class java.lang.StringBuilder: Bad argument: -19 < 0> ...=> public java.lang.String java.lang.StringBuilder.toString() -....=> static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -....<= static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -> <class java.lang.String: Bad argument: -19 < 0> +....=> public static java.lang.String java.lang.StringFactory.newStringFromChars(char[],int,int) +.....=> static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) +.....<= static java.lang.String java.lang.StringFactory.newStringFromChars(int,int,char[]) -> <class java.lang.String: Bad argument: -19 < 0> +....<= public static java.lang.String java.lang.StringFactory.newStringFromChars(char[],int,int) -> <class java.lang.String: Bad argument: -19 < 0> ...<= public java.lang.String java.lang.StringBuilder.toString() -> <class java.lang.String: Bad argument: -19 < 0> ...=> public java.lang.Error(java.lang.String) ....=> public java.lang.Throwable(java.lang.String) diff --git a/test/999-redefine-hiddenapi/api-blacklist.txt b/test/999-redefine-hiddenapi/api-blacklist.txt new file mode 100644 index 0000000000..63e37aa757 --- /dev/null +++ b/test/999-redefine-hiddenapi/api-blacklist.txt @@ -0,0 +1,2 @@ +Lart/Test999;->foo()V +Lart/Test999;->bar:I diff --git a/test/999-redefine-hiddenapi/build b/test/999-redefine-hiddenapi/build new file mode 100644 index 0000000000..f4b029fb82 --- /dev/null +++ b/test/999-redefine-hiddenapi/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 2018 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. + +USE_HIDDENAPI=true ./default-build "$@" diff --git a/test/999-redefine-hiddenapi/expected.txt b/test/999-redefine-hiddenapi/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/999-redefine-hiddenapi/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/999-redefine-hiddenapi/info.txt b/test/999-redefine-hiddenapi/info.txt new file mode 100644 index 0000000000..87bc30cf80 --- /dev/null +++ b/test/999-redefine-hiddenapi/info.txt @@ -0,0 +1 @@ +Tests that JVMTI class redefinition does not strip away hidden API access flags. diff --git a/test/999-redefine-hiddenapi/run b/test/999-redefine-hiddenapi/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/999-redefine-hiddenapi/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/999-redefine-hiddenapi/src-ex/Test999.java b/test/999-redefine-hiddenapi/src-ex/Test999.java new file mode 100644 index 0000000000..97495c5a47 --- /dev/null +++ b/test/999-redefine-hiddenapi/src-ex/Test999.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 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. + */ + +package art; + +public class Test999 { + public void foo() { + System.out.println("hello"); + } + + public int bar = 42; +} diff --git a/test/999-redefine-hiddenapi/src-redefine/art/Test999.java b/test/999-redefine-hiddenapi/src-redefine/art/Test999.java new file mode 100644 index 0000000000..c1b838ccc7 --- /dev/null +++ b/test/999-redefine-hiddenapi/src-redefine/art/Test999.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 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. + */ + +package art; + +public class Test999 { + public void foo() { + System.out.println("Goodbye"); + } + + public int bar = 64; +} diff --git a/test/999-redefine-hiddenapi/src-redefine/gen.sh b/test/999-redefine-hiddenapi/src-redefine/gen.sh new file mode 100755 index 0000000000..6948cbbfc3 --- /dev/null +++ b/test/999-redefine-hiddenapi/src-redefine/gen.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright 2018 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. + +set -e +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +TMP=`mktemp -d` + +CLASS "art/Test999" + +(cd "$TMP" && javac -d "${TMP}" "$DIR/${CLASS}.java" && d8 --output . "$TMP/${CLASS}.class") + +echo ' private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(' +base64 "${TMP}/${CLASS}.class" | sed -E 's/^/ "/' | sed ':a;N;$!ba;s/\n/" +\n/g' | sed -E '$ s/$/");/' +echo ' private static final byte[] DEX_BYTES = Base64.getDecoder().decode(' +base64 "${TMP}/classes.dex" | sed -E 's/^/ "/' | sed ':a;N;$!ba;s/\n/" +\n/g' | sed -E '$ s/$/");/' + +rm -rf "$TMP" diff --git a/test/999-redefine-hiddenapi/src/Main.java b/test/999-redefine-hiddenapi/src/Main.java new file mode 100644 index 0000000000..c6365ac234 --- /dev/null +++ b/test/999-redefine-hiddenapi/src/Main.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 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.io.File; +import java.lang.reflect.Method; +import java.util.Base64; + +public class Main { + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + + // Run the initialization routine. This will enable hidden API checks in + // the runtime, in case they are not enabled by default. + init(); + + // Load the '-ex' APK and attach it to the boot class path. + appendToBootClassLoader(DEX_EXTRA); + + // Find the test class in boot class loader and verify that its members are hidden. + Class<?> klass = Class.forName("art.Test999", true, BOOT_CLASS_LOADER); + assertMethodIsHidden(klass, "before redefinition"); + assertFieldIsHidden(klass, "before redefinition"); + + // Redefine the class using JVMTI. + art.Redefinition.setTestConfiguration(art.Redefinition.Config.COMMON_REDEFINE); + art.Redefinition.doCommonClassRedefinition(klass, CLASS_BYTES, DEX_BYTES); + + // Verify that the class members are still hidden. + assertMethodIsHidden(klass, "after redefinition"); + assertFieldIsHidden(klass, "after redefinition"); + } + + private static void assertMethodIsHidden(Class<?> klass, String msg) throws Exception { + try { + klass.getDeclaredMethod("foo"); + // Unexpected. Should have thrown NoSuchMethodException. + throw new Exception("Method should not be accessible " + msg); + } catch (NoSuchMethodException ex) { + // Expected. + } + } + + private static void assertFieldIsHidden(Class<?> klass, String msg) throws Exception { + try { + klass.getDeclaredField("bar"); + // Unexpected. Should have thrown NoSuchFieldException. + throw new Exception("Field should not be accessible " + msg); + } catch (NoSuchFieldException ex) { + // Expected. + } + } + + private static final String DEX_EXTRA = + new File(System.getenv("DEX_LOCATION"), "999-redefine-hiddenapi-ex.jar").getAbsolutePath(); + + private static ClassLoader BOOT_CLASS_LOADER = Object.class.getClassLoader(); + + // Native functions. Note that these are implemented in 674-hiddenapi/hiddenapi.cc. + private static native void appendToBootClassLoader(String dexPath); + private static native void init(); + + /** + * base64 encoded class/dex file for + * + * public class Test999 { + * public void foo() { + * System.out.println("Goodbye"); + * } + * + * public int bar = 64; + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADUAIAoABwARCQAGABIJABMAFAgAFQoAFgAXBwAYBwAZAQADYmFyAQABSQEABjxpbml0" + + "PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAANmb28BAApTb3VyY2VGaWxlAQAMVGVz" + + "dDk5OS5qYXZhDAAKAAsMAAgACQcAGgwAGwAcAQAHR29vZGJ5ZQcAHQwAHgAfAQALYXJ0L1Rlc3Q5" + + "OTkBABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lv" + + "L1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xh" + + "bmcvU3RyaW5nOylWACEABgAHAAAAAQABAAgACQAAAAIAAQAKAAsAAQAMAAAAJwACAAEAAAALKrcA" + + "ASoQQLUAArEAAAABAA0AAAAKAAIAAAATAAQAGAABAA4ACwABAAwAAAAlAAIAAQAAAAmyAAMSBLYA" + + "BbEAAAABAA0AAAAKAAIAAAAVAAgAFgABAA8AAAACABA="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQD0dZ+IWxOi+cJDSWjfTnUerlZj1Lll3ONIAwAAcAAAAHhWNBIAAAAAAAAAAJwCAAAQ" + + "AAAAcAAAAAcAAACwAAAAAgAAAMwAAAACAAAA5AAAAAQAAAD0AAAAAQAAABQBAAAUAgAANAEAAIYB" + + "AACOAQAAlwEAAJoBAACpAQAAwAEAANQBAADoAQAA/AEAAAoCAAANAgAAEQIAABYCAAAbAgAAIAIA" + + "ACkCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAACAAQAA" + + "AQAAAAsAAAAFAAIADQAAAAEAAAAAAAAAAQAAAAwAAAACAAEADgAAAAMAAAAAAAAAAQAAAAEAAAAD" + + "AAAAAAAAAAgAAAAAAAAAhwIAAAAAAAACAAEAAQAAAHQBAAAIAAAAcBADAAEAEwBAAFkQAAAOAAMA" + + "AQACAAAAeQEAAAgAAABiAAEAGgEBAG4gAgAQAA4AEwAOQAAVAA54AAAAAQAAAAQABjxpbml0PgAH" + + "R29vZGJ5ZQABSQANTGFydC9UZXN0OTk5OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9s" + + "YW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxUZXN0" + + "OTk5LmphdmEAAVYAAlZMAANiYXIAA2ZvbwADb3V0AAdwcmludGxuAFx+fkQ4eyJtaW4tYXBpIjox" + + "LCJzaGEtMSI6IjU2YzJlMzBmNTIzM2I4NDRmZjZkZGQ4N2ZiNTNkMzRmYjE3MjM3ZGYiLCJ2ZXJz" + + "aW9uIjoidjEuMi4xNS1kZXYifQAAAQEBAAEAgYAEtAIBAdQCAAAAAAAOAAAAAAAAAAEAAAAAAAAA" + + "AQAAABAAAABwAAAAAgAAAAcAAACwAAAAAwAAAAIAAADMAAAABAAAAAIAAADkAAAABQAAAAQAAAD0" + + "AAAABgAAAAEAAAAUAQAAASAAAAIAAAA0AQAAAyAAAAIAAAB0AQAAARAAAAEAAACAAQAAAiAAABAA" + + "AACGAQAAACAAAAEAAACHAgAAAxAAAAEAAACYAgAAABAAAAEAAACcAgAA"); +} diff --git a/test/999-redefine-hiddenapi/src/art/Redefinition.java b/test/999-redefine-hiddenapi/src/art/Redefinition.java new file mode 100644 index 0000000000..1eec70b48c --- /dev/null +++ b/test/999-redefine-hiddenapi/src/art/Redefinition.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018 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. + */ + +package art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/Android.bp b/test/Android.bp index 76189f62a9..7909bf897a 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -64,6 +64,7 @@ art_cc_defaults { "libart-gtest", "libdexfiled", "libprofiled", + "libartbased", "libbase", "libicuuc", @@ -117,6 +118,7 @@ art_cc_defaults { "libartd-compiler", "libdexfiled", "libprofiled", + "libartbased", ], static_libs: [ "libgtest", @@ -156,6 +158,7 @@ art_cc_library { "libartd-compiler", "libdexfiled", "libprofiled", + "libartbased", "libbase", "libbacktrace", ], @@ -187,6 +190,7 @@ art_cc_test_library { "libart", "libdexfile", "libprofile", + "libartbase", ], } @@ -201,6 +205,7 @@ art_cc_test_library { "libartd", "libdexfiled", "libprofiled", + "libartbased", ], } @@ -322,6 +327,7 @@ art_cc_test_library { "libart", "libdexfile", "libprofile", + "libartbase", ], } @@ -335,6 +341,7 @@ art_cc_test_library { "libartd", "libdexfiled", "libprofiled", + "libartbased", ], } @@ -370,22 +377,27 @@ cc_library_static { } art_cc_defaults { - name: "libtistress-defaults", + name: "libtistress-srcs", defaults: ["libartagent-defaults"], srcs: [ "ti-stress/stress.cc", ], + header_libs: ["libopenjdkjvmti_headers"], +} + +art_cc_defaults { + name: "libtistress-defaults", + defaults: ["libtistress-srcs"], shared_libs: [ "libbase", "slicer", ], - header_libs: ["libopenjdkjvmti_headers"], } art_cc_test_library { name: "libtistress", defaults: ["libtistress-defaults"], - shared_libs: ["libart"], + shared_libs: ["libartbase"], } art_cc_test_library { @@ -394,7 +406,30 @@ art_cc_test_library { "art_debug_defaults", "libtistress-defaults", ], - shared_libs: ["libartd"], + shared_libs: ["libartbased"], +} + +art_cc_defaults { + name: "libtistress-static-defaults", + defaults: ["libtistress-srcs"], + static_libs: art_static_dependencies + [ + "slicer", + ], +} + +art_cc_test_library { + name: "libtistresss", + defaults: ["libtistress-static-defaults"], + static_libs: ["libartbase"], +} + +art_cc_test_library { + name: "libtistressds", + defaults: [ + "art_debug_defaults", + "libtistress-static-defaults" + ], + static_libs: ["libartbased"], } cc_defaults { @@ -468,6 +503,7 @@ art_cc_test_library { "libart", "libdexfile", "libprofile", + "libartbase", ], } @@ -481,6 +517,7 @@ art_cc_test_library { "libartd", "libdexfiled", "libprofiled", + "libartbased", ], } diff --git a/test/etc/default-build b/test/etc/default-build index 8bb898c7c1..c61de0ab6e 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -561,6 +561,11 @@ fi if [[ -d classes-ex ]] && [ ${NEED_DEX} = "true" ]; then make_dex classes-ex + # Apply hiddenapi on the dex files if the test has API list file(s). + if [ ${USE_HIDDENAPI} = "true" -a ${HAS_HIDDENAPI_SPEC} = "true" ]; then + make_hiddenapi classes-ex.dex + fi + # quick shuffle so that the stored name is "classes.dex" mv classes.dex classes-1.dex mv classes-ex.dex classes.dex diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index fad801192a..1ba433e974 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -861,9 +861,9 @@ if [ "$HOST" = "n" ]; then # System libraries needed by libarttestd.so PUBLIC_LIBS=libc++.so:libbacktrace.so:libbase.so:libnativehelper.so if [ "$TEST_IS_NDEBUG" = "y" ]; then - PUBLIC_LIBS=$PUBLIC_LIBS:libart.so:libdexfile.so:libprofile.so + PUBLIC_LIBS=$PUBLIC_LIBS:libart.so:libdexfile.so:libprofile.so:libartbase.so else - PUBLIC_LIBS=$PUBLIC_LIBS:libartd.so:libdexfiled.so:libprofiled.so + PUBLIC_LIBS=$PUBLIC_LIBS:libartd.so:libdexfiled.so:libprofiled.so:libartbased.so fi # Create a script with the command. The command can get longer than the longest diff --git a/test/knownfailures.json b/test/knownfailures.json index f473a99a27..493582fa48 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -454,7 +454,8 @@ "674-hiddenapi", "649-vdex-duplicate-method", "804-class-extends-itself", - "921-hello-failure" + "921-hello-failure", + "999-redefine-hiddenapi" ], "description": [ "Tests that use illegal dex files or otherwise break dexter assumptions" @@ -471,7 +472,8 @@ "629-vdex-speed", "647-jni-get-field-id", "674-hiddenapi", - "944-transform-classloaders" + "944-transform-classloaders", + "999-redefine-hiddenapi" ], "description": [ "Tests that use custom class loaders or other features not supported ", @@ -649,12 +651,6 @@ "description": ["Requires zip, which isn't available on device"] }, { - "tests": "712-varhandle-invocations", - "variant": "speed-profile & debug & gcstress & target", - "bug": "b/73275005", - "description": ["Time out"] - }, - { "tests": ["1941-dispose-stress", "522-checker-regression-monitor-exit"], "variant": "jvm", "bug": "b/73888836", @@ -876,7 +872,6 @@ "667-jit-jni-stub", "667-out-of-bounds", "668-aiobe", - "674-hiddenapi", "674-hotness-compiled", "674-vdex-uncompress", "675-checker-unverified-method", @@ -954,8 +949,11 @@ }, { "tests": ["616-cha-unloading", + "674-hiddenapi", + "677-fsi2", "678-quickening", - "679-locks"], + "679-locks", + "999-redefine-hiddenapi"], "variant": "jvm", "description": ["Doesn't run on RI."] }, @@ -981,5 +979,11 @@ "991-field-trace-2"], "variant": "gcstress & debug & target", "description": ["Test can time out on gcstress with debug"] + }, + { + "tests": ["080-oom-throw"], + "variant": "jit", + "bug": "b/77567088", + "description": ["Test throws exception before or during OOME."] } ] diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc index bbe74656dd..0eba7426c0 100644 --- a/test/ti-stress/stress.cc +++ b/test/ti-stress/stress.cc @@ -25,7 +25,6 @@ #include <jni.h> #include "base/utils.h" -#include "exec_utils.h" #include "jvmti.h" #pragma clang diagnostic push @@ -920,4 +919,8 @@ extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, return 0; } +extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { + return Agent_OnLoad(vm, options, reserved); +} + } // namespace art diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp index 39e57bd667..23cc917f1d 100644 --- a/tools/cpp-define-generator/Android.bp +++ b/tools/cpp-define-generator/Android.bp @@ -31,6 +31,7 @@ cc_binary { // Do not use art_cc_binary because HOST_PREFER_32_BIT is incompatib include_dirs: [ "art/libartbase", "art/libdexfile", + "art/libartbase", "art/runtime", ], srcs: ["main.cc"], diff --git a/tools/cpp-define-generator/constant_lockword.def b/tools/cpp-define-generator/constant_lockword.def index 08d588505d..977d1ca12d 100644 --- a/tools/cpp-define-generator/constant_lockword.def +++ b/tools/cpp-define-generator/constant_lockword.def @@ -23,23 +23,29 @@ #define DEFINE_LOCK_WORD_EXPR(macro_name, type, constant_field_name) \ DEFINE_EXPR(LOCK_WORD_ ## macro_name, type, art::LockWord::constant_field_name) +// FIXME: The naming is inconsistent, the `Shifted` -> `_SHIFTED` suffix is sometimes missing. DEFINE_LOCK_WORD_EXPR(STATE_SHIFT, int32_t, kStateShift) -DEFINE_LOCK_WORD_EXPR(STATE_MASK, uint32_t, kStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(STATE_MASK_SHIFTED, uint32_t, kStateMaskShifted) DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_SHIFT, int32_t, kReadBarrierStateShift) -DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK, uint32_t, kReadBarrierStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK, uint32_t, kReadBarrierStateMaskShifted) DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK_TOGGLED, uint32_t, kReadBarrierStateMaskShiftedToggled) -DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE, int32_t, kThinLockCountOne) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SIZE, int32_t, kThinLockCountSize) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_SHIFT, int32_t, kThinLockCountShift) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_MASK_SHIFTED, uint32_t, kThinLockCountMaskShifted) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE, uint32_t, kThinLockCountOne) +DEFINE_LOCK_WORD_EXPR(THIN_LOCK_OWNER_MASK_SHIFTED, uint32_t, kThinLockOwnerMaskShifted) -DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS, uint32_t, kStateForwardingAddress) +DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS, uint32_t, kStateForwardingAddress) DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_OVERFLOW, uint32_t, kStateForwardingAddressOverflow) DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_SHIFT, uint32_t, kForwardingAddressShift) -DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED, uint32_t, kGCStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED, uint32_t, kGCStateMaskShifted) DEFINE_LOCK_WORD_EXPR(GC_STATE_MASK_SHIFTED_TOGGLED, uint32_t, kGCStateMaskShiftedToggled) -DEFINE_LOCK_WORD_EXPR(GC_STATE_SHIFT, int32_t, kGCStateShift) +DEFINE_LOCK_WORD_EXPR(GC_STATE_SIZE, int32_t, kGCStateSize) +DEFINE_LOCK_WORD_EXPR(GC_STATE_SHIFT, int32_t, kGCStateShift) -DEFINE_LOCK_WORD_EXPR(MARK_BIT_SHIFT, int32_t, kMarkBitStateShift) -DEFINE_LOCK_WORD_EXPR(MARK_BIT_MASK_SHIFTED, uint32_t, kMarkBitStateMaskShifted) +DEFINE_LOCK_WORD_EXPR(MARK_BIT_SHIFT, int32_t, kMarkBitStateShift) +DEFINE_LOCK_WORD_EXPR(MARK_BIT_MASK_SHIFTED, uint32_t, kMarkBitStateMaskShifted) #undef DEFINE_LOCK_WORD_EXPR diff --git a/tools/dexanalyze/Android.bp b/tools/dexanalyze/Android.bp index 2754e6445e..a229d73d01 100644 --- a/tools/dexanalyze/Android.bp +++ b/tools/dexanalyze/Android.bp @@ -37,6 +37,7 @@ art_cc_binary { defaults: ["dexanalyze-defaults"], shared_libs: [ "libdexfile", + "libartbase", "libbase", ], } diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc index a5f647cc56..46c48520e3 100644 --- a/tools/dexanalyze/dexanalyze.cc +++ b/tools/dexanalyze/dexanalyze.cc @@ -15,6 +15,7 @@ */ #include <cstdint> +#include <iostream> #include <set> #include <sstream> @@ -29,7 +30,19 @@ namespace art { class DexAnalyze { - static const int kExitCodeUsageError = 1; + static constexpr int kExitCodeUsageError = 1; + static constexpr int kExitCodeFailedToOpenFile = 2; + static constexpr int kExitCodeFailedToOpenDex = 3; + static constexpr int kExitCodeFailedToProcessDex = 4; + + static void StdoutLogger(android::base::LogId, + android::base::LogSeverity, + const char*, + const char*, + unsigned int, + const char* message) { + std::cout << message << std::endl; + } static int Usage(char** argv) { LOG(ERROR) @@ -53,6 +66,8 @@ class DexAnalyze { run_all_experiments_ = true; } else if (arg == "-count-indices") { exp_count_indices_ = true; + } else if (arg == "-analyze-strings") { + exp_analyze_strings_ = true; } else if (arg == "-d") { dump_per_input_dex_ = true; } else if (!arg.empty() && arg[0] == '-') { @@ -72,6 +87,7 @@ class DexAnalyze { bool run_dex_file_verifier_ = true; bool dump_per_input_dex_ = false; bool exp_count_indices_ = false; + bool exp_analyze_strings_ = false; bool run_all_experiments_ = false; std::vector<std::string> filenames_; }; @@ -82,29 +98,36 @@ class DexAnalyze { if (options->run_all_experiments_ || options->exp_count_indices_) { experiments_.emplace_back(new CountDexIndices); } + if (options->run_all_experiments_ || options->exp_analyze_strings_) { + experiments_.emplace_back(new AnalyzeStrings); + } } bool ProcessDexFile(const DexFile& dex_file) { for (std::unique_ptr<Experiment>& experiment : experiments_) { experiment->ProcessDexFile(dex_file); } + total_size_ += dex_file.Size(); ++dex_count_; return true; } void Dump(std::ostream& os) { for (std::unique_ptr<Experiment>& experiment : experiments_) { - experiment->Dump(os); + experiment->Dump(os, total_size_); } } const Options* const options_; std::vector<std::unique_ptr<Experiment>> experiments_; size_t dex_count_ = 0; + uint64_t total_size_ = 0u; }; public: static int Run(int argc, char** argv) { + android::base::SetLogger(StdoutLogger); + Options options; int result = options.Parse(argc, argv); if (result != 0) { @@ -115,10 +138,10 @@ class DexAnalyze { Analysis cumulative(&options); for (const std::string& filename : options.filenames_) { std::string content; - // TODO: once added, use an api to android::base to read a std::vector<uint8_t>. + // TODO: once added, use an API to android::base to read a std::vector<uint8_t>. if (!android::base::ReadFileToString(filename.c_str(), &content)) { LOG(ERROR) << "ReadFileToString failed for " + filename << std::endl; - continue; + return kExitCodeFailedToOpenFile; } std::vector<std::unique_ptr<const DexFile>> dex_files; const DexFileLoader dex_file_loader; @@ -130,14 +153,14 @@ class DexAnalyze { &error_msg, &dex_files)) { LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl; - continue; + return kExitCodeFailedToOpenDex; } for (std::unique_ptr<const DexFile>& dex_file : dex_files) { if (options.dump_per_input_dex_) { Analysis current(&options); if (!current.ProcessDexFile(*dex_file)) { LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; - continue; + return kExitCodeFailedToProcessDex; } LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl; current.Dump(LOG_STREAM(INFO)); @@ -154,7 +177,6 @@ class DexAnalyze { } // namespace art int main(int argc, char** argv) { - android::base::SetLogger(android::base::StderrLogger); return art::DexAnalyze::Run(argc, argv); } diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index e1f119df59..adc515472d 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -15,12 +15,109 @@ */ #include "dexanalyze_experiments.h" + +#include <stdint.h> +#include <inttypes.h> +#include <iostream> +#include <map> +#include <vector> + +#include "android-base/stringprintf.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_instruction-inl.h" #include "dex/standard_dex_file.h" +#include "dex/utf-inl.h" namespace art { +std::string Percent(uint64_t value, uint64_t max) { + if (max == 0) { + ++max; + } + return android::base::StringPrintf("%" PRId64 "(%.2f%%)", + value, + static_cast<double>(value * 100) / static_cast<double>(max)); +} + +static size_t PrefixLen(const std::string& a, const std::string& b) { + size_t len = 0; + for (; len < a.length() && len < b.length() && a[len] == b[len]; ++len) {} + return len; +} + +void AnalyzeStrings::ProcessDexFile(const DexFile& dex_file) { + std::vector<std::string> strings; + for (size_t i = 0; i < dex_file.NumStringIds(); ++i) { + uint32_t length = 0; + const char* data = dex_file.StringDataAndUtf16LengthByIdx(dex::StringIndex(i), &length); + // Analyze if the string has any UTF16 chars. + bool have_wide_char = false; + const char* ptr = data; + for (size_t j = 0; j < length; ++j) { + have_wide_char = have_wide_char || GetUtf16FromUtf8(&ptr) >= 0x100; + } + if (have_wide_char) { + wide_string_bytes_ += 2 * length; + } else { + ascii_string_bytes_ += length; + } + string_data_bytes_ += ptr - data; + + strings.push_back(data); + } + // Note that the strings are probably already sorted. + std::sort(strings.begin(), strings.end()); + + // Tunable parameters. + static const size_t kMinPrefixLen = 3; + static const size_t kPrefixConstantCost = 5; + static const size_t kPrefixIndexCost = 2; + + // Calculate total shared prefix. + std::vector<size_t> shared_len; + std::set<std::string> prefixes; + for (size_t i = 0; i < strings.size(); ++i) { + size_t best_len = 0; + if (i > 0) { + best_len = std::max(best_len, PrefixLen(strings[i], strings[i - 1])); + } + if (i < strings.size() - 1) { + best_len = std::max(best_len, PrefixLen(strings[i], strings[i + 1])); + } + std::string prefix; + if (best_len >= kMinPrefixLen) { + prefix = strings[i].substr(0, best_len); + prefixes.insert(prefix); + total_prefix_savings_ += prefix.length(); + } + total_prefix_index_cost_ += kPrefixIndexCost; + } + total_num_prefixes_ += prefixes.size(); + for (const std::string& s : prefixes) { + // 4 bytes for an offset, one for length. + total_prefix_dict_ += s.length(); + total_prefix_table_ += kPrefixConstantCost; + } +} + +void AnalyzeStrings::Dump(std::ostream& os, uint64_t total_size) const { + os << "Total string data bytes " << Percent(string_data_bytes_, total_size) << "\n"; + os << "UTF-16 string data bytes " << Percent(wide_string_bytes_, total_size) << "\n"; + os << "ASCII string data bytes " << Percent(ascii_string_bytes_, total_size) << "\n"; + + // Prefix based strings. + os << "Total shared prefix bytes " << Percent(total_prefix_savings_, total_size) << "\n"; + os << "Prefix dictionary cost " << Percent(total_prefix_dict_, total_size) << "\n"; + os << "Prefix table cost " << Percent(total_prefix_table_, total_size) << "\n"; + os << "Prefix index cost " << Percent(total_prefix_index_cost_, total_size) << "\n"; + int64_t net_savings = total_prefix_savings_; + net_savings -= total_prefix_dict_; + net_savings -= total_prefix_table_; + net_savings -= total_prefix_index_cost_; + os << "Prefix net savings " << Percent(net_savings, total_size) << "\n"; + os << "Prefix dictionary elements " << total_num_prefixes_ << "\n"; +} + void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { num_string_ids_ += dex_file.NumStringIds(); num_method_ids_ += dex_file.NumMethodIds(); @@ -107,7 +204,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { } } -void CountDexIndices::Dump(std::ostream& os) const { +void CountDexIndices::Dump(std::ostream& os, uint64_t total_size) const { os << "Num string ids: " << num_string_ids_ << "\n"; os << "Num method ids: " << num_method_ids_ << "\n"; os << "Num field ids: " << num_field_ids_ << "\n"; @@ -127,6 +224,7 @@ void CountDexIndices::Dump(std::ostream& os) const { os << "Same class invoke: " << same_class_total << "\n"; os << "Other class invoke: " << other_class_total << "\n"; os << "Invokes from code: " << (same_class_total + other_class_total) << "\n"; + os << "Total dex size: " << total_size << "\n"; } } // namespace art diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h index 5d0f51b821..0fb4d32005 100644 --- a/tools/dexanalyze/dexanalyze_experiments.h +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -24,12 +24,31 @@ namespace art { class DexFile; +std::string Percent(uint64_t value, uint64_t max); + // An experiment a stateful visitor that runs on dex files. Results are cumulative. class Experiment { public: virtual ~Experiment() {} virtual void ProcessDexFile(const DexFile& dex_file) = 0; - virtual void Dump(std::ostream& os) const = 0; + virtual void Dump(std::ostream& os, uint64_t total_size) const = 0; +}; + +// Analyze string data and strings accessed from code. +class AnalyzeStrings : public Experiment { + public: + void ProcessDexFile(const DexFile& dex_file); + void Dump(std::ostream& os, uint64_t total_size) const; + + private: + int64_t wide_string_bytes_ = 0u; + int64_t ascii_string_bytes_ = 0u; + int64_t string_data_bytes_ = 0u; + int64_t total_prefix_savings_ = 0u; + int64_t total_prefix_dict_ = 0u; + int64_t total_prefix_table_ = 0u; + int64_t total_prefix_index_cost_ = 0u; + int64_t total_num_prefixes_ = 0u; }; // Count numbers of dex indices. @@ -37,7 +56,7 @@ class CountDexIndices : public Experiment { public: void ProcessDexFile(const DexFile& dex_file); - void Dump(std::ostream& os) const; + void Dump(std::ostream& os, uint64_t total_size) const; private: // Total string ids loaded from dex code. @@ -65,4 +84,3 @@ class CountDexIndices : public Experiment { } // namespace art #endif // ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ - diff --git a/tools/dexanalyze/dexanalyze_test.cc b/tools/dexanalyze/dexanalyze_test.cc index c9b8f53d24..96be3f9b8d 100644 --- a/tools/dexanalyze/dexanalyze_test.cc +++ b/tools/dexanalyze/dexanalyze_test.cc @@ -36,10 +36,22 @@ class DexAnalyzeTest : public CommonRuntimeTest { } }; +TEST_F(DexAnalyzeTest, NoInputFileGiven) { + DexAnalyzeExec({ "-a" }, /*expect_success*/ false); +} + +TEST_F(DexAnalyzeTest, CantOpenInput) { + DexAnalyzeExec({ "-a", "/non/existent/path" }, /*expect_success*/ false); +} + TEST_F(DexAnalyzeTest, TestAnalyzeMultidex) { DexAnalyzeExec({ "-a", GetTestDexFileName("MultiDex") }, /*expect_success*/ true); } +TEST_F(DexAnalyzeTest, TestAnalizeCoreDex) { + DexAnalyzeExec({ "-a", GetLibCoreDexFileNames()[0] }, /*expect_success*/ true); +} + TEST_F(DexAnalyzeTest, TestInvalidArg) { DexAnalyzeExec({ "-invalid-option" }, /*expect_success*/ false); } diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp index af87d31e53..3b364b67c3 100644 --- a/tools/hiddenapi/Android.bp +++ b/tools/hiddenapi/Android.bp @@ -40,6 +40,7 @@ art_cc_binary { shared_libs: [ "libart", "libdexfile", + "libartbase", ], } @@ -52,6 +53,7 @@ art_cc_binary { shared_libs: [ "libartd", "libdexfiled", + "libartbased", ], } diff --git a/tools/public.libraries.buildbot.txt b/tools/public.libraries.buildbot.txt index 6c8114558e..9b171a2502 100644 --- a/tools/public.libraries.buildbot.txt +++ b/tools/public.libraries.buildbot.txt @@ -1,5 +1,7 @@ libart.so libartd.so +libartbase.so +libartbased.so libdexfile.so libdexfiled.so libbacktrace.so diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index d376cad9da..eebc09278a 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -360,7 +360,9 @@ echo "Killing stalled dalvikvm processes..." if [[ $mode == "host" ]]; then pkill -9 -f /bin/dalvikvm else - adb shell pkill -9 -f /bin/dalvikvm + # Tests may run on older Android versions where pkill requires "-l SIGNAL" + # rather than "-SIGNAL". + adb shell pkill -l 9 -f /bin/dalvikvm fi echo "Done." diff --git a/tools/ti-fast/Android.bp b/tools/ti-fast/Android.bp new file mode 100644 index 0000000000..fd867c9bcc --- /dev/null +++ b/tools/ti-fast/Android.bp @@ -0,0 +1,56 @@ +// +// Copyright (C) 2018 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. +// + +// Build variants {target,host} x {debug,ndebug} x {32,64} +cc_defaults { + name: "tifast-defaults", + host_supported: true, + srcs: ["tifast.cc"], + defaults: ["art_defaults"], + + // Note that this tool needs to be built for both 32-bit and 64-bit since it requires + // to be same ISA as what it is attached to. + compile_multilib: "both", + + shared_libs: [ + "libbase", + ], + header_libs: [ + "libopenjdkjvmti_headers", + ], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + symlink_preferred_arch: true, +} + +art_cc_library { + name: "libtifast", + defaults: ["tifast-defaults"], +} + +art_cc_library { + name: "libtifastd", + defaults: [ + "art_debug_defaults", + "tifast-defaults", + ], +} diff --git a/tools/ti-fast/README.md b/tools/ti-fast/README.md new file mode 100644 index 0000000000..bc468826ec --- /dev/null +++ b/tools/ti-fast/README.md @@ -0,0 +1,101 @@ +# tifast + +tifast is a JVMTI agent designed for profiling the performance impact listening +to various JVMTI events. It is called tifast since none of the event handlers do +anything meaning that it can be considered speed-of-light. + +# Usage +### Build +> `make libtifast` + +The libraries will be built for 32-bit, 64-bit, host and target. Below examples +assume you want to use the 64-bit version. + +### Command Line + +The agent is loaded using -agentpath like normal. It takes arguments in the +following format: +> `[log,][EventName1[,EventName2[,...]]]` + +* If 'log' is the first argument the event handlers will LOG(INFO) when they are + called. This behavior is static. The no-log methods have no branches and just + immediately return. + +* The event-names are the same names as are used in the jvmtiEventCallbacks + struct. + +* All required capabilities are automatically gained. No capabilities other than + those needed to listen for the events are gained. + +* Only events which do not require additional function calls to cause delivery + and are sent more than once are supported. + +#### Supported events + +The following events may be listened for with this agent + +* `SingleStep` + +* `MethodEntry` + +* `MethodExit` + +* `NativeMethodBind` + +* `Exception` + +* `ExceptionCatch` + +* `ThreadStart` + +* `ThreadEnd` + +* `ClassLoad` + +* `ClassPrepare` + +* `ClassFileLoadHook` + +* `CompiledMethodLoad` + +* `CompiledMethodUnload` + +* `DynamicCodeGenerated` + +* `DataDumpRequest` + +* `MonitorContendedEnter` + +* `MonitorContendedEntered` + +* `MonitorWait` + +* `MonitorWaited` + +* `ResourceExhausted` + +* `VMObjectAlloc` + +* `GarbageCollectionStart` + +* `GarbageCollectionFinish` + +All other events cannot be listened for by this agent. Most of these missing +events either require the use of other functions in order to be called +(`FramePop`, `ObjectFree`, etc) or are only called once (`VMInit`, `VMDeath`, +etc). + +#### ART +> `art -Xplugin:$ANDROID_HOST_OUT/lib64/libopenjdkjvmti.so '-agentpath:libtifast.so=MethodEntry' -cp tmp/java/helloworld.dex -Xint helloworld` + +* `-Xplugin` and `-agentpath` need to be used, otherwise the agent will fail during init. +* If using `libartd.so`, make sure to use the debug version of jvmti. + +> `adb shell setenforce 0` +> +> `adb push $ANDROID_PRODUCT_OUT/system/lib64/libtifast.so /data/local/tmp/` +> +> `adb shell am start-activity --attach-agent /data/local/tmp/libtifast.so=MonitorWait,ClassPrepare some.debuggable.apps/.the.app.MainActivity` + +#### RI +> `java '-agentpath:libtifast.so=MethodEntry' -cp tmp/helloworld/classes helloworld` diff --git a/tools/ti-fast/tifast.cc b/tools/ti-fast/tifast.cc new file mode 100644 index 0000000000..428304e517 --- /dev/null +++ b/tools/ti-fast/tifast.cc @@ -0,0 +1,205 @@ +// Copyright (C) 2018 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 <android-base/logging.h> + +#include <atomic> +#include <iostream> +#include <istream> +#include <iomanip> +#include <jni.h> +#include <jvmti.h> +#include <memory> +#include <string> +#include <sstream> +#include <vector> + +namespace tifast { + +#define EVENT(x) JVMTI_EVENT_ ## x + +namespace { + +static void AddCapsForEvent(jvmtiEvent event, jvmtiCapabilities* caps) { + switch (event) { +#define DO_CASE(name, cap_name) \ + case EVENT(name): \ + caps->cap_name = 1; \ + break + DO_CASE(SINGLE_STEP, can_generate_single_step_events); + DO_CASE(METHOD_ENTRY, can_generate_method_entry_events); + DO_CASE(METHOD_EXIT, can_generate_method_exit_events); + DO_CASE(NATIVE_METHOD_BIND, can_generate_native_method_bind_events); + DO_CASE(EXCEPTION, can_generate_exception_events); + DO_CASE(EXCEPTION_CATCH, can_generate_exception_events); + DO_CASE(COMPILED_METHOD_LOAD, can_generate_compiled_method_load_events); + DO_CASE(COMPILED_METHOD_UNLOAD, can_generate_compiled_method_load_events); + DO_CASE(MONITOR_CONTENDED_ENTER, can_generate_monitor_events); + DO_CASE(MONITOR_CONTENDED_ENTERED, can_generate_monitor_events); + DO_CASE(MONITOR_WAIT, can_generate_monitor_events); + DO_CASE(MONITOR_WAITED, can_generate_monitor_events); + DO_CASE(VM_OBJECT_ALLOC, can_generate_vm_object_alloc_events); + DO_CASE(GARBAGE_COLLECTION_START, can_generate_garbage_collection_events); + DO_CASE(GARBAGE_COLLECTION_FINISH, can_generate_garbage_collection_events); +#undef DO_CASE + default: break; + } +} + +// Setup for all supported events. Give a macro with fun(name, event_num, args) +#define FOR_ALL_SUPPORTED_EVENTS(fun) \ + fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation)) \ + fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv*, JNIEnv*, jthread, jmethodID)) \ + fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jboolean, jvalue)) \ + fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, void*, void**)) \ + fun(Exception, EVENT(EXCEPTION), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject, jmethodID, jlocation)) \ + fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject)) \ + fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv*, JNIEnv*, jthread)) \ + fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv*, JNIEnv*, jthread)) \ + fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \ + fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \ + fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv*, JNIEnv*, jclass, jobject, const char*, jobject, jint, const unsigned char*, jint*, unsigned char**)) \ + fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv*, jmethodID, jint, const void*, jint, const jvmtiAddrLocationMap*, const void*)) \ + fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv*, jmethodID, const void*)) \ + fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv*, const char*, const void*, jint)) \ + fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv*)) \ + fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \ + fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \ + fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv*, JNIEnv*, jthread, jobject, jlong)) \ + fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv*, JNIEnv*, jthread, jobject, jboolean)) \ + fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv*, JNIEnv*, jint, const void*, const char*)) \ + fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv*, JNIEnv*, jthread, jobject, jclass, jlong)) \ + fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv*)) \ + fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv*)) + +#define GENERATE_EMPTY_FUNCTION(name, number, args) \ + static void JNICALL empty ## name args { } +FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION) +#undef GENERATE_EMPTY_FUNCTION + +static jvmtiEventCallbacks kEmptyCallbacks { +#define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args) \ + .name = empty ## name, + FOR_ALL_SUPPORTED_EVENTS(CREATE_EMPTY_EVENT_CALLBACKS) +#undef CREATE_EMPTY_EVENT_CALLBACKS +}; + +#define GENERATE_LOG_FUNCTION(name, number, args) \ + static void JNICALL log ## name args { \ + LOG(INFO) << "Got event " << #name ; \ + } +FOR_ALL_SUPPORTED_EVENTS(GENERATE_LOG_FUNCTION) +#undef GENERATE_LOG_FUNCTION + +static jvmtiEventCallbacks kLogCallbacks { +#define CREATE_LOG_EVENT_CALLBACK(name, num, args) \ + .name = log ## name, + FOR_ALL_SUPPORTED_EVENTS(CREATE_LOG_EVENT_CALLBACK) +#undef CREATE_LOG_EVENT_CALLBACK +}; + +static jvmtiEvent NameToEvent(const std::string& desired_name) { +#define CHECK_NAME(name, event, args) \ + if (desired_name == #name) { \ + return event; \ + } + FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME); + LOG(FATAL) << "Unknown event " << desired_name; + __builtin_unreachable(); +#undef CHECK_NAME +} + +#undef FOR_ALL_SUPPORTED_EVENTS +static std::vector<jvmtiEvent> GetRequestedEventList(const std::string& args) { + std::vector<jvmtiEvent> res; + std::stringstream args_stream(args); + std::string item; + while (std::getline(args_stream, item, ',')) { + if (item == "") { + continue; + } + res.push_back(NameToEvent(item)); + } + return res; +} + +} // namespace + +static jint AgentStart(JavaVM* vm, + char* options, + void* reserved ATTRIBUTE_UNUSED) { + jvmtiEnv* jvmti = nullptr; + jvmtiError error = JVMTI_ERROR_NONE; + { + jint res = 0; + res = vm->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION_1_1); + + if (res != JNI_OK || jvmti == nullptr) { + LOG(ERROR) << "Unable to access JVMTI, error code " << res; + return JNI_ERR; + } + } + std::string args(options); + bool is_log = false; + if (args.compare(0, 3, "log") == 0) { + is_log = true; + args = args.substr(3); + } + + std::vector<jvmtiEvent> events = GetRequestedEventList(args); + + jvmtiCapabilities caps{}; + for (jvmtiEvent e : events) { + AddCapsForEvent(e, &caps); + } + error = jvmti->AddCapabilities(&caps); + if (error != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to set caps"; + return JNI_ERR; + } + + if (is_log) { + error = jvmti->SetEventCallbacks(&kLogCallbacks, static_cast<jint>(sizeof(kLogCallbacks))); + } else { + error = jvmti->SetEventCallbacks(&kEmptyCallbacks, static_cast<jint>(sizeof(kEmptyCallbacks))); + } + if (error != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to set event callbacks."; + return JNI_ERR; + } + for (jvmtiEvent e : events) { + error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, + e, + nullptr /* all threads */); + if (error != JVMTI_ERROR_NONE) { + LOG(ERROR) << "Unable to enable event " << e; + return JNI_ERR; + } + } + return JNI_OK; +} + +// Late attachment (e.g. 'am attach-agent'). +extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char* options, void* reserved) { + return AgentStart(vm, options, reserved); +} + +// Early attachment +extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) { + return AgentStart(jvm, options, reserved); +} + +} // namespace tifast + diff --git a/tools/tracefast-plugin/Android.bp b/tools/tracefast-plugin/Android.bp new file mode 100644 index 0000000000..1d7dd302c0 --- /dev/null +++ b/tools/tracefast-plugin/Android.bp @@ -0,0 +1,108 @@ +// +// Copyright (C) 2018 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. +// + +// Build variants {target,host} x {debug,ndebug} x {32,64} + +cc_defaults { + name: "tracefast-defaults", + host_supported: true, + srcs: ["tracefast.cc"], + defaults: ["art_defaults"], + + // Note that this tool needs to be built for both 32-bit and 64-bit since it requires + // to be same ISA as what it is attached to. + compile_multilib: "both", + + shared_libs: [ + "libbase", + ], + target: { + android: { + shared_libs: [ + "libcutils", + ], + }, + darwin: { + enabled: false, + }, + }, + header_libs: [ + "libnativehelper_header_only", + ], + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + symlink_preferred_arch: true, +} + +cc_defaults { + name: "tracefast-interpreter-defaults", + defaults: ["tracefast-defaults"], + cflags: ["-DTRACEFAST_INTERPRETER=1"], +} + +cc_defaults { + name: "tracefast-trampoline-defaults", + defaults: ["tracefast-defaults"], + cflags: ["-DTRACEFAST_TRAMPOLINE=1"], +} + +art_cc_library { + name: "libtracefast-interpreter", + defaults: ["tracefast-interpreter-defaults"], + shared_libs: [ + "libart", + "libartbase", + ], +} + +art_cc_library { + name: "libtracefast-interpreterd", + defaults: [ + "art_debug_defaults", + "tracefast-interpreter-defaults", + ], + shared_libs: [ + "libartd", + "libartbased", + ], +} + +art_cc_library { + name: "libtracefast-trampoline", + defaults: ["tracefast-trampoline-defaults"], + shared_libs: [ + "libart", + "libartbase", + ], +} + +art_cc_library { + name: "libtracefast-trampolined", + defaults: [ + "art_debug_defaults", + "tracefast-trampoline-defaults", + ], + shared_libs: [ + "libartd", + "libartbased", + ], +} diff --git a/tools/tracefast-plugin/tracefast.cc b/tools/tracefast-plugin/tracefast.cc new file mode 100644 index 0000000000..ed6ac3d199 --- /dev/null +++ b/tools/tracefast-plugin/tracefast.cc @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2018 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 "gc/scoped_gc_critical_section.h" +#include "instrumentation.h" +#include "runtime.h" +#include "runtime_callbacks.h" +#include "scoped_thread_state_change-inl.h" +#include "thread-inl.h" +#include "thread_list.h" + +namespace tracefast { + +#if ((!defined(TRACEFAST_INTERPRETER) && !defined(TRACEFAST_TRAMPOLINE)) || \ + (defined(TRACEFAST_INTERPRETER) && defined(TRACEFAST_TRAMPOLINE))) +#error Must set one of TRACEFAST_TRAMPOLINE or TRACEFAST_INTERPRETER during build +#endif + + +#ifdef TRACEFAST_INTERPRETER +static constexpr const char* kTracerInstrumentationKey = "tracefast_INTERPRETER"; +static constexpr bool kNeedsInterpreter = true; +#else // defined(TRACEFAST_TRAMPOLINE) +static constexpr const char* kTracerInstrumentationKey = "tracefast_TRAMPOLINE"; +static constexpr bool kNeedsInterpreter = false; +#endif // TRACEFAST_INITERPRETER + +class Tracer FINAL : public art::instrumentation::InstrumentationListener { + public: + Tracer() {} + + void MethodEntered(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> return_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodExited(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + const art::JValue& return_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void MethodUnwind(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void DexPcMoved(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t new_dex_pc ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldRead(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> field_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void FieldWritten(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtField* field ATTRIBUTE_UNUSED, + const art::JValue& field_value ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void ExceptionThrown(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Throwable> exception_object ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void ExceptionHandled(art::Thread* self ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Throwable> throwable ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void Branch(art::Thread* thread ATTRIBUTE_UNUSED, + art::ArtMethod* method ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + int32_t dex_pc_offset ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void InvokeVirtualOrInterface(art::Thread* thread ATTRIBUTE_UNUSED, + art::Handle<art::mirror::Object> this_object ATTRIBUTE_UNUSED, + art::ArtMethod* caller ATTRIBUTE_UNUSED, + uint32_t dex_pc ATTRIBUTE_UNUSED, + art::ArtMethod* callee ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + void WatchedFramePop(art::Thread* thread ATTRIBUTE_UNUSED, + const art::ShadowFrame& frame ATTRIBUTE_UNUSED) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { } + + private: + DISALLOW_COPY_AND_ASSIGN(Tracer); +}; + +Tracer gEmptyTracer; + +static void StartTracing() REQUIRES(!art::Locks::mutator_lock_, + !art::Locks::thread_list_lock_, + !art::Locks::thread_suspend_count_lock_) { + art::Thread* self = art::Thread::Current(); + art::Runtime* runtime = art::Runtime::Current(); + art::gc::ScopedGCCriticalSection gcs(self, + art::gc::kGcCauseInstrumentation, + art::gc::kCollectorTypeInstrumentation); + art::ScopedSuspendAll ssa("starting fast tracing"); + runtime->GetInstrumentation()->AddListener(&gEmptyTracer, + art::instrumentation::Instrumentation::kMethodEntered | + art::instrumentation::Instrumentation::kMethodExited | + art::instrumentation::Instrumentation::kMethodUnwind); + runtime->GetInstrumentation()->EnableMethodTracing(kTracerInstrumentationKey, kNeedsInterpreter); +} + +class TraceFastPhaseCB : public art::RuntimePhaseCallback { + public: + TraceFastPhaseCB() {} + + void NextRuntimePhase(art::RuntimePhaseCallback::RuntimePhase phase) + OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) { + if (phase == art::RuntimePhaseCallback::RuntimePhase::kInit) { + art::ScopedThreadSuspension sts(art::Thread::Current(), + art::ThreadState::kWaitingForMethodTracingStart); + StartTracing(); + } + } +}; +TraceFastPhaseCB gPhaseCallback; + +// The plugin initialization function. +extern "C" bool ArtPlugin_Initialize() REQUIRES_SHARED(art::Locks::mutator_lock_) { + art::Runtime* runtime = art::Runtime::Current(); + art::ScopedThreadSuspension stsc(art::Thread::Current(), + art::ThreadState::kWaitingForMethodTracingStart); + art::ScopedSuspendAll ssa("Add phase callback"); + runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gPhaseCallback); + return true; +} + +extern "C" bool ArtPlugin_Deinitialize() { + // Don't need to bother doing anything. + return true; +} + +} // namespace tracefast diff --git a/tools/veridex/Android.bp b/tools/veridex/Android.bp index 570960c4da..5186c43ca2 100644 --- a/tools/veridex/Android.bp +++ b/tools/veridex/Android.bp @@ -24,7 +24,11 @@ cc_binary { "veridex.cc", ], cflags: ["-Wall", "-Werror"], - shared_libs: ["libdexfile", "libbase"], + shared_libs: [ + "libdexfile", + "libartbase", + "libbase", + ], header_libs: [ "art_libartbase_headers", ], |