diff options
Diffstat (limited to 'compiler')
81 files changed, 656 insertions, 1051 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index fc19b54131..d4d72f380b 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -249,6 +249,13 @@ art_cc_library { shared_libs: [ "libart", ], + + pgo: { + instrumentation: true, + profile_file: "dex2oat.profdata", + benchmarks: ["dex2oat"], + enable_profile_use: false, + } } art_cc_library { @@ -318,7 +325,7 @@ art_cc_test { "linker/linker_patch_test.cc", "linker/output_stream_test.cc", "optimizing/bounds_check_elimination_test.cc", - "optimizing/cloner_test.cc", + "optimizing/superblock_cloner_test.cc", "optimizing/data_type_test.cc", "optimizing/dominator_test.cc", "optimizing/find_loops_test.cc", diff --git a/compiler/compiler.cc b/compiler/compiler.cc index bb614ae7b2..7c7ae71d77 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -19,6 +19,7 @@ #include <android-base/logging.h> #include "base/macros.h" +#include "dex/code_item_accessors-inl.h" #include "driver/compiler_driver.h" #include "optimizing/optimizing_compiler.h" #include "utils.h" @@ -46,15 +47,16 @@ bool Compiler::IsPathologicalCase(const DexFile::CodeItem& code_item, * Dalvik uses 16-bit uints for instruction and register counts. We'll limit to a quarter * of that, which also guarantees we cannot overflow our 16-bit internal Quick SSA name space. */ - if (code_item.insns_size_in_code_units_ >= UINT16_MAX / 4) { + CodeItemDataAccessor accessor(dex_file, &code_item); + if (accessor.InsnsSizeInCodeUnits() >= UINT16_MAX / 4) { LOG(INFO) << "Method exceeds compiler instruction limit: " - << code_item.insns_size_in_code_units_ + << accessor.InsnsSizeInCodeUnits() << " in " << dex_file.PrettyMethod(method_idx); return true; } - if (code_item.registers_size_ >= UINT16_MAX / 4) { + if (accessor.RegistersSize() >= UINT16_MAX / 4) { LOG(INFO) << "Method exceeds compiler virtual register limit: " - << code_item.registers_size_ << " in " << dex_file.PrettyMethod(method_idx); + << accessor.RegistersSize() << " in " << dex_file.PrettyMethod(method_idx); return true; } return false; diff --git a/compiler/compiler.h b/compiler/compiler.h index 85abd6654c..b92bff61a9 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -18,7 +18,7 @@ #define ART_COMPILER_COMPILER_H_ #include "base/mutex.h" -#include "dex_file.h" +#include "dex/dex_file.h" #include "os.h" namespace art { diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 107ed488cd..713f8eb05d 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -22,14 +22,14 @@ #include <vector> #include "art_field-inl.h" -#include "code_item_accessors-inl.h" #include "debug/dwarf/debug_abbrev_writer.h" #include "debug/dwarf/debug_info_entry_writer.h" #include "debug/elf_compilation_unit.h" #include "debug/elf_debug_loc_writer.h" #include "debug/method_debug_info.h" -#include "dex_file-inl.h" -#include "dex_file.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file.h" #include "heap_poisoning.h" #include "linear_alloc.h" #include "linker/elf_builder.h" @@ -49,7 +49,7 @@ static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) { static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) { std::vector<const char*> names; - CodeItemDebugInfoAccessor accessor(mi->dex_file, mi->code_item); + CodeItemDebugInfoAccessor accessor(*mi->dex_file, mi->code_item); if (accessor.HasCodeItem()) { DCHECK(mi->dex_file != nullptr); const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset()); @@ -163,7 +163,7 @@ class ElfCompilationUnitWriter { for (auto mi : compilation_unit.methods) { DCHECK(mi->dex_file != nullptr); const DexFile* dex = mi->dex_file; - CodeItemDebugInfoAccessor accessor(dex, mi->code_item); + CodeItemDebugInfoAccessor accessor(*dex, mi->code_item); const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index); const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method); const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto); @@ -260,14 +260,10 @@ class ElfCompilationUnitWriter { // Write local variables. LocalInfos local_infos; - if (dex->DecodeDebugLocalInfo(accessor.RegistersSize(), - accessor.InsSize(), - accessor.InsnsSizeInCodeUnits(), - accessor.DebugInfoOffset(), - is_static, - mi->dex_method_index, - LocalInfoCallback, - &local_infos)) { + if (accessor.DecodeDebugLocalInfo(is_static, + mi->dex_method_index, + LocalInfoCallback, + &local_infos)) { for (const DexFile::LocalInfo& var : local_infos) { if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) { info_.StartTag(DW_TAG_variable); diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h index d7fd52448c..4e37f4e4ba 100644 --- a/compiler/debug/elf_debug_line_writer.h +++ b/compiler/debug/elf_debug_line_writer.h @@ -24,7 +24,7 @@ #include "debug/dwarf/headers.h" #include "debug/elf_compilation_unit.h" #include "debug/src_map_elem.h" -#include "dex_file-inl.h" +#include "dex/dex_file-inl.h" #include "linker/elf_builder.h" #include "oat_file.h" #include "stack_map.h" @@ -159,7 +159,7 @@ class ElfDebugLineWriter { PositionInfos dex2line_map; DCHECK(mi->dex_file != nullptr); const DexFile* dex = mi->dex_file; - CodeItemDebugInfoAccessor accessor(dex, mi->code_item); + CodeItemDebugInfoAccessor accessor(*dex, mi->code_item); const uint32_t debug_info_offset = accessor.DebugInfoOffset(); if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) { continue; diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index 1d609af4e6..9ea9f01cd9 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -149,11 +149,12 @@ static std::vector<VariableLocation> GetVariableLocations( DCHECK_LT(stack_map_index, dex_register_maps.size()); DexRegisterMap dex_register_map = dex_register_maps[stack_map_index]; DCHECK(dex_register_map.IsValid()); + CodeItemDataAccessor accessor(*method_info->dex_file, method_info->code_item); reg_lo = dex_register_map.GetDexRegisterLocation( - vreg, method_info->code_item->registers_size_, code_info, encoding); + vreg, accessor.RegistersSize(), code_info, encoding); if (is64bitValue) { reg_hi = dex_register_map.GetDexRegisterLocation( - vreg + 1, method_info->code_item->registers_size_, code_info, encoding); + vreg + 1, accessor.RegistersSize(), code_info, encoding); } // Add location entry for this address range. diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h index a8225fa2b4..43c8de26aa 100644 --- a/compiler/debug/method_debug_info.h +++ b/compiler/debug/method_debug_info.h @@ -21,7 +21,7 @@ #include "arch/instruction_set.h" #include "base/array_ref.h" -#include "dex_file.h" +#include "dex/dex_file.h" namespace art { namespace debug { diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index ead909af9a..52cb217980 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -26,8 +26,8 @@ #include "base/mutex.h" #include "bytecode_utils.h" #include "compiled_method.h" -#include "dex_file-inl.h" -#include "dex_instruction-inl.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_instruction-inl.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" #include "mirror/dex_cache.h" @@ -114,7 +114,8 @@ class DexCompiler { void DexCompiler::Compile() { DCHECK_EQ(dex_to_dex_compilation_level_, DexToDexCompilationLevel::kOptimize); - IterationRange<DexInstructionIterator> instructions = unit_.GetCodeItem()->Instructions(); + IterationRange<DexInstructionIterator> instructions(unit_.GetCodeItemAccessor().begin(), + unit_.GetCodeItemAccessor().end()); for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) { const uint32_t dex_pc = it.DexPc(); Instruction* inst = const_cast<Instruction*>(&it.Inst()); @@ -364,7 +365,7 @@ CompiledMethod* ArtCompileDEX( if (kIsDebugBuild) { // Double check that the counts line up with the size of the quicken info. size_t quicken_count = 0; - for (const DexInstructionPcPair& pair : code_item->Instructions()) { + for (const DexInstructionPcPair& pair : unit.GetCodeItemAccessor()) { if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) { ++quicken_count; } @@ -376,7 +377,7 @@ CompiledMethod* ArtCompileDEX( // Dex pc is not serialized, only used for checking the instructions. Since we access the // array based on the index of the quickened instruction, the indexes must line up perfectly. // The reader side uses the NeedsIndexForInstruction function too. - const Instruction& inst = code_item->InstructionAt(info.dex_pc); + const Instruction& inst = unit.GetCodeItemAccessor().InstructionAt(info.dex_pc); CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode(); // Add the index. quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0)); diff --git a/compiler/dex/dex_to_dex_compiler.h b/compiler/dex/dex_to_dex_compiler.h index 87ddb395ad..80b94d2dc3 100644 --- a/compiler/dex/dex_to_dex_compiler.h +++ b/compiler/dex/dex_to_dex_compiler.h @@ -17,7 +17,7 @@ #ifndef ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ #define ART_COMPILER_DEX_DEX_TO_DEX_COMPILER_H_ -#include "dex_file.h" +#include "dex/dex_file.h" #include "handle.h" #include "invoke_type.h" diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 979c4c4ce2..19b190093f 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -20,7 +20,7 @@ #include "common_compiler_test.h" #include "compiled_method-inl.h" #include "compiler_callbacks.h" -#include "dex_file.h" +#include "dex/dex_file.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "handle_scope-inl.h" @@ -99,8 +99,10 @@ class DexToDexDecompilerTest : public CommonCompilerTest { if (compiled_method != nullptr) { table = compiled_method->GetVmapTable(); } - optimizer::ArtDecompileDEX( - *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true); + optimizer::ArtDecompileDEX(*updated_dex_file, + *it.GetMethodCodeItem(), + table, + /* decompile_return_instruction */ true); it.Next(); } DCHECK(!it.HasNext()); diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index b409eb2dbb..ce67b85b99 100644 --- a/compiler/dex/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -20,11 +20,11 @@ #include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" -#include "code_item_accessors-inl.h" -#include "dex_file-inl.h" -#include "dex_instruction-inl.h" -#include "dex_instruction.h" -#include "dex_instruction_utils.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_instruction-inl.h" +#include "dex/dex_instruction.h" +#include "dex/dex_instruction_utils.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" @@ -141,8 +141,11 @@ bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pat ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT); - DCHECK_EQ(invoke_direct->VRegC_35c(), - method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_); + if (kIsDebugBuild) { + CodeItemDataAccessor accessor(method); + DCHECK_EQ(invoke_direct->VRegC_35c(), + accessor.RegistersSize() - accessor.InsSize()); + } uint32_t method_index = invoke_direct->VRegB_35c(); ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod( method_index, method->GetDexCache(), method->GetClassLoader()); @@ -323,7 +326,7 @@ bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item, if (target_method->GetDeclaringClass()->IsObjectClass()) { DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID); } else { - CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method); + CodeItemDataAccessor target_code_item(target_method); if (!target_code_item.HasCodeItem()) { return false; // Native constructor? } @@ -427,7 +430,7 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { - CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method); + CodeItemDataAccessor code_item(method); if (!code_item.HasCodeItem()) { // Native or abstract. return false; diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h index cde2147995..837cc85456 100644 --- a/compiler/dex/inline_method_analyser.h +++ b/compiler/dex/inline_method_analyser.h @@ -19,8 +19,8 @@ #include "base/macros.h" #include "base/mutex.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "method_reference.h" /* diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc index 92b123013d..540bd0ce45 100644 --- a/compiler/dex/quick_compiler_callbacks.cc +++ b/compiler/dex/quick_compiler_callbacks.cc @@ -38,7 +38,7 @@ ClassStatus QuickCompilerCallbacks::GetPreviousClassState(ClassReference ref) { // If we don't have class unloading enabled in the compiler, we will never see class that were // previously verified. Return false to avoid overhead from the lookup in the compiler driver. if (!does_class_unloading_) { - return ClassStatus::kStatusNotReady; + return ClassStatus::kNotReady; } DCHECK(compiler_driver_ != nullptr); // In the case of the quicken filter: avoiding verification of quickened instructions, which the diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc index 8934201b10..f2da3ffc2f 100644 --- a/compiler/dex/verified_method.cc +++ b/compiler/dex/verified_method.cc @@ -21,9 +21,9 @@ #include <android-base/logging.h> -#include "code_item_accessors-inl.h" -#include "dex_file.h" -#include "dex_instruction-inl.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction-inl.h" #include "runtime.h" #include "verifier/method_verifier-inl.h" #include "verifier/reg_type-inl.h" diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h index 64b3f448e6..2ed17f1dfd 100644 --- a/compiler/dex/verified_method.h +++ b/compiler/dex/verified_method.h @@ -20,7 +20,7 @@ #include <vector> #include "base/mutex.h" -#include "dex_file.h" +#include "dex/dex_file.h" #include "method_reference.h" #include "safe_map.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 1c65df8bb5..c0886d0185 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -42,13 +42,13 @@ #include "compiler.h" #include "compiler_callbacks.h" #include "compiler_driver-inl.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file_annotations.h" +#include "dex/dex_instruction-inl.h" #include "dex/dex_to_dex_compiler.h" #include "dex/verification_results.h" #include "dex/verified_method.h" #include "dex_compilation_unit.h" -#include "dex_file-inl.h" -#include "dex_file_annotations.h" -#include "dex_instruction-inl.h" #include "driver/compiler_options.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" @@ -402,12 +402,6 @@ static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel( Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file, const DexFile::ClassDef& class_def) REQUIRES_SHARED(Locks::mutator_lock_) { - // When the dex file is uncompressed in the APK, we do not generate a copy in the .vdex - // file. As a result, dex2oat will map the dex file read-only, and we only need to check - // that to know if we can do quickening. - if (dex_file.GetContainer() != nullptr && dex_file.GetContainer()->IsReadOnly()) { - return optimizer::DexToDexCompilationLevel::kDontDexToDexCompile; - } auto* const runtime = Runtime::Current(); DCHECK(driver.GetCompilerOptions().IsQuickeningCompilationEnabled()); const char* descriptor = dex_file.GetClassDescriptor(class_def); @@ -708,6 +702,7 @@ void CompilerDriver::Resolve(jobject class_loader, // stable order. static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, + const DexFile& dex_file, const DexFile::CodeItem* code_item) REQUIRES_SHARED(Locks::mutator_lock_) { if (code_item == nullptr) { @@ -716,7 +711,7 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, } ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - for (const DexInstructionPcPair& inst : code_item->Instructions()) { + for (const DexInstructionPcPair& inst : CodeItemInstructionAccessor(dex_file, code_item)) { switch (inst->Opcode()) { case Instruction::CONST_STRING: case Instruction::CONST_STRING_JUMBO: { @@ -778,7 +773,7 @@ static void ResolveConstStrings(CompilerDriver* driver, continue; } previous_method_idx = method_idx; - ResolveConstStrings(dex_cache, it.GetMethodCodeItem()); + ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem()); it.Next(); } DCHECK(!it.HasNext()); @@ -955,14 +950,14 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { ArtMethod* method, std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = method->GetCodeItem(); - if (code_item == nullptr) { + if (method->GetCodeItem() == nullptr) { return; // native or abstract method } - if (code_item->tries_size_ == 0) { + CodeItemDataAccessor accessor(method); + if (accessor.TriesSize() == 0) { return; // nothing to process } - const uint8_t* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0); + const uint8_t* encoded_catch_handler_list = accessor.GetCatchHandlerData(); size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list); for (size_t i = 0; i < num_encoded_catch_handlers; i++) { int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list); @@ -1814,7 +1809,7 @@ static void PopulateVerifiedMethods(const DexFile& dex_file, static void LoadAndUpdateStatus(const DexFile& dex_file, const DexFile::ClassDef& class_def, - mirror::Class::Status status, + ClassStatus status, Handle<mirror::ClassLoader> class_loader, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -1873,16 +1868,16 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // Just update the compiled_classes_ map. The compiler doesn't need to resolve // the type. ClassReference ref(dex_file, i); - mirror::Class::Status existing = mirror::Class::kStatusNotReady; + ClassStatus existing = ClassStatus::kNotReady; DCHECK(compiled_classes_.Get(ref, &existing)) << ref.dex_file->GetLocation(); ClassStateTable::InsertResult result = - compiled_classes_.Insert(ref, existing, mirror::Class::kStatusVerified); + compiled_classes_.Insert(ref, existing, ClassStatus::kVerified); CHECK_EQ(result, ClassStateTable::kInsertResultSuccess); } else { // Update the class status, so later compilation stages know they don't need to verify // the class. LoadAndUpdateStatus( - *dex_file, class_def, mirror::Class::kStatusVerified, class_loader, soa.Self()); + *dex_file, class_def, ClassStatus::kVerified, class_loader, soa.Self()); // Create `VerifiedMethod`s for each methods, the compiler expects one for // quickening or compiling. // Note that this means: @@ -1896,7 +1891,7 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // this class again. LoadAndUpdateStatus(*dex_file, class_def, - mirror::Class::kStatusRetryVerificationAtRuntime, + ClassStatus::kRetryVerificationAtRuntime, class_loader, soa.Self()); } @@ -2110,10 +2105,10 @@ class SetVerifiedClassVisitor : public CompilationVisitor { // Only do this if the class is resolved. If even resolution fails, quickening will go very, // very wrong. if (klass->IsResolved() && !klass->IsErroneousResolved()) { - if (klass->GetStatus() < mirror::Class::kStatusVerified) { + if (klass->GetStatus() < ClassStatus::kVerified) { ObjectLock<mirror::Class> lock(soa.Self(), klass); // Set class status to verified. - mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self()); + mirror::Class::SetStatus(klass, ClassStatus::kVerified, soa.Self()); // Mark methods as pre-verified. If we don't do this, the interpreter will run with // access checks. klass->SetSkipAccessChecksFlagOnAllMethods( @@ -2190,7 +2185,7 @@ class InitializeClassVisitor : public CompilationVisitor { const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage(); const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage(); - mirror::Class::Status old_status = klass->GetStatus(); + ClassStatus old_status = klass->GetStatus(); // Don't initialize classes in boot space when compiling app image if (is_app_image && klass->IsBootStrapClassLoaded()) { // Also return early and don't store the class status in the recorded class status. @@ -2315,7 +2310,7 @@ class InitializeClassVisitor : public CompilationVisitor { // would do so they can be skipped at runtime. if (!klass->IsInitialized() && manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) { - old_status = mirror::Class::kStatusSuperclassValidated; + old_status = ClassStatus::kSuperclassValidated; } else { soa.Self()->ClearException(); } @@ -2358,9 +2353,7 @@ class InitializeClassVisitor : public CompilationVisitor { // Intern strings seen in <clinit>. ArtMethod* clinit = klass->FindClassInitializer(class_linker->GetImagePointerSize()); if (clinit != nullptr) { - const DexFile::CodeItem* code_item = clinit->GetCodeItem(); - DCHECK(code_item != nullptr); - for (const DexInstructionPcPair& inst : code_item->Instructions()) { + for (const DexInstructionPcPair& inst : clinit->DexInstructions()) { if (inst->Opcode() == Instruction::CONST_STRING) { ObjPtr<mirror::String> s = class_linker->ResolveString( dex::StringIndex(inst->VRegB_21c()), dex_cache); @@ -2778,36 +2771,36 @@ void CompilerDriver::AddCompiledMethod(const MethodReference& method_ref, DCHECK(GetCompiledMethod(method_ref) != nullptr) << method_ref.PrettyMethod(); } -bool CompilerDriver::GetCompiledClass(const ClassReference& ref, - mirror::Class::Status* status) const { +bool CompilerDriver::GetCompiledClass(const ClassReference& ref, ClassStatus* status) const { DCHECK(status != nullptr); // The table doesn't know if something wasn't inserted. For this case it will return - // kStatusNotReady. To handle this, just assume anything we didn't try to verify is not compiled. + // ClassStatus::kNotReady. To handle this, just assume anything we didn't try to verify + // is not compiled. if (!compiled_classes_.Get(ref, status) || - *status < mirror::Class::kStatusRetryVerificationAtRuntime) { + *status < ClassStatus::kRetryVerificationAtRuntime) { return false; } return true; } -mirror::Class::Status CompilerDriver::GetClassStatus(const ClassReference& ref) const { - mirror::Class::Status status = ClassStatus::kStatusNotReady; +ClassStatus CompilerDriver::GetClassStatus(const ClassReference& ref) const { + ClassStatus status = ClassStatus::kNotReady; if (!GetCompiledClass(ref, &status)) { classpath_classes_.Get(ref, &status); } return status; } -void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class::Status status) { +void CompilerDriver::RecordClassStatus(const ClassReference& ref, ClassStatus status) { switch (status) { - case mirror::Class::kStatusErrorResolved: - case mirror::Class::kStatusErrorUnresolved: - case mirror::Class::kStatusNotReady: - case mirror::Class::kStatusResolved: - case mirror::Class::kStatusRetryVerificationAtRuntime: - case mirror::Class::kStatusVerified: - case mirror::Class::kStatusSuperclassValidated: - case mirror::Class::kStatusInitialized: + case ClassStatus::kErrorResolved: + case ClassStatus::kErrorUnresolved: + case ClassStatus::kNotReady: + case ClassStatus::kResolved: + case ClassStatus::kRetryVerificationAtRuntime: + case ClassStatus::kVerified: + case ClassStatus::kSuperclassValidated: + case ClassStatus::kInitialized: break; // Expected states. default: LOG(FATAL) << "Unexpected class status for class " @@ -2819,7 +2812,7 @@ void CompilerDriver::RecordClassStatus(const ClassReference& ref, mirror::Class: ClassStateTable::InsertResult result; ClassStateTable* table = &compiled_classes_; do { - mirror::Class::Status existing = mirror::Class::kStatusNotReady; + ClassStatus existing = ClassStatus::kNotReady; if (!table->Get(ref, &existing)) { // A classpath class. if (kIsDebugBuild) { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 07b65438b0..ef16212fb7 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -31,13 +31,13 @@ #include "base/mutex.h" #include "base/timing_logger.h" #include "class_reference.h" +#include "class_status.h" #include "compiler.h" -#include "dex_file.h" -#include "dex_file_types.h" +#include "dex/dex_file.h" +#include "dex/dex_file_types.h" #include "driver/compiled_method_storage.h" #include "jit/profile_compilation_info.h" #include "method_reference.h" -#include "mirror/class.h" // For mirror::Class::Status. #include "os.h" #include "safe_map.h" #include "thread_pool.h" @@ -47,6 +47,7 @@ namespace art { namespace mirror { +class Class; class DexCache; } // namespace mirror @@ -55,18 +56,21 @@ class MethodVerifier; class VerifierDepsTest; } // namespace verifier +class ArtField; class BitVector; class CompiledMethod; class CompilerOptions; class DexCompilationUnit; +template<class T> class Handle; struct InlineIGetIPutData; class InstructionSetFeatures; class InternTable; enum InvokeType : uint32_t; +class MemberOffset; +template<class MirrorType> class ObjPtr; class ParallelCompilationManager; class ScopedObjectAccess; template <class Allocator> class SrcMap; -template<class T> class Handle; class TimingLogger; class VdexFile; class VerificationResults; @@ -102,13 +106,13 @@ class CompilerDriver { ~CompilerDriver(); - // Set dex files associated with the oat file being compiled. + // Set dex files that will be stored in the oat file after being compiled. void SetDexFilesForOatFile(const std::vector<const DexFile*>& dex_files); // Set dex files classpath. void SetClasspathDexFiles(const std::vector<const DexFile*>& dex_files); - // Get dex files associated with the the oat file being compiled. + // Get dex file that will be stored in the oat file after being compiled. ArrayRef<const DexFile* const> GetDexFilesForOatFile() const { return ArrayRef<const DexFile* const>(dex_files_for_oat_file_); } @@ -152,8 +156,8 @@ class CompilerDriver { std::unique_ptr<const std::vector<uint8_t>> CreateQuickResolutionTrampoline() const; std::unique_ptr<const std::vector<uint8_t>> CreateQuickToInterpreterBridge() const; - mirror::Class::Status GetClassStatus(const ClassReference& ref) const; - bool GetCompiledClass(const ClassReference& ref, mirror::Class::Status* status) const; + ClassStatus GetClassStatus(const ClassReference& ref) const; + bool GetCompiledClass(const ClassReference& ref, ClassStatus* status) const; CompiledMethod* GetCompiledMethod(MethodReference ref) const; size_t GetNonRelativeLinkerPatchCount() const; @@ -321,7 +325,7 @@ class CompilerDriver { // according to the profile file. bool ShouldVerifyClassBasedOnProfile(const DexFile& dex_file, uint16_t class_idx) const; - void RecordClassStatus(const ClassReference& ref, mirror::Class::Status status); + void RecordClassStatus(const ClassReference& ref, ClassStatus status); // Checks if the specified method has been verified without failures. Returns // false if the method is not in the verification results (GetVerificationResults). @@ -476,7 +480,7 @@ class CompilerDriver { GUARDED_BY(requires_constructor_barrier_lock_); // All class references that this compiler has compiled. Indexed by class defs. - using ClassStateTable = AtomicDexRefMap<ClassReference, mirror::Class::Status>; + using ClassStateTable = AtomicDexRefMap<ClassReference, ClassStatus>; ClassStateTable compiled_classes_; // All class references that are in the classpath. Indexed by class defs. ClassStateTable classpath_classes_; @@ -525,7 +529,7 @@ class CompilerDriver { bool support_boot_image_fixup_; - // List of dex files associates with the oat file. + // List of dex files that will be stored in the oat file. std::vector<const DexFile*> dex_files_for_oat_file_; CompiledMethodStorage compiled_method_storage_; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 278358b250..162904c0e7 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -16,16 +16,18 @@ #include "driver/compiler_driver.h" +#include <limits> #include <stdint.h> #include <stdio.h> #include <memory> #include "art_method-inl.h" +#include "base/casts.h" #include "class_linker-inl.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" -#include "dex_file.h" -#include "dex_file_types.h" +#include "dex/dex_file.h" +#include "dex/dex_file_types.h" #include "gc/heap.h" #include "handle_scope-inl.h" #include "jit/profile_compilation_info.h" @@ -344,11 +346,11 @@ class CompilerDriverVerifyTest : public CompilerDriverTest { ASSERT_NE(klass, nullptr); EXPECT_TRUE(klass->IsVerified()); - mirror::Class::Status status; + ClassStatus status; bool found = compiler_driver_->GetCompiledClass( ClassReference(&klass->GetDexFile(), klass->GetDexTypeIndex().index_), &status); ASSERT_TRUE(found); - EXPECT_EQ(status, mirror::Class::kStatusVerified); + EXPECT_EQ(status, ClassStatus::kVerified); } }; @@ -367,8 +369,8 @@ TEST_F(CompilerDriverVerifyTest, VerifyCompilation) { CheckVerifiedClass(class_loader, "LSecond;"); } -// Test that a class of status kStatusRetryVerificationAtRuntime is indeed recorded that way in the -// driver. +// Test that a class of status ClassStatus::kRetryVerificationAtRuntime is indeed +// recorded that way in the driver. TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) { Thread* const self = Thread::Current(); jobject class_loader; @@ -386,17 +388,19 @@ TEST_F(CompilerDriverVerifyTest, RetryVerifcationStatusCheckVerified) { callbacks_->SetDoesClassUnloading(true, compiler_driver_.get()); ClassReference ref(dex_file, 0u); // Test that the status is read from the compiler driver as expected. - for (size_t i = mirror::Class::kStatusRetryVerificationAtRuntime; - i < mirror::Class::kStatusMax; - ++i) { - const mirror::Class::Status expected_status = static_cast<mirror::Class::Status>(i); + static_assert(enum_cast<size_t>(ClassStatus::kLast) < std::numeric_limits<size_t>::max(), + "Make sure incrementing the class status does not overflow."); + for (size_t i = enum_cast<size_t>(ClassStatus::kRetryVerificationAtRuntime); + i <= enum_cast<size_t>(ClassStatus::kLast); + ++i) { + const ClassStatus expected_status = enum_cast<ClassStatus>(i); // Skip unsupported status that are not supposed to be ever recorded. - if (expected_status == mirror::Class::kStatusVerifyingAtRuntime || - expected_status == mirror::Class::kStatusInitializing) { + if (expected_status == ClassStatus::kVerifyingAtRuntime || + expected_status == ClassStatus::kInitializing) { continue; } compiler_driver_->RecordClassStatus(ref, expected_status); - mirror::Class::Status status = {}; + ClassStatus status = {}; ASSERT_TRUE(compiler_driver_->GetCompiledClass(ref, &status)); EXPECT_EQ(status, expected_status); } diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index c0a9a05aa6..1780b1d7ed 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -20,6 +20,7 @@ #include "android-base/stringprintf.h" +#include "base/runtime_debug.h" #include "base/variant_map.h" #include "cmdline_parser.h" #include "compiler_options_map-inl.h" @@ -68,17 +69,16 @@ CompilerOptions::~CompilerOptions() { // because we don't want to include the PassManagerOptions definition from the header file. } +namespace { + +bool kEmitRuntimeReadBarrierChecks = kIsDebugBuild && + RegisterRuntimeDebugFlag(&kEmitRuntimeReadBarrierChecks); + +} // namespace + bool CompilerOptions::EmitRunTimeChecksInDebugMode() const { - // Run-time checks (e.g. Marking Register checks) are only emitted - // in debug mode, and - // - when running on device; or - // - when running on host, but only - // - when compiling the core image (which is used only for testing); or - // - when JIT compiling (only relevant for non-native methods). - // This is to prevent these checks from being emitted into pre-opted - // boot image or apps, as these are compiled with dex2oatd. - return kIsDebugBuild && - (kIsTargetBuild || IsCoreImage() || Runtime::Current()->UseJitCompilation()); + // Run-time checks (e.g. Marking Register checks) are only emitted in slow-debug mode. + return kEmitRuntimeReadBarrierChecks; } bool CompilerOptions::ParseDumpInitFailures(const std::string& option, std::string* error_msg) { diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index 7e8e812c4a..28e68c94df 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -16,6 +16,7 @@ #include "dex_compilation_unit.h" +#include "dex/code_item_accessors-inl.h" #include "mirror/dex_cache.h" #include "utils.h" @@ -38,8 +39,8 @@ DexCompilationUnit::DexCompilationUnit(Handle<mirror::ClassLoader> class_loader, dex_method_idx_(method_idx), access_flags_(access_flags), verified_method_(verified_method), - dex_cache_(dex_cache) { -} + dex_cache_(dex_cache), + code_item_accessor_(dex_file, code_item) {} const std::string& DexCompilationUnit::GetSymbol() { if (symbol_.empty()) { diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 24a9a5b653..c1ae3c938b 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -20,7 +20,8 @@ #include <stdint.h> #include "base/arena_object.h" -#include "dex_file.h" +#include "dex/code_item_accessors.h" +#include "dex/dex_file.h" #include "handle.h" #include "jni.h" @@ -112,6 +113,10 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { return dex_cache_; } + const CodeItemDataAccessor& GetCodeItemAccessor() const { + return code_item_accessor_; + } + private: const Handle<mirror::ClassLoader> class_loader_; @@ -127,6 +132,8 @@ class DexCompilationUnit : public DeletableArenaObject<kArenaAllocMisc> { const Handle<mirror::DexCache> dex_cache_; + const CodeItemDataAccessor code_item_accessor_; + std::string symbol_; }; diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index 897b50bdac..7bacacf91d 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -21,8 +21,10 @@ #include "base/enums.h" #include "class_linker.h" #include "common_runtime_test.h" -#include "dex_file-inl.h" -#include "dex_file.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file.h" +#include "dex/dex_file_exception_helpers.h" #include "gtest/gtest.h" #include "handle_scope-inl.h" #include "leb128.h" @@ -128,19 +130,18 @@ class ExceptionTest : public CommonRuntimeTest { TEST_F(ExceptionTest, FindCatchHandler) { ScopedObjectAccess soa(Thread::Current()); - const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset()); + CodeItemDataAccessor accessor(*dex_, dex_->GetCodeItem(method_f_->GetCodeItemOffset())); - ASSERT_TRUE(code_item != nullptr); + ASSERT_TRUE(accessor.HasCodeItem()); - ASSERT_EQ(2u, code_item->tries_size_); - ASSERT_NE(0u, code_item->insns_size_in_code_units_); + ASSERT_EQ(2u, accessor.TriesSize()); + ASSERT_NE(0u, accessor.InsnsSizeInCodeUnits()); - const DexFile::TryItem *t0, *t1; - t0 = dex_->GetTryItems(*code_item, 0); - t1 = dex_->GetTryItems(*code_item, 1); - EXPECT_LE(t0->start_addr_, t1->start_addr_); + const DexFile::TryItem& t0 = accessor.TryItems().begin()[0]; + const DexFile::TryItem& t1 = accessor.TryItems().begin()[1]; + EXPECT_LE(t0.start_addr_, t1.start_addr_); { - CatchHandlerIterator iter(*code_item, 4 /* Dex PC in the first try block */); + CatchHandlerIterator iter(accessor, 4 /* Dex PC in the first try block */); EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); ASSERT_TRUE(iter.HasNext()); iter.Next(); @@ -150,14 +151,14 @@ TEST_F(ExceptionTest, FindCatchHandler) { EXPECT_FALSE(iter.HasNext()); } { - CatchHandlerIterator iter(*code_item, 8 /* Dex PC in the second try block */); + CatchHandlerIterator iter(accessor, 8 /* Dex PC in the second try block */); EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); ASSERT_TRUE(iter.HasNext()); iter.Next(); EXPECT_FALSE(iter.HasNext()); } { - CatchHandlerIterator iter(*code_item, 11 /* Dex PC not in any try block */); + CatchHandlerIterator iter(accessor, 11 /* Dex PC not in any try block */); EXPECT_FALSE(iter.HasNext()); } } diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index daf64d1298..f34e9b844b 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -24,7 +24,7 @@ #include "class_linker.h" #include "common_compiler_test.h" #include "compiler.h" -#include "dex_file.h" +#include "dex/dex_file.h" #include "gtest/gtest.h" #include "indirect_reference_table.h" #include "java_vm_ext.h" @@ -299,7 +299,6 @@ class JniCompilerTest : public CommonCompilerTest { } // JNI operations after runtime start. env_ = Thread::Current()->GetJniEnv(); - library_search_path_ = env_->NewStringUTF(""); jklass_ = env_->FindClass("MyClassNatives"); ASSERT_TRUE(jklass_ != nullptr) << method_name << " " << method_sig; @@ -380,7 +379,6 @@ class JniCompilerTest : public CommonCompilerTest { void CriticalNativeImpl(); JNIEnv* env_; - jstring library_search_path_; jmethodID jmethod_; private: @@ -660,7 +658,7 @@ void JniCompilerTest::CompileAndRunIntMethodThroughStubImpl() { std::string reason; ASSERT_TRUE(Runtime::Current()->GetJavaVM()-> - LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason)) + LoadNativeLibrary(env_, "", class_loader_, &reason)) << reason; jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 24); @@ -676,7 +674,7 @@ void JniCompilerTest::CompileAndRunStaticIntMethodThroughStubImpl() { std::string reason; ASSERT_TRUE(Runtime::Current()->GetJavaVM()-> - LoadNativeLibrary(env_, "", class_loader_, library_search_path_, &reason)) + LoadNativeLibrary(env_, "", class_loader_, &reason)) << reason; jint result = env_->CallStaticIntMethod(jklass_, jmethod_, 42); diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 136e3db062..fc44927231 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -30,7 +30,7 @@ #include "calling_convention.h" #include "class_linker.h" #include "debug/dwarf/debug_frame_opcode_writer.h" -#include "dex_file-inl.h" +#include "dex/dex_file-inl.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "entrypoints/quick/quick_entrypoints.h" diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index 2cb23d1710..cedbe5d97f 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -19,7 +19,7 @@ #include "base/stl_util.h" #include "compiled_method-inl.h" #include "debug/method_debug_info.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "linker/linker_patch.h" #include "linker/output_stream.h" #include "oat.h" diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h index aa3cd98595..5262ab6f3b 100644 --- a/compiler/linker/elf_builder.h +++ b/compiler/linker/elf_builder.h @@ -38,9 +38,10 @@ namespace linker { // Elf_Ehdr - The ELF header. // Elf_Phdr[] - Program headers for the linker. // .note.gnu.build-id - Optional build ID section (SHA-1 digest). -// .rodata - DEX files and oat metadata. +// .rodata - Oat metadata. // .text - Compiled code. // .bss - Zero-initialized writeable section. +// .dex - Reserved NOBITS space for dex-related data. // .MIPS.abiflags - MIPS specific section. // .dynstr - Names for .dynsym. // .dynsym - A few oat-specific dynamic symbols. @@ -503,6 +504,7 @@ class ElfBuilder FINAL { rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0), bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), + dex_(this, ".dex", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize), dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_), hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)), @@ -525,6 +527,7 @@ class ElfBuilder FINAL { virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; + dex_.phdr_flags_ = PF_R; dynamic_.phdr_flags_ = PF_R | PF_W; dynamic_.phdr_type_ = PT_DYNAMIC; eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME; @@ -538,6 +541,7 @@ class ElfBuilder FINAL { Section* GetRoData() { return &rodata_; } Section* GetText() { return &text_; } Section* GetBss() { return &bss_; } + Section* GetDex() { return &dex_; } StringSection* GetStrTab() { return &strtab_; } SymbolSection* GetSymTab() { return &symtab_; } Section* GetEhFrame() { return &eh_frame_; } @@ -666,7 +670,8 @@ class ElfBuilder FINAL { Elf_Word text_size, Elf_Word bss_size, Elf_Word bss_methods_offset, - Elf_Word bss_roots_offset) { + Elf_Word bss_roots_offset, + Elf_Word dex_size) { std::string soname(elf_file_path); size_t directory_separator_pos = soname.rfind('/'); if (directory_separator_pos != std::string::npos) { @@ -679,6 +684,9 @@ class ElfBuilder FINAL { if (bss_size != 0) { bss_.AllocateVirtualMemory(bss_size); } + if (dex_size != 0) { + dex_.AllocateVirtualMemory(dex_size); + } if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) { abiflags_.AllocateVirtualMemory(abiflags_.GetSize()); } @@ -725,6 +733,14 @@ class ElfBuilder FINAL { Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4; dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT); } + if (dex_size != 0u) { + Elf_Word oatdex = dynstr_.Add("oatdex"); + dynsym_.Add(oatdex, &dex_, dex_.GetAddress(), dex_size, STB_GLOBAL, STT_OBJECT); + Elf_Word oatdexlastword = dynstr_.Add("oatdexlastword"); + Elf_Word oatdexlastword_address = dex_.GetAddress() + dex_size - 4; + dynsym_.Add(oatdexlastword, &dex_, oatdexlastword_address, 4, STB_GLOBAL, STT_OBJECT); + } + Elf_Word soname_offset = dynstr_.Add(soname); // We do not really need a hash-table since there is so few entries. @@ -967,6 +983,7 @@ class ElfBuilder FINAL { Section rodata_; Section text_; Section bss_; + Section dex_; CachedStringSection dynstr_; SymbolSection dynsym_; CachedSection hash_; diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc index 58f591bd1e..2b568bcffd 100644 --- a/compiler/optimizing/block_builder.cc +++ b/compiler/optimizing/block_builder.cc @@ -18,10 +18,32 @@ #include "base/logging.h" // FOR VLOG. #include "bytecode_utils.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file_exception_helpers.h" #include "quicken_info.h" namespace art { +HBasicBlockBuilder::HBasicBlockBuilder(HGraph* graph, + const DexFile* const dex_file, + const CodeItemDebugInfoAccessor& accessor, + ScopedArenaAllocator* local_allocator) + : allocator_(graph->GetAllocator()), + graph_(graph), + dex_file_(dex_file), + code_item_accessor_(accessor), + local_allocator_(local_allocator), + branch_targets_(code_item_accessor_.HasCodeItem() + ? code_item_accessor_.InsnsSizeInCodeUnits() + : /* fake dex_pc=0 for intrinsic graph */ 1u, + nullptr, + local_allocator->Adapter(kArenaAllocGraphBuilder)), + throwing_blocks_(kDefaultNumberOfThrowingBlocks, + local_allocator->Adapter(kArenaAllocGraphBuilder)), + number_of_branches_(0u), + quicken_index_for_dex_pc_(std::less<uint32_t>(), + local_allocator->Adapter(kArenaAllocGraphBuilder)) {} + HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t dex_pc) { return MaybeCreateBlockAt(dex_pc, dex_pc); } @@ -41,20 +63,19 @@ bool HBasicBlockBuilder::CreateBranchTargets() { // Create the first block for the dex instructions, single successor of the entry block. MaybeCreateBlockAt(0u); - if (code_item_->tries_size_ != 0) { + if (code_item_accessor_.TriesSize() != 0) { // Create branch targets at the start/end of the TryItem range. These are // places where the program might fall through into/out of the a block and // where TryBoundary instructions will be inserted later. Other edges which // enter/exit the try blocks are a result of branches/switches. - for (size_t idx = 0; idx < code_item_->tries_size_; ++idx) { - const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item_, idx); - uint32_t dex_pc_start = try_item->start_addr_; - uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_; + for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) { + uint32_t dex_pc_start = try_item.start_addr_; + uint32_t dex_pc_end = dex_pc_start + try_item.insn_count_; MaybeCreateBlockAt(dex_pc_start); - if (dex_pc_end < code_item_->insns_size_in_code_units_) { + if (dex_pc_end < code_item_accessor_.InsnsSizeInCodeUnits()) { // TODO: Do not create block if the last instruction cannot fall through. MaybeCreateBlockAt(dex_pc_end); - } else if (dex_pc_end == code_item_->insns_size_in_code_units_) { + } else if (dex_pc_end == code_item_accessor_.InsnsSizeInCodeUnits()) { // The TryItem spans until the very end of the CodeItem and therefore // cannot have any code afterwards. } else { @@ -65,7 +86,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { } // Create branch targets for exception handlers. - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); + const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData(); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; ++idx) { CatchHandlerIterator iterator(handlers_ptr); @@ -78,8 +99,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { // Iterate over all instructions and find branching instructions. Create blocks for // the locations these instructions branch to. - IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); - for (const DexInstructionPcPair& pair : instructions) { + for (const DexInstructionPcPair& pair : code_item_accessor_) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); @@ -109,7 +129,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { if (instruction.CanFlowThrough()) { DexInstructionIterator next(std::next(DexInstructionIterator(pair))); - if (next == instructions.end()) { + if (next == code_item_accessor_.end()) { // In the normal case we should never hit this but someone can artificially forge a dex // file to fall-through out the method code. In this case we bail out compilation. VLOG(compiler) << "Not compiled: Fall-through beyond the CodeItem"; @@ -130,7 +150,7 @@ void HBasicBlockBuilder::ConnectBasicBlocks() { bool is_throwing_block = false; // Calculate the qucikening index here instead of CreateBranchTargets since it's easier to // calculate in dex_pc order. - for (const DexInstructionPcPair& pair : code_item_->Instructions()) { + for (const DexInstructionPcPair& pair : code_item_accessor_) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); @@ -213,10 +233,12 @@ static const DexFile::TryItem* GetTryItem( // successors matches the order in which runtime exception delivery searches // for a handler. static void LinkToCatchBlocks(HTryBoundary* try_boundary, - const DexFile::CodeItem& code_item, + const CodeItemDataAccessor& accessor, const DexFile::TryItem* try_item, const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) { - for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) { + for (CatchHandlerIterator it(accessor.GetCatchHandlerData(try_item->handler_off_)); + it.HasNext(); + it.Next()) { try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress())); } } @@ -232,7 +254,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc } } - const Instruction& first = code_item_->InstructionAt(catch_block->GetDexPc()); + const Instruction& first = code_item_accessor_.InstructionAt(catch_block->GetDexPc()); if (first.Opcode() == Instruction::MOVE_EXCEPTION) { // Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then // it has no live normal predecessors. @@ -250,7 +272,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc } void HBasicBlockBuilder::InsertTryBoundaryBlocks() { - if (code_item_->tries_size_ == 0) { + if (code_item_accessor_.TriesSize() == 0) { return; } @@ -272,12 +294,10 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // loop for synchronized blocks. if (ContainsElement(throwing_blocks_, block)) { // Try to find a TryItem covering the block. - const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(*code_item_, 0u), - code_item_->tries_size_, - block->GetDexPc()); - if (try_item_idx != -1) { + const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(block->GetDexPc()); + if (try_item != nullptr) { // Block throwing and in a TryItem. Store the try block information. - try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(*code_item_, try_item_idx)); + try_block_info.Put(block->GetBlockId(), try_item); } } } @@ -288,7 +308,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // Iterate over catch blocks, create artifical landing pads if necessary to // simplify the CFG, and set metadata. - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); + const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData(); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; ++idx) { CatchHandlerIterator iterator(handlers_ptr); @@ -336,7 +356,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { HTryBoundary* try_entry = new (allocator_) HTryBoundary( HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc()); try_block->CreateImmediateDominator()->AddInstruction(try_entry); - LinkToCatchBlocks(try_entry, *code_item_, try_item, catch_blocks); + LinkToCatchBlocks(try_entry, code_item_accessor_, try_item, catch_blocks); break; } } @@ -364,13 +384,13 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { HTryBoundary* try_exit = new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc()); graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); - LinkToCatchBlocks(try_exit, *code_item_, try_item, catch_blocks); + LinkToCatchBlocks(try_exit, code_item_accessor_, try_item, catch_blocks); } } } bool HBasicBlockBuilder::Build() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc)); @@ -388,7 +408,7 @@ bool HBasicBlockBuilder::Build() { } void HBasicBlockBuilder::BuildIntrinsic() { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); // Create blocks. diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h index 7d0f56db34..2c1f034d80 100644 --- a/compiler/optimizing/block_builder.h +++ b/compiler/optimizing/block_builder.h @@ -19,7 +19,8 @@ #include "base/scoped_arena_allocator.h" #include "base/scoped_arena_containers.h" -#include "dex_file.h" +#include "dex/code_item_accessors.h" +#include "dex/dex_file.h" #include "nodes.h" namespace art { @@ -28,22 +29,8 @@ class HBasicBlockBuilder : public ValueObject { public: HBasicBlockBuilder(HGraph* graph, const DexFile* const dex_file, - const DexFile::CodeItem* code_item, - ScopedArenaAllocator* local_allocator) - : allocator_(graph->GetAllocator()), - graph_(graph), - dex_file_(dex_file), - code_item_(code_item), - local_allocator_(local_allocator), - branch_targets_(code_item != nullptr ? code_item->insns_size_in_code_units_ - : /* fake dex_pc=0 for intrinsic graph */ 1u, - nullptr, - local_allocator->Adapter(kArenaAllocGraphBuilder)), - throwing_blocks_(kDefaultNumberOfThrowingBlocks, - local_allocator->Adapter(kArenaAllocGraphBuilder)), - number_of_branches_(0u), - quicken_index_for_dex_pc_(std::less<uint32_t>(), - local_allocator->Adapter(kArenaAllocGraphBuilder)) {} + const CodeItemDebugInfoAccessor& accessor, + ScopedArenaAllocator* local_allocator); // Creates basic blocks in `graph_` at branch target dex_pc positions of the // `code_item_`. Blocks are connected but left unpopulated with instructions. @@ -83,7 +70,7 @@ class HBasicBlockBuilder : public ValueObject { HGraph* const graph_; const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + CodeItemDataAccessor code_item_accessor_; // null code item for intrinsic graph. ScopedArenaAllocator* const local_allocator_; ScopedArenaVector<HBasicBlock*> branch_targets_; diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index d73ef1f3a1..af537dd653 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -37,7 +37,7 @@ namespace art { HGraphBuilder::HGraphBuilder(HGraph* graph, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, CompilerDriver* driver, @@ -47,7 +47,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, VariableSizedHandleScope* handles) : graph_(graph), dex_file_(&graph->GetDexFile()), - code_item_(code_item), + code_item_accessor_(accessor), dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), compiler_driver_(driver), @@ -57,6 +57,23 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, handles_(handles), return_type_(DataType::FromShorty(dex_compilation_unit_->GetShorty()[0])) {} +HGraphBuilder::HGraphBuilder(HGraph* graph, + const DexCompilationUnit* dex_compilation_unit, + const CodeItemDebugInfoAccessor& accessor, + VariableSizedHandleScope* handles, + DataType::Type return_type) + : graph_(graph), + dex_file_(&graph->GetDexFile()), + code_item_accessor_(accessor), + dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(nullptr), + compiler_driver_(nullptr), + code_generator_(nullptr), + compilation_stats_(nullptr), + interpreter_metadata_(nullptr), + handles_(handles), + return_type_(return_type) {} + bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { if (compiler_driver_ == nullptr) { // Note that the compiler driver is null when unit testing. @@ -69,20 +86,20 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { return false; } - if (compiler_options.IsHugeMethod(code_item_->insns_size_in_code_units_)) { + const uint32_t code_units = code_item_accessor_.InsnsSizeInCodeUnits(); + if (compiler_options.IsHugeMethod(code_units)) { VLOG(compiler) << "Skip compilation of huge method " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_->insns_size_in_code_units_ << " code units"; + << ": " << code_units << " code units"; MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledHugeMethod); return true; } // If it's large and contains no branches, it's likely to be machine generated initialization. - if (compiler_options.IsLargeMethod(code_item_->insns_size_in_code_units_) - && (number_of_branches == 0)) { + if (compiler_options.IsLargeMethod(code_units) && (number_of_branches == 0)) { VLOG(compiler) << "Skip compilation of large method with no branch " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_->insns_size_in_code_units_ << " code units"; + << ": " << code_units << " code units"; MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledLargeMethodNoBranches); return true; } @@ -91,17 +108,17 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { } GraphAnalysisResult HGraphBuilder::BuildGraph() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); - graph_->SetNumberOfVRegs(code_item_->registers_size_); - graph_->SetNumberOfInVRegs(code_item_->ins_size_); - graph_->SetMaximumNumberOfOutVRegs(code_item_->outs_size_); - graph_->SetHasTryCatch(code_item_->tries_size_ != 0); + graph_->SetNumberOfVRegs(code_item_accessor_.RegistersSize()); + graph_->SetNumberOfInVRegs(code_item_accessor_.InsSize()); + graph_->SetMaximumNumberOfOutVRegs(code_item_accessor_.OutsSize()); + graph_->SetHasTryCatch(code_item_accessor_.TriesSize() != 0); // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); - HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_, &local_allocator); + HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_accessor_, &local_allocator); SsaBuilder ssa_builder(graph_, dex_compilation_unit_->GetClassLoader(), dex_compilation_unit_->GetDexCache(), @@ -111,7 +128,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { &block_builder, &ssa_builder, dex_file_, - code_item_, + code_item_accessor_, return_type_, dex_compilation_unit_, outer_compilation_unit_, @@ -150,7 +167,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { } void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); // Determine the number of arguments and associated vregs. @@ -170,7 +187,10 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); - HBasicBlockBuilder block_builder(graph_, dex_file_, /* code_item */ nullptr, &local_allocator); + HBasicBlockBuilder block_builder(graph_, + dex_file_, + CodeItemDebugInfoAccessor(), + &local_allocator); SsaBuilder ssa_builder(graph_, dex_compilation_unit_->GetClassLoader(), dex_compilation_unit_->GetDexCache(), @@ -180,7 +200,7 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { &block_builder, &ssa_builder, dex_file_, - /* code_item */ nullptr, + CodeItemDebugInfoAccessor(), return_type_, dex_compilation_unit_, outer_compilation_unit_, diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 0bb3a051f7..c16a3a928d 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -18,8 +18,9 @@ #define ART_COMPILER_OPTIMIZING_BUILDER_H_ #include "base/arena_object.h" -#include "dex_file-inl.h" -#include "dex_file.h" +#include "dex/code_item_accessors.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file.h" #include "driver/compiler_driver.h" #include "nodes.h" @@ -33,7 +34,7 @@ class OptimizingCompilerStats; class HGraphBuilder : public ValueObject { public: HGraphBuilder(HGraph* graph, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, CompilerDriver* driver, @@ -45,20 +46,9 @@ class HGraphBuilder : public ValueObject { // Only for unit testing. HGraphBuilder(HGraph* graph, const DexCompilationUnit* dex_compilation_unit, - const DexFile::CodeItem& code_item, + const CodeItemDebugInfoAccessor& accessor, VariableSizedHandleScope* handles, - DataType::Type return_type = DataType::Type::kInt32) - : graph_(graph), - dex_file_(&graph->GetDexFile()), - code_item_(&code_item), - dex_compilation_unit_(dex_compilation_unit), - outer_compilation_unit_(nullptr), - compiler_driver_(nullptr), - code_generator_(nullptr), - compilation_stats_(nullptr), - interpreter_metadata_(nullptr), - handles_(handles), - return_type_(return_type) {} + DataType::Type return_type = DataType::Type::kInt32); GraphAnalysisResult BuildGraph(); void BuildIntrinsicGraph(ArtMethod* method); @@ -70,7 +60,7 @@ class HGraphBuilder : public ValueObject { HGraph* const graph_; const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph. // The compilation unit of the current method being compiled. Note that // it can be an inlined method. diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index dee74e96dc..01155dcd37 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -46,6 +46,7 @@ #include "bytecode_utils.h" #include "class_linker.h" #include "compiled_method.h" +#include "dex/code_item_accessors-inl.h" #include "dex/verified_method.h" #include "driver/compiler_driver.h" #include "graph_visualizer.h" @@ -910,7 +911,8 @@ static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph, } ArenaVector<size_t> covered( loop_headers.size(), 0, graph.GetAllocator()->Adapter(kArenaAllocMisc)); - for (const DexInstructionPcPair& pair : code_item.Instructions()) { + for (const DexInstructionPcPair& pair : CodeItemInstructionAccessor(graph.GetDexFile(), + &code_item)) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); if (instruction.IsBranch()) { diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index f9dcb5d6ef..28f481670c 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -2097,15 +2097,18 @@ void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCod Register class_reg) { UseScratchRegisterScope temps(GetVIXLAssembler()); Register temp = temps.AcquireW(); - size_t status_offset = mirror::Class::StatusOffset().SizeValue(); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); // Even if the initialized flag is set, we need to ensure consistent memory ordering. // TODO(vixl): Let the MacroAssembler handle MemOperand. - __ Add(temp, class_reg, status_offset); + __ Add(temp, class_reg, status_byte_offset); __ Ldarb(temp, HeapOperand(temp)); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(ne, slow_path->GetEntryLabel()); - // Use Bne instead of Blt because ARM64 doesn't have Ldarsb. + __ Cmp(temp, shifted_initialized_value); + __ B(lo, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index e53773c73d..f92c94fda7 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -20,7 +20,7 @@ #include "arch/arm64/quick_method_frame_info_arm64.h" #include "code_generator.h" #include "common_arm64.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 017598d484..f1ad4e187e 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -1128,7 +1128,7 @@ class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARMVIXL // // Note that this field could also hold a different object, if // another thread had concurrently changed it. In that case, the - // LDREX/SUBS/ITNE sequence of instructions in the compare-and-set + // LDREX/CMP/BNE sequence of instructions in the compare-and-set // (CAS) operation below would abort the CAS, leaving the field // as-is. __ Cmp(temp1_, ref_reg); @@ -1168,28 +1168,16 @@ class LoadReferenceWithBakerReadBarrierAndUpdateFieldSlowPathARMVIXL // tmp = [r_ptr] - expected; // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); - vixl32::Label loop_head, exit_loop; + vixl32::Label loop_head, comparison_failed, exit_loop; __ Bind(&loop_head); - __ Ldrex(tmp, MemOperand(tmp_ptr)); - - __ Subs(tmp, tmp, expected); - - { - ExactAssemblyScope aas(arm_codegen->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - - __ it(ne); - __ clrex(ne); - } - - __ B(ne, &exit_loop, /* far_target */ false); - + __ Cmp(tmp, expected); + __ B(ne, &comparison_failed, /* far_target */ false); __ Strex(tmp, value, MemOperand(tmp_ptr)); - __ Cmp(tmp, 1); - __ B(eq, &loop_head, /* far_target */ false); - + __ CompareAndBranchIfZero(tmp, &exit_loop, /* far_target */ false); + __ B(&loop_head); + __ Bind(&comparison_failed); + __ Clrex(); __ Bind(&exit_loop); if (kPoisonHeapReferences) { @@ -5609,42 +5597,13 @@ Location LocationsBuilderARMVIXL::ArmEncodableConstantOrRegister(HInstruction* c return Location::RequiresRegister(); } -bool LocationsBuilderARMVIXL::CanEncodeConstantAsImmediate(HConstant* input_cst, - Opcode opcode) { - uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst)); - if (DataType::Is64BitType(input_cst->GetType())) { - Opcode high_opcode = opcode; - SetCc low_set_cc = kCcDontCare; - switch (opcode) { - case SUB: - // Flip the operation to an ADD. - value = -value; - opcode = ADD; - FALLTHROUGH_INTENDED; - case ADD: - if (Low32Bits(value) == 0u) { - return CanEncodeConstantAsImmediate(High32Bits(value), opcode, kCcDontCare); - } - high_opcode = ADC; - low_set_cc = kCcSet; - break; - default: - break; - } - return CanEncodeConstantAsImmediate(Low32Bits(value), opcode, low_set_cc) && - CanEncodeConstantAsImmediate(High32Bits(value), high_opcode, kCcDontCare); - } else { - return CanEncodeConstantAsImmediate(Low32Bits(value), opcode); - } -} - -// TODO(VIXL): Replace art::arm::SetCc` with `vixl32::FlagsUpdate after flags set optimization -// enabled. -bool LocationsBuilderARMVIXL::CanEncodeConstantAsImmediate(uint32_t value, - Opcode opcode, - SetCc set_cc) { - ArmVIXLAssembler* assembler = codegen_->GetAssembler(); - if (assembler->ShifterOperandCanHold(opcode, value, set_cc)) { +static bool CanEncode32BitConstantAsImmediate( + CodeGeneratorARMVIXL* codegen, + uint32_t value, + Opcode opcode, + vixl32::FlagsUpdate flags_update = vixl32::FlagsUpdate::DontCare) { + ArmVIXLAssembler* assembler = codegen->GetAssembler(); + if (assembler->ShifterOperandCanHold(opcode, value, flags_update)) { return true; } Opcode neg_opcode = kNoOperand; @@ -5661,13 +5620,41 @@ bool LocationsBuilderARMVIXL::CanEncodeConstantAsImmediate(uint32_t value, return false; } - if (assembler->ShifterOperandCanHold(neg_opcode, neg_value, set_cc)) { + if (assembler->ShifterOperandCanHold(neg_opcode, neg_value, flags_update)) { return true; } return opcode == AND && IsPowerOfTwo(value + 1); } +bool LocationsBuilderARMVIXL::CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode) { + uint64_t value = static_cast<uint64_t>(Int64FromConstant(input_cst)); + if (DataType::Is64BitType(input_cst->GetType())) { + Opcode high_opcode = opcode; + vixl32::FlagsUpdate low_flags_update = vixl32::FlagsUpdate::DontCare; + switch (opcode) { + case SUB: + // Flip the operation to an ADD. + value = -value; + opcode = ADD; + FALLTHROUGH_INTENDED; + case ADD: + if (Low32Bits(value) == 0u) { + return CanEncode32BitConstantAsImmediate(codegen_, High32Bits(value), opcode); + } + high_opcode = ADC; + low_flags_update = vixl32::FlagsUpdate::SetFlags; + break; + default: + break; + } + return CanEncode32BitConstantAsImmediate(codegen_, High32Bits(value), high_opcode) && + CanEncode32BitConstantAsImmediate(codegen_, Low32Bits(value), opcode, low_flags_update); + } else { + return CanEncode32BitConstantAsImmediate(codegen_, Low32Bits(value), opcode); + } +} + void InstructionCodeGeneratorARMVIXL::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); @@ -7185,12 +7172,15 @@ void InstructionCodeGeneratorARMVIXL::GenerateClassInitializationCheck( LoadClassSlowPathARMVIXL* slow_path, vixl32::Register class_reg) { UseScratchRegisterScope temps(GetVIXLAssembler()); vixl32::Register temp = temps.Acquire(); - GetAssembler()->LoadFromOffset(kLoadSignedByte, - temp, - class_reg, - mirror::Class::StatusOffset().Int32Value()); - __ Cmp(temp, mirror::Class::kStatusInitialized); - __ B(lt, slow_path->GetEntryLabel()); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); + + GetAssembler()->LoadFromOffset(kLoadUnsignedByte, temp, class_reg, status_byte_offset); + __ Cmp(temp, shifted_initialized_value); + __ B(lo, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we may be in a situation where caches are not synced // properly. Therefore, we do a memory fence. __ Dmb(ISH); @@ -8143,13 +8133,11 @@ void InstructionCodeGeneratorARMVIXL::GenerateAddLongConst(Location out, return; } __ Adds(out_low, first_low, value_low); - if (GetAssembler()->ShifterOperandCanHold(ADC, value_high, kCcDontCare)) { + if (GetAssembler()->ShifterOperandCanHold(ADC, value_high)) { __ Adc(out_high, first_high, value_high); - } else if (GetAssembler()->ShifterOperandCanHold(SBC, ~value_high, kCcDontCare)) { - __ Sbc(out_high, first_high, ~value_high); } else { - LOG(FATAL) << "Unexpected constant " << value_high; - UNREACHABLE(); + DCHECK(GetAssembler()->ShifterOperandCanHold(SBC, ~value_high)); + __ Sbc(out_high, first_high, ~value_high); } } diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index c46d17ccec..38570bb0fe 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -287,7 +287,6 @@ class LocationsBuilderARMVIXL : public HGraphVisitor { Location ArithmeticZeroOrFpuRegister(HInstruction* input); Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode); bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode); - bool CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode, SetCc set_cc = kCcDontCare); CodeGeneratorARMVIXL* const codegen_; InvokeDexCallingConventionVisitorARMVIXL parameter_visitor_; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 9f4c2349e7..c8bd5d4fc8 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1915,9 +1915,15 @@ void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool d void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg) { - __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); - __ LoadConst32(AT, mirror::Class::kStatusInitialized); - __ Blt(TMP, AT, slow_path->GetEntryLabel()); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); + + __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset); + __ LoadConst32(AT, shifted_initialized_value); + __ Bltu(TMP, AT, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we need to ensure consistent memory ordering. __ Sync(0); __ Bind(slow_path->GetExitLabel()); @@ -3774,8 +3780,12 @@ void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruct if (IsUint<16>(abs_imm - 1)) { __ Andi(out, out, abs_imm - 1); } else { - __ Sll(out, out, 32 - ctz_imm); - __ Srl(out, out, 32 - ctz_imm); + if (codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()) { + __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm); + } else { + __ Sll(out, out, 32 - ctz_imm); + __ Srl(out, out, 32 - ctz_imm); + } } __ Subu(out, out, TMP); } diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index cf8e7a373a..32b3e4221f 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -18,7 +18,7 @@ #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_ #include "code_generator.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index eb64f1be23..bbdc3be5c1 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -1761,9 +1761,15 @@ void CodeGeneratorMIPS64::GenerateInvokeRuntime(int32_t entry_point_offset) { void InstructionCodeGeneratorMIPS64::GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg) { - __ LoadFromOffset(kLoadSignedByte, TMP, class_reg, mirror::Class::StatusOffset().Int32Value()); - __ LoadConst32(AT, mirror::Class::kStatusInitialized); - __ Bltc(TMP, AT, slow_path->GetEntryLabel()); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); + + __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset); + __ LoadConst32(AT, shifted_initialized_value); + __ Bltuc(TMP, AT, slow_path->GetEntryLabel()); // Even if the initialized flag is set, we need to ensure consistent memory ordering. __ Sync(0); __ Bind(slow_path->GetExitLabel()); @@ -3311,12 +3317,7 @@ void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instru __ Sra(TMP, dividend, 31); __ Srl(TMP, TMP, 32 - ctz_imm); __ Addu(out, dividend, TMP); - if (IsUint<16>(abs_imm - 1)) { - __ Andi(out, out, abs_imm - 1); - } else { - __ Sll(out, out, 32 - ctz_imm); - __ Srl(out, out, 32 - ctz_imm); - } + __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm); __ Subu(out, out, TMP); } } else { @@ -3335,17 +3336,7 @@ void InstructionCodeGeneratorMIPS64::DivRemByPowerOfTwo(HBinaryOperation* instru __ Dsrl32(TMP, TMP, 32 - ctz_imm); } __ Daddu(out, dividend, TMP); - if (IsUint<16>(abs_imm - 1)) { - __ Andi(out, out, abs_imm - 1); - } else { - if (ctz_imm > 32) { - __ Dsll(out, out, 64 - ctz_imm); - __ Dsrl(out, out, 64 - ctz_imm); - } else { - __ Dsll32(out, out, 32 - ctz_imm); - __ Dsrl32(out, out, 32 - ctz_imm); - } - } + __ DblIns(out, ZERO, ctz_imm, 64 - ctz_imm); __ Dsubu(out, out, TMP); } } diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index ba222fe532..537e97aacf 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -6219,9 +6219,14 @@ void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) { void InstructionCodeGeneratorX86::GenerateClassInitializationCheck( SlowPathCode* slow_path, Register class_reg) { - __ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), - Immediate(mirror::Class::kStatusInitialized)); - __ j(kLess, slow_path->GetEntryLabel()); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); + + __ cmpb(Address(class_reg, status_byte_offset), Immediate(shifted_initialized_value)); + __ j(kBelow, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); // No need for memory fence, thanks to the X86 memory model. } diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 40b7e3c54f..0082853184 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -20,7 +20,7 @@ #include "arch/x86/instruction_set_features_x86.h" #include "base/enums.h" #include "code_generator.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "driver/compiler_options.h" #include "nodes.h" #include "parallel_move_resolver.h" diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index caad7885bd..4a6428592e 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -5425,9 +5425,14 @@ void ParallelMoveResolverX86_64::RestoreScratch(int reg) { void InstructionCodeGeneratorX86_64::GenerateClassInitializationCheck( SlowPathCode* slow_path, CpuRegister class_reg) { - __ cmpb(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), - Immediate(mirror::Class::kStatusInitialized)); - __ j(kLess, slow_path->GetEntryLabel()); + constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf(); + const size_t status_byte_offset = + mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte); + constexpr uint32_t shifted_initialized_value = + enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte); + + __ cmpb(Address(class_reg, status_byte_offset), Immediate(shifted_initialized_value)); + __ j(kBelow, slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); // No need for memory fence, thanks to the x86-64 memory model. } diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index ba431a5b08..6eda289861 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -20,8 +20,8 @@ #include "base/macros.h" #include "builder.h" #include "codegen_test_utils.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc index 6bf3a5943f..572466eec8 100644 --- a/compiler/optimizing/dominator_test.cc +++ b/compiler/optimizing/dominator_test.cc @@ -16,7 +16,7 @@ #include "base/arena_allocator.h" #include "builder.h" -#include "dex_instruction.h" +#include "dex/dex_instruction.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc index c91752855b..b799fb4688 100644 --- a/compiler/optimizing/find_loops_test.cc +++ b/compiler/optimizing/find_loops_test.cc @@ -16,8 +16,8 @@ #include "base/arena_allocator.h" #include "builder.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "pretty_printer.h" diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 8750910fe1..b2ad8ec400 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1381,26 +1381,26 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, bool same_dex_file = IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *method->GetDexFile()); - const DexFile::CodeItem* code_item = method->GetCodeItem(); + CodeItemDataAccessor accessor(method); - if (code_item == nullptr) { + if (!accessor.HasCodeItem()) { LOG_FAIL_NO_STAT() << "Method " << method->PrettyMethod() << " is not inlined because it is native"; return false; } size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits(); - if (code_item->insns_size_in_code_units_ > inline_max_code_units) { + if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem) << "Method " << method->PrettyMethod() << " is not inlined because its code item is too big: " - << code_item->insns_size_in_code_units_ + << accessor.InsnsSizeInCodeUnits() << " > " << inline_max_code_units; return false; } - if (code_item->tries_size_ != 0) { + if (accessor.TriesSize() != 0) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch) << "Method " << method->PrettyMethod() << " is not inlined because of try block"; return false; @@ -1660,6 +1660,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); uint32_t method_index = resolved_method->GetDexMethodIndex(); + CodeItemDebugInfoAccessor code_item_accessor(callee_dex_file, code_item); ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(), caller_compilation_unit_.GetDexCache(), @@ -1714,7 +1715,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } } HGraphBuilder builder(callee_graph, - code_item, + code_item_accessor, &dex_compilation_unit, &outer_compilation_unit_, compiler_driver_, @@ -1967,6 +1968,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph, return; } + CodeItemDataAccessor accessor(callee_graph->GetDexFile(), code_item); HInliner inliner(callee_graph, outermost_graph_, codegen_, @@ -1975,7 +1977,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph, compiler_driver_, handles_, inline_stats_, - total_number_of_dex_registers_ + code_item->registers_size_, + total_number_of_dex_registers_ + accessor.RegistersSize(), total_number_of_instructions_ + number_of_instructions, this, depth_ + 1); diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 042eee3204..e81d97b0a8 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -17,7 +17,7 @@ #ifndef ART_COMPILER_OPTIMIZING_INLINER_H_ #define ART_COMPILER_OPTIMIZING_INLINER_H_ -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "invoke_type.h" #include "jit/profile_compilation_info.h" #include "optimization.h" diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index e36d91fb05..72a93c1f77 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -23,7 +23,7 @@ #include "bytecode_utils.h" #include "class_linker.h" #include "data_type-inl.h" -#include "dex_instruction-inl.h" +#include "dex/dex_instruction-inl.h" #include "driver/compiler_driver-inl.h" #include "driver/dex_compilation_unit.h" #include "driver/compiler_options.h" @@ -39,6 +39,44 @@ namespace art { +HInstructionBuilder::HInstructionBuilder(HGraph* graph, + HBasicBlockBuilder* block_builder, + SsaBuilder* ssa_builder, + const DexFile* dex_file, + const CodeItemDebugInfoAccessor& accessor, + DataType::Type return_type, + const DexCompilationUnit* dex_compilation_unit, + const DexCompilationUnit* outer_compilation_unit, + CompilerDriver* compiler_driver, + CodeGenerator* code_generator, + const uint8_t* interpreter_metadata, + OptimizingCompilerStats* compiler_stats, + VariableSizedHandleScope* handles, + ScopedArenaAllocator* local_allocator) + : allocator_(graph->GetAllocator()), + graph_(graph), + handles_(handles), + dex_file_(dex_file), + code_item_accessor_(accessor), + return_type_(return_type), + block_builder_(block_builder), + ssa_builder_(ssa_builder), + compiler_driver_(compiler_driver), + code_generator_(code_generator), + dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(outer_compilation_unit), + quicken_info_(interpreter_metadata), + compilation_stats_(compiler_stats), + local_allocator_(local_allocator), + locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)), + current_block_(nullptr), + current_locals_(nullptr), + latest_result_(nullptr), + current_this_parameter_(nullptr), + loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { + loop_headers_.reserve(kDefaultNumberOfLoops); +} + HBasicBlock* HInstructionBuilder::FindBlockStartingAt(uint32_t dex_pc) const { return block_builder_->GetBlockAt(dex_pc); } @@ -273,7 +311,7 @@ static bool IsBlockPopulated(HBasicBlock* block) { } bool HInstructionBuilder::Build() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); locals_for_.resize( graph_->GetBlocks().size(), ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder))); @@ -323,7 +361,7 @@ bool HInstructionBuilder::Build() { quicken_index = block_builder_->GetQuickenIndex(block_dex_pc); } - for (const DexInstructionPcPair& pair : code_item_->Instructions(block_dex_pc)) { + for (const DexInstructionPcPair& pair : code_item_accessor_.InstructionsFrom(block_dex_pc)) { if (current_block_ == nullptr) { // The previous instruction ended this block. break; @@ -367,7 +405,7 @@ bool HInstructionBuilder::Build() { } void HInstructionBuilder::BuildIntrinsic(ArtMethod* method) { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(method->IsIntrinsic()); locals_for_.resize( @@ -442,15 +480,16 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() { return false; } }; - CodeItemDebugInfoAccessor accessor(dex_file_, code_item_); ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_, - accessor.InsnsSizeInCodeUnits(), + code_item_accessor_.InsnsSizeInCodeUnits(), /* expandable */ false, kArenaAllocGraphBuilder); locations->ClearAllBits(); - dex_file_->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), Callback::Position, locations); + dex_file_->DecodeDebugPositionInfo(code_item_accessor_.DebugInfoOffset(), + Callback::Position, + locations); // Instruction-specific tweaks. - for (const DexInstructionPcPair& inst : accessor) { + for (const DexInstructionPcPair& inst : code_item_accessor_) { switch (inst->Opcode()) { case Instruction::MOVE_EXCEPTION: { // Stop in native debugger after the exception has been moved. @@ -459,7 +498,7 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() { locations->ClearBit(inst.DexPc()); DexInstructionIterator next = std::next(DexInstructionIterator(inst)); DCHECK(next.DexPc() != inst.DexPc()); - if (next != accessor.end()) { + if (next != code_item_accessor_.end()) { locations->SetBit(next.DexPc()); } break; @@ -1706,7 +1745,8 @@ void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uin int32_t payload_offset = instruction.VRegB_31t() + dex_pc; const Instruction::ArrayDataPayload* payload = - reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item_->insns_ + payload_offset); + reinterpret_cast<const Instruction::ArrayDataPayload*>( + code_item_accessor_.Insns() + payload_offset); const uint8_t* data = payload->data; uint32_t element_count = payload->element_count; diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 0500d40cd3..708a09711a 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -20,8 +20,9 @@ #include "base/scoped_arena_allocator.h" #include "base/scoped_arena_containers.h" #include "data_type.h" -#include "dex_file.h" -#include "dex_file_types.h" +#include "dex/code_item_accessors.h" +#include "dex/dex_file.h" +#include "dex/dex_file_types.h" #include "handle.h" #include "nodes.h" #include "quicken_info.h" @@ -50,7 +51,7 @@ class HInstructionBuilder : public ValueObject { HBasicBlockBuilder* block_builder, SsaBuilder* ssa_builder, const DexFile* dex_file, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, DataType::Type return_type, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, @@ -59,30 +60,7 @@ class HInstructionBuilder : public ValueObject { const uint8_t* interpreter_metadata, OptimizingCompilerStats* compiler_stats, VariableSizedHandleScope* handles, - ScopedArenaAllocator* local_allocator) - : allocator_(graph->GetAllocator()), - graph_(graph), - handles_(handles), - dex_file_(dex_file), - code_item_(code_item), - return_type_(return_type), - block_builder_(block_builder), - ssa_builder_(ssa_builder), - compiler_driver_(compiler_driver), - code_generator_(code_generator), - dex_compilation_unit_(dex_compilation_unit), - outer_compilation_unit_(outer_compilation_unit), - quicken_info_(interpreter_metadata), - compilation_stats_(compiler_stats), - local_allocator_(local_allocator), - locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)), - current_block_(nullptr), - current_locals_(nullptr), - latest_result_(nullptr), - current_this_parameter_(nullptr), - loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { - loop_headers_.reserve(kDefaultNumberOfLoops); - } + ScopedArenaAllocator* local_allocator); bool Build(); void BuildIntrinsic(ArtMethod* method); @@ -329,7 +307,7 @@ class HInstructionBuilder : public ValueObject { // The dex file where the method being compiled is, and the bytecode data. const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph. // The return type of the method being compiled. const DataType::Type return_type_; diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 1d8ea092a4..99b8b5df74 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -1458,30 +1458,38 @@ void IntrinsicLocationsBuilderARMVIXL::VisitStringCompareTo(HInvoke* invoke) { locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); } +// Forward declaration. +// +// ART build system imposes a size limit (deviceFrameSizeLimit) on the stack frames generated +// by the compiler for every C++ function, and if this function gets inlined in +// IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo, the limit will be exceeded, resulting in a +// build failure. That is the reason why NO_INLINE attribute is used. +static void NO_INLINE GenerateStringCompareToLoop(ArmVIXLAssembler* assembler, + HInvoke* invoke, + vixl32::Label* end, + vixl32::Label* different_compression); + void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { ArmVIXLAssembler* assembler = GetAssembler(); LocationSummary* locations = invoke->GetLocations(); - vixl32::Register str = InputRegisterAt(invoke, 0); - vixl32::Register arg = InputRegisterAt(invoke, 1); - vixl32::Register out = OutputRegister(invoke); + const vixl32::Register str = InputRegisterAt(invoke, 0); + const vixl32::Register arg = InputRegisterAt(invoke, 1); + const vixl32::Register out = OutputRegister(invoke); - vixl32::Register temp0 = RegisterFrom(locations->GetTemp(0)); - vixl32::Register temp1 = RegisterFrom(locations->GetTemp(1)); - vixl32::Register temp2 = RegisterFrom(locations->GetTemp(2)); + const vixl32::Register temp0 = RegisterFrom(locations->GetTemp(0)); + const vixl32::Register temp1 = RegisterFrom(locations->GetTemp(1)); + const vixl32::Register temp2 = RegisterFrom(locations->GetTemp(2)); vixl32::Register temp3; if (mirror::kUseStringCompression) { temp3 = RegisterFrom(locations->GetTemp(3)); } - vixl32::Label loop; - vixl32::Label find_char_diff; vixl32::Label end; vixl32::Label different_compression; // Get offsets of count and value fields within a string object. const int32_t count_offset = mirror::String::CountOffset().Int32Value(); - const int32_t value_offset = mirror::String::ValueOffset().Int32Value(); // Note that the null check must have been done earlier. DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); @@ -1546,6 +1554,38 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { __ add(ne, temp0, temp0, temp0); } + + GenerateStringCompareToLoop(assembler, invoke, &end, &different_compression); + + __ Bind(&end); + + if (can_slow_path) { + __ Bind(slow_path->GetExitLabel()); + } +} + +static void GenerateStringCompareToLoop(ArmVIXLAssembler* assembler, + HInvoke* invoke, + vixl32::Label* end, + vixl32::Label* different_compression) { + LocationSummary* locations = invoke->GetLocations(); + + const vixl32::Register str = InputRegisterAt(invoke, 0); + const vixl32::Register arg = InputRegisterAt(invoke, 1); + const vixl32::Register out = OutputRegister(invoke); + + const vixl32::Register temp0 = RegisterFrom(locations->GetTemp(0)); + const vixl32::Register temp1 = RegisterFrom(locations->GetTemp(1)); + const vixl32::Register temp2 = RegisterFrom(locations->GetTemp(2)); + vixl32::Register temp3; + if (mirror::kUseStringCompression) { + temp3 = RegisterFrom(locations->GetTemp(3)); + } + + vixl32::Label loop; + vixl32::Label find_char_diff; + + const int32_t value_offset = mirror::String::ValueOffset().Int32Value(); // Store offset of string value in preparation for comparison loop. __ Mov(temp1, value_offset); @@ -1577,12 +1617,12 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { // With string compression, we have compared 8 bytes, otherwise 4 chars. __ Subs(temp0, temp0, (mirror::kUseStringCompression ? 8 : 4)); __ B(hi, &loop, /* far_target */ false); - __ B(&end); + __ B(end); __ Bind(&find_char_diff_2nd_cmp); if (mirror::kUseStringCompression) { __ Subs(temp0, temp0, 4); // 4 bytes previously compared. - __ B(ls, &end, /* far_target */ false); // Was the second comparison fully beyond the end? + __ B(ls, end, /* far_target */ false); // Was the second comparison fully beyond the end? } else { // Without string compression, we can start treating temp0 as signed // and rely on the signed comparison below. @@ -1610,7 +1650,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { // the remaining string data, so just return length diff (out). // The comparison is unsigned for string compression, otherwise signed. __ Cmp(temp0, Operand(temp1, vixl32::LSR, (mirror::kUseStringCompression ? 3 : 4))); - __ B((mirror::kUseStringCompression ? ls : le), &end, /* far_target */ false); + __ B((mirror::kUseStringCompression ? ls : le), end, /* far_target */ false); // Extract the characters and calculate the difference. if (mirror::kUseStringCompression) { @@ -1637,8 +1677,8 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { temps.Release(temp_reg); if (mirror::kUseStringCompression) { - __ B(&end); - __ Bind(&different_compression); + __ B(end); + __ Bind(different_compression); // Comparison for different compression style. const size_t c_char_size = DataType::Size(DataType::Type::kInt8); @@ -1680,7 +1720,7 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { __ B(ne, &different_compression_diff, /* far_target */ false); __ Subs(temp0, temp0, 2); __ B(hi, &different_compression_loop, /* far_target */ false); - __ B(&end); + __ B(end); // Calculate the difference. __ Bind(&different_compression_diff); @@ -1698,12 +1738,6 @@ void IntrinsicCodeGeneratorARMVIXL::VisitStringCompareTo(HInvoke* invoke) { __ it(cc); __ rsb(cc, out, out, 0); } - - __ Bind(&end); - - if (can_slow_path) { - __ Bind(slow_path->GetExitLabel()); - } } // The cut off for unrolling the loop in String.equals() intrinsic for const strings. diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc index b2a9c0a8e7..43b63a73ef 100644 --- a/compiler/optimizing/linearize_test.cc +++ b/compiler/optimizing/linearize_test.cc @@ -21,8 +21,8 @@ #include "builder.h" #include "code_generator.h" #include "code_generator_x86.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "driver/compiler_options.h" #include "graph_visualizer.h" #include "nodes.h" diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc index ddcad5aed8..e45d7c820c 100644 --- a/compiler/optimizing/live_ranges_test.cc +++ b/compiler/optimizing/live_ranges_test.cc @@ -19,8 +19,8 @@ #include "builder.h" #include "code_generator.h" #include "code_generator_x86.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc index 3eadc8f8fc..35bc4ff8b3 100644 --- a/compiler/optimizing/liveness_test.cc +++ b/compiler/optimizing/liveness_test.cc @@ -19,8 +19,8 @@ #include "builder.h" #include "code_generator.h" #include "code_generator_x86.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index d13f5b42bf..d4382c6b4c 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -30,8 +30,8 @@ #include "base/transform_array_ref.h" #include "data_type.h" #include "deoptimization_kind.h" -#include "dex_file.h" -#include "dex_file_types.h" +#include "dex/dex_file.h" +#include "dex/dex_file_types.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "handle.h" #include "handle_scope.h" diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 7149d93d07..57db7a634c 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -39,6 +39,7 @@ #include "constant_folding.h" #include "constructor_fence_redundancy_elimination.h" #include "dead_code_elimination.h" +#include "dex/code_item_accessors-inl.h" #include "driver/dex_compilation_unit.h" #include "gvn.h" #include "induction_var_analysis.h" @@ -241,7 +242,8 @@ ArenaVector<HOptimization*> ConstructOptimizations( opt = new (allocator) HDeadCodeElimination(graph, stats, name); break; case OptimizationPass::kInliner: { - size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(*dex_compilation_unit.GetDexFile(), + dex_compilation_unit.GetCodeItem()); opt = new (allocator) HInliner(graph, // outer_graph graph, // outermost_graph codegen, @@ -250,7 +252,7 @@ ArenaVector<HOptimization*> ConstructOptimizations( driver, handles, stats, - number_of_dex_registers, + accessor.RegistersSize(), /* total_number_of_instructions */ 0, /* parent */ nullptr, /* depth */ 0, diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc index 4ad29961be..e2b2106f65 100644 --- a/compiler/optimizing/optimizing_cfi_test.cc +++ b/compiler/optimizing/optimizing_cfi_test.cc @@ -18,6 +18,7 @@ #include <vector> #include "arch/instruction_set.h" +#include "base/runtime_debug.h" #include "cfi_test.h" #include "driver/compiler_options.h" #include "gtest/gtest.h" @@ -56,6 +57,9 @@ class OptimizingCFITest : public CFITest { ArenaAllocator* GetAllocator() { return pool_and_allocator_.GetAllocator(); } void SetUpFrame(InstructionSet isa) { + // Ensure that slow-debug is off, so that there is no unexpected read-barrier check emitted. + SetRuntimeDebugFlagsEnabled(false); + // Setup simple context. std::string error; isa_features_ = InstructionSetFeatures::FromVariant(isa, "default", &error); diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 24b1a123ee..f4115f7e7b 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -36,9 +36,9 @@ #include "compiler.h" #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" +#include "dex/dex_file_types.h" #include "dex/verification_results.h" #include "dex/verified_method.h" -#include "dex_file_types.h" #include "driver/compiler_driver-inl.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" @@ -766,11 +766,13 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, static constexpr size_t kSpaceFilterOptimizingThreshold = 128; const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace) - && (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) { + && (CodeItemInstructionAccessor(dex_file, code_item).InsnsSizeInCodeUnits() > + kSpaceFilterOptimizingThreshold)) { MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledSpaceFilter); return nullptr; } + CodeItemDebugInfoAccessor code_item_accessor(dex_file, code_item); HGraph* graph = new (allocator) HGraph( allocator, arena_stack, @@ -814,7 +816,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, VLOG(compiler) << "Building " << pass_observer.GetMethodName(); PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); HGraphBuilder builder(graph, - code_item, + code_item_accessor, &dex_compilation_unit, &dex_compilation_unit, compiler_driver, @@ -932,7 +934,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( VLOG(compiler) << "Building intrinsic graph " << pass_observer.GetMethodName(); PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); HGraphBuilder builder(graph, - /* code_item */ nullptr, + CodeItemDebugInfoAccessor(), // Null code item. &dex_compilation_unit, &dex_compilation_unit, compiler_driver, diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index 158c252f45..8c97d57f4a 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -20,8 +20,9 @@ #include "base/scoped_arena_allocator.h" #include "builder.h" #include "common_compiler_test.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/code_item_accessors-inl.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "driver/dex_compilation_unit.h" #include "handle_scope-inl.h" #include "mirror/class_loader.h" @@ -145,7 +146,8 @@ class OptimizingUnitTest : public CommonCompilerTest { /* access_flags */ 0u, /* verified_method */ nullptr, handles_->NewHandle<mirror::DexCache>(nullptr)); - HGraphBuilder builder(graph, dex_compilation_unit, *code_item, handles_.get(), return_type); + CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item); + HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type); bool graph_built = (builder.BuildGraph() == kAnalysisSuccess); return graph_built ? graph : nullptr; } diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 1ed190d328..f843c008d8 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -16,7 +16,7 @@ #include "prepare_for_register_allocation.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "jni_internal.h" #include "optimizing_compiler_stats.h" #include "well_known_classes.h" diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc index 4aec6d3999..4fc7fe9427 100644 --- a/compiler/optimizing/pretty_printer_test.cc +++ b/compiler/optimizing/pretty_printer_test.cc @@ -18,8 +18,8 @@ #include "base/arena_allocator.h" #include "builder.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index 69ed8c7fcc..3748d599a3 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -21,9 +21,9 @@ #include "builder.h" #include "code_generator.h" #include "code_generator_x86.h" -#include "dex_file.h" -#include "dex_file_types.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_file_types.h" +#include "dex/dex_instruction.h" #include "driver/compiler_options.h" #include "nodes.h" #include "optimizing_unit_test.h" diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc index b3c8f105d1..8dcadaad2e 100644 --- a/compiler/optimizing/scheduler_arm.cc +++ b/compiler/optimizing/scheduler_arm.cc @@ -330,10 +330,12 @@ bool SchedulingLatencyVisitorARM::CanGenerateTest(HCondition* condition) { } } else if (c == kCondLE || c == kCondGT) { if (value < std::numeric_limits<int64_t>::max() && - !codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value + 1), kCcSet)) { + !codegen_->GetAssembler()->ShifterOperandCanHold( + SBC, High32Bits(value + 1), vixl32::FlagsUpdate::SetFlags)) { return false; } - } else if (!codegen_->GetAssembler()->ShifterOperandCanHold(SBC, High32Bits(value), kCcSet)) { + } else if (!codegen_->GetAssembler()->ShifterOperandCanHold( + SBC, High32Bits(value), vixl32::FlagsUpdate::SetFlags)) { return false; } } diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc index e08904e84b..77e70d733e 100644 --- a/compiler/optimizing/ssa_test.cc +++ b/compiler/optimizing/ssa_test.cc @@ -18,8 +18,8 @@ #include "base/arena_allocator.h" #include "builder.h" -#include "dex_file.h" -#include "dex_instruction.h" +#include "dex/dex_file.h" +#include "dex/dex_instruction.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "pretty_printer.h" diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index 4f43eb374c..7010e3f380 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -18,7 +18,7 @@ #include "art_method-inl.h" #include "base/stl_util.h" -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "optimizing/optimizing_compiler.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" diff --git a/compiler/optimizing/cloner_test.cc b/compiler/optimizing/superblock_cloner_test.cc index d34dd81767..fd77eb81fc 100644 --- a/compiler/optimizing/cloner_test.cc +++ b/compiler/optimizing/superblock_cloner_test.cc @@ -24,9 +24,9 @@ namespace art { // This class provides methods and helpers for testing various cloning and copying routines: // individual instruction cloning and cloning of the more coarse-grain structures. -class ClonerTest : public OptimizingUnitTest { +class SuperblockClonerTest : public OptimizingUnitTest { public: - ClonerTest() + SuperblockClonerTest() : graph_(CreateGraph()), entry_block_(nullptr), exit_block_(nullptr), parameter_(nullptr) {} void CreateBasicLoopControlFlow(/* out */ HBasicBlock** header_p, @@ -154,7 +154,7 @@ class ClonerTest : public OptimizingUnitTest { HInstruction* parameter_; }; -TEST_F(ClonerTest, IndividualInstrCloner) { +TEST_F(SuperblockClonerTest, IndividualInstrCloner) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc index 88336b0009..7e83f8ce5f 100644 --- a/compiler/optimizing/suspend_check_test.cc +++ b/compiler/optimizing/suspend_check_test.cc @@ -15,7 +15,7 @@ */ #include "builder.h" -#include "dex_instruction.h" +#include "dex/dex_instruction.h" #include "nodes.h" #include "optimizing_unit_test.h" #include "pretty_printer.h" diff --git a/compiler/trampolines/trampoline_compiler.h b/compiler/trampolines/trampoline_compiler.h index 1a10e4c799..64c1eb5022 100644 --- a/compiler/trampolines/trampoline_compiler.h +++ b/compiler/trampolines/trampoline_compiler.h @@ -21,6 +21,7 @@ #include <vector> #include "driver/compiler_driver.h" +#include "offsets.h" namespace art { diff --git a/compiler/utils/arm/assembler_arm_shared.h b/compiler/utils/arm/assembler_arm_shared.h index 21f13eeab7..7464052d93 100644 --- a/compiler/utils/arm/assembler_arm_shared.h +++ b/compiler/utils/arm/assembler_arm_shared.h @@ -40,13 +40,6 @@ enum StoreOperandType { kStoreDWord }; -// Set condition codes request. -enum SetCc { - kCcDontCare, // Allows prioritizing 16-bit instructions on Thumb2 whether they set CCs or not. - kCcSet, - kCcKeep, -}; - } // namespace arm } // namespace art diff --git a/compiler/utils/arm/assembler_arm_test.h b/compiler/utils/arm/assembler_arm_test.h deleted file mode 100644 index 8c3a11f2cf..0000000000 --- a/compiler/utils/arm/assembler_arm_test.h +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_ -#define ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_ - -#include "utils/assembler_test.h" - -namespace art { - -template<typename Ass, - typename Reg, - typename FPReg, - typename Imm, - typename SOp, - typename Cond, - typename SetCc> -class AssemblerArmTest : public AssemblerTest<Ass, Reg, FPReg, Imm> { - public: - typedef AssemblerTest<Ass, Reg, FPReg, Imm> Base; - - using Base::GetRegisters; - using Base::GetRegName; - using Base::CreateImmediate; - using Base::WarnOnCombinations; - - static constexpr int64_t kFullImmRangeThreshold = 32; - - virtual void FillImmediates(std::vector<Imm>& immediates, int64_t imm_min, int64_t imm_max) { - // Small range: do completely. - if (imm_max - imm_min <= kFullImmRangeThreshold) { - for (int64_t i = imm_min; i <= imm_max; ++i) { - immediates.push_back(CreateImmediate(i)); - } - } else { - immediates.push_back(CreateImmediate(imm_min)); - immediates.push_back(CreateImmediate(imm_max)); - if (imm_min < imm_max - 1) { - immediates.push_back(CreateImmediate(imm_min + 1)); - } - if (imm_min < imm_max - 2) { - immediates.push_back(CreateImmediate(imm_min + 2)); - } - if (imm_min < imm_max - 3) { - immediates.push_back(CreateImmediate(imm_max - 1)); - } - if (imm_min < imm_max - 4) { - immediates.push_back(CreateImmediate((imm_min + imm_max) / 2)); - } - } - } - - std::string RepeatRRIIC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond), - int64_t imm1_min, int64_t imm1_max, - int64_t imm2_min, int64_t imm2_max, - std::string fmt) { - return RepeatTemplatedRRIIC(f, GetRegisters(), GetRegisters(), - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - imm1_min, imm1_max, imm2_min, imm2_max, - fmt); - } - - template <typename Reg1, typename Reg2> - std::string RepeatTemplatedRRIIC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond), - const std::vector<Reg1*> reg1_registers, - const std::vector<Reg2*> reg2_registers, - std::string (AssemblerArmTest::*GetName1)(const Reg1&), - std::string (AssemblerArmTest::*GetName2)(const Reg2&), - int64_t imm1_min, int64_t imm1_max, - int64_t imm2_min, int64_t imm2_max, - std::string fmt) { - std::vector<Imm> immediates1; - FillImmediates(immediates1, imm1_min, imm1_max); - std::vector<Imm> immediates2; - FillImmediates(immediates2, imm2_min, imm2_max); - - std::vector<Cond>& cond = GetConditions(); - - WarnOnCombinations(cond.size() * immediates1.size() * immediates2.size() * - reg1_registers.size() * reg2_registers.size()); - - std::ostringstream oss; - bool first = true; - for (Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (Imm i : immediates1) { - std::string base = after_cond; - - size_t imm1_index = base.find(IMM1_TOKEN); - if (imm1_index != std::string::npos) { - std::ostringstream sreg; - sreg << i; - std::string imm_string = sreg.str(); - base.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string); - } - - for (Imm j : immediates2) { - std::string base2 = base; - - size_t imm2_index = base2.find(IMM2_TOKEN); - if (imm2_index != std::string::npos) { - std::ostringstream sreg; - sreg << j; - std::string imm_string = sreg.str(); - base2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string); - } - - for (auto reg1 : reg1_registers) { - std::string base3 = base2; - - std::string reg1_string = (this->*GetName1)(*reg1); - size_t reg1_index; - while ((reg1_index = base3.find(Base::REG1_TOKEN)) != std::string::npos) { - base3.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); - } - - for (auto reg2 : reg2_registers) { - std::string base4 = base3; - - std::string reg2_string = (this->*GetName2)(*reg2); - size_t reg2_index; - while ((reg2_index = base4.find(Base::REG2_TOKEN)) != std::string::npos) { - base4.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << base4; - - (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c); - } - } - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - std::string RepeatRRiiC(void (Ass::*f)(Reg, Reg, Imm, Imm, Cond), - std::vector<std::pair<Imm, Imm>>& immediates, - std::string fmt) { - return RepeatTemplatedRRiiC<Reg, Reg>(f, GetRegisters(), GetRegisters(), - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - immediates, fmt); - } - - template <typename Reg1, typename Reg2> - std::string RepeatTemplatedRRiiC(void (Ass::*f)(Reg1, Reg2, Imm, Imm, Cond), - const std::vector<Reg1*> reg1_registers, - const std::vector<Reg2*> reg2_registers, - std::string (AssemblerArmTest::*GetName1)(const Reg1&), - std::string (AssemblerArmTest::*GetName2)(const Reg2&), - std::vector<std::pair<Imm, Imm>>& immediates, - std::string fmt) { - std::vector<Cond>& cond = GetConditions(); - - WarnOnCombinations(cond.size() * immediates.size() * reg1_registers.size() * - reg2_registers.size()); - - std::ostringstream oss; - bool first = true; - for (Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (std::pair<Imm, Imm>& pair : immediates) { - Imm i = pair.first; - Imm j = pair.second; - std::string after_imm1 = after_cond; - - size_t imm1_index = after_imm1.find(IMM1_TOKEN); - if (imm1_index != std::string::npos) { - std::ostringstream sreg; - sreg << i; - std::string imm_string = sreg.str(); - after_imm1.replace(imm1_index, ConstexprStrLen(IMM1_TOKEN), imm_string); - } - - std::string after_imm2 = after_imm1; - - size_t imm2_index = after_imm2.find(IMM2_TOKEN); - if (imm2_index != std::string::npos) { - std::ostringstream sreg; - sreg << j; - std::string imm_string = sreg.str(); - after_imm2.replace(imm2_index, ConstexprStrLen(IMM2_TOKEN), imm_string); - } - - for (auto reg1 : reg1_registers) { - std::string after_reg1 = after_imm2; - - std::string reg1_string = (this->*GetName1)(*reg1); - size_t reg1_index; - while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { - after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); - } - - for (auto reg2 : reg2_registers) { - std::string after_reg2 = after_reg1; - - std::string reg2_string = (this->*GetName2)(*reg2); - size_t reg2_index; - while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { - after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << after_reg2; - - (Base::GetAssembler()->*f)(*reg1, *reg2, i, j, c); - } - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - std::string RepeatRRC(void (Ass::*f)(Reg, Reg, Cond), std::string fmt) { - return RepeatTemplatedRRC(f, GetRegisters(), GetRegisters(), GetConditions(), - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - fmt); - } - - template <typename Reg1, typename Reg2> - std::string RepeatTemplatedRRC(void (Ass::*f)(Reg1, Reg2, Cond), - const std::vector<Reg1*>& reg1_registers, - const std::vector<Reg2*>& reg2_registers, - const std::vector<Cond>& cond, - std::string (AssemblerArmTest::*GetName1)(const Reg1&), - std::string (AssemblerArmTest::*GetName2)(const Reg2&), - std::string fmt) { - WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size()); - - std::ostringstream oss; - bool first = true; - for (const Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (auto reg1 : reg1_registers) { - std::string after_reg1 = after_cond; - - std::string reg1_string = (this->*GetName1)(*reg1); - size_t reg1_index; - while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { - after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); - } - - for (auto reg2 : reg2_registers) { - std::string after_reg2 = after_reg1; - - std::string reg2_string = (this->*GetName2)(*reg2); - size_t reg2_index; - while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { - after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << after_reg2; - - (Base::GetAssembler()->*f)(*reg1, *reg2, c); - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - std::string RepeatRRRC(void (Ass::*f)(Reg, Reg, Reg, Cond), std::string fmt) { - return RepeatTemplatedRRRC(f, GetRegisters(), GetRegisters(), GetRegisters(), GetConditions(), - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - &AssemblerArmTest::template GetRegName<RegisterView::kUsePrimaryName>, - fmt); - } - - template <typename Reg1, typename Reg2, typename Reg3> - std::string RepeatTemplatedRRRC(void (Ass::*f)(Reg1, Reg2, Reg3, Cond), - const std::vector<Reg1*>& reg1_registers, - const std::vector<Reg2*>& reg2_registers, - const std::vector<Reg3*>& reg3_registers, - const std::vector<Cond>& cond, - std::string (AssemblerArmTest::*GetName1)(const Reg1&), - std::string (AssemblerArmTest::*GetName2)(const Reg2&), - std::string (AssemblerArmTest::*GetName3)(const Reg3&), - std::string fmt) { - WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * - reg3_registers.size()); - - std::ostringstream oss; - bool first = true; - for (const Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (auto reg1 : reg1_registers) { - std::string after_reg1 = after_cond; - - std::string reg1_string = (this->*GetName1)(*reg1); - size_t reg1_index; - while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { - after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); - } - - for (auto reg2 : reg2_registers) { - std::string after_reg2 = after_reg1; - - std::string reg2_string = (this->*GetName2)(*reg2); - size_t reg2_index; - while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { - after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); - } - - for (auto reg3 : reg3_registers) { - std::string after_reg3 = after_reg2; - - std::string reg3_string = (this->*GetName3)(*reg3); - size_t reg3_index; - while ((reg3_index = after_reg3.find(REG3_TOKEN)) != std::string::npos) { - after_reg3.replace(reg3_index, ConstexprStrLen(REG3_TOKEN), reg3_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << after_reg3; - - (Base::GetAssembler()->*f)(*reg1, *reg2, *reg3, c); - } - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - template <typename RegT> - std::string RepeatTemplatedRSC(void (Ass::*f)(RegT, SOp, Cond), - const std::vector<RegT*>& registers, - const std::vector<SOp>& shifts, - const std::vector<Cond>& cond, - std::string (AssemblerArmTest::*GetName)(const RegT&), - std::string fmt) { - WarnOnCombinations(cond.size() * registers.size() * shifts.size()); - - std::ostringstream oss; - bool first = true; - for (const Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (const SOp& shift : shifts) { - std::string after_shift = after_cond; - - std::string shift_string = GetShiftString(shift); - size_t shift_index; - while ((shift_index = after_shift.find(Base::SHIFT_TOKEN)) != std::string::npos) { - after_shift.replace(shift_index, ConstexprStrLen(Base::SHIFT_TOKEN), shift_string); - } - - for (auto reg : registers) { - std::string after_reg = after_shift; - - std::string reg_string = (this->*GetName)(*reg); - size_t reg_index; - while ((reg_index = after_reg.find(Base::REG_TOKEN)) != std::string::npos) { - after_reg.replace(reg_index, ConstexprStrLen(Base::REG_TOKEN), reg_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << after_reg; - - (Base::GetAssembler()->*f)(*reg, shift, c); - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - template <typename Reg1, typename Reg2> - std::string RepeatTemplatedRRSC(void (Ass::*f)(Reg1, Reg2, const SOp&, Cond), - const std::vector<Reg1*>& reg1_registers, - const std::vector<Reg2*>& reg2_registers, - const std::vector<SOp>& shifts, - const std::vector<Cond>& cond, - std::string (AssemblerArmTest::*GetName1)(const Reg1&), - std::string (AssemblerArmTest::*GetName2)(const Reg2&), - std::string fmt) { - WarnOnCombinations(cond.size() * reg1_registers.size() * reg2_registers.size() * shifts.size()); - - std::ostringstream oss; - bool first = true; - for (const Cond& c : cond) { - std::string after_cond = fmt; - - size_t cond_index = after_cond.find(COND_TOKEN); - if (cond_index != std::string::npos) { - after_cond.replace(cond_index, ConstexprStrLen(COND_TOKEN), GetConditionString(c)); - } - - for (const SOp& shift : shifts) { - std::string after_shift = after_cond; - - std::string shift_string = GetShiftString(shift); - size_t shift_index; - while ((shift_index = after_shift.find(SHIFT_TOKEN)) != std::string::npos) { - after_shift.replace(shift_index, ConstexprStrLen(SHIFT_TOKEN), shift_string); - } - - for (auto reg1 : reg1_registers) { - std::string after_reg1 = after_shift; - - std::string reg1_string = (this->*GetName1)(*reg1); - size_t reg1_index; - while ((reg1_index = after_reg1.find(Base::REG1_TOKEN)) != std::string::npos) { - after_reg1.replace(reg1_index, ConstexprStrLen(Base::REG1_TOKEN), reg1_string); - } - - for (auto reg2 : reg2_registers) { - std::string after_reg2 = after_reg1; - - std::string reg2_string = (this->*GetName2)(*reg2); - size_t reg2_index; - while ((reg2_index = after_reg2.find(Base::REG2_TOKEN)) != std::string::npos) { - after_reg2.replace(reg2_index, ConstexprStrLen(Base::REG2_TOKEN), reg2_string); - } - - if (first) { - first = false; - } else { - oss << "\n"; - } - oss << after_reg2; - - (Base::GetAssembler()->*f)(*reg1, *reg2, shift, c); - } - } - } - } - // Add a newline at the end. - oss << "\n"; - - return oss.str(); - } - - protected: - AssemblerArmTest() {} - - virtual std::vector<Cond>& GetConditions() = 0; - virtual std::string GetConditionString(Cond c) = 0; - - virtual std::vector<SetCc>& GetSetCcs() = 0; - virtual std::string GetSetCcString(SetCc s) = 0; - - virtual std::vector<SOp>& GetShiftOperands() = 0; - virtual std::string GetShiftString(SOp sop) = 0; - - virtual Reg GetPCRegister() = 0; - virtual std::vector<Reg*> GetRegistersWithoutPC() { - std::vector<Reg*> without_pc = GetRegisters(); - Reg pc_reg = GetPCRegister(); - - for (auto it = without_pc.begin(); it != without_pc.end(); ++it) { - if (**it == pc_reg) { - without_pc.erase(it); - break; - } - } - - return without_pc; - } - - static constexpr const char* IMM1_TOKEN = "{imm1}"; - static constexpr const char* IMM2_TOKEN = "{imm2}"; - static constexpr const char* REG3_TOKEN = "{reg3}"; - static constexpr const char* REG4_TOKEN = "{reg4}"; - static constexpr const char* COND_TOKEN = "{cond}"; - static constexpr const char* SET_CC_TOKEN = "{s}"; - static constexpr const char* SHIFT_TOKEN = "{shift}"; - - private: - DISALLOW_COPY_AND_ASSIGN(AssemblerArmTest); -}; - -} // namespace art - -#endif // ART_COMPILER_UTILS_ARM_ASSEMBLER_ARM_TEST_H_ diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc index 34849cd58d..05250a4157 100644 --- a/compiler/utils/arm/assembler_arm_vixl.cc +++ b/compiler/utils/arm/assembler_arm_vixl.cc @@ -112,12 +112,14 @@ bool ArmVIXLAssembler::ShifterOperandCanAlwaysHold(uint32_t immediate) { return vixl_masm_.IsModifiedImmediate(immediate); } -bool ArmVIXLAssembler::ShifterOperandCanHold(Opcode opcode, uint32_t immediate, SetCc set_cc) { +bool ArmVIXLAssembler::ShifterOperandCanHold(Opcode opcode, + uint32_t immediate, + vixl::aarch32::FlagsUpdate update_flags) { switch (opcode) { case ADD: case SUB: // Less than (or equal to) 12 bits can be done if we don't need to set condition codes. - if (IsUint<12>(immediate) && set_cc != kCcSet) { + if (IsUint<12>(immediate) && update_flags != vixl::aarch32::SetFlags) { return true; } return ShifterOperandCanAlwaysHold(immediate); @@ -483,13 +485,9 @@ void ArmVIXLMacroAssembler::CompareAndBranchIfNonZero(vixl32::Register rn, void ArmVIXLMacroAssembler::B(vixl32::Label* label) { if (!label->IsBound()) { - // Try to use 16-bit T2 encoding of B instruction. + // Try to use a 16-bit encoding of the B instruction. DCHECK(OutsideITBlock()); - ExactAssemblyScope guard(this, - k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - b(al, Narrow, label); - AddBranchLabel(label); + BPreferNear(label); return; } MacroAssembler::B(label); @@ -497,18 +495,11 @@ void ArmVIXLMacroAssembler::B(vixl32::Label* label) { void ArmVIXLMacroAssembler::B(vixl32::Condition cond, vixl32::Label* label, bool is_far_target) { if (!label->IsBound() && !is_far_target) { - // Try to use 16-bit T2 encoding of B instruction. + // Try to use a 16-bit encoding of the B instruction. DCHECK(OutsideITBlock()); - ExactAssemblyScope guard(this, - k16BitT32InstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - b(cond, Narrow, label); - AddBranchLabel(label); + BPreferNear(cond, label); return; } - // To further reduce the Bcc encoding size and use 16-bit T1 encoding, - // we can provide a hint to this function: i.e. far_target=false. - // By default this function uses 'EncodingSizeType::Best' which generates 32-bit T3 encoding. MacroAssembler::B(cond, label); } diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h index 1377e64073..b0310f2fb6 100644 --- a/compiler/utils/arm/assembler_arm_vixl.h +++ b/compiler/utils/arm/assembler_arm_vixl.h @@ -218,7 +218,9 @@ class ArmVIXLAssembler FINAL : public Assembler { void StoreRegisterList(RegList regs, size_t stack_offset); bool ShifterOperandCanAlwaysHold(uint32_t immediate); - bool ShifterOperandCanHold(Opcode opcode, uint32_t immediate, SetCc set_cc = kCcDontCare); + bool ShifterOperandCanHold(Opcode opcode, + uint32_t immediate, + vixl::aarch32::FlagsUpdate update_flags = vixl::aarch32::DontCare); bool CanSplitLoadStoreOffset(int32_t allowed_offset_bits, int32_t offset, /*out*/ int32_t* add_to_base, diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc index 0bae4d4b69..065c3de23c 100644 --- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc +++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc @@ -492,7 +492,7 @@ void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister mout_reg, temps.Exclude(in_reg.AsVIXLRegister()); ___ Cmp(in_reg.AsVIXLRegister(), 0); - if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) { + if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value())) { if (!out_reg.Equals(in_reg)) { ExactAssemblyScope guard(asm_.GetVIXLAssembler(), 3 * vixl32::kMaxInstructionSizeInBytes, @@ -531,7 +531,7 @@ void ArmVIXLJNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off, // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) ___ Cmp(scratch.AsVIXLRegister(), 0); - if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) { + if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value())) { ExactAssemblyScope guard(asm_.GetVIXLAssembler(), 2 * vixl32::kMaxInstructionSizeInBytes, CodeBufferCheckScope::kMaximumSize); @@ -624,14 +624,8 @@ void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t s Thread::ExceptionOffset<kArmPointerSize>().Int32Value()); ___ Cmp(scratch.AsVIXLRegister(), 0); - { - ExactAssemblyScope guard(asm_.GetVIXLAssembler(), - vixl32::kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - vixl32::Label* label = exception_blocks_.back()->Entry(); - ___ b(ne, Narrow, label); - ___ AddBranchLabel(label); - } + vixl32::Label* label = exception_blocks_.back()->Entry(); + ___ BPreferNear(ne, label); // TODO: think about using CBNZ here. } diff --git a/compiler/utils/atomic_dex_ref_map-inl.h b/compiler/utils/atomic_dex_ref_map-inl.h index 33d59f9d42..203e484fb7 100644 --- a/compiler/utils/atomic_dex_ref_map-inl.h +++ b/compiler/utils/atomic_dex_ref_map-inl.h @@ -21,8 +21,8 @@ #include <type_traits> -#include "dex_file-inl.h" #include "class_reference.h" +#include "dex/dex_file-inl.h" #include "method_reference.h" #include "type_reference.h" @@ -58,7 +58,7 @@ inline typename AtomicDexRefMap<DexFileReferenceType, Value>::InsertResult return kInsertResultInvalidDexFile; } DCHECK_LT(ref.index, array->size()); - return (*array)[ref.index].CompareExchangeStrongSequentiallyConsistent(expected, desired) + return (*array)[ref.index].CompareAndSetStrongSequentiallyConsistent(expected, desired) ? kInsertResultSuccess : kInsertResultCASFailure; } diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h index 205543f31d..9ff506d6a4 100644 --- a/compiler/utils/atomic_dex_ref_map.h +++ b/compiler/utils/atomic_dex_ref_map.h @@ -18,7 +18,7 @@ #define ART_COMPILER_UTILS_ATOMIC_DEX_REF_MAP_H_ #include "base/dchecked_vector.h" -#include "dex_file_reference.h" +#include "dex/dex_file_reference.h" #include "safe_map.h" namespace art { diff --git a/compiler/utils/atomic_dex_ref_map_test.cc b/compiler/utils/atomic_dex_ref_map_test.cc index 8fce36f021..d58d60b4f3 100644 --- a/compiler/utils/atomic_dex_ref_map_test.cc +++ b/compiler/utils/atomic_dex_ref_map_test.cc @@ -19,7 +19,7 @@ #include <memory> #include "common_runtime_test.h" -#include "dex_file-inl.h" +#include "dex/dex_file-inl.h" #include "method_reference.h" #include "scoped_thread_state_change-inl.h" diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index bf56877499..e1b0e75108 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -430,6 +430,20 @@ void Mips64Assembler::Dext(GpuRegister rt, GpuRegister rs, int pos, int size) { EmitR(0x1f, rs, rt, static_cast<GpuRegister>(size - 1), pos, 0x3); } +void Mips64Assembler::Ins(GpuRegister rd, GpuRegister rt, int pos, int size) { + CHECK(IsUint<5>(pos)) << pos; + CHECK(IsUint<5>(size - 1)) << size; + CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size; + EmitR(0x1f, rt, rd, static_cast<GpuRegister>(pos + size - 1), pos, 0x04); +} + +void Mips64Assembler::Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size) { + CHECK(IsUint<5>(pos)) << pos; + CHECK(2 <= size && size <= 64) << size; + CHECK(IsUint<5>(pos + size - 33)) << pos << " + " << size; + EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos, 0x5); +} + void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) { CHECK(IsUint<5>(pos - 32)) << pos; CHECK(IsUint<5>(size - 1)) << size; @@ -437,6 +451,23 @@ void Mips64Assembler::Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size) { EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 33), pos - 32, 0x6); } +void Mips64Assembler::Dins(GpuRegister rt, GpuRegister rs, int pos, int size) { + CHECK(IsUint<5>(pos)) << pos; + CHECK(IsUint<5>(size - 1)) << size; + CHECK(IsUint<5>(pos + size - 1)) << pos << " + " << size; + EmitR(0x1f, rs, rt, static_cast<GpuRegister>(pos + size - 1), pos, 0x7); +} + +void Mips64Assembler::DblIns(GpuRegister rt, GpuRegister rs, int pos, int size) { + if (pos >= 32) { + Dinsu(rt, rs, pos, size); + } else if ((static_cast<int64_t>(pos) + size - 1) >= 32) { + Dinsm(rt, rs, pos, size); + } else { + Dins(rt, rs, pos, size); + } +} + void Mips64Assembler::Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne) { CHECK(1 <= saPlusOne && saPlusOne <= 4) << saPlusOne; int sa = saPlusOne - 1; diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 9f5e6aaa88..7a61f39e64 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -478,7 +478,11 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer void Dsbh(GpuRegister rd, GpuRegister rt); // MIPS64 void Dshd(GpuRegister rd, GpuRegister rt); // MIPS64 void Dext(GpuRegister rs, GpuRegister rt, int pos, int size); // MIPS64 + void Ins(GpuRegister rt, GpuRegister rs, int pos, int size); + void Dins(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 + void Dinsm(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 void Dinsu(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 + void DblIns(GpuRegister rt, GpuRegister rs, int pos, int size); // MIPS64 void Lsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); void Dlsa(GpuRegister rd, GpuRegister rs, GpuRegister rt, int saPlusOne); // MIPS64 void Wsbh(GpuRegister rd, GpuRegister rt); diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc index d89ca3d6ea..b0e1d91c3f 100644 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ b/compiler/utils/mips64/assembler_mips64_test.cc @@ -1353,23 +1353,42 @@ TEST_F(AssemblerMIPS64Test, Dext) { DriverStr(expected.str(), "Dext"); } -TEST_F(AssemblerMIPS64Test, Dinsu) { +TEST_F(AssemblerMIPS64Test, Ins) { + std::vector<mips64::GpuRegister*> regs = GetRegisters(); + WarnOnCombinations(regs.size() * regs.size() * 33 * 16); + std::string expected; + for (mips64::GpuRegister* reg1 : regs) { + for (mips64::GpuRegister* reg2 : regs) { + for (int32_t pos = 0; pos < 32; pos++) { + for (int32_t size = 1; pos + size <= 32; size++) { + __ Ins(*reg1, *reg2, pos, size); + std::ostringstream instr; + instr << "ins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; + expected += instr.str(); + } + } + } + } + DriverStr(expected, "Ins"); +} + +TEST_F(AssemblerMIPS64Test, DblIns) { std::vector<mips64::GpuRegister*> reg1_registers = GetRegisters(); std::vector<mips64::GpuRegister*> reg2_registers = GetRegisters(); - WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 33 * 16); + WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * 65 * 32); std::ostringstream expected; for (mips64::GpuRegister* reg1 : reg1_registers) { for (mips64::GpuRegister* reg2 : reg2_registers) { - for (int32_t pos = 32; pos < 64; pos++) { + for (int32_t pos = 0; pos < 64; pos++) { for (int32_t size = 1; pos + size <= 64; size++) { - __ Dinsu(*reg1, *reg2, pos, size); - expected << "dinsu $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; + __ DblIns(*reg1, *reg2, pos, size); + expected << "dins $" << *reg1 << ", $" << *reg2 << ", " << pos << ", " << size << "\n"; } } } } - DriverStr(expected.str(), "Dinsu"); + DriverStr(expected.str(), "DblIns"); } TEST_F(AssemblerMIPS64Test, Lsa) { diff --git a/compiler/utils/string_reference_test.cc b/compiler/utils/string_reference_test.cc index 90335eb048..4b07e65771 100644 --- a/compiler/utils/string_reference_test.cc +++ b/compiler/utils/string_reference_test.cc @@ -18,7 +18,7 @@ #include <memory> -#include "dex_file_types.h" +#include "dex/dex_file_types.h" #include "gtest/gtest.h" #include "utils/test_dex_file_builder.h" diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h index 441ef8e117..58f1ec7b08 100644 --- a/compiler/utils/test_dex_file_builder.h +++ b/compiler/utils/test_dex_file_builder.h @@ -27,8 +27,9 @@ #include <android-base/logging.h> #include "base/bit_utils.h" -#include "dex_file_loader.h" -#include "standard_dex_file.h" +#include "dex/art_dex_file_loader.h" +#include "dex/dex_file_loader.h" +#include "dex/standard_dex_file.h" namespace art { @@ -233,7 +234,8 @@ class TestDexFileBuilder { static constexpr bool kVerify = false; static constexpr bool kVerifyChecksum = false; std::string error_msg; - std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open( &dex_file_data_[0], dex_file_data_.size(), dex_location, diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc index c76739b3b1..736a17edac 100644 --- a/compiler/utils/test_dex_file_builder_test.cc +++ b/compiler/utils/test_dex_file_builder_test.cc @@ -16,7 +16,7 @@ #include "test_dex_file_builder.h" -#include "dex_file-inl.h" +#include "dex/dex_file-inl.h" #include "gtest/gtest.h" #include "utils.h" diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index ee1d7c69bc..76448d819c 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -21,10 +21,10 @@ #include "class_linker.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" +#include "dex/dex_file-inl.h" +#include "dex/dex_file_types.h" #include "dex/verification_results.h" #include "dex/verified_method.h" -#include "dex_file-inl.h" -#include "dex_file_types.h" #include "driver/compiler_driver-inl.h" #include "driver/compiler_options.h" #include "handle_scope-inl.h" @@ -237,9 +237,9 @@ class VerifierDepsTest : public CommonCompilerTest { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); } else if (unverified_classes.find(class_def.class_idx_) == unverified_classes.end()) { - ASSERT_EQ(cls->GetStatus(), mirror::Class::kStatusVerified); + ASSERT_EQ(cls->GetStatus(), ClassStatus::kVerified); } else { - ASSERT_LT(cls->GetStatus(), mirror::Class::kStatusVerified); + ASSERT_LT(cls->GetStatus(), ClassStatus::kVerified); } } } |