diff options
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/code_generator.cc | 24 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.h | 22 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_cfi_test.cc | 151 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_cfi_test_expected.inc | 275 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 346 |
5 files changed, 613 insertions, 205 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index a1bb5e0838..ce92470868 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -42,7 +42,7 @@ #include "compiled_method.h" #include "dex/verified_method.h" -#include "driver/dex_compilation_unit.h" +#include "driver/compiler_driver.h" #include "gc_map_builder.h" #include "graph_visualizer.h" #include "intrinsics.h" @@ -787,9 +787,10 @@ CodeGenerator* CodeGenerator::Create(HGraph* graph, } void CodeGenerator::BuildNativeGCMap( - ArenaVector<uint8_t>* data, const DexCompilationUnit& dex_compilation_unit) const { + ArenaVector<uint8_t>* data, const CompilerDriver& compiler_driver) const { const std::vector<uint8_t>& gc_map_raw = - dex_compilation_unit.GetVerifiedMethod()->GetDexGcMap(); + compiler_driver.GetVerifiedMethod(&GetGraph()->GetDexFile(), GetGraph()->GetMethodIdx()) + ->GetDexGcMap(); verifier::DexPcToReferenceMap dex_gc_map(&(gc_map_raw)[0]); uint32_t max_native_offset = stack_map_stream_.ComputeMaxNativePcOffset(); @@ -911,19 +912,22 @@ void CodeGenerator::BuildVMapTable(ArenaVector<uint8_t>* data) const { vmap_encoder.PushBackUnsigned(VmapTable::kAdjustedFpMarker); } -void CodeGenerator::BuildStackMaps(ArenaVector<uint8_t>* data) { - uint32_t size = stack_map_stream_.PrepareForFillIn(); - data->resize(size); - MemoryRegion region(data->data(), size); +size_t CodeGenerator::ComputeStackMapsSize() { + return stack_map_stream_.PrepareForFillIn(); +} + +void CodeGenerator::BuildStackMaps(MemoryRegion region) { stack_map_stream_.FillIn(region); } void CodeGenerator::RecordNativeDebugInfo(uint32_t dex_pc, uintptr_t native_pc_begin, uintptr_t native_pc_end) { - if (src_map_ != nullptr && dex_pc != kNoDexPc && native_pc_begin != native_pc_end) { - src_map_->push_back(SrcMapElem({static_cast<uint32_t>(native_pc_begin), - static_cast<int32_t>(dex_pc)})); + if (compiler_options_.GetGenerateDebugInfo() && + dex_pc != kNoDexPc && + native_pc_begin != native_pc_end) { + src_map_.push_back(SrcMapElem({static_cast<uint32_t>(native_pc_begin), + static_cast<int32_t>(dex_pc)})); } } diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 47b6f30450..a92014dc79 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -22,6 +22,7 @@ #include "base/arena_containers.h" #include "base/arena_object.h" #include "base/bit_field.h" +#include "compiled_method.h" #include "driver/compiler_options.h" #include "globals.h" #include "graph_visualizer.h" @@ -51,13 +52,9 @@ static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff); class Assembler; class CodeGenerator; -class DexCompilationUnit; +class CompilerDriver; class LinkerPatch; class ParallelMoveResolver; -class SrcMapElem; -template <class Alloc> -class SrcMap; -using DefaultSrcMap = SrcMap<std::allocator<SrcMapElem>>; class CodeAllocator { public: @@ -284,13 +281,12 @@ class CodeGenerator { slow_paths_.push_back(slow_path); } - void SetSrcMap(DefaultSrcMap* src_map) { src_map_ = src_map; } - void BuildMappingTable(ArenaVector<uint8_t>* vector) const; void BuildVMapTable(ArenaVector<uint8_t>* vector) const; void BuildNativeGCMap( - ArenaVector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const; - void BuildStackMaps(ArenaVector<uint8_t>* vector); + ArenaVector<uint8_t>* vector, const CompilerDriver& compiler_driver) const; + void BuildStackMaps(MemoryRegion region); + size_t ComputeStackMapsSize(); bool IsBaseline() const { return is_baseline_; @@ -446,6 +442,10 @@ class CodeGenerator { // Copy the result of a call into the given target. virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0; + const ArenaVector<SrcMapElem>& GetSrcMappingTable() const { + return src_map_; + } + protected: // Method patch info used for recording locations of required linker patches and // target methods. The target method can be used for various purposes, whether for @@ -488,7 +488,7 @@ class CodeGenerator { stats_(stats), graph_(graph), compiler_options_(compiler_options), - src_map_(nullptr), + src_map_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), slow_paths_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), current_block_index_(0), is_leaf_(true), @@ -602,7 +602,7 @@ class CodeGenerator { const CompilerOptions& compiler_options_; // Native to dex_pc map used for native debugging/profiling tools. - DefaultSrcMap* src_map_; + ArenaVector<SrcMapElem> src_map_; ArenaVector<SlowPathCode*> slow_paths_; // The current block index in `block_order_` of the block diff --git a/compiler/optimizing/optimizing_cfi_test.cc b/compiler/optimizing/optimizing_cfi_test.cc index 05c6b2ca57..34f1fe5949 100644 --- a/compiler/optimizing/optimizing_cfi_test.cc +++ b/compiler/optimizing/optimizing_cfi_test.cc @@ -23,6 +23,8 @@ #include "optimizing/code_generator.h" #include "optimizing/optimizing_unit_test.h" #include "utils/assembler.h" +#include "utils/arm/assembler_thumb2.h" +#include "utils/mips/assembler_mips.h" #include "optimizing/optimizing_cfi_test_expected.inc" @@ -36,52 +38,62 @@ class OptimizingCFITest : public CFITest { // Enable this flag to generate the expected outputs. static constexpr bool kGenerateExpected = false; - void TestImpl(InstructionSet isa, const char* isa_str, - const std::vector<uint8_t>& expected_asm, - const std::vector<uint8_t>& expected_cfi) { + OptimizingCFITest() + : pool_(), + allocator_(&pool_), + opts_(), + isa_features_(), + graph_(nullptr), + code_gen_(), + blocks_(allocator_.Adapter()) {} + + void SetUpFrame(InstructionSet isa) { // Setup simple context. - ArenaPool pool; - ArenaAllocator allocator(&pool); - CompilerOptions opts; - std::unique_ptr<const InstructionSetFeatures> isa_features; std::string error; - isa_features.reset(InstructionSetFeatures::FromVariant(isa, "default", &error)); - HGraph* graph = CreateGraph(&allocator); + isa_features_.reset(InstructionSetFeatures::FromVariant(isa, "default", &error)); + graph_ = CreateGraph(&allocator_); // Generate simple frame with some spills. - std::unique_ptr<CodeGenerator> code_gen( - CodeGenerator::Create(graph, isa, *isa_features.get(), opts)); + code_gen_.reset(CodeGenerator::Create(graph_, isa, *isa_features_, opts_)); + code_gen_->GetAssembler()->cfi().SetEnabled(true); const int frame_size = 64; int core_reg = 0; int fp_reg = 0; for (int i = 0; i < 2; i++) { // Two registers of each kind. for (; core_reg < 32; core_reg++) { - if (code_gen->IsCoreCalleeSaveRegister(core_reg)) { + if (code_gen_->IsCoreCalleeSaveRegister(core_reg)) { auto location = Location::RegisterLocation(core_reg); - code_gen->AddAllocatedRegister(location); + code_gen_->AddAllocatedRegister(location); core_reg++; break; } } for (; fp_reg < 32; fp_reg++) { - if (code_gen->IsFloatingPointCalleeSaveRegister(fp_reg)) { + if (code_gen_->IsFloatingPointCalleeSaveRegister(fp_reg)) { auto location = Location::FpuRegisterLocation(fp_reg); - code_gen->AddAllocatedRegister(location); + code_gen_->AddAllocatedRegister(location); fp_reg++; break; } } } - ArenaVector<HBasicBlock*> blocks(allocator.Adapter()); - code_gen->block_order_ = &blocks; - code_gen->ComputeSpillMask(); - code_gen->SetFrameSize(frame_size); - code_gen->GenerateFrameEntry(); - code_gen->GenerateFrameExit(); + code_gen_->block_order_ = &blocks_; + code_gen_->ComputeSpillMask(); + code_gen_->SetFrameSize(frame_size); + code_gen_->GenerateFrameEntry(); + } + + void Finish() { + code_gen_->GenerateFrameExit(); + code_gen_->Finalize(&code_allocator_); + } + + void Check(InstructionSet isa, + const char* isa_str, + const std::vector<uint8_t>& expected_asm, + const std::vector<uint8_t>& expected_cfi) { // Get the outputs. - InternalCodeAllocator code_allocator; - code_gen->Finalize(&code_allocator); - const std::vector<uint8_t>& actual_asm = code_allocator.GetMemory(); - Assembler* opt_asm = code_gen->GetAssembler(); + const std::vector<uint8_t>& actual_asm = code_allocator_.GetMemory(); + Assembler* opt_asm = code_gen_->GetAssembler(); const std::vector<uint8_t>& actual_cfi = *(opt_asm->cfi().data()); if (kGenerateExpected) { @@ -92,6 +104,19 @@ class OptimizingCFITest : public CFITest { } } + void TestImpl(InstructionSet isa, const char* + isa_str, + const std::vector<uint8_t>& expected_asm, + const std::vector<uint8_t>& expected_cfi) { + SetUpFrame(isa); + Finish(); + Check(isa, isa_str, expected_asm, expected_cfi); + } + + CodeGenerator* GetCodeGenerator() { + return code_gen_.get(); + } + private: class InternalCodeAllocator : public CodeAllocator { public: @@ -109,21 +134,83 @@ class OptimizingCFITest : public CFITest { DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); }; + + ArenaPool pool_; + ArenaAllocator allocator_; + CompilerOptions opts_; + std::unique_ptr<const InstructionSetFeatures> isa_features_; + HGraph* graph_; + std::unique_ptr<CodeGenerator> code_gen_; + ArenaVector<HBasicBlock*> blocks_; + InternalCodeAllocator code_allocator_; }; -#define TEST_ISA(isa) \ - TEST_F(OptimizingCFITest, isa) { \ - std::vector<uint8_t> expected_asm(expected_asm_##isa, \ - expected_asm_##isa + arraysize(expected_asm_##isa)); \ - std::vector<uint8_t> expected_cfi(expected_cfi_##isa, \ - expected_cfi_##isa + arraysize(expected_cfi_##isa)); \ - TestImpl(isa, #isa, expected_asm, expected_cfi); \ +#define TEST_ISA(isa) \ + TEST_F(OptimizingCFITest, isa) { \ + std::vector<uint8_t> expected_asm( \ + expected_asm_##isa, \ + expected_asm_##isa + arraysize(expected_asm_##isa)); \ + std::vector<uint8_t> expected_cfi( \ + expected_cfi_##isa, \ + expected_cfi_##isa + arraysize(expected_cfi_##isa)); \ + TestImpl(isa, #isa, expected_asm, expected_cfi); \ } TEST_ISA(kThumb2) TEST_ISA(kArm64) TEST_ISA(kX86) TEST_ISA(kX86_64) +TEST_ISA(kMips) +TEST_ISA(kMips64) + +TEST_F(OptimizingCFITest, kThumb2Adjust) { + std::vector<uint8_t> expected_asm( + expected_asm_kThumb2_adjust, + expected_asm_kThumb2_adjust + arraysize(expected_asm_kThumb2_adjust)); + std::vector<uint8_t> expected_cfi( + expected_cfi_kThumb2_adjust, + expected_cfi_kThumb2_adjust + arraysize(expected_cfi_kThumb2_adjust)); + SetUpFrame(kThumb2); +#define __ down_cast<arm::Thumb2Assembler*>(GetCodeGenerator()->GetAssembler())-> + Label target; + __ CompareAndBranchIfZero(arm::R0, &target); + // Push the target out of range of CBZ. + for (size_t i = 0; i != 65; ++i) { + __ ldr(arm::R0, arm::Address(arm::R0)); + } + __ Bind(&target); +#undef __ + Finish(); + Check(kThumb2, "kThumb2_adjust", expected_asm, expected_cfi); +} + +TEST_F(OptimizingCFITest, kMipsAdjust) { + // One NOP in delay slot, 1 << 15 NOPS have size 1 << 17 which exceeds 18-bit signed maximum. + static constexpr size_t kNumNops = 1u + (1u << 15); + std::vector<uint8_t> expected_asm( + expected_asm_kMips_adjust_head, + expected_asm_kMips_adjust_head + arraysize(expected_asm_kMips_adjust_head)); + expected_asm.resize(expected_asm.size() + kNumNops * 4u, 0u); + expected_asm.insert( + expected_asm.end(), + expected_asm_kMips_adjust_tail, + expected_asm_kMips_adjust_tail + arraysize(expected_asm_kMips_adjust_tail)); + std::vector<uint8_t> expected_cfi( + expected_cfi_kMips_adjust, + expected_cfi_kMips_adjust + arraysize(expected_cfi_kMips_adjust)); + SetUpFrame(kMips); +#define __ down_cast<mips::MipsAssembler*>(GetCodeGenerator()->GetAssembler())-> + mips::MipsLabel target; + __ Beqz(mips::A0, &target); + // Push the target out of range of BEQZ. + for (size_t i = 0; i != kNumNops; ++i) { + __ Nop(); + } + __ Bind(&target); +#undef __ + Finish(); + Check(kMips, "kMips_adjust", expected_asm, expected_cfi); +} #endif // __ANDROID__ diff --git a/compiler/optimizing/optimizing_cfi_test_expected.inc b/compiler/optimizing/optimizing_cfi_test_expected.inc index 2c2c55f295..4571ebf2d4 100644 --- a/compiler/optimizing/optimizing_cfi_test_expected.inc +++ b/compiler/optimizing/optimizing_cfi_test_expected.inc @@ -138,3 +138,278 @@ static constexpr uint8_t expected_cfi_kX86_64[] = { // 0x0000002c: ret // 0x0000002d: .cfi_restore_state // 0x0000002d: .cfi_def_cfa_offset: 64 + +static constexpr uint8_t expected_asm_kMips[] = { + 0xE4, 0xFF, 0xBD, 0x27, 0x18, 0x00, 0xBF, 0xAF, 0x14, 0x00, 0xB1, 0xAF, + 0x10, 0x00, 0xB0, 0xAF, 0x08, 0x00, 0xB6, 0xE7, 0x0C, 0x00, 0xB7, 0xE7, + 0x00, 0x00, 0xB4, 0xE7, 0x04, 0x00, 0xB5, 0xE7, 0xDC, 0xFF, 0xBD, 0x27, + 0x00, 0x00, 0xA4, 0xAF, 0x24, 0x00, 0xBD, 0x27, 0x00, 0x00, 0xB4, 0xC7, + 0x04, 0x00, 0xB5, 0xC7, 0x08, 0x00, 0xB6, 0xC7, 0x0C, 0x00, 0xB7, 0xC7, + 0x10, 0x00, 0xB0, 0x8F, 0x14, 0x00, 0xB1, 0x8F, 0x18, 0x00, 0xBF, 0x8F, + 0x1C, 0x00, 0xBD, 0x27, 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, +}; +static constexpr uint8_t expected_cfi_kMips[] = { + 0x44, 0x0E, 0x1C, 0x44, 0x9F, 0x01, 0x44, 0x91, 0x02, 0x44, 0x90, 0x03, + 0x54, 0x0E, 0x40, 0x44, 0x0A, 0x44, 0x0E, 0x1C, 0x54, 0xD0, 0x44, 0xD1, + 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, +}; +// 0x00000000: addiu r29, r29, -28 +// 0x00000004: .cfi_def_cfa_offset: 28 +// 0x00000004: sw r31, +24(r29) +// 0x00000008: .cfi_offset: r31 at cfa-4 +// 0x00000008: sw r17, +20(r29) +// 0x0000000c: .cfi_offset: r17 at cfa-8 +// 0x0000000c: sw r16, +16(r29) +// 0x00000010: .cfi_offset: r16 at cfa-12 +// 0x00000010: swc1 f22, +8(r29) +// 0x00000014: swc1 f23, +12(r29) +// 0x00000018: swc1 f20, +0(r29) +// 0x0000001c: swc1 f21, +4(r29) +// 0x00000020: addiu r29, r29, -36 +// 0x00000024: .cfi_def_cfa_offset: 64 +// 0x00000024: sw r4, +0(r29) +// 0x00000028: .cfi_remember_state +// 0x00000028: addiu r29, r29, 36 +// 0x0000002c: .cfi_def_cfa_offset: 28 +// 0x0000002c: lwc1 f20, +0(r29) +// 0x00000030: lwc1 f21, +4(r29) +// 0x00000034: lwc1 f22, +8(r29) +// 0x00000038: lwc1 f23, +12(r29) +// 0x0000003c: lw r16, +16(r29) +// 0x00000040: .cfi_restore: r16 +// 0x00000040: lw r17, +20(r29) +// 0x00000044: .cfi_restore: r17 +// 0x00000044: lw r31, +24(r29) +// 0x00000048: .cfi_restore: r31 +// 0x00000048: addiu r29, r29, 28 +// 0x0000004c: .cfi_def_cfa_offset: 0 +// 0x0000004c: jr r31 +// 0x00000050: nop +// 0x00000054: .cfi_restore_state +// 0x00000054: .cfi_def_cfa_offset: 64 + +static constexpr uint8_t expected_asm_kMips64[] = { + 0xD8, 0xFF, 0xBD, 0x67, 0x20, 0x00, 0xBF, 0xFF, 0x18, 0x00, 0xB1, 0xFF, + 0x10, 0x00, 0xB0, 0xFF, 0x08, 0x00, 0xB9, 0xF7, 0x00, 0x00, 0xB8, 0xF7, + 0xE8, 0xFF, 0xBD, 0x67, 0x00, 0x00, 0xA4, 0xFF, 0x18, 0x00, 0xBD, 0x67, + 0x00, 0x00, 0xB8, 0xD7, 0x08, 0x00, 0xB9, 0xD7, 0x10, 0x00, 0xB0, 0xDF, + 0x18, 0x00, 0xB1, 0xDF, 0x20, 0x00, 0xBF, 0xDF, 0x28, 0x00, 0xBD, 0x67, + 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, +}; +static constexpr uint8_t expected_cfi_kMips64[] = { + 0x44, 0x0E, 0x28, 0x44, 0x9F, 0x02, 0x44, 0x91, 0x04, 0x44, 0x90, 0x06, + 0x4C, 0x0E, 0x40, 0x44, 0x0A, 0x44, 0x0E, 0x28, 0x4C, 0xD0, 0x44, 0xD1, + 0x44, 0xDF, 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, +}; +// 0x00000000: daddiu r29, r29, -40 +// 0x00000004: .cfi_def_cfa_offset: 40 +// 0x00000004: sd r31, +32(r29) +// 0x00000008: .cfi_offset: r31 at cfa-8 +// 0x00000008: sd r17, +24(r29) +// 0x0000000c: .cfi_offset: r17 at cfa-16 +// 0x0000000c: sd r16, +16(r29) +// 0x00000010: .cfi_offset: r16 at cfa-24 +// 0x00000010: sdc1 f25, +8(r29) +// 0x00000014: sdc1 f24, +0(r29) +// 0x00000018: daddiu r29, r29, -24 +// 0x0000001c: .cfi_def_cfa_offset: 64 +// 0x0000001c: sd r4, +0(r29) +// 0x00000020: .cfi_remember_state +// 0x00000020: daddiu r29, r29, 24 +// 0x00000024: .cfi_def_cfa_offset: 40 +// 0x00000024: ldc1 f24, +0(r29) +// 0x00000028: ldc1 f25, +8(r29) +// 0x0000002c: ld r16, +16(r29) +// 0x00000030: .cfi_restore: r16 +// 0x00000030: ld r17, +24(r29) +// 0x00000034: .cfi_restore: r17 +// 0x00000034: ld r31, +32(r29) +// 0x00000038: .cfi_restore: r31 +// 0x00000038: daddiu r29, r29, 40 +// 0x0000003c: .cfi_def_cfa_offset: 0 +// 0x0000003c: jr r31 +// 0x00000040: nop +// 0x00000044: .cfi_restore_state +// 0x00000044: .cfi_def_cfa_offset: 64 + +static constexpr uint8_t expected_asm_kThumb2_adjust[] = { + 0x60, 0xB5, 0x2D, 0xED, 0x02, 0x8A, 0x8B, 0xB0, 0x00, 0x90, 0x00, 0x28, + 0x40, 0xD0, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, 0x00, 0x68, + 0x0B, 0xB0, 0xBD, 0xEC, 0x02, 0x8A, 0x60, 0xBD, +}; +static constexpr uint8_t expected_cfi_kThumb2_adjust[] = { + 0x42, 0x0E, 0x0C, 0x85, 0x03, 0x86, 0x02, 0x8E, 0x01, 0x44, 0x0E, 0x14, + 0x05, 0x50, 0x05, 0x05, 0x51, 0x04, 0x42, 0x0E, 0x40, 0x02, 0x88, 0x0A, + 0x42, 0x0E, 0x14, 0x44, 0x0E, 0x0C, 0x06, 0x50, 0x06, 0x51, 0x42, 0x0B, + 0x0E, 0x40, +}; +// 0x00000000: push {r5, r6, lr} +// 0x00000002: .cfi_def_cfa_offset: 12 +// 0x00000002: .cfi_offset: r5 at cfa-12 +// 0x00000002: .cfi_offset: r6 at cfa-8 +// 0x00000002: .cfi_offset: r14 at cfa-4 +// 0x00000002: vpush.f32 {s16-s17} +// 0x00000006: .cfi_def_cfa_offset: 20 +// 0x00000006: .cfi_offset_extended: r80 at cfa-20 +// 0x00000006: .cfi_offset_extended: r81 at cfa-16 +// 0x00000006: sub sp, sp, #44 +// 0x00000008: .cfi_def_cfa_offset: 64 +// 0x00000008: str r0, [sp, #0] +// 0x0000000a: cmp r0, #0 +// 0x0000000c: beq +128 (0x00000090) +// 0x0000000e: ldr r0, [r0, #0] +// 0x00000010: ldr r0, [r0, #0] +// 0x00000012: ldr r0, [r0, #0] +// 0x00000014: ldr r0, [r0, #0] +// 0x00000016: ldr r0, [r0, #0] +// 0x00000018: ldr r0, [r0, #0] +// 0x0000001a: ldr r0, [r0, #0] +// 0x0000001c: ldr r0, [r0, #0] +// 0x0000001e: ldr r0, [r0, #0] +// 0x00000020: ldr r0, [r0, #0] +// 0x00000022: ldr r0, [r0, #0] +// 0x00000024: ldr r0, [r0, #0] +// 0x00000026: ldr r0, [r0, #0] +// 0x00000028: ldr r0, [r0, #0] +// 0x0000002a: ldr r0, [r0, #0] +// 0x0000002c: ldr r0, [r0, #0] +// 0x0000002e: ldr r0, [r0, #0] +// 0x00000030: ldr r0, [r0, #0] +// 0x00000032: ldr r0, [r0, #0] +// 0x00000034: ldr r0, [r0, #0] +// 0x00000036: ldr r0, [r0, #0] +// 0x00000038: ldr r0, [r0, #0] +// 0x0000003a: ldr r0, [r0, #0] +// 0x0000003c: ldr r0, [r0, #0] +// 0x0000003e: ldr r0, [r0, #0] +// 0x00000040: ldr r0, [r0, #0] +// 0x00000042: ldr r0, [r0, #0] +// 0x00000044: ldr r0, [r0, #0] +// 0x00000046: ldr r0, [r0, #0] +// 0x00000048: ldr r0, [r0, #0] +// 0x0000004a: ldr r0, [r0, #0] +// 0x0000004c: ldr r0, [r0, #0] +// 0x0000004e: ldr r0, [r0, #0] +// 0x00000050: ldr r0, [r0, #0] +// 0x00000052: ldr r0, [r0, #0] +// 0x00000054: ldr r0, [r0, #0] +// 0x00000056: ldr r0, [r0, #0] +// 0x00000058: ldr r0, [r0, #0] +// 0x0000005a: ldr r0, [r0, #0] +// 0x0000005c: ldr r0, [r0, #0] +// 0x0000005e: ldr r0, [r0, #0] +// 0x00000060: ldr r0, [r0, #0] +// 0x00000062: ldr r0, [r0, #0] +// 0x00000064: ldr r0, [r0, #0] +// 0x00000066: ldr r0, [r0, #0] +// 0x00000068: ldr r0, [r0, #0] +// 0x0000006a: ldr r0, [r0, #0] +// 0x0000006c: ldr r0, [r0, #0] +// 0x0000006e: ldr r0, [r0, #0] +// 0x00000070: ldr r0, [r0, #0] +// 0x00000072: ldr r0, [r0, #0] +// 0x00000074: ldr r0, [r0, #0] +// 0x00000076: ldr r0, [r0, #0] +// 0x00000078: ldr r0, [r0, #0] +// 0x0000007a: ldr r0, [r0, #0] +// 0x0000007c: ldr r0, [r0, #0] +// 0x0000007e: ldr r0, [r0, #0] +// 0x00000080: ldr r0, [r0, #0] +// 0x00000082: ldr r0, [r0, #0] +// 0x00000084: ldr r0, [r0, #0] +// 0x00000086: ldr r0, [r0, #0] +// 0x00000088: ldr r0, [r0, #0] +// 0x0000008a: ldr r0, [r0, #0] +// 0x0000008c: ldr r0, [r0, #0] +// 0x0000008e: ldr r0, [r0, #0] +// 0x00000090: .cfi_remember_state +// 0x00000090: add sp, sp, #44 +// 0x00000092: .cfi_def_cfa_offset: 20 +// 0x00000092: vpop.f32 {s16-s17} +// 0x00000096: .cfi_def_cfa_offset: 12 +// 0x00000096: .cfi_restore_extended: r80 +// 0x00000096: .cfi_restore_extended: r81 +// 0x00000096: pop {r5, r6, pc} +// 0x00000098: .cfi_restore_state +// 0x00000098: .cfi_def_cfa_offset: 64 + +static constexpr uint8_t expected_asm_kMips_adjust_head[] = { + 0xE4, 0xFF, 0xBD, 0x27, 0x18, 0x00, 0xBF, 0xAF, 0x14, 0x00, 0xB1, 0xAF, + 0x10, 0x00, 0xB0, 0xAF, 0x08, 0x00, 0xB6, 0xE7, 0x0C, 0x00, 0xB7, 0xE7, + 0x00, 0x00, 0xB4, 0xE7, 0x04, 0x00, 0xB5, 0xE7, 0xDC, 0xFF, 0xBD, 0x27, + 0x00, 0x00, 0xA4, 0xAF, 0x08, 0x00, 0x04, 0x14, 0xFC, 0xFF, 0xBD, 0x27, + 0x00, 0x00, 0xBF, 0xAF, 0x00, 0x00, 0x10, 0x04, 0x02, 0x00, 0x01, 0x3C, + 0x18, 0x00, 0x21, 0x34, 0x21, 0x08, 0x3F, 0x00, 0x00, 0x00, 0xBF, 0x8F, + 0x09, 0x00, 0x20, 0x00, 0x04, 0x00, 0xBD, 0x27, +}; +static constexpr uint8_t expected_asm_kMips_adjust_tail[] = { + 0x24, 0x00, 0xBD, 0x27, 0x00, 0x00, 0xB4, 0xC7, 0x04, 0x00, 0xB5, 0xC7, + 0x08, 0x00, 0xB6, 0xC7, 0x0C, 0x00, 0xB7, 0xC7, 0x10, 0x00, 0xB0, 0x8F, + 0x14, 0x00, 0xB1, 0x8F, 0x18, 0x00, 0xBF, 0x8F, 0x1C, 0x00, 0xBD, 0x27, + 0x09, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, +}; +static constexpr uint8_t expected_cfi_kMips_adjust[] = { + 0x44, 0x0E, 0x1C, 0x44, 0x9F, 0x01, 0x44, 0x91, 0x02, 0x44, 0x90, 0x03, + 0x54, 0x0E, 0x40, 0x4C, 0x0E, 0x44, 0x60, 0x0E, 0x40, 0x04, 0x04, 0x00, + 0x02, 0x00, 0x0A, 0x44, 0x0E, 0x1C, 0x54, 0xD0, 0x44, 0xD1, 0x44, 0xDF, + 0x44, 0x0E, 0x00, 0x48, 0x0B, 0x0E, 0x40, +}; +// 0x00000000: addiu r29, r29, -28 +// 0x00000004: .cfi_def_cfa_offset: 28 +// 0x00000004: sw r31, +24(r29) +// 0x00000008: .cfi_offset: r31 at cfa-4 +// 0x00000008: sw r17, +20(r29) +// 0x0000000c: .cfi_offset: r17 at cfa-8 +// 0x0000000c: sw r16, +16(r29) +// 0x00000010: .cfi_offset: r16 at cfa-12 +// 0x00000010: swc1 f22, +8(r29) +// 0x00000014: swc1 f23, +12(r29) +// 0x00000018: swc1 f20, +0(r29) +// 0x0000001c: swc1 f21, +4(r29) +// 0x00000020: addiu r29, r29, -36 +// 0x00000024: .cfi_def_cfa_offset: 64 +// 0x00000024: sw r4, +0(r29) +// 0x00000028: bne r0, r4, 0x0000004c ; +36 +// 0x0000002c: addiu r29, r29, -4 +// 0x00000030: .cfi_def_cfa_offset: 68 +// 0x00000030: sw r31, +0(r29) +// 0x00000034: bltzal r0, 0x00000038 ; +4 +// 0x00000038: lui r1, 0x20000 +// 0x0000003c: ori r1, r1, 24 +// 0x00000040: addu r1, r1, r31 +// 0x00000044: lw r31, +0(r29) +// 0x00000048: jr r1 +// 0x0000004c: addiu r29, r29, 4 +// 0x00000050: .cfi_def_cfa_offset: 64 +// 0x00000050: nop +// ... +// 0x00020050: nop +// 0x00020054: .cfi_remember_state +// 0x00020054: addiu r29, r29, 36 +// 0x00020058: .cfi_def_cfa_offset: 28 +// 0x00020058: lwc1 f20, +0(r29) +// 0x0002005c: lwc1 f21, +4(r29) +// 0x00020060: lwc1 f22, +8(r29) +// 0x00020064: lwc1 f23, +12(r29) +// 0x00020068: lw r16, +16(r29) +// 0x0002006c: .cfi_restore: r16 +// 0x0002006c: lw r17, +20(r29) +// 0x00020070: .cfi_restore: r17 +// 0x00020070: lw r31, +24(r29) +// 0x00020074: .cfi_restore: r31 +// 0x00020074: addiu r29, r29, 28 +// 0x00020078: .cfi_def_cfa_offset: 0 +// 0x00020078: jr r31 +// 0x0002007c: nop +// 0x00020080: .cfi_restore_state +// 0x00020080: .cfi_def_cfa_offset: 64 diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 8cb2cfc816..7e3c5e602e 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -56,6 +56,7 @@ #include "inliner.h" #include "instruction_simplifier.h" #include "intrinsics.h" +#include "jit/jit_code_cache.h" #include "licm.h" #include "jni/quick/jni_compiler.h" #include "load_store_elimination.h" @@ -258,15 +259,6 @@ class OptimizingCompiler FINAL : public Compiler { const DexFile& dex_file, Handle<mirror::DexCache> dex_cache) const OVERRIDE; - CompiledMethod* TryCompile(const DexFile::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) const; - CompiledMethod* JniCompile(uint32_t access_flags, uint32_t method_idx, const DexFile& dex_file) const OVERRIDE { @@ -291,23 +283,45 @@ class OptimizingCompiler FINAL : public Compiler { } } + bool JitCompile(Thread* self, jit::JitCodeCache* code_cache, ArtMethod* method) + OVERRIDE + SHARED_REQUIRES(Locks::mutator_lock_); + private: // Whether we should run any optimization or register allocation. If false, will // just run the code generation after the graph was built. const bool run_optimizations_; - // Optimize and compile `graph`. - CompiledMethod* CompileOptimized(HGraph* graph, - CodeGenerator* codegen, - CompilerDriver* driver, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const; - - // Just compile without doing optimizations. - CompiledMethod* CompileBaseline(CodeGenerator* codegen, - CompilerDriver* driver, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const; + // Create a 'CompiledMethod' for an optimized graph. + CompiledMethod* EmitOptimized(ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, + CodeGenerator* codegen, + CompilerDriver* driver) const; + + // Create a 'CompiledMethod' for a non-optimized graph. + CompiledMethod* EmitBaseline(ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, + CodeGenerator* codegen, + CompilerDriver* driver) const; + + // Try compiling a method and return the code generator used for + // compiling it. + // This method: + // 1) Builds the graph. Returns null if it failed to build it. + // 2) If `run_optimizations_` is set: + // 2.1) Transform the graph to SSA. Returns null if it failed. + // 2.2) Run optimizations on the graph, including register allocator. + // 3) Generate code with the `code_allocator` provided. + CodeGenerator* TryCompile(ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, + const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint16_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file, + Handle<mirror::DexCache> dex_cache) const; std::unique_ptr<OptimizingCompilerStats> compilation_stats_; @@ -446,13 +460,32 @@ static void RunArchOptimizations(InstructionSet instruction_set, } } +NO_INLINE // Avoid increasing caller's frame size by large stack-allocated objects. +static void AllocateRegisters(HGraph* graph, + CodeGenerator* codegen, + PassObserver* pass_observer) { + PrepareForRegisterAllocation(graph).Run(); + SsaLivenessAnalysis liveness(graph, codegen); + { + PassScope scope(SsaLivenessAnalysis::kLivenessPassName, pass_observer); + liveness.Analyze(); + } + { + PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer); + RegisterAllocator(graph->GetArena(), codegen, liveness).AllocateRegisters(); + } +} + static void RunOptimizations(HGraph* graph, CodeGenerator* codegen, CompilerDriver* driver, OptimizingCompilerStats* stats, const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer, - StackHandleScopeCollection* handles) { + PassObserver* pass_observer) { + ScopedObjectAccess soa(Thread::Current()); + StackHandleScopeCollection handles(soa.Self()); + ScopedThreadSuspension sts(soa.Self(), kNative); + ArenaAllocator* arena = graph->GetArena(); HDeadCodeElimination* dce1 = new (arena) HDeadCodeElimination( graph, stats, HDeadCodeElimination::kInitialDeadCodeEliminationPassName); @@ -469,7 +502,7 @@ static void RunOptimizations(HGraph* graph, HInductionVarAnalysis* induction = new (arena) HInductionVarAnalysis(graph); BoundsCheckElimination* bce = new (arena) BoundsCheckElimination(graph, induction); ReferenceTypePropagation* type_propagation = - new (arena) ReferenceTypePropagation(graph, handles); + new (arena) ReferenceTypePropagation(graph, &handles); HSharpening* sharpening = new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver); InstructionSimplifier* simplify2 = new (arena) InstructionSimplifier( graph, stats, "instruction_simplifier_after_types"); @@ -492,7 +525,7 @@ static void RunOptimizations(HGraph* graph, RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer); - MaybeRunInliner(graph, codegen, driver, stats, dex_compilation_unit, pass_observer, handles); + MaybeRunInliner(graph, codegen, driver, stats, dex_compilation_unit, pass_observer, &handles); // TODO: Update passes incompatible with try/catch so we have the same // pipeline for all methods. @@ -532,6 +565,7 @@ static void RunOptimizations(HGraph* graph, } RunArchOptimizations(driver->GetInstructionSet(), graph, stats, pass_observer); + AllocateRegisters(graph, codegen, pass_observer); } // The stack map we generate must be 4-byte aligned on ARM. Since existing @@ -545,22 +579,6 @@ static ArrayRef<const uint8_t> AlignVectorSize(ArenaVector<uint8_t>& vector) { return ArrayRef<const uint8_t>(vector); } -NO_INLINE // Avoid increasing caller's frame size by large stack-allocated objects. -static void AllocateRegisters(HGraph* graph, - CodeGenerator* codegen, - PassObserver* pass_observer) { - PrepareForRegisterAllocation(graph).Run(); - SsaLivenessAnalysis liveness(graph, codegen); - { - PassScope scope(SsaLivenessAnalysis::kLivenessPassName, pass_observer); - liveness.Analyze(); - } - { - PassScope scope(RegisterAllocator::kRegisterAllocatorPassName, pass_observer); - RegisterAllocator(graph->GetArena(), codegen, liveness).AllocateRegisters(); - } -} - static ArenaVector<LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) { ArenaVector<LinkerPatch> linker_patches(codegen->GetGraph()->GetArena()->Adapter()); codegen->EmitLinkerPatches(&linker_patches); @@ -574,74 +592,42 @@ static ArenaVector<LinkerPatch> EmitAndSortLinkerPatches(CodeGenerator* codegen) return linker_patches; } -CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph, - CodeGenerator* codegen, - CompilerDriver* compiler_driver, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const { - ScopedObjectAccess soa(Thread::Current()); - StackHandleScopeCollection handles(soa.Self()); - soa.Self()->TransitionFromRunnableToSuspended(kNative); - RunOptimizations(graph, - codegen, - compiler_driver, - compilation_stats_.get(), - dex_compilation_unit, - pass_observer, - &handles); - - AllocateRegisters(graph, codegen, pass_observer); - - ArenaAllocator* arena = graph->GetArena(); - CodeVectorAllocator allocator(arena); - DefaultSrcMap src_mapping_table; - codegen->SetSrcMap(compiler_driver->GetCompilerOptions().GetGenerateDebugInfo() - ? &src_mapping_table - : nullptr); - codegen->CompileOptimized(&allocator); - +CompiledMethod* OptimizingCompiler::EmitOptimized(ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, + CodeGenerator* codegen, + CompilerDriver* compiler_driver) const { ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen); - ArenaVector<uint8_t> stack_map(arena->Adapter(kArenaAllocStackMaps)); - codegen->BuildStackMaps(&stack_map); + stack_map.resize(codegen->ComputeStackMapsSize()); + codegen->BuildStackMaps(MemoryRegion(stack_map.data(), stack_map.size())); MaybeRecordStat(MethodCompilationStat::kCompiledOptimized); CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod( compiler_driver, codegen->GetInstructionSet(), - ArrayRef<const uint8_t>(allocator.GetMemory()), + ArrayRef<const uint8_t>(code_allocator->GetMemory()), // Follow Quick's behavior and set the frame size to zero if it is // considered "empty" (see the definition of // art::CodeGenerator::HasEmptyFrame). codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), - ArrayRef<const SrcMapElem>(src_mapping_table), + ArrayRef<const SrcMapElem>(codegen->GetSrcMappingTable()), ArrayRef<const uint8_t>(), // mapping_table. ArrayRef<const uint8_t>(stack_map), ArrayRef<const uint8_t>(), // native_gc_map. ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()), ArrayRef<const LinkerPatch>(linker_patches)); - pass_observer->DumpDisassembly(); - soa.Self()->TransitionFromSuspendedToRunnable(); return compiled_method; } -CompiledMethod* OptimizingCompiler::CompileBaseline( +CompiledMethod* OptimizingCompiler::EmitBaseline( + ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, CodeGenerator* codegen, - CompilerDriver* compiler_driver, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const { - ArenaAllocator* arena = codegen->GetGraph()->GetArena(); - CodeVectorAllocator allocator(arena); - DefaultSrcMap src_mapping_table; - codegen->SetSrcMap(compiler_driver->GetCompilerOptions().GetGenerateDebugInfo() - ? &src_mapping_table - : nullptr); - codegen->CompileBaseline(&allocator); - + CompilerDriver* compiler_driver) const { ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen); ArenaVector<uint8_t> mapping_table(arena->Adapter(kArenaAllocBaselineMaps)); @@ -649,37 +635,38 @@ CompiledMethod* OptimizingCompiler::CompileBaseline( ArenaVector<uint8_t> vmap_table(arena->Adapter(kArenaAllocBaselineMaps)); codegen->BuildVMapTable(&vmap_table); ArenaVector<uint8_t> gc_map(arena->Adapter(kArenaAllocBaselineMaps)); - codegen->BuildNativeGCMap(&gc_map, dex_compilation_unit); + codegen->BuildNativeGCMap(&gc_map, *compiler_driver); MaybeRecordStat(MethodCompilationStat::kCompiledBaseline); CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod( compiler_driver, codegen->GetInstructionSet(), - ArrayRef<const uint8_t>(allocator.GetMemory()), + ArrayRef<const uint8_t>(code_allocator->GetMemory()), // Follow Quick's behavior and set the frame size to zero if it is // considered "empty" (see the definition of // art::CodeGenerator::HasEmptyFrame). codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), - ArrayRef<const SrcMapElem>(src_mapping_table), + ArrayRef<const SrcMapElem>(codegen->GetSrcMappingTable()), AlignVectorSize(mapping_table), AlignVectorSize(vmap_table), AlignVectorSize(gc_map), ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()), ArrayRef<const LinkerPatch>(linker_patches)); - pass_observer->DumpDisassembly(); return compiled_method; } -CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item, - uint32_t access_flags, - InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const DexFile& dex_file, - Handle<mirror::DexCache> dex_cache) const { +CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena, + CodeVectorAllocator* code_allocator, + const DexFile::CodeItem* code_item, + uint32_t access_flags, + InvokeType invoke_type, + uint16_t class_def_idx, + uint32_t method_idx, + jobject class_loader, + const DexFile& dex_file, + Handle<mirror::DexCache> dex_cache) const { std::string method_name = PrettyMethod(method_idx, dex_file); MaybeRecordStat(MethodCompilationStat::kAttemptCompilation); CompilerDriver* compiler_driver = GetCompilerDriver(); @@ -721,13 +708,10 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite && compiler_driver->RequiresConstructorBarrier(Thread::Current(), dex_compilation_unit.GetDexFile(), dex_compilation_unit.GetClassDefIndex()); - ArenaAllocator arena(Runtime::Current()->GetArenaPool()); - HGraph* graph = new (&arena) HGraph( - &arena, dex_file, method_idx, requires_barrier, compiler_driver->GetInstructionSet(), + HGraph* graph = new (arena) HGraph( + arena, dex_file, method_idx, requires_barrier, compiler_driver->GetInstructionSet(), kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable()); - bool shouldOptimize = method_name.find("$opt$reg$") != std::string::npos && run_optimizations_; - std::unique_ptr<CodeGenerator> codegen( CodeGenerator::Create(graph, instruction_set, @@ -779,16 +763,8 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite } } - bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set); - - // `run_optimizations_` is set explicitly (either through a compiler filter - // or the debuggable flag). If it is set, we can run baseline. Otherwise, we fall back - // to Quick. - bool can_use_baseline = !run_optimizations_ && builder.CanUseBaselineForStringInit(); - CompiledMethod* compiled_method = nullptr; - if (run_optimizations_ && can_allocate_registers) { - VLOG(compiler) << "Optimizing " << method_name; - + VLOG(compiler) << "Optimizing " << method_name; + if (run_optimizations_) { { PassScope scope(SsaBuilder::kSsaBuilderPassName, &pass_observer); if (!graph->TryBuildingSsa()) { @@ -800,37 +776,26 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite } } - compiled_method = CompileOptimized(graph, - codegen.get(), - compiler_driver, - dex_compilation_unit, - &pass_observer); - } else if (shouldOptimize && can_allocate_registers) { - LOG(FATAL) << "Could not allocate registers in optimizing compiler"; - UNREACHABLE(); - } else if (can_use_baseline) { - VLOG(compiler) << "Compile baseline " << method_name; - - if (!run_optimizations_) { - MaybeRecordStat(MethodCompilationStat::kNotOptimizedDisabled); - } else if (!can_allocate_registers) { - MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator); - } - - compiled_method = CompileBaseline(codegen.get(), - compiler_driver, - dex_compilation_unit, - &pass_observer); + RunOptimizations(graph, + codegen.get(), + compiler_driver, + compilation_stats_.get(), + dex_compilation_unit, + &pass_observer); + codegen->CompileOptimized(code_allocator); + } else { + codegen->CompileBaseline(code_allocator); } + pass_observer.DumpDisassembly(); if (kArenaAllocatorCountAllocations) { - if (arena.BytesAllocated() > 4 * MB) { - MemStats mem_stats(arena.GetMemStats()); + if (arena->BytesAllocated() > 4 * MB) { + MemStats mem_stats(arena->GetMemStats()); LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); } } - return compiled_method; + return codegen.release(); } static bool CanHandleVerificationFailure(const VerifiedMethod* verified_method) { @@ -852,26 +817,37 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, Handle<mirror::DexCache> dex_cache) const { CompilerDriver* compiler_driver = GetCompilerDriver(); CompiledMethod* method = nullptr; - if (Runtime::Current()->IsAotCompiler()) { - const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx); - DCHECK(!verified_method->HasRuntimeThrow()); - if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) - || CanHandleVerificationFailure(verified_method)) { - method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, - method_idx, jclass_loader, dex_file, dex_cache); - } else { - if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) { - MaybeRecordStat(MethodCompilationStat::kNotCompiledVerifyAtRuntime); + DCHECK(Runtime::Current()->IsAotCompiler()); + const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx); + DCHECK(!verified_method->HasRuntimeThrow()); + if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) + || CanHandleVerificationFailure(verified_method)) { + ArenaAllocator arena(Runtime::Current()->GetArenaPool()); + CodeVectorAllocator code_allocator(&arena); + std::unique_ptr<CodeGenerator> codegen( + TryCompile(&arena, + &code_allocator, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + jclass_loader, + dex_file, + dex_cache)); + if (codegen.get() != nullptr) { + if (run_optimizations_) { + method = EmitOptimized(&arena, &code_allocator, codegen.get(), compiler_driver); } else { - MaybeRecordStat(MethodCompilationStat::kNotCompiledClassNotVerified); + method = EmitBaseline(&arena, &code_allocator, codegen.get(), compiler_driver); } } } else { - // This is for the JIT compiler, which has already ensured the class is verified. - // We can go straight to compiling. - DCHECK(Runtime::Current()->UseJit()); - method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, - method_idx, jclass_loader, dex_file, dex_cache); + if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) { + MaybeRecordStat(MethodCompilationStat::kNotCompiledVerifyAtRuntime); + } else { + MaybeRecordStat(MethodCompilationStat::kNotCompiledClassNotVerified); + } } if (kIsDebugBuild && @@ -896,4 +872,70 @@ bool IsCompilingWithCoreImage() { return EndsWith(image, "core.art") || EndsWith(image, "core-optimizing.art"); } +bool OptimizingCompiler::JitCompile(Thread* self, + jit::JitCodeCache* code_cache, + ArtMethod* method) { + StackHandleScope<2> hs(self); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + method->GetDeclaringClass()->GetClassLoader())); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); + + jobject jclass_loader = class_loader.ToJObject(); + const DexFile* dex_file = method->GetDexFile(); + const uint16_t class_def_idx = method->GetClassDefIndex(); + const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset()); + const uint32_t method_idx = method->GetDexMethodIndex(); + const uint32_t access_flags = method->GetAccessFlags(); + const InvokeType invoke_type = method->GetInvokeType(); + + ArenaAllocator arena(Runtime::Current()->GetArenaPool()); + CodeVectorAllocator code_allocator(&arena); + std::unique_ptr<CodeGenerator> codegen; + { + // Go to native so that we don't block GC during compilation. + ScopedThreadSuspension sts(self, kNative); + + DCHECK(run_optimizations_); + codegen.reset( + TryCompile(&arena, + &code_allocator, + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + jclass_loader, + *dex_file, + dex_cache)); + if (codegen.get() == nullptr) { + return false; + } + } + + size_t stack_map_size = codegen->ComputeStackMapsSize(); + uint8_t* stack_map_data = code_cache->ReserveData(self, stack_map_size); + if (stack_map_data == nullptr) { + return false; + } + codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size)); + const void* code = code_cache->CommitCode( + self, + method, + nullptr, + stack_map_data, + nullptr, + codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), + codegen->GetCoreSpillMask(), + codegen->GetFpuSpillMask(), + code_allocator.GetMemory().data(), + code_allocator.GetSize()); + + if (code == nullptr) { + code_cache->ClearData(self, stack_map_data); + return false; + } + + return true; +} + } // namespace art |