diff options
author | Andreas Gampe <agampe@google.com> | 2014-08-12 23:19:23 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2014-08-22 21:20:08 -0700 |
commit | 53c913bb71b218714823c8c87a1f92830c336f61 (patch) | |
tree | 96aebfc9ae62eb1454b78286236567e2b6f3e5c7 | |
parent | e18aa4316eb9a15cd6b1051f27a1ce49967c170e (diff) | |
download | art-53c913bb71b218714823c8c87a1f92830c336f61.zip art-53c913bb71b218714823c8c87a1f92830c336f61.tar.gz art-53c913bb71b218714823c8c87a1f92830c336f61.tar.bz2 |
ART: Clean up compiler
Clean up the compiler: less extern functions, dis-entangle
compilers, hide some compiler specifics, lower global includes.
Change-Id: Ibaf88d02505d86994d7845cf0075be5041cc8438
47 files changed, 1440 insertions, 1100 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 5c5163d..6e48bdf 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -48,6 +48,7 @@ LIBART_COMPILER_SRC_FILES := \ dex/quick/mips/target_mips.cc \ dex/quick/mips/utility_mips.cc \ dex/quick/mir_to_lir.cc \ + dex/quick/quick_compiler.cc \ dex/quick/ralloc_util.cc \ dex/quick/resource_mask.cc \ dex/quick/x86/assemble_x86.cc \ @@ -62,6 +63,7 @@ LIBART_COMPILER_SRC_FILES := \ dex/mir_method_info.cc \ dex/mir_optimization.cc \ dex/bb_optimizations.cc \ + dex/compiler_ir.cc \ dex/post_opt_passes.cc \ dex/pass_driver_me_opts.cc \ dex/pass_driver_me_post_opt.cc \ @@ -82,6 +84,7 @@ LIBART_COMPILER_SRC_FILES := \ jni/quick/x86_64/calling_convention_x86_64.cc \ jni/quick/calling_convention.cc \ jni/quick/jni_compiler.cc \ + llvm/llvm_compiler.cc \ optimizing/builder.cc \ optimizing/code_generator.cc \ optimizing/code_generator_arm.cc \ @@ -116,7 +119,6 @@ LIBART_COMPILER_SRC_FILES := \ utils/x86_64/managed_register_x86_64.cc \ utils/scoped_arena_allocator.cc \ buffered_output_stream.cc \ - compilers.cc \ compiler.cc \ elf_fixup.cc \ elf_patcher.cc \ diff --git a/compiler/compiler.cc b/compiler/compiler.cc index a832c31..fbfd8e6 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -15,14 +15,12 @@ */ #include "compiler.h" -#include "compilers.h" -#include "driver/compiler_driver.h" -#include "mirror/art_method-inl.h" -#ifdef ART_USE_PORTABLE_COMPILER -#include "dex/portable/mir_to_gbc.h" -#include "elf_writer_mclinker.h" -#endif +#include "base/logging.h" +#include "dex/quick/quick_compiler.h" +#include "driver/compiler_driver.h" +#include "llvm/llvm_compiler.h" +#include "optimizing/optimizing_compiler.h" namespace art { @@ -60,137 +58,21 @@ CompiledMethod* Compiler::TryCompileWithSeaIR(const art::DexFile::CodeItem* code return nullptr; } - -#ifdef ART_USE_PORTABLE_COMPILER - -extern "C" void ArtInitCompilerContext(art::CompilerDriver* driver); - -extern "C" void ArtUnInitCompilerContext(art::CompilerDriver* driver); - -extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver* driver, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, - art::InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const art::DexFile& dex_file); - -extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver* driver, - uint32_t access_flags, uint32_t method_idx, - const art::DexFile& dex_file); - -extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver* driver, - std::string const& filename); - - -class LLVMCompiler FINAL : public Compiler { - public: - explicit LLVMCompiler(CompilerDriver* driver) : Compiler(driver, 1000) {} - - void Init() const OVERRIDE { - ArtInitCompilerContext(GetCompilerDriver()); - } - - void UnInit() const OVERRIDE { - ArtUnInitCompilerContext(GetCompilerDriver()); - } - - CompiledMethod* Compile(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) const OVERRIDE { - CompiledMethod* method = TryCompileWithSeaIR(code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file); - if (method != nullptr) { - return method; - } - - return ArtCompileMethod(GetCompilerDriver(), - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file); - } - - CompiledMethod* JniCompile(uint32_t access_flags, - uint32_t method_idx, - const DexFile& dex_file) const OVERRIDE { - return ArtLLVMJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); - } - - uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const { - return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode()); - } - - bool WriteElf(art::File* file, - OatWriter* oat_writer, - const std::vector<const art::DexFile*>& dex_files, - const std::string& android_root, - bool is_host, const CompilerDriver& driver) const - OVERRIDE - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return art::ElfWriterMclinker::Create( - file, oat_writer, dex_files, android_root, is_host, driver); - } - - Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { - return PortableCodeGenerator( - cu, cu->mir_graph.get(), &cu->arena, - reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit)); - } - - void InitCompilationUnit(CompilationUnit& cu) const { - // Fused long branches not currently useful in bitcode. - cu.disable_opt |= - (1 << kBranchFusing) | - (1 << kSuppressExceptionEdges); - } - - bool IsPortable() const OVERRIDE { - return true; - } - - void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) { - typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&); - - SetBitcodeFileNameFn set_bitcode_file_name = - reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName); - - set_bitcode_file_name(driver, filename); - } - - private: - DISALLOW_COPY_AND_ASSIGN(LLVMCompiler); -}; -#endif - Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) { switch (kind) { case kQuick: - return new QuickCompiler(driver); - break; + return CreateQuickCompiler(driver); + case kOptimizing: - return new OptimizingCompiler(driver); - break; + return CreateOptimizingCompiler(driver); + case kPortable: -#ifdef ART_USE_PORTABLE_COMPILER - return new LLVMCompiler(driver); -#else - LOG(FATAL) << "Portable compiler not compiled"; -#endif - break; + { + Compiler* compiler = CreateLLVMCompiler(driver); + CHECK(compiler != nullptr) << "Portable compiler not compiled"; + return compiler; + } + default: LOG(FATAL) << "UNREACHABLE"; } diff --git a/compiler/compiler.h b/compiler/compiler.h index 4caebf3..05fa858 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -26,13 +26,19 @@ class Backend; struct CompilationUnit; class CompilerDriver; class CompiledMethod; -class MIRGraph; class OatWriter; namespace mirror { class ArtMethod; } +// Base class for compiler-specific thread-local storage for compiler worker threads +class CompilerTls { + public: + CompilerTls() {} + ~CompilerTls() {} +}; + class Compiler { public: enum Kind { @@ -47,6 +53,9 @@ class Compiler { virtual void UnInit() const = 0; + virtual bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) + const = 0; + virtual CompiledMethod* Compile(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, @@ -109,6 +118,10 @@ class Compiler { return nullptr; } + virtual CompilerTls* CreateNewCompilerTls() { + return nullptr; + } + protected: explicit Compiler(CompilerDriver* driver, uint64_t warning) : driver_(driver), maximum_compilation_time_before_warning_(warning) { diff --git a/compiler/compilers.cc b/compiler/compilers.cc deleted file mode 100644 index 5cf846f..0000000 --- a/compiler/compilers.cc +++ /dev/null @@ -1,143 +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. - */ - -#include "compilers.h" - -#include "dex/mir_graph.h" -#include "dex/quick/mir_to_lir.h" -#include "elf_writer_quick.h" -#include "mirror/art_method-inl.h" - -namespace art { - -extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver* driver); -extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver* driver); -extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver* driver, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, - art::InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const art::DexFile& dex_file); - -extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver* driver, - uint32_t access_flags, uint32_t method_idx, - const art::DexFile& dex_file); - -void QuickCompiler::Init() const { - ArtInitQuickCompilerContext(GetCompilerDriver()); -} - -void QuickCompiler::UnInit() const { - ArtUnInitQuickCompilerContext(GetCompilerDriver()); -} - -CompiledMethod* QuickCompiler::Compile(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) const { - CompiledMethod* method = TryCompileWithSeaIR(code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file); - if (method != nullptr) { - return method; - } - - return ArtQuickCompileMethod(GetCompilerDriver(), - code_item, - access_flags, - invoke_type, - class_def_idx, - method_idx, - class_loader, - dex_file); -} - -CompiledMethod* QuickCompiler::JniCompile(uint32_t access_flags, - uint32_t method_idx, - const DexFile& dex_file) const { - return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); -} - -uintptr_t QuickCompiler::GetEntryPointOf(mirror::ArtMethod* method) const { - return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()); -} - -bool QuickCompiler::WriteElf(art::File* file, - OatWriter* oat_writer, - const std::vector<const art::DexFile*>& dex_files, - const std::string& android_root, - bool is_host) const { - return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, - *GetCompilerDriver()); -} - -Backend* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { - Mir2Lir* mir_to_lir = nullptr; - switch (cu->instruction_set) { - case kThumb2: - mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena); - break; - case kArm64: - mir_to_lir = Arm64CodeGenerator(cu, cu->mir_graph.get(), &cu->arena); - break; - case kMips: - mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena); - break; - case kX86: - // Fall-through. - case kX86_64: - mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena); - break; - default: - LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set; - } - - /* The number of compiler temporaries depends on backend so set it up now if possible */ - if (mir_to_lir) { - size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps(); - bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps); - CHECK(set_max); - } - return mir_to_lir; -} - -CompiledMethod* OptimizingCompiler::Compile(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) const { - CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, - method_idx, class_loader, dex_file); - if (method != nullptr) { - return method; - } - - return QuickCompiler::Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, - class_loader, dex_file); -} - -} // namespace art diff --git a/compiler/compilers.h b/compiler/compilers.h deleted file mode 100644 index 151bf6f..0000000 --- a/compiler/compilers.h +++ /dev/null @@ -1,91 +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_COMPILERS_H_ -#define ART_COMPILER_COMPILERS_H_ - -#include "compiler.h" - -namespace art { - -class QuickCompiler : public Compiler { - public: - explicit QuickCompiler(CompilerDriver* driver) : Compiler(driver, 100) {} - - void Init() const OVERRIDE; - - void UnInit() const OVERRIDE; - - CompiledMethod* Compile(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) const OVERRIDE; - - CompiledMethod* JniCompile(uint32_t access_flags, - uint32_t method_idx, - const DexFile& dex_file) const OVERRIDE; - - uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - bool WriteElf(art::File* file, - OatWriter* oat_writer, - const std::vector<const art::DexFile*>& dex_files, - const std::string& android_root, - bool is_host) const - OVERRIDE - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE; - - void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE {} - - private: - DISALLOW_COPY_AND_ASSIGN(QuickCompiler); -}; - -class OptimizingCompiler FINAL : public QuickCompiler { - public: - explicit OptimizingCompiler(CompilerDriver* driver); - - CompiledMethod* Compile(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) 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) const; - - private: - std::unique_ptr<std::ostream> visualizer_output_; - - DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler); -}; - -} // namespace art - -#endif // ART_COMPILER_COMPILERS_H_ diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index 7395324..4d6cdf6 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_ #define ART_COMPILER_DEX_BB_OPTIMIZATIONS_H_ +#include "base/casts.h" #include "compiler_internals.h" #include "pass_me.h" diff --git a/compiler/dex/compiler_internals.h b/compiler/dex/compiler_internals.h index 9dd0272..2019f0b 100644 --- a/compiler/dex/compiler_internals.h +++ b/compiler/dex/compiler_internals.h @@ -23,14 +23,9 @@ #include <stdio.h> #include "base/logging.h" -#include "class_linker.h" -#include "driver/compiler_driver.h" -#include "quick/mir_to_lir.h" #include "mir_graph.h" #include "compiler_ir.h" -#include "frontend.h" -#include "monitor.h" -#include "thread.h" +#include "frontend.h" // Debug flags. #include "utils.h" #endif // ART_COMPILER_DEX_COMPILER_INTERNALS_H_ diff --git a/compiler/dex/compiler_ir.cc b/compiler/dex/compiler_ir.cc new file mode 100644 index 0000000..7a5b114 --- /dev/null +++ b/compiler/dex/compiler_ir.cc @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include "compiler_ir.h" + +#include "backend.h" +#include "frontend.h" +#include "mir_graph.h" + +namespace art { + +CompilationUnit::CompilationUnit(ArenaPool* pool) + : compiler_driver(nullptr), + class_linker(nullptr), + dex_file(nullptr), + class_loader(nullptr), + class_def_idx(0), + method_idx(0), + code_item(nullptr), + access_flags(0), + invoke_type(kDirect), + shorty(nullptr), + disable_opt(0), + enable_debug(0), + verbose(false), + compiler(nullptr), + instruction_set(kNone), + target64(false), + num_dalvik_registers(0), + insns(nullptr), + num_ins(0), + num_outs(0), + num_regs(0), + compiler_flip_match(false), + arena(pool), + arena_stack(pool), + mir_graph(nullptr), + cg(nullptr), + timings("QuickCompiler", true, false), + print_pass(false) { +} + +CompilationUnit::~CompilationUnit() { +} + +void CompilationUnit::StartTimingSplit(const char* label) { + if (compiler_driver->GetDumpPasses()) { + timings.StartTiming(label); + } +} + +void CompilationUnit::NewTimingSplit(const char* label) { + if (compiler_driver->GetDumpPasses()) { + timings.EndTiming(); + timings.StartTiming(label); + } +} + +void CompilationUnit::EndTiming() { + if (compiler_driver->GetDumpPasses()) { + timings.EndTiming(); + if (enable_debug & (1 << kDebugTimings)) { + LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file); + LOG(INFO) << Dumpable<TimingLogger>(timings); + } + } +} + +} // namespace art diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 66fb608..67bf88a 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -20,22 +20,24 @@ #include <vector> #include "compiler_enums.h" -#include "dex/quick/mir_to_lir.h" -#include "dex_instruction.h" #include "driver/compiler_driver.h" -#include "driver/dex_compilation_unit.h" -#include "safe_map.h" #include "utils/scoped_arena_allocator.h" #include "base/timing_logger.h" #include "utils/arena_allocator.h" namespace art { -struct ArenaMemBlock; class Backend; -struct Memstats; +class ClassLinker; class MIRGraph; -class Mir2Lir; + +/* + * TODO: refactoring pass to move these (and other) typedefs towards usage style of runtime to + * add type safety (see runtime/offsets.h). + */ +typedef uint32_t DexOffset; // Dex offset in code units. +typedef uint16_t NarrowDexOffset; // For use in structs, Dex offsets range from 0 .. 0xffff. +typedef uint32_t CodeOffset; // Native code offset in bytes. struct CompilationUnit { explicit CompilationUnit(ArenaPool* pool); diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index c44a116..078ddf1 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -14,14 +14,15 @@ * limitations under the License. */ +#include "frontend.h" + #include <cstdint> +#include "backend.h" #include "compiler.h" #include "compiler_internals.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" -#include "dataflow_iterator-inl.h" -#include "leb128.h" #include "mirror/object.h" #include "pass_driver_me_opts.h" #include "runtime.h" @@ -32,14 +33,6 @@ namespace art { -extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver* driver) { - CHECK(driver->GetCompilerContext() == nullptr); -} - -extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver* driver) { - CHECK(driver->GetCompilerContext() == nullptr); -} - /* Default optimizer/debug setting for the compiler. */ static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations // (1 << kLoadStoreElimination) | @@ -81,542 +74,8 @@ static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes // (1 << kDebugCodegenDump) | 0; -COMPILE_ASSERT(0U == static_cast<size_t>(kNone), kNone_not_0); -COMPILE_ASSERT(1U == static_cast<size_t>(kArm), kArm_not_1); -COMPILE_ASSERT(2U == static_cast<size_t>(kArm64), kArm64_not_2); -COMPILE_ASSERT(3U == static_cast<size_t>(kThumb2), kThumb2_not_3); -COMPILE_ASSERT(4U == static_cast<size_t>(kX86), kX86_not_4); -COMPILE_ASSERT(5U == static_cast<size_t>(kX86_64), kX86_64_not_5); -COMPILE_ASSERT(6U == static_cast<size_t>(kMips), kMips_not_6); -COMPILE_ASSERT(7U == static_cast<size_t>(kMips64), kMips64_not_7); - -// Additional disabled optimizations (over generally disabled) per instruction set. -static constexpr uint32_t kDisabledOptimizationsPerISA[] = { - // 0 = kNone. - ~0U, - // 1 = kArm, unused (will use kThumb2). - ~0U, - // 2 = kArm64. - 0, - // 3 = kThumb2. - 0, - // 4 = kX86. - (1 << kLoadStoreElimination) | - 0, - // 5 = kX86_64. - (1 << kLoadStoreElimination) | - 0, - // 6 = kMips. - (1 << kLoadStoreElimination) | - (1 << kLoadHoisting) | - (1 << kSuppressLoads) | - (1 << kNullCheckElimination) | - (1 << kPromoteRegs) | - (1 << kTrackLiveTemps) | - (1 << kSafeOptimizations) | - (1 << kBBOpt) | - (1 << kMatch) | - (1 << kPromoteCompilerTemps) | - 0, - // 7 = kMips64. - ~0U -}; -COMPILE_ASSERT(sizeof(kDisabledOptimizationsPerISA) == 8 * sizeof(uint32_t), kDisabledOpts_unexp); - -// Supported shorty types per instruction set. nullptr means that all are available. -// Z : boolean -// B : byte -// S : short -// C : char -// I : int -// J : long -// F : float -// D : double -// L : reference(object, array) -// V : void -static const char* kSupportedTypes[] = { - // 0 = kNone. - "", - // 1 = kArm, unused (will use kThumb2). - "", - // 2 = kArm64. - nullptr, - // 3 = kThumb2. - nullptr, - // 4 = kX86. - nullptr, - // 5 = kX86_64. - nullptr, - // 6 = kMips. - nullptr, - // 7 = kMips64. - "" -}; -COMPILE_ASSERT(sizeof(kSupportedTypes) == 8 * sizeof(char*), kSupportedTypes_unexp); - -static int kAllOpcodes[] = { - Instruction::NOP, - Instruction::MOVE, - Instruction::MOVE_FROM16, - Instruction::MOVE_16, - Instruction::MOVE_WIDE, - Instruction::MOVE_WIDE_FROM16, - Instruction::MOVE_WIDE_16, - Instruction::MOVE_OBJECT, - Instruction::MOVE_OBJECT_FROM16, - Instruction::MOVE_OBJECT_16, - Instruction::MOVE_RESULT, - Instruction::MOVE_RESULT_WIDE, - Instruction::MOVE_RESULT_OBJECT, - Instruction::MOVE_EXCEPTION, - Instruction::RETURN_VOID, - Instruction::RETURN, - Instruction::RETURN_WIDE, - Instruction::RETURN_OBJECT, - Instruction::CONST_4, - Instruction::CONST_16, - Instruction::CONST, - Instruction::CONST_HIGH16, - Instruction::CONST_WIDE_16, - Instruction::CONST_WIDE_32, - Instruction::CONST_WIDE, - Instruction::CONST_WIDE_HIGH16, - Instruction::CONST_STRING, - Instruction::CONST_STRING_JUMBO, - Instruction::CONST_CLASS, - Instruction::MONITOR_ENTER, - Instruction::MONITOR_EXIT, - Instruction::CHECK_CAST, - Instruction::INSTANCE_OF, - Instruction::ARRAY_LENGTH, - Instruction::NEW_INSTANCE, - Instruction::NEW_ARRAY, - Instruction::FILLED_NEW_ARRAY, - Instruction::FILLED_NEW_ARRAY_RANGE, - Instruction::FILL_ARRAY_DATA, - Instruction::THROW, - Instruction::GOTO, - Instruction::GOTO_16, - Instruction::GOTO_32, - Instruction::PACKED_SWITCH, - Instruction::SPARSE_SWITCH, - Instruction::CMPL_FLOAT, - Instruction::CMPG_FLOAT, - Instruction::CMPL_DOUBLE, - Instruction::CMPG_DOUBLE, - Instruction::CMP_LONG, - Instruction::IF_EQ, - Instruction::IF_NE, - Instruction::IF_LT, - Instruction::IF_GE, - Instruction::IF_GT, - Instruction::IF_LE, - Instruction::IF_EQZ, - Instruction::IF_NEZ, - Instruction::IF_LTZ, - Instruction::IF_GEZ, - Instruction::IF_GTZ, - Instruction::IF_LEZ, - Instruction::UNUSED_3E, - Instruction::UNUSED_3F, - Instruction::UNUSED_40, - Instruction::UNUSED_41, - Instruction::UNUSED_42, - Instruction::UNUSED_43, - Instruction::AGET, - Instruction::AGET_WIDE, - Instruction::AGET_OBJECT, - Instruction::AGET_BOOLEAN, - Instruction::AGET_BYTE, - Instruction::AGET_CHAR, - Instruction::AGET_SHORT, - Instruction::APUT, - Instruction::APUT_WIDE, - Instruction::APUT_OBJECT, - Instruction::APUT_BOOLEAN, - Instruction::APUT_BYTE, - Instruction::APUT_CHAR, - Instruction::APUT_SHORT, - Instruction::IGET, - Instruction::IGET_WIDE, - Instruction::IGET_OBJECT, - Instruction::IGET_BOOLEAN, - Instruction::IGET_BYTE, - Instruction::IGET_CHAR, - Instruction::IGET_SHORT, - Instruction::IPUT, - Instruction::IPUT_WIDE, - Instruction::IPUT_OBJECT, - Instruction::IPUT_BOOLEAN, - Instruction::IPUT_BYTE, - Instruction::IPUT_CHAR, - Instruction::IPUT_SHORT, - Instruction::SGET, - Instruction::SGET_WIDE, - Instruction::SGET_OBJECT, - Instruction::SGET_BOOLEAN, - Instruction::SGET_BYTE, - Instruction::SGET_CHAR, - Instruction::SGET_SHORT, - Instruction::SPUT, - Instruction::SPUT_WIDE, - Instruction::SPUT_OBJECT, - Instruction::SPUT_BOOLEAN, - Instruction::SPUT_BYTE, - Instruction::SPUT_CHAR, - Instruction::SPUT_SHORT, - Instruction::INVOKE_VIRTUAL, - Instruction::INVOKE_SUPER, - Instruction::INVOKE_DIRECT, - Instruction::INVOKE_STATIC, - Instruction::INVOKE_INTERFACE, - Instruction::RETURN_VOID_BARRIER, - Instruction::INVOKE_VIRTUAL_RANGE, - Instruction::INVOKE_SUPER_RANGE, - Instruction::INVOKE_DIRECT_RANGE, - Instruction::INVOKE_STATIC_RANGE, - Instruction::INVOKE_INTERFACE_RANGE, - Instruction::UNUSED_79, - Instruction::UNUSED_7A, - Instruction::NEG_INT, - Instruction::NOT_INT, - Instruction::NEG_LONG, - Instruction::NOT_LONG, - Instruction::NEG_FLOAT, - Instruction::NEG_DOUBLE, - Instruction::INT_TO_LONG, - Instruction::INT_TO_FLOAT, - Instruction::INT_TO_DOUBLE, - Instruction::LONG_TO_INT, - Instruction::LONG_TO_FLOAT, - Instruction::LONG_TO_DOUBLE, - Instruction::FLOAT_TO_INT, - Instruction::FLOAT_TO_LONG, - Instruction::FLOAT_TO_DOUBLE, - Instruction::DOUBLE_TO_INT, - Instruction::DOUBLE_TO_LONG, - Instruction::DOUBLE_TO_FLOAT, - Instruction::INT_TO_BYTE, - Instruction::INT_TO_CHAR, - Instruction::INT_TO_SHORT, - Instruction::ADD_INT, - Instruction::SUB_INT, - Instruction::MUL_INT, - Instruction::DIV_INT, - Instruction::REM_INT, - Instruction::AND_INT, - Instruction::OR_INT, - Instruction::XOR_INT, - Instruction::SHL_INT, - Instruction::SHR_INT, - Instruction::USHR_INT, - Instruction::ADD_LONG, - Instruction::SUB_LONG, - Instruction::MUL_LONG, - Instruction::DIV_LONG, - Instruction::REM_LONG, - Instruction::AND_LONG, - Instruction::OR_LONG, - Instruction::XOR_LONG, - Instruction::SHL_LONG, - Instruction::SHR_LONG, - Instruction::USHR_LONG, - Instruction::ADD_FLOAT, - Instruction::SUB_FLOAT, - Instruction::MUL_FLOAT, - Instruction::DIV_FLOAT, - Instruction::REM_FLOAT, - Instruction::ADD_DOUBLE, - Instruction::SUB_DOUBLE, - Instruction::MUL_DOUBLE, - Instruction::DIV_DOUBLE, - Instruction::REM_DOUBLE, - Instruction::ADD_INT_2ADDR, - Instruction::SUB_INT_2ADDR, - Instruction::MUL_INT_2ADDR, - Instruction::DIV_INT_2ADDR, - Instruction::REM_INT_2ADDR, - Instruction::AND_INT_2ADDR, - Instruction::OR_INT_2ADDR, - Instruction::XOR_INT_2ADDR, - Instruction::SHL_INT_2ADDR, - Instruction::SHR_INT_2ADDR, - Instruction::USHR_INT_2ADDR, - Instruction::ADD_LONG_2ADDR, - Instruction::SUB_LONG_2ADDR, - Instruction::MUL_LONG_2ADDR, - Instruction::DIV_LONG_2ADDR, - Instruction::REM_LONG_2ADDR, - Instruction::AND_LONG_2ADDR, - Instruction::OR_LONG_2ADDR, - Instruction::XOR_LONG_2ADDR, - Instruction::SHL_LONG_2ADDR, - Instruction::SHR_LONG_2ADDR, - Instruction::USHR_LONG_2ADDR, - Instruction::ADD_FLOAT_2ADDR, - Instruction::SUB_FLOAT_2ADDR, - Instruction::MUL_FLOAT_2ADDR, - Instruction::DIV_FLOAT_2ADDR, - Instruction::REM_FLOAT_2ADDR, - Instruction::ADD_DOUBLE_2ADDR, - Instruction::SUB_DOUBLE_2ADDR, - Instruction::MUL_DOUBLE_2ADDR, - Instruction::DIV_DOUBLE_2ADDR, - Instruction::REM_DOUBLE_2ADDR, - Instruction::ADD_INT_LIT16, - Instruction::RSUB_INT, - Instruction::MUL_INT_LIT16, - Instruction::DIV_INT_LIT16, - Instruction::REM_INT_LIT16, - Instruction::AND_INT_LIT16, - Instruction::OR_INT_LIT16, - Instruction::XOR_INT_LIT16, - Instruction::ADD_INT_LIT8, - Instruction::RSUB_INT_LIT8, - Instruction::MUL_INT_LIT8, - Instruction::DIV_INT_LIT8, - Instruction::REM_INT_LIT8, - Instruction::AND_INT_LIT8, - Instruction::OR_INT_LIT8, - Instruction::XOR_INT_LIT8, - Instruction::SHL_INT_LIT8, - Instruction::SHR_INT_LIT8, - Instruction::USHR_INT_LIT8, - Instruction::IGET_QUICK, - Instruction::IGET_WIDE_QUICK, - Instruction::IGET_OBJECT_QUICK, - Instruction::IPUT_QUICK, - Instruction::IPUT_WIDE_QUICK, - Instruction::IPUT_OBJECT_QUICK, - Instruction::INVOKE_VIRTUAL_QUICK, - Instruction::INVOKE_VIRTUAL_RANGE_QUICK, - Instruction::UNUSED_EB, - Instruction::UNUSED_EC, - Instruction::UNUSED_ED, - Instruction::UNUSED_EE, - Instruction::UNUSED_EF, - Instruction::UNUSED_F0, - Instruction::UNUSED_F1, - Instruction::UNUSED_F2, - Instruction::UNUSED_F3, - Instruction::UNUSED_F4, - Instruction::UNUSED_F5, - Instruction::UNUSED_F6, - Instruction::UNUSED_F7, - Instruction::UNUSED_F8, - Instruction::UNUSED_F9, - Instruction::UNUSED_FA, - Instruction::UNUSED_FB, - Instruction::UNUSED_FC, - Instruction::UNUSED_FD, - Instruction::UNUSED_FE, - Instruction::UNUSED_FF, - // ----- ExtendedMIROpcode ----- - kMirOpPhi, - kMirOpCopy, - kMirOpFusedCmplFloat, - kMirOpFusedCmpgFloat, - kMirOpFusedCmplDouble, - kMirOpFusedCmpgDouble, - kMirOpFusedCmpLong, - kMirOpNop, - kMirOpNullCheck, - kMirOpRangeCheck, - kMirOpDivZeroCheck, - kMirOpCheck, - kMirOpCheckPart2, - kMirOpSelect, -}; - -// Unsupported opcodes. nullptr can be used when everything is supported. Size of the lists is -// recorded below. -static const int* kUnsupportedOpcodes[] = { - // 0 = kNone. - kAllOpcodes, - // 1 = kArm, unused (will use kThumb2). - kAllOpcodes, - // 2 = kArm64. - nullptr, - // 3 = kThumb2. - nullptr, - // 4 = kX86. - nullptr, - // 5 = kX86_64. - nullptr, - // 6 = kMips. - nullptr, - // 7 = kMips64. - kAllOpcodes -}; -COMPILE_ASSERT(sizeof(kUnsupportedOpcodes) == 8 * sizeof(int*), kUnsupportedOpcodes_unexp); - -// Size of the arrays stored above. -static const size_t kUnsupportedOpcodesSize[] = { - // 0 = kNone. - arraysize(kAllOpcodes), - // 1 = kArm, unused (will use kThumb2). - arraysize(kAllOpcodes), - // 2 = kArm64. - 0, - // 3 = kThumb2. - 0, - // 4 = kX86. - 0, - // 5 = kX86_64. - 0, - // 6 = kMips. - 0, - // 7 = kMips64. - arraysize(kAllOpcodes), -}; -COMPILE_ASSERT(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t), - kUnsupportedOpcodesSize_unexp); - -// The maximum amount of Dalvik register in a method for which we will start compiling. Tries to -// avoid an abort when we need to manage more SSA registers than we can. -static constexpr size_t kMaxAllowedDalvikRegisters = INT16_MAX / 2; - -CompilationUnit::CompilationUnit(ArenaPool* pool) - : compiler_driver(nullptr), - class_linker(nullptr), - dex_file(nullptr), - class_loader(nullptr), - class_def_idx(0), - method_idx(0), - code_item(nullptr), - access_flags(0), - invoke_type(kDirect), - shorty(nullptr), - disable_opt(0), - enable_debug(0), - verbose(false), - compiler(nullptr), - instruction_set(kNone), - target64(false), - num_dalvik_registers(0), - insns(nullptr), - num_ins(0), - num_outs(0), - num_regs(0), - compiler_flip_match(false), - arena(pool), - arena_stack(pool), - mir_graph(nullptr), - cg(nullptr), - timings("QuickCompiler", true, false), - print_pass(false) { -} - -CompilationUnit::~CompilationUnit() { -} - -void CompilationUnit::StartTimingSplit(const char* label) { - if (compiler_driver->GetDumpPasses()) { - timings.StartTiming(label); - } -} - -void CompilationUnit::NewTimingSplit(const char* label) { - if (compiler_driver->GetDumpPasses()) { - timings.EndTiming(); - timings.StartTiming(label); - } -} - -void CompilationUnit::EndTiming() { - if (compiler_driver->GetDumpPasses()) { - timings.EndTiming(); - if (enable_debug & (1 << kDebugTimings)) { - LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file); - LOG(INFO) << Dumpable<TimingLogger>(timings); - } - } -} - -static bool CanCompileShorty(const char* shorty, InstructionSet instruction_set) { - const char* supported_types = kSupportedTypes[instruction_set]; - if (supported_types == nullptr) { - // Everything available. - return true; - } - - uint32_t shorty_size = strlen(shorty); - CHECK_GE(shorty_size, 1u); - - for (uint32_t i = 0; i < shorty_size; i++) { - if (strchr(supported_types, shorty[i]) == nullptr) { - return false; - } - } - return true; -}; - -// Skip the method that we do not support currently. -static bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, - CompilationUnit& cu) { - // This is a limitation in mir_graph. See MirGraph::SetNumSSARegs. - if (cu.num_dalvik_registers > kMaxAllowedDalvikRegisters) { - VLOG(compiler) << "Too many dalvik registers : " << cu.num_dalvik_registers; - return false; - } - - // Check whether we do have limitations at all. - if (kSupportedTypes[cu.instruction_set] == nullptr && - kUnsupportedOpcodesSize[cu.instruction_set] == 0U) { - return true; - } - - // Check if we can compile the prototype. - const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); - if (!CanCompileShorty(shorty, cu.instruction_set)) { - VLOG(compiler) << "Unsupported shorty : " << shorty; - return false; - } - - const int *unsupport_list = kUnsupportedOpcodes[cu.instruction_set]; - int unsupport_list_size = kUnsupportedOpcodesSize[cu.instruction_set]; - - for (unsigned int idx = 0; idx < cu.mir_graph->GetNumBlocks(); idx++) { - BasicBlock* bb = cu.mir_graph->GetBasicBlock(idx); - if (bb == NULL) continue; - if (bb->block_type == kDead) continue; - for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { - int opcode = mir->dalvikInsn.opcode; - // Check if we support the byte code. - if (std::find(unsupport_list, unsupport_list + unsupport_list_size, - opcode) != unsupport_list + unsupport_list_size) { - if (!MIR::DecodedInstruction::IsPseudoMirOp(opcode)) { - VLOG(compiler) << "Unsupported dalvik byte code : " - << mir->dalvikInsn.opcode; - } else { - VLOG(compiler) << "Unsupported extended MIR opcode : " - << MIRGraph::extended_mir_op_names_[opcode - kMirOpFirst]; - } - return false; - } - // Check if it invokes a prototype that we cannot support. - if (Instruction::INVOKE_VIRTUAL == opcode || - Instruction::INVOKE_SUPER == opcode || - Instruction::INVOKE_DIRECT == opcode || - Instruction::INVOKE_STATIC == opcode || - Instruction::INVOKE_INTERFACE == opcode) { - uint32_t invoke_method_idx = mir->dalvikInsn.vB; - const char* invoke_method_shorty = dex_file.GetMethodShorty( - dex_file.GetMethodId(invoke_method_idx)); - if (!CanCompileShorty(invoke_method_shorty, cu.instruction_set)) { - VLOG(compiler) << "Unsupported to invoke '" - << PrettyMethod(invoke_method_idx, dex_file) - << "' with shorty : " << invoke_method_shorty; - return false; - } - } - } - } - return true; -} - static CompiledMethod* CompileMethod(CompilerDriver& driver, - Compiler* compiler, + const Compiler* compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, @@ -687,9 +146,6 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, compiler->InitCompilationUnit(cu); - // Disable optimizations according to instruction set. - cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set]; - cu.StartTimingSplit("BuildMIRGraph"); cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena)); @@ -709,7 +165,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file); - if (!CanCompileMethod(method_idx, dex_file, cu)) { + if (!compiler->CanCompileMethod(method_idx, dex_file, &cu)) { VLOG(compiler) << cu.instruction_set << ": Cannot compile method : " << PrettyMethod(method_idx, dex_file); return nullptr; @@ -791,8 +247,8 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, return result; } -CompiledMethod* CompileOneMethod(CompilerDriver& driver, - Compiler* compiler, +CompiledMethod* CompileOneMethod(CompilerDriver* driver, + const Compiler* compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, @@ -801,22 +257,8 @@ CompiledMethod* CompileOneMethod(CompilerDriver& driver, jobject class_loader, const DexFile& dex_file, void* compilation_unit) { - return CompileMethod(driver, compiler, code_item, access_flags, invoke_type, class_def_idx, + return CompileMethod(*driver, compiler, code_item, access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file, compilation_unit); } } // namespace art - -extern "C" art::CompiledMethod* - ArtQuickCompileMethod(art::CompilerDriver& driver, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, art::InvokeType invoke_type, - uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, - const art::DexFile& dex_file) { - // TODO: check method fingerprint here to determine appropriate backend type. Until then, use - // build default. - art::Compiler* compiler = driver.GetCompiler(); - return art::CompileOneMethod(driver, compiler, code_item, access_flags, invoke_type, - class_def_idx, method_idx, class_loader, dex_file, - NULL /* use thread llvm_info */); -} diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index f4cbdfb..51b6d68 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -20,16 +20,11 @@ #include "dex_file.h" #include "invoke_type.h" -namespace llvm { - class Module; - class LLVMContext; -} - namespace art { -namespace llvm { - class IntrinsicHelper; - class IRBuilder; -} + +class CompiledMethod; +class Compiler; +class CompilerDriver; /* * Assembly is an iterative process, and usually terminates within @@ -81,48 +76,17 @@ enum debugControlVector { kDebugCodegenDump }; -class LLVMInfo { - public: - LLVMInfo(); - ~LLVMInfo(); - - ::llvm::LLVMContext* GetLLVMContext() { - return llvm_context_.get(); - } - - ::llvm::Module* GetLLVMModule() { - return llvm_module_; - } - - art::llvm::IntrinsicHelper* GetIntrinsicHelper() { - return intrinsic_helper_.get(); - } - - art::llvm::IRBuilder* GetIRBuilder() { - return ir_builder_.get(); - } - - private: - std::unique_ptr< ::llvm::LLVMContext> llvm_context_; - ::llvm::Module* llvm_module_; // Managed by context_. - std::unique_ptr<art::llvm::IntrinsicHelper> intrinsic_helper_; - std::unique_ptr<art::llvm::IRBuilder> ir_builder_; -}; - -class CompiledMethod; -class CompilerDriver; +CompiledMethod* CompileOneMethod(CompilerDriver* driver, + const Compiler* compiler, + 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, + void* compilation_unit); } // namespace art -extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, - art::InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const art::DexFile& dex_file); - - - #endif // ART_COMPILER_DEX_FRONTEND_H_ diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 574b6ea..963a586 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -29,6 +29,7 @@ #include "dex/quick/dex_file_method_inliner.h" #include "leb128.h" #include "pass_driver_me_post_opt.h" +#include "stack.h" #include "utils/scoped_arena_containers.h" namespace art { diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 3de4e3d..3d713d4 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -19,9 +19,10 @@ #include <stdint.h> +#include "compiler_ir.h" #include "dex_file.h" #include "dex_instruction.h" -#include "compiler_ir.h" +#include "driver/dex_compilation_unit.h" #include "invoke_type.h" #include "mir_field_info.h" #include "mir_method_info.h" diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index d37e9b6..870edbd 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -22,6 +22,7 @@ #include "dex/global_value_numbering.h" #include "dex/quick/dex_file_method_inliner.h" #include "dex/quick/dex_file_to_method_inliner_map.h" +#include "stack.h" #include "utils/scoped_arena_containers.h" namespace art { diff --git a/compiler/dex/portable/mir_to_gbc.h b/compiler/dex/portable/mir_to_gbc.h index e97634c..4459eb6 100644 --- a/compiler/dex/portable/mir_to_gbc.h +++ b/compiler/dex/portable/mir_to_gbc.h @@ -32,8 +32,46 @@ #include "llvm/llvm_compilation_unit.h" #include "safe_map.h" +namespace llvm { + class Module; + class LLVMContext; +} + namespace art { +namespace llvm { + class IntrinsicHelper; + class IRBuilder; +} + +class LLVMInfo { + public: + LLVMInfo(); + ~LLVMInfo(); + + ::llvm::LLVMContext* GetLLVMContext() { + return llvm_context_.get(); + } + + ::llvm::Module* GetLLVMModule() { + return llvm_module_; + } + + art::llvm::IntrinsicHelper* GetIntrinsicHelper() { + return intrinsic_helper_.get(); + } + + art::llvm::IRBuilder* GetIRBuilder() { + return ir_builder_.get(); + } + + private: + std::unique_ptr< ::llvm::LLVMContext> llvm_context_; + ::llvm::Module* llvm_module_; // Managed by context_. + std::unique_ptr<art::llvm::IntrinsicHelper> intrinsic_helper_; + std::unique_ptr<art::llvm::IRBuilder> ir_builder_; +}; + struct BasicBlock; struct CallInfo; struct CompilationUnit; diff --git a/compiler/dex/post_opt_passes.h b/compiler/dex/post_opt_passes.h index a1b0df4..550d254 100644 --- a/compiler/dex/post_opt_passes.h +++ b/compiler/dex/post_opt_passes.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DEX_POST_OPT_PASSES_H_ #define ART_COMPILER_DEX_POST_OPT_PASSES_H_ +#include "dex/quick/mir_to_lir.h" #include "compiler_internals.h" #include "pass_me.h" diff --git a/compiler/dex/quick/arm/backend_arm.h b/compiler/dex/quick/arm/backend_arm.h new file mode 100644 index 0000000..42a9bca --- /dev/null +++ b/compiler/dex/quick/arm/backend_arm.h @@ -0,0 +1,32 @@ +/* + * 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_DEX_QUICK_ARM_BACKEND_ARM_H_ +#define ART_COMPILER_DEX_QUICK_ARM_BACKEND_ARM_H_ + +namespace art { + +struct CompilationUnit; +class Mir2Lir; +class MIRGraph; +class ArenaAllocator; + +Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, + ArenaAllocator* const arena); + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_ARM_BACKEND_ARM_H_ diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h index cd6c9cc..66a98ba 100644 --- a/compiler/dex/quick/arm/codegen_arm.h +++ b/compiler/dex/quick/arm/codegen_arm.h @@ -19,6 +19,7 @@ #include "arm_lir.h" #include "dex/compiler_internals.h" +#include "dex/quick/mir_to_lir.h" namespace art { diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 0509ad3..0be478d 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -20,6 +20,7 @@ #include <string> +#include "backend_arm.h" #include "dex/compiler_internals.h" #include "dex/quick/mir_to_lir-inl.h" diff --git a/compiler/dex/quick/arm64/backend_arm64.h b/compiler/dex/quick/arm64/backend_arm64.h new file mode 100644 index 0000000..53650c4 --- /dev/null +++ b/compiler/dex/quick/arm64/backend_arm64.h @@ -0,0 +1,32 @@ +/* + * 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_DEX_QUICK_ARM64_BACKEND_ARM64_H_ +#define ART_COMPILER_DEX_QUICK_ARM64_BACKEND_ARM64_H_ + +namespace art { + +struct CompilationUnit; +class Mir2Lir; +class MIRGraph; +class ArenaAllocator; + +Mir2Lir* Arm64CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, + ArenaAllocator* const arena); + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_ARM64_BACKEND_ARM64_H_ diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h index be10dd7..cc3f90a 100644 --- a/compiler/dex/quick/arm64/codegen_arm64.h +++ b/compiler/dex/quick/arm64/codegen_arm64.h @@ -19,6 +19,7 @@ #include "arm64_lir.h" #include "dex/compiler_internals.h" +#include "dex/quick/mir_to_lir.h" #include <map> diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc index 685f8d5..bb21c7f 100644 --- a/compiler/dex/quick/arm64/target_arm64.cc +++ b/compiler/dex/quick/arm64/target_arm64.cc @@ -20,6 +20,7 @@ #include <string> +#include "backend_arm64.h" #include "dex/compiler_internals.h" #include "dex/quick/mir_to_lir-inl.h" #include "dex/reg_storage_eq.h" diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 5e0ba15..ffcce7d 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -25,8 +25,10 @@ #include "thread.h" #include "thread-inl.h" #include "dex/mir_graph.h" +#include "dex/quick/mir_to_lir.h" #include "dex_instruction.h" #include "dex_instruction-inl.h" +#include "driver/dex_compilation_unit.h" #include "verifier/method_verifier.h" #include "verifier/method_verifier-inl.h" diff --git a/compiler/dex/quick/mips/backend_mips.h b/compiler/dex/quick/mips/backend_mips.h new file mode 100644 index 0000000..f65e984 --- /dev/null +++ b/compiler/dex/quick/mips/backend_mips.h @@ -0,0 +1,32 @@ +/* + * 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_DEX_QUICK_MIPS_BACKEND_MIPS_H_ +#define ART_COMPILER_DEX_QUICK_MIPS_BACKEND_MIPS_H_ + +namespace art { + +struct CompilationUnit; +class Mir2Lir; +class MIRGraph; +class ArenaAllocator; + +Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, + ArenaAllocator* const arena); + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_MIPS_BACKEND_MIPS_H_ diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 43cbde7..9f1af69 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -18,6 +18,7 @@ #define ART_COMPILER_DEX_QUICK_MIPS_CODEGEN_MIPS_H_ #include "dex/compiler_internals.h" +#include "dex/quick/mir_to_lir.h" #include "mips_lir.h" namespace art { diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index bc91fbc..9c4426f 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -20,6 +20,7 @@ #include <string> +#include "backend_mips.h" #include "dex/compiler_internals.h" #include "dex/quick/mir_to_lir-inl.h" #include "mips_lir.h" diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 8e73728..64ef48d 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -38,14 +38,6 @@ namespace art { -/* - * TODO: refactoring pass to move these (and other) typdefs towards usage style of runtime to - * add type safety (see runtime/offsets.h). - */ -typedef uint32_t DexOffset; // Dex offset in code units. -typedef uint16_t NarrowDexOffset; // For use in structs, Dex offsets range from 0 .. 0xffff. -typedef uint32_t CodeOffset; // Native code offset in bytes. - // Set to 1 to measure cost of suspend check. #define NO_SUSPEND 0 @@ -187,16 +179,6 @@ struct LIR { int32_t operands[5]; // [0..4] = [dest, src1, src2, extra, extra2]. }; -// Target-specific initialization. -Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, - ArenaAllocator* const arena); -Mir2Lir* Arm64CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, - ArenaAllocator* const arena); -Mir2Lir* MipsCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, - ArenaAllocator* const arena); -Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, - ArenaAllocator* const arena); - // Utility macros to traverse the LIR list. #define NEXT_LIR(lir) (lir->next) #define PREV_LIR(lir) (lir->prev) diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc new file mode 100644 index 0000000..4fea1f0 --- /dev/null +++ b/compiler/dex/quick/quick_compiler.cc @@ -0,0 +1,650 @@ +/* + * 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. + */ + +#include "quick_compiler.h" + +#include <cstdint> + +#include "compiler.h" +#include "dex/frontend.h" +#include "dex/mir_graph.h" +#include "dex/quick/mir_to_lir.h" +#include "driver/compiler_driver.h" +#include "elf_writer_quick.h" +#include "jni/quick/jni_compiler.h" +#include "mirror/art_method-inl.h" +#include "base/logging.h" + +// Specific compiler backends. +#include "dex/quick/arm/backend_arm.h" +#include "dex/quick/arm64/backend_arm64.h" +#include "dex/quick/mips/backend_mips.h" +#include "dex/quick/x86/backend_x86.h" + +namespace art { + +class QuickCompiler : public Compiler { + public: + explicit QuickCompiler(CompilerDriver* driver) : Compiler(driver, 100) {} + + void Init() const OVERRIDE; + + void UnInit() const OVERRIDE; + + bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const + OVERRIDE; + + CompiledMethod* Compile(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) const OVERRIDE; + + CompiledMethod* JniCompile(uint32_t access_flags, + uint32_t method_idx, + const DexFile& dex_file) const OVERRIDE; + + uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + bool WriteElf(art::File* file, + OatWriter* oat_writer, + const std::vector<const art::DexFile*>& dex_files, + const std::string& android_root, + bool is_host) const + OVERRIDE + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE; + + void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(QuickCompiler); +}; + +COMPILE_ASSERT(0U == static_cast<size_t>(kNone), kNone_not_0); +COMPILE_ASSERT(1U == static_cast<size_t>(kArm), kArm_not_1); +COMPILE_ASSERT(2U == static_cast<size_t>(kArm64), kArm64_not_2); +COMPILE_ASSERT(3U == static_cast<size_t>(kThumb2), kThumb2_not_3); +COMPILE_ASSERT(4U == static_cast<size_t>(kX86), kX86_not_4); +COMPILE_ASSERT(5U == static_cast<size_t>(kX86_64), kX86_64_not_5); +COMPILE_ASSERT(6U == static_cast<size_t>(kMips), kMips_not_6); +COMPILE_ASSERT(7U == static_cast<size_t>(kMips64), kMips64_not_7); + +// Additional disabled optimizations (over generally disabled) per instruction set. +static constexpr uint32_t kDisabledOptimizationsPerISA[] = { + // 0 = kNone. + ~0U, + // 1 = kArm, unused (will use kThumb2). + ~0U, + // 2 = kArm64. + 0, + // 3 = kThumb2. + 0, + // 4 = kX86. + (1 << kLoadStoreElimination) | + 0, + // 5 = kX86_64. + (1 << kLoadStoreElimination) | + 0, + // 6 = kMips. + (1 << kLoadStoreElimination) | + (1 << kLoadHoisting) | + (1 << kSuppressLoads) | + (1 << kNullCheckElimination) | + (1 << kPromoteRegs) | + (1 << kTrackLiveTemps) | + (1 << kSafeOptimizations) | + (1 << kBBOpt) | + (1 << kMatch) | + (1 << kPromoteCompilerTemps) | + 0, + // 7 = kMips64. + ~0U +}; +COMPILE_ASSERT(sizeof(kDisabledOptimizationsPerISA) == 8 * sizeof(uint32_t), kDisabledOpts_unexp); + +// Supported shorty types per instruction set. nullptr means that all are available. +// Z : boolean +// B : byte +// S : short +// C : char +// I : int +// J : long +// F : float +// D : double +// L : reference(object, array) +// V : void +static const char* kSupportedTypes[] = { + // 0 = kNone. + "", + // 1 = kArm, unused (will use kThumb2). + "", + // 2 = kArm64. + nullptr, + // 3 = kThumb2. + nullptr, + // 4 = kX86. + nullptr, + // 5 = kX86_64. + nullptr, + // 6 = kMips. + nullptr, + // 7 = kMips64. + "" +}; +COMPILE_ASSERT(sizeof(kSupportedTypes) == 8 * sizeof(char*), kSupportedTypes_unexp); + +static int kAllOpcodes[] = { + Instruction::NOP, + Instruction::MOVE, + Instruction::MOVE_FROM16, + Instruction::MOVE_16, + Instruction::MOVE_WIDE, + Instruction::MOVE_WIDE_FROM16, + Instruction::MOVE_WIDE_16, + Instruction::MOVE_OBJECT, + Instruction::MOVE_OBJECT_FROM16, + Instruction::MOVE_OBJECT_16, + Instruction::MOVE_RESULT, + Instruction::MOVE_RESULT_WIDE, + Instruction::MOVE_RESULT_OBJECT, + Instruction::MOVE_EXCEPTION, + Instruction::RETURN_VOID, + Instruction::RETURN, + Instruction::RETURN_WIDE, + Instruction::RETURN_OBJECT, + Instruction::CONST_4, + Instruction::CONST_16, + Instruction::CONST, + Instruction::CONST_HIGH16, + Instruction::CONST_WIDE_16, + Instruction::CONST_WIDE_32, + Instruction::CONST_WIDE, + Instruction::CONST_WIDE_HIGH16, + Instruction::CONST_STRING, + Instruction::CONST_STRING_JUMBO, + Instruction::CONST_CLASS, + Instruction::MONITOR_ENTER, + Instruction::MONITOR_EXIT, + Instruction::CHECK_CAST, + Instruction::INSTANCE_OF, + Instruction::ARRAY_LENGTH, + Instruction::NEW_INSTANCE, + Instruction::NEW_ARRAY, + Instruction::FILLED_NEW_ARRAY, + Instruction::FILLED_NEW_ARRAY_RANGE, + Instruction::FILL_ARRAY_DATA, + Instruction::THROW, + Instruction::GOTO, + Instruction::GOTO_16, + Instruction::GOTO_32, + Instruction::PACKED_SWITCH, + Instruction::SPARSE_SWITCH, + Instruction::CMPL_FLOAT, + Instruction::CMPG_FLOAT, + Instruction::CMPL_DOUBLE, + Instruction::CMPG_DOUBLE, + Instruction::CMP_LONG, + Instruction::IF_EQ, + Instruction::IF_NE, + Instruction::IF_LT, + Instruction::IF_GE, + Instruction::IF_GT, + Instruction::IF_LE, + Instruction::IF_EQZ, + Instruction::IF_NEZ, + Instruction::IF_LTZ, + Instruction::IF_GEZ, + Instruction::IF_GTZ, + Instruction::IF_LEZ, + Instruction::UNUSED_3E, + Instruction::UNUSED_3F, + Instruction::UNUSED_40, + Instruction::UNUSED_41, + Instruction::UNUSED_42, + Instruction::UNUSED_43, + Instruction::AGET, + Instruction::AGET_WIDE, + Instruction::AGET_OBJECT, + Instruction::AGET_BOOLEAN, + Instruction::AGET_BYTE, + Instruction::AGET_CHAR, + Instruction::AGET_SHORT, + Instruction::APUT, + Instruction::APUT_WIDE, + Instruction::APUT_OBJECT, + Instruction::APUT_BOOLEAN, + Instruction::APUT_BYTE, + Instruction::APUT_CHAR, + Instruction::APUT_SHORT, + Instruction::IGET, + Instruction::IGET_WIDE, + Instruction::IGET_OBJECT, + Instruction::IGET_BOOLEAN, + Instruction::IGET_BYTE, + Instruction::IGET_CHAR, + Instruction::IGET_SHORT, + Instruction::IPUT, + Instruction::IPUT_WIDE, + Instruction::IPUT_OBJECT, + Instruction::IPUT_BOOLEAN, + Instruction::IPUT_BYTE, + Instruction::IPUT_CHAR, + Instruction::IPUT_SHORT, + Instruction::SGET, + Instruction::SGET_WIDE, + Instruction::SGET_OBJECT, + Instruction::SGET_BOOLEAN, + Instruction::SGET_BYTE, + Instruction::SGET_CHAR, + Instruction::SGET_SHORT, + Instruction::SPUT, + Instruction::SPUT_WIDE, + Instruction::SPUT_OBJECT, + Instruction::SPUT_BOOLEAN, + Instruction::SPUT_BYTE, + Instruction::SPUT_CHAR, + Instruction::SPUT_SHORT, + Instruction::INVOKE_VIRTUAL, + Instruction::INVOKE_SUPER, + Instruction::INVOKE_DIRECT, + Instruction::INVOKE_STATIC, + Instruction::INVOKE_INTERFACE, + Instruction::RETURN_VOID_BARRIER, + Instruction::INVOKE_VIRTUAL_RANGE, + Instruction::INVOKE_SUPER_RANGE, + Instruction::INVOKE_DIRECT_RANGE, + Instruction::INVOKE_STATIC_RANGE, + Instruction::INVOKE_INTERFACE_RANGE, + Instruction::UNUSED_79, + Instruction::UNUSED_7A, + Instruction::NEG_INT, + Instruction::NOT_INT, + Instruction::NEG_LONG, + Instruction::NOT_LONG, + Instruction::NEG_FLOAT, + Instruction::NEG_DOUBLE, + Instruction::INT_TO_LONG, + Instruction::INT_TO_FLOAT, + Instruction::INT_TO_DOUBLE, + Instruction::LONG_TO_INT, + Instruction::LONG_TO_FLOAT, + Instruction::LONG_TO_DOUBLE, + Instruction::FLOAT_TO_INT, + Instruction::FLOAT_TO_LONG, + Instruction::FLOAT_TO_DOUBLE, + Instruction::DOUBLE_TO_INT, + Instruction::DOUBLE_TO_LONG, + Instruction::DOUBLE_TO_FLOAT, + Instruction::INT_TO_BYTE, + Instruction::INT_TO_CHAR, + Instruction::INT_TO_SHORT, + Instruction::ADD_INT, + Instruction::SUB_INT, + Instruction::MUL_INT, + Instruction::DIV_INT, + Instruction::REM_INT, + Instruction::AND_INT, + Instruction::OR_INT, + Instruction::XOR_INT, + Instruction::SHL_INT, + Instruction::SHR_INT, + Instruction::USHR_INT, + Instruction::ADD_LONG, + Instruction::SUB_LONG, + Instruction::MUL_LONG, + Instruction::DIV_LONG, + Instruction::REM_LONG, + Instruction::AND_LONG, + Instruction::OR_LONG, + Instruction::XOR_LONG, + Instruction::SHL_LONG, + Instruction::SHR_LONG, + Instruction::USHR_LONG, + Instruction::ADD_FLOAT, + Instruction::SUB_FLOAT, + Instruction::MUL_FLOAT, + Instruction::DIV_FLOAT, + Instruction::REM_FLOAT, + Instruction::ADD_DOUBLE, + Instruction::SUB_DOUBLE, + Instruction::MUL_DOUBLE, + Instruction::DIV_DOUBLE, + Instruction::REM_DOUBLE, + Instruction::ADD_INT_2ADDR, + Instruction::SUB_INT_2ADDR, + Instruction::MUL_INT_2ADDR, + Instruction::DIV_INT_2ADDR, + Instruction::REM_INT_2ADDR, + Instruction::AND_INT_2ADDR, + Instruction::OR_INT_2ADDR, + Instruction::XOR_INT_2ADDR, + Instruction::SHL_INT_2ADDR, + Instruction::SHR_INT_2ADDR, + Instruction::USHR_INT_2ADDR, + Instruction::ADD_LONG_2ADDR, + Instruction::SUB_LONG_2ADDR, + Instruction::MUL_LONG_2ADDR, + Instruction::DIV_LONG_2ADDR, + Instruction::REM_LONG_2ADDR, + Instruction::AND_LONG_2ADDR, + Instruction::OR_LONG_2ADDR, + Instruction::XOR_LONG_2ADDR, + Instruction::SHL_LONG_2ADDR, + Instruction::SHR_LONG_2ADDR, + Instruction::USHR_LONG_2ADDR, + Instruction::ADD_FLOAT_2ADDR, + Instruction::SUB_FLOAT_2ADDR, + Instruction::MUL_FLOAT_2ADDR, + Instruction::DIV_FLOAT_2ADDR, + Instruction::REM_FLOAT_2ADDR, + Instruction::ADD_DOUBLE_2ADDR, + Instruction::SUB_DOUBLE_2ADDR, + Instruction::MUL_DOUBLE_2ADDR, + Instruction::DIV_DOUBLE_2ADDR, + Instruction::REM_DOUBLE_2ADDR, + Instruction::ADD_INT_LIT16, + Instruction::RSUB_INT, + Instruction::MUL_INT_LIT16, + Instruction::DIV_INT_LIT16, + Instruction::REM_INT_LIT16, + Instruction::AND_INT_LIT16, + Instruction::OR_INT_LIT16, + Instruction::XOR_INT_LIT16, + Instruction::ADD_INT_LIT8, + Instruction::RSUB_INT_LIT8, + Instruction::MUL_INT_LIT8, + Instruction::DIV_INT_LIT8, + Instruction::REM_INT_LIT8, + Instruction::AND_INT_LIT8, + Instruction::OR_INT_LIT8, + Instruction::XOR_INT_LIT8, + Instruction::SHL_INT_LIT8, + Instruction::SHR_INT_LIT8, + Instruction::USHR_INT_LIT8, + Instruction::IGET_QUICK, + Instruction::IGET_WIDE_QUICK, + Instruction::IGET_OBJECT_QUICK, + Instruction::IPUT_QUICK, + Instruction::IPUT_WIDE_QUICK, + Instruction::IPUT_OBJECT_QUICK, + Instruction::INVOKE_VIRTUAL_QUICK, + Instruction::INVOKE_VIRTUAL_RANGE_QUICK, + Instruction::UNUSED_EB, + Instruction::UNUSED_EC, + Instruction::UNUSED_ED, + Instruction::UNUSED_EE, + Instruction::UNUSED_EF, + Instruction::UNUSED_F0, + Instruction::UNUSED_F1, + Instruction::UNUSED_F2, + Instruction::UNUSED_F3, + Instruction::UNUSED_F4, + Instruction::UNUSED_F5, + Instruction::UNUSED_F6, + Instruction::UNUSED_F7, + Instruction::UNUSED_F8, + Instruction::UNUSED_F9, + Instruction::UNUSED_FA, + Instruction::UNUSED_FB, + Instruction::UNUSED_FC, + Instruction::UNUSED_FD, + Instruction::UNUSED_FE, + Instruction::UNUSED_FF, + // ----- ExtendedMIROpcode ----- + kMirOpPhi, + kMirOpCopy, + kMirOpFusedCmplFloat, + kMirOpFusedCmpgFloat, + kMirOpFusedCmplDouble, + kMirOpFusedCmpgDouble, + kMirOpFusedCmpLong, + kMirOpNop, + kMirOpNullCheck, + kMirOpRangeCheck, + kMirOpDivZeroCheck, + kMirOpCheck, + kMirOpCheckPart2, + kMirOpSelect, +}; + +// Unsupported opcodes. nullptr can be used when everything is supported. Size of the lists is +// recorded below. +static const int* kUnsupportedOpcodes[] = { + // 0 = kNone. + kAllOpcodes, + // 1 = kArm, unused (will use kThumb2). + kAllOpcodes, + // 2 = kArm64. + nullptr, + // 3 = kThumb2. + nullptr, + // 4 = kX86. + nullptr, + // 5 = kX86_64. + nullptr, + // 6 = kMips. + nullptr, + // 7 = kMips64. + kAllOpcodes +}; +COMPILE_ASSERT(sizeof(kUnsupportedOpcodes) == 8 * sizeof(int*), kUnsupportedOpcodes_unexp); + +// Size of the arrays stored above. +static const size_t kUnsupportedOpcodesSize[] = { + // 0 = kNone. + arraysize(kAllOpcodes), + // 1 = kArm, unused (will use kThumb2). + arraysize(kAllOpcodes), + // 2 = kArm64. + 0, + // 3 = kThumb2. + 0, + // 4 = kX86. + 0, + // 5 = kX86_64. + 0, + // 6 = kMips. + 0, + // 7 = kMips64. + arraysize(kAllOpcodes), +}; +COMPILE_ASSERT(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t), + kUnsupportedOpcodesSize_unexp); + +// The maximum amount of Dalvik register in a method for which we will start compiling. Tries to +// avoid an abort when we need to manage more SSA registers than we can. +static constexpr size_t kMaxAllowedDalvikRegisters = INT16_MAX / 2; + +static bool CanCompileShorty(const char* shorty, InstructionSet instruction_set) { + const char* supported_types = kSupportedTypes[instruction_set]; + if (supported_types == nullptr) { + // Everything available. + return true; + } + + uint32_t shorty_size = strlen(shorty); + CHECK_GE(shorty_size, 1u); + + for (uint32_t i = 0; i < shorty_size; i++) { + if (strchr(supported_types, shorty[i]) == nullptr) { + return false; + } + } + return true; +}; + +// Skip the method that we do not support currently. +bool QuickCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, + CompilationUnit* cu) const { + // This is a limitation in mir_graph. See MirGraph::SetNumSSARegs. + if (cu->num_dalvik_registers > kMaxAllowedDalvikRegisters) { + VLOG(compiler) << "Too many dalvik registers : " << cu->num_dalvik_registers; + return false; + } + + // Check whether we do have limitations at all. + if (kSupportedTypes[cu->instruction_set] == nullptr && + kUnsupportedOpcodesSize[cu->instruction_set] == 0U) { + return true; + } + + // Check if we can compile the prototype. + const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); + if (!CanCompileShorty(shorty, cu->instruction_set)) { + VLOG(compiler) << "Unsupported shorty : " << shorty; + return false; + } + + const int *unsupport_list = kUnsupportedOpcodes[cu->instruction_set]; + int unsupport_list_size = kUnsupportedOpcodesSize[cu->instruction_set]; + + for (unsigned int idx = 0; idx < cu->mir_graph->GetNumBlocks(); idx++) { + BasicBlock* bb = cu->mir_graph->GetBasicBlock(idx); + if (bb == NULL) continue; + if (bb->block_type == kDead) continue; + for (MIR* mir = bb->first_mir_insn; mir != nullptr; mir = mir->next) { + int opcode = mir->dalvikInsn.opcode; + // Check if we support the byte code. + if (std::find(unsupport_list, unsupport_list + unsupport_list_size, + opcode) != unsupport_list + unsupport_list_size) { + if (!MIR::DecodedInstruction::IsPseudoMirOp(opcode)) { + VLOG(compiler) << "Unsupported dalvik byte code : " + << mir->dalvikInsn.opcode; + } else { + VLOG(compiler) << "Unsupported extended MIR opcode : " + << MIRGraph::extended_mir_op_names_[opcode - kMirOpFirst]; + } + return false; + } + // Check if it invokes a prototype that we cannot support. + if (Instruction::INVOKE_VIRTUAL == opcode || + Instruction::INVOKE_SUPER == opcode || + Instruction::INVOKE_DIRECT == opcode || + Instruction::INVOKE_STATIC == opcode || + Instruction::INVOKE_INTERFACE == opcode) { + uint32_t invoke_method_idx = mir->dalvikInsn.vB; + const char* invoke_method_shorty = dex_file.GetMethodShorty( + dex_file.GetMethodId(invoke_method_idx)); + if (!CanCompileShorty(invoke_method_shorty, cu->instruction_set)) { + VLOG(compiler) << "Unsupported to invoke '" + << PrettyMethod(invoke_method_idx, dex_file) + << "' with shorty : " << invoke_method_shorty; + return false; + } + } + } + } + return true; +} + +void QuickCompiler::InitCompilationUnit(CompilationUnit& cu) const { + // Disable optimizations according to instruction set. + cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set]; +} + +void QuickCompiler::Init() const { + CHECK(GetCompilerDriver()->GetCompilerContext() == nullptr); +} + +void QuickCompiler::UnInit() const { + CHECK(GetCompilerDriver()->GetCompilerContext() == nullptr); +} + +CompiledMethod* QuickCompiler::Compile(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) const { + CompiledMethod* method = TryCompileWithSeaIR(code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + class_loader, + dex_file); + if (method != nullptr) { + return method; + } + + // TODO: check method fingerprint here to determine appropriate backend type. Until then, use + // build default. + CompilerDriver* driver = GetCompilerDriver(); + return CompileOneMethod(driver, this, code_item, access_flags, invoke_type, class_def_idx, + method_idx, class_loader, dex_file, nullptr /* use thread llvm_info */); +} + +CompiledMethod* QuickCompiler::JniCompile(uint32_t access_flags, + uint32_t method_idx, + const DexFile& dex_file) const { + return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); +} + +uintptr_t QuickCompiler::GetEntryPointOf(mirror::ArtMethod* method) const { + return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()); +} + +bool QuickCompiler::WriteElf(art::File* file, + OatWriter* oat_writer, + const std::vector<const art::DexFile*>& dex_files, + const std::string& android_root, + bool is_host) const { + return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, + *GetCompilerDriver()); +} + +Backend* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { + Mir2Lir* mir_to_lir = nullptr; + switch (cu->instruction_set) { + case kThumb2: + mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena); + break; + case kArm64: + mir_to_lir = Arm64CodeGenerator(cu, cu->mir_graph.get(), &cu->arena); + break; + case kMips: + mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena); + break; + case kX86: + // Fall-through. + case kX86_64: + mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena); + break; + default: + LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set; + } + + /* The number of compiler temporaries depends on backend so set it up now if possible */ + if (mir_to_lir) { + size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps(); + bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps); + CHECK(set_max); + } + return mir_to_lir; +} + + +Compiler* CreateQuickCompiler(CompilerDriver* driver) { + return new QuickCompiler(driver); +} + +} // namespace art diff --git a/compiler/dex/quick/quick_compiler.h b/compiler/dex/quick/quick_compiler.h new file mode 100644 index 0000000..10de5fb --- /dev/null +++ b/compiler/dex/quick/quick_compiler.h @@ -0,0 +1,29 @@ +/* + * 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_DEX_QUICK_QUICK_COMPILER_H_ +#define ART_COMPILER_DEX_QUICK_QUICK_COMPILER_H_ + +namespace art { + +class Compiler; +class CompilerDriver; + +Compiler* CreateQuickCompiler(CompilerDriver* driver); + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_QUICK_COMPILER_H_ diff --git a/compiler/dex/quick/x86/backend_x86.h b/compiler/dex/quick/x86/backend_x86.h new file mode 100644 index 0000000..f73db94 --- /dev/null +++ b/compiler/dex/quick/x86/backend_x86.h @@ -0,0 +1,32 @@ +/* + * 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_DEX_QUICK_X86_BACKEND_X86_H_ +#define ART_COMPILER_DEX_QUICK_X86_BACKEND_X86_H_ + +namespace art { + +struct CompilationUnit; +class Mir2Lir; +class MIRGraph; +class ArenaAllocator; + +Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, + ArenaAllocator* const arena); + +} // namespace art + +#endif // ART_COMPILER_DEX_QUICK_X86_BACKEND_X86_H_ diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 7d1e20e..9c50121 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -18,6 +18,7 @@ #define ART_COMPILER_DEX_QUICK_X86_CODEGEN_X86_H_ #include "dex/compiler_internals.h" +#include "dex/quick/mir_to_lir.h" #include "x86_lir.h" #include <map> diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 8c6aa5f..604f4bf 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -17,6 +17,7 @@ #include <string> #include <inttypes.h> +#include "backend_x86.h" #include "codegen_x86.h" #include "dex/compiler_internals.h" #include "dex/quick/mir_to_lir-inl.h" diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc index 4a3e071..f13165e 100644 --- a/compiler/dex/vreg_analysis.cc +++ b/compiler/dex/vreg_analysis.cc @@ -404,30 +404,15 @@ bool MIRGraph::InferTypeAndSize(BasicBlock* bb, MIR* mir, bool changed) { static const char* storage_name[] = {" Frame ", "PhysReg", " Spill "}; void MIRGraph::DumpRegLocTable(RegLocation* table, int count) { - // FIXME: Quick-specific. Move to Quick (and make a generic version for MIRGraph? - Mir2Lir* cg = static_cast<Mir2Lir*>(cu_->cg.get()); - if (cg != NULL) { - for (int i = 0; i < count; i++) { - LOG(INFO) << StringPrintf("Loc[%02d] : %s, %c %c %c %c %c %c 0x%04x S%d", - table[i].orig_sreg, storage_name[table[i].location], - table[i].wide ? 'W' : 'N', table[i].defined ? 'D' : 'U', - table[i].fp ? 'F' : table[i].ref ? 'R' :'C', - table[i].is_const ? 'c' : 'n', - table[i].high_word ? 'H' : 'L', table[i].home ? 'h' : 't', - table[i].reg.GetRawBits(), - table[i].s_reg_low); - } - } else { - // Either pre-regalloc or Portable. - for (int i = 0; i < count; i++) { - LOG(INFO) << StringPrintf("Loc[%02d] : %s, %c %c %c %c %c %c S%d", - table[i].orig_sreg, storage_name[table[i].location], - table[i].wide ? 'W' : 'N', table[i].defined ? 'D' : 'U', - table[i].fp ? 'F' : table[i].ref ? 'R' :'C', - table[i].is_const ? 'c' : 'n', - table[i].high_word ? 'H' : 'L', table[i].home ? 'h' : 't', - table[i].s_reg_low); - } + for (int i = 0; i < count; i++) { + LOG(INFO) << StringPrintf("Loc[%02d] : %s, %c %c %c %c %c %c 0x%04x S%d", + table[i].orig_sreg, storage_name[table[i].location], + table[i].wide ? 'W' : 'N', table[i].defined ? 'D' : 'U', + table[i].fp ? 'F' : table[i].ref ? 'R' :'C', + table[i].is_const ? 'c' : 'n', + table[i].high_word ? 'H' : 'L', table[i].home ? 'h' : 't', + table[i].reg.GetRawBits(), + table[i].s_reg_low); } } diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 022ec6b..4d5d253 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -20,6 +20,7 @@ #include "compiler_driver.h" #include "dex/compiler_ir.h" +#include "dex_compilation_unit.h" #include "field_helper.h" #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 3915381..3b0c8af 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -444,7 +444,7 @@ CompilerTls* CompilerDriver::GetTls() { // Lazily create thread-local storage CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_)); if (res == NULL) { - res = new CompilerTls(); + res = compiler_->CreateNewCompilerTls(); CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls"); } return res; diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index d8f318b..87523bf 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -76,20 +76,6 @@ enum DexToDexCompilationLevel { kOptimize // Perform required transformation and peep-hole optimizations. }; -// Thread-local storage compiler worker threads -class CompilerTls { - public: - CompilerTls() : llvm_info_(NULL) {} - ~CompilerTls() {} - - void* GetLLVMInfo() { return llvm_info_; } - - void SetLLVMInfo(void* llvm_info) { llvm_info_ = llvm_info; } - - private: - void* llvm_info_; -}; - class CompilerDriver { public: // Create a compiler targeting the requested "instruction_set". diff --git a/compiler/elf_patcher.cc b/compiler/elf_patcher.cc index 9ae755d..72bf7d3 100644 --- a/compiler/elf_patcher.cc +++ b/compiler/elf_patcher.cc @@ -19,6 +19,7 @@ #include <vector> #include <set> +#include "class_linker.h" #include "elf_file.h" #include "elf_utils.h" #include "mirror/art_field-inl.h" diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 3d119bb..f2a16e5 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -21,6 +21,7 @@ #include <vector> #include "base/unix_file/fd_file.h" +#include "class_linker.h" #include "common_compiler_test.h" #include "elf_fixup.h" #include "gc/space/image_space.h" diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 8e87021..78a228b 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "jni_compiler.h" + #include <algorithm> #include <memory> #include <vector> @@ -546,10 +548,9 @@ static void SetNativeParameter(Assembler* jni_asm, } } -} // namespace art - -extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver* compiler, - uint32_t access_flags, uint32_t method_idx, - const art::DexFile& dex_file) { +CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags, + uint32_t method_idx, const DexFile& dex_file) { return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, dex_file); } + +} // namespace art diff --git a/compiler/jni/quick/jni_compiler.h b/compiler/jni/quick/jni_compiler.h new file mode 100644 index 0000000..46277f1 --- /dev/null +++ b/compiler/jni/quick/jni_compiler.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_COMPILER_JNI_QUICK_JNI_COMPILER_H_ +#define ART_COMPILER_JNI_QUICK_JNI_COMPILER_H_ + +#include "dex_file.h" + +namespace art { + +class CompilerDriver; +class CompiledMethod; + +CompiledMethod* ArtQuickJniCompileMethod(CompilerDriver* compiler, uint32_t access_flags, + uint32_t method_idx, const DexFile& dex_file); + +} // namespace art + +#endif // ART_COMPILER_JNI_QUICK_JNI_COMPILER_H_ diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 5990e8c..3aeecad 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -141,7 +141,7 @@ CompileDexMethod(DexCompilationUnit* dex_compilation_unit, InvokeType invoke_typ cunit->SetDexCompilationUnit(dex_compilation_unit); cunit->SetCompilerDriver(compiler_driver_); // TODO: consolidate ArtCompileMethods - CompileOneMethod(*compiler_driver_, + CompileOneMethod(compiler_driver_, compiler_driver_->GetCompiler(), dex_compilation_unit->GetCodeItem(), dex_compilation_unit->GetAccessFlags(), @@ -172,68 +172,62 @@ CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) { } -} // namespace llvm -} // namespace art - -static art::llvm::CompilerLLVM* ContextOf(art::CompilerDriver* driver) { +static CompilerLLVM* ContextOf(art::CompilerDriver* driver) { void *compiler_context = driver->GetCompilerContext(); CHECK(compiler_context != NULL); - return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context); + return reinterpret_cast<CompilerLLVM*>(compiler_context); } -static art::llvm::CompilerLLVM* ContextOf(const art::CompilerDriver& driver) { +static CompilerLLVM* ContextOf(const art::CompilerDriver& driver) { void *compiler_context = driver.GetCompilerContext(); CHECK(compiler_context != NULL); - return reinterpret_cast<art::llvm::CompilerLLVM*>(compiler_context); + return reinterpret_cast<CompilerLLVM*>(compiler_context); } -extern "C" void ArtInitCompilerContext(art::CompilerDriver* driver) { +void ArtInitCompilerContext(CompilerDriver* driver) { CHECK(driver->GetCompilerContext() == nullptr); - art::llvm::CompilerLLVM* compiler_llvm = new art::llvm::CompilerLLVM(driver, - driver->GetInstructionSet()); + CompilerLLVM* compiler_llvm = new CompilerLLVM(driver, driver->GetInstructionSet()); driver->SetCompilerContext(compiler_llvm); } -extern "C" void ArtUnInitCompilerContext(art::CompilerDriver* driver) { +void ArtUnInitCompilerContext(CompilerDriver* driver) { delete ContextOf(driver); driver->SetCompilerContext(nullptr); } -extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver* driver, - const art::DexFile::CodeItem* code_item, - uint32_t access_flags, - art::InvokeType invoke_type, - uint16_t class_def_idx, - uint32_t method_idx, - jobject class_loader, - const art::DexFile& dex_file) { + +CompiledMethod* ArtCompileMethod(CompilerDriver* driver, 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) { UNUSED(class_def_idx); // TODO: this is used with Compiler::RequiresConstructorBarrier. - art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); + ClassLinker *class_linker = Runtime::Current()->GetClassLinker(); - art::DexCompilationUnit dex_compilation_unit( - NULL, class_loader, class_linker, dex_file, code_item, - class_def_idx, method_idx, access_flags, driver->GetVerifiedMethod(&dex_file, method_idx)); - art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); - art::CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type); + DexCompilationUnit dex_compilation_unit(nullptr, class_loader, class_linker, dex_file, code_item, + class_def_idx, method_idx, access_flags, + driver->GetVerifiedMethod(&dex_file, method_idx)); + CompilerLLVM* compiler_llvm = ContextOf(driver); + CompiledMethod* result = compiler_llvm->CompileDexMethod(&dex_compilation_unit, invoke_type); return result; } -extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver* driver, - uint32_t access_flags, uint32_t method_idx, - const art::DexFile& dex_file) { - art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker(); +CompiledMethod* ArtLLVMJniCompileMethod(CompilerDriver* driver, uint32_t access_flags, + uint32_t method_idx, const DexFile& dex_file) { + ClassLinker *class_linker = Runtime::Current()->GetClassLinker(); - art::DexCompilationUnit dex_compilation_unit( - nullptr, nullptr, class_linker, dex_file, nullptr, - 0, method_idx, access_flags, nullptr); + DexCompilationUnit dex_compilation_unit(nullptr, nullptr, class_linker, dex_file, nullptr, + 0, method_idx, access_flags, nullptr); - art::llvm::CompilerLLVM* compiler_llvm = ContextOf(driver); - art::CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit); + CompilerLLVM* compiler_llvm = ContextOf(driver); + CompiledMethod* result = compiler_llvm->CompileNativeMethod(&dex_compilation_unit); return result; } -extern "C" void compilerLLVMSetBitcodeFileName(const art::CompilerDriver& driver, - const std::string& filename) { +void compilerLLVMSetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) { ContextOf(driver)->SetBitcodeFileName(filename); } + +} // namespace llvm +} // namespace art + diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h index cc74deb..7d29198 100644 --- a/compiler/llvm/compiler_llvm.h +++ b/compiler/llvm/compiler_llvm.h @@ -95,6 +95,19 @@ class CompilerLLVM { DISALLOW_COPY_AND_ASSIGN(CompilerLLVM); }; +void ArtInitCompilerContext(CompilerDriver* driver); + +void ArtUnInitCompilerContext(CompilerDriver* driver); + +CompiledMethod* ArtCompileMethod(CompilerDriver* driver, 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); + +CompiledMethod* ArtLLVMJniCompileMethod(CompilerDriver* driver, uint32_t access_flags, + uint32_t method_idx, const DexFile& dex_file); + +void compilerLLVMSetBitcodeFileName(const CompilerDriver& driver, const std::string& filename); } // namespace llvm } // namespace art diff --git a/compiler/llvm/llvm_compiler.cc b/compiler/llvm/llvm_compiler.cc new file mode 100644 index 0000000..55af614 --- /dev/null +++ b/compiler/llvm/llvm_compiler.cc @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#include "llvm_compiler.h" + +#ifdef ART_USE_PORTABLE_COMPILER +#include "compiler.h" +#include "compiler_llvm.h" +#include "dex/portable/mir_to_gbc.h" +#include "dex_file.h" +#include "elf_writer_mclinker.h" +#include "mirror/art_method-inl.h" +#endif + +namespace art { + +#ifdef ART_USE_PORTABLE_COMPILER + +namespace llvm { + +// Thread-local storage compiler worker threads +class LLVMCompilerTls : public CompilerTls { + public: + LLVMCompilerTls() : llvm_info_(nullptr) {} + ~LLVMCompilerTls() {} + + void* GetLLVMInfo() { return llvm_info_; } + + void SetLLVMInfo(void* llvm_info) { llvm_info_ = llvm_info; } + + private: + void* llvm_info_; +}; + + + +class LLVMCompiler FINAL : public Compiler { + public: + explicit LLVMCompiler(CompilerDriver* driver) : Compiler(driver, 1000) {} + + CompilerTls* CreateNewCompilerTls() { + return new LLVMCompilerTls(); + } + + void Init() const OVERRIDE { + ArtInitCompilerContext(GetCompilerDriver()); + } + + void UnInit() const OVERRIDE { + ArtUnInitCompilerContext(GetCompilerDriver()); + } + + bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const + OVERRIDE { + return true; + } + + CompiledMethod* Compile(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) const OVERRIDE { + CompiledMethod* method = TryCompileWithSeaIR(code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + class_loader, + dex_file); + if (method != nullptr) { + return method; + } + + return ArtCompileMethod(GetCompilerDriver(), + code_item, + access_flags, + invoke_type, + class_def_idx, + method_idx, + class_loader, + dex_file); + } + + CompiledMethod* JniCompile(uint32_t access_flags, + uint32_t method_idx, + const DexFile& dex_file) const OVERRIDE { + return ArtLLVMJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file); + } + + uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const { + return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode()); + } + + bool WriteElf(art::File* file, + OatWriter* oat_writer, + const std::vector<const art::DexFile*>& dex_files, + const std::string& android_root, + bool is_host, const CompilerDriver& driver) const + OVERRIDE + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return art::ElfWriterMclinker::Create( + file, oat_writer, dex_files, android_root, is_host, driver); + } + + Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { + return PortableCodeGenerator( + cu, cu->mir_graph.get(), &cu->arena, + reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit)); + } + + void InitCompilationUnit(CompilationUnit& cu) const { + // Fused long branches not currently useful in bitcode. + cu.disable_opt |= + (1 << kBranchFusing) | + (1 << kSuppressExceptionEdges); + } + + bool IsPortable() const OVERRIDE { + return true; + } + + void SetBitcodeFileName(const CompilerDriver& driver, const std::string& filename) { + typedef void (*SetBitcodeFileNameFn)(const CompilerDriver&, const std::string&); + + SetBitcodeFileNameFn set_bitcode_file_name = + reinterpret_cast<SetBitcodeFileNameFn>(compilerLLVMSetBitcodeFileName); + + set_bitcode_file_name(driver, filename); + } + + private: + DISALLOW_COPY_AND_ASSIGN(LLVMCompiler); +}; + +} // namespace llvm +#endif + +Compiler* CreateLLVMCompiler(CompilerDriver* driver) { +#ifdef ART_USE_PORTABLE_COMPILER + return new llvm::LLVMCompiler(driver); +#else + return nullptr; +#endif +} + +} // namespace art diff --git a/compiler/llvm/llvm_compiler.h b/compiler/llvm/llvm_compiler.h new file mode 100644 index 0000000..da6d0e9 --- /dev/null +++ b/compiler/llvm/llvm_compiler.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012 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_LLVM_LLVM_COMPILER_H_ +#define ART_COMPILER_LLVM_LLVM_COMPILER_H_ + +namespace art { + +class Compiler; +class CompilerDriver; + +Compiler* CreateLLVMCompiler(CompilerDriver* driver); + +} + +#endif // ART_COMPILER_LLVM_LLVM_COMPILER_H_ diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 11d1728..28710e0 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "class_linker.h" #include "common_compiler_test.h" #include "compiler.h" #include "dex/verification_results.h" diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index fce6ab0..3461276 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -14,12 +14,14 @@ * limitations under the License. */ +#include "optimizing_compiler.h" + #include <fstream> #include <stdint.h> #include "builder.h" #include "code_generator.h" -#include "compilers.h" +#include "compiler.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" #include "graph_visualizer.h" @@ -65,12 +67,105 @@ static bool kIsVisualizerEnabled = false; */ static const char* kStringFilter = ""; -OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : QuickCompiler(driver) { +class OptimizingCompiler FINAL : public Compiler { + public: + explicit OptimizingCompiler(CompilerDriver* driver); + + bool CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, CompilationUnit* cu) const + OVERRIDE; + + CompiledMethod* Compile(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) 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) const; + + // For the following methods we will use the fallback. This is a delegation pattern. + CompiledMethod* JniCompile(uint32_t access_flags, + uint32_t method_idx, + const DexFile& dex_file) const OVERRIDE; + + uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const OVERRIDE + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + bool WriteElf(art::File* file, + OatWriter* oat_writer, + const std::vector<const art::DexFile*>& dex_files, + const std::string& android_root, + bool is_host) const OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const OVERRIDE; + + void InitCompilationUnit(CompilationUnit& cu) const OVERRIDE; + + void Init() const OVERRIDE; + + void UnInit() const OVERRIDE; + + private: + std::unique_ptr<std::ostream> visualizer_output_; + + // Delegate to another compiler in case the optimizing compiler cannot compile a method. + // Currently the fallback is the quick compiler. + std::unique_ptr<Compiler> delegate_; + + DISALLOW_COPY_AND_ASSIGN(OptimizingCompiler); +}; + +OptimizingCompiler::OptimizingCompiler(CompilerDriver* driver) : Compiler(driver, 100), + delegate_(Create(driver, Compiler::Kind::kQuick)) { if (kIsVisualizerEnabled) { visualizer_output_.reset(new std::ofstream("art.cfg")); } } +void OptimizingCompiler::Init() const { + delegate_->Init(); +} + +void OptimizingCompiler::UnInit() const { + delegate_->UnInit(); +} + +bool OptimizingCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file, + CompilationUnit* cu) const { + return delegate_->CanCompileMethod(method_idx, dex_file, cu); +} + +CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, + uint32_t method_idx, + const DexFile& dex_file) const { + return delegate_->JniCompile(access_flags, method_idx, dex_file); +} + +uintptr_t OptimizingCompiler::GetEntryPointOf(mirror::ArtMethod* method) const { + return delegate_->GetEntryPointOf(method); +} + +bool OptimizingCompiler::WriteElf(art::File* file, OatWriter* oat_writer, + const std::vector<const art::DexFile*>& dex_files, + const std::string& android_root, bool is_host) const { + return delegate_->WriteElf(file, oat_writer, dex_files, android_root, is_host); +} + +Backend* OptimizingCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const { + return delegate_->GetCodeGenerator(cu, compilation_unit); +} + +void OptimizingCompiler::InitCompilationUnit(CompilationUnit& cu) const { + delegate_->InitCompilationUnit(cu); +} + CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, @@ -183,4 +278,25 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite nullptr); } +CompiledMethod* OptimizingCompiler::Compile(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) const { + CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, + method_idx, class_loader, dex_file); + if (method != nullptr) { + return method; + } + + return delegate_->Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx, + class_loader, dex_file); +} + +Compiler* CreateOptimizingCompiler(CompilerDriver* driver) { + return new OptimizingCompiler(driver); +} + } // namespace art diff --git a/compiler/optimizing/optimizing_compiler.h b/compiler/optimizing/optimizing_compiler.h new file mode 100644 index 0000000..a415eca --- /dev/null +++ b/compiler/optimizing/optimizing_compiler.h @@ -0,0 +1,29 @@ +/* + * 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_OPTIMIZING_OPTIMIZING_COMPILER_H_ +#define ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_H_ + +namespace art { + +class Compiler; +class CompilerDriver; + +Compiler* CreateOptimizingCompiler(CompilerDriver* driver); + +} + +#endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_COMPILER_H_ |