diff options
Diffstat (limited to 'compiler')
42 files changed, 1311 insertions, 363 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index f81b460ee4..5caf688d29 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -94,9 +94,12 @@ LIBART_COMPILER_SRC_FILES := \ ifeq ($(ART_SEA_IR_MODE),true) LIBART_COMPILER_SRC_FILES += \ sea_ir/frontend.cc \ - sea_ir/instruction_tools.cc \ - sea_ir/sea.cc \ - sea_ir/code_gen.cc + sea_ir/ir/instruction_tools.cc \ + sea_ir/ir/sea.cc \ + sea_ir/code_gen/code_gen.cc \ + sea_ir/types/type_inference.cc \ + sea_ir/types/type_inference_visitor.cc \ + sea_ir/debug/dot_gen.cc endif LIBART_COMPILER_CFLAGS := diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 60e638c584..a0e2c1e9aa 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -20,10 +20,10 @@ #include "dex_instruction-inl.h" #include "driver/compiler_driver.h" #include "driver/dex_compilation_unit.h" -#include "mirror/abstract_method-inl.h" +#include "mirror/art_field-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" -#include "mirror/field-inl.h" namespace art { namespace optimizer { diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc index 90cec75039..7831cf6f7a 100644 --- a/compiler/dex/portable/mir_to_gbc.cc +++ b/compiler/dex/portable/mir_to_gbc.cc @@ -1972,7 +1972,7 @@ void MirConverter::MethodMIR2Bitcode() { ::llvm::OwningPtr< ::llvm::tool_output_file> out_file( new ::llvm::tool_output_file(fname.c_str(), errmsg, - ::llvm::sys::fs::F_Binary)); + ::llvm::raw_fd_ostream::F_Binary)); if (!errmsg.empty()) { LOG(ERROR) << "Failed to create bitcode output file: " << errmsg; diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 298d3898c8..e5c7fb150e 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -347,7 +347,7 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do RegLocation rl_method = LoadCurrMethod(); rBase = AllocTemp(); LoadWordDisp(rl_method.low_reg, - mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase); + mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase); if (IsTemp(rl_method.low_reg)) { FreeTemp(rl_method.low_reg); } @@ -365,7 +365,7 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do rBase = TargetReg(kArg0); LockTemp(rBase); LoadWordDisp(r_method, - mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), + mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), rBase); LoadWordDisp(rBase, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + @@ -433,7 +433,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, RegLocation rl_method = LoadCurrMethod(); rBase = AllocTemp(); LoadWordDisp(rl_method.low_reg, - mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), rBase); + mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase); } else { // Medium path, static storage base in a different class which requires checks that the other // class is initialized @@ -448,7 +448,7 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, rBase = TargetReg(kArg0); LockTemp(rBase); LoadWordDisp(r_method, - mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), + mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), rBase); LoadWordDisp(rBase, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + sizeof(int32_t*) * ssb_index, rBase); @@ -746,7 +746,7 @@ void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { } else { // We're don't need access checks, load type from dex cache int32_t dex_cache_offset = - mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(); + mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(); LoadWordDisp(rl_method.low_reg, dex_cache_offset, res_reg); int32_t offset_of_type = mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) @@ -799,7 +799,7 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { LockCallTemps(); // Using explicit registers LoadCurrMethodDirect(TargetReg(kArg2)); LoadWordDisp(TargetReg(kArg2), - mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0)); + mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0)); // Might call out to helper, which will return resolved string in kRet0 int r_tgt = CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(pResolveString)); LoadWordDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0)); @@ -835,7 +835,7 @@ void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { int res_reg = AllocTemp(); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); LoadWordDisp(rl_method.low_reg, - mirror::AbstractMethod::DexCacheStringsOffset().Int32Value(), res_reg); + mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), res_reg); LoadWordDisp(res_reg, offset_of_string, rl_result.low_reg); StoreValue(rl_dest, rl_result); } @@ -884,11 +884,11 @@ void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, Re LoadCurrMethodDirect(check_class); if (use_declaring_class) { - LoadWordDisp(check_class, mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + LoadWordDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class); LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class); } else { - LoadWordDisp(check_class, mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), + LoadWordDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), check_class); LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class); int32_t offset_of_type = @@ -940,12 +940,12 @@ void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_know } else if (use_declaring_class) { LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref LoadWordDisp(TargetReg(kArg1), - mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg); + mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg); } else { // Load dex cache entry into class_reg (kArg2) LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref LoadWordDisp(TargetReg(kArg1), - mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); + mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); int32_t offset_of_type = mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) * type_idx); @@ -1078,11 +1078,11 @@ void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_ OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path } else if (use_declaring_class) { LoadWordDisp(TargetReg(kArg1), - mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), class_reg); + mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg); } else { // Load dex cache entry into class_reg (kArg2) LoadWordDisp(TargetReg(kArg1), - mirror::AbstractMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); + mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); int32_t offset_of_type = mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) * type_idx); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 20d683a947..073b550d78 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -365,7 +365,7 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, break; case 1: // Get method->dex_cache_resolved_methods_ cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0)); + mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0)); // Set up direct code if known. if (direct_code != 0) { if (direct_code != static_cast<unsigned int>(-1)) { @@ -395,7 +395,7 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, if (cu->instruction_set != kX86) { if (direct_code == 0) { cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), cg->TargetReg(kInvokeTgt)); } break; @@ -448,7 +448,7 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, case 4: // Get the compiled code address [uses kArg0, sets kInvokeTgt] if (cu->instruction_set != kX86) { cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), cg->TargetReg(kInvokeTgt)); break; } @@ -514,7 +514,7 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, break; case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0] cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(), + mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), cg->TargetReg(kArg0)); break; case 2: // Grab target method* [set/use kArg0] @@ -1407,7 +1407,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) { } else { if (fast_path && info->type != kInterface) { call_inst = OpMem(kOpBlx, TargetReg(kArg0), - mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value()); + mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value()); } else { ThreadOffset trampoline(-1); switch (info->type) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 56b629c576..b8727fe103 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -16,8 +16,10 @@ #include "compiler_driver.h" -#include <vector> +#define ATRACE_TAG ATRACE_TAG_DALVIK +#include <utils/Trace.h> +#include <vector> #include <unistd.h> #include "base/stl_util.h" @@ -31,11 +33,11 @@ #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" #include "gc/space/space.h" +#include "mirror/art_field-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/class_loader.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" -#include "mirror/field-inl.h" -#include "mirror/abstract_method-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/throwable.h" @@ -62,7 +64,7 @@ static void DumpStat(size_t x, size_t y, const char* str) { if (x == 0 && y == 0) { return; } - LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases"; + VLOG(compiler) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases"; } class AOTCompilationStats { @@ -513,7 +515,7 @@ static DexToDexCompilationLevel GetDexToDexCompilationlevel(mirror::ClassLoader* } } -void CompilerDriver::CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) { +void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLogger& timings) { DCHECK(!Runtime::Current()->IsStarted()); Thread* self = Thread::Current(); jobject jclass_loader; @@ -630,12 +632,12 @@ static bool ResolveCatchBlockExceptionsClassVisitor(mirror::Class* c, void* arg) reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*> >*>(arg); MethodHelper mh; for (size_t i = 0; i < c->NumVirtualMethods(); ++i) { - mirror::AbstractMethod* m = c->GetVirtualMethod(i); + mirror::ArtMethod* m = c->GetVirtualMethod(i); mh.ChangeMethod(m); ResolveExceptionsForMethod(&mh, *exceptions_to_resolve); } for (size_t i = 0; i < c->NumDirectMethods(); ++i) { - mirror::AbstractMethod* m = c->GetDirectMethod(i); + mirror::ArtMethod* m = c->GetDirectMethod(i); mh.ChangeMethod(m); ResolveExceptionsForMethod(&mh, *exceptions_to_resolve); } @@ -722,7 +724,7 @@ static void MaybeAddToImageClasses(mirror::Class* klass, CompilerDriver::Descrip std::pair<CompilerDriver::DescriptorSet::iterator, bool> result = image_classes->insert(descriptor); if (result.second) { - LOG(INFO) << "Adding " << descriptor << " to image classes"; + VLOG(compiler) << "Adding " << descriptor << " to image classes"; } else { return; } @@ -893,7 +895,7 @@ static mirror::Class* ComputeCompilingMethodsClass(ScopedObjectAccess& soa, dex_cache, class_loader); } -static mirror::Field* ComputeFieldReferencedFromCompilingMethod(ScopedObjectAccess& soa, +static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod(ScopedObjectAccess& soa, const DexCompilationUnit* mUnit, uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -903,7 +905,7 @@ static mirror::Field* ComputeFieldReferencedFromCompilingMethod(ScopedObjectAcce class_loader, false); } -static mirror::AbstractMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa, +static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa, const DexCompilationUnit* mUnit, uint32_t method_idx, InvokeType type) @@ -921,7 +923,7 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi field_offset = -1; is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static). - mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); + mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && !resolved_field->IsStatic()) { mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), @@ -972,7 +974,7 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila is_referrers_class = false; is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static). - mirror::Field* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); + mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && resolved_field->IsStatic()) { mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, resolved_field->GetDeclaringClass()->GetDexCache(), @@ -1049,7 +1051,7 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, - mirror::AbstractMethod* method, + mirror::ArtMethod* method, uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats) { @@ -1112,7 +1114,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui vtable_idx = -1; direct_code = 0; direct_method = 0; - mirror::AbstractMethod* resolved_method = + mirror::ArtMethod* resolved_method = ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index, invoke_type); if (resolved_method != NULL) { @@ -1177,7 +1179,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui mUnit->GetClassLinker()->FindDexCache(*devirt_map_target->dex_file); mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()); - mirror::AbstractMethod* called_method = + mirror::ArtMethod* called_method = mUnit->GetClassLinker()->ResolveMethod(*devirt_map_target->dex_file, devirt_map_target->dex_method_index, target_dex_cache, class_loader, NULL, @@ -1469,7 +1471,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); ClassDataItemIterator it(dex_file, class_data); while (it.HasNextStaticField()) { - mirror::Field* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, + mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, true); if (field == NULL) { CHECK(self->IsExceptionPending()); @@ -1485,7 +1487,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag requires_constructor_barrier = true; } - mirror::Field* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, + mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, class_loader, false); if (field == NULL) { CHECK(self->IsExceptionPending()); @@ -1498,7 +1500,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag class_def_index); } while (it.HasNextDirectMethod()) { - mirror::AbstractMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), + mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, class_loader, NULL, it.GetMethodInvokeType(class_def)); if (method == NULL) { @@ -1508,7 +1510,7 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag it.Next(); } while (it.HasNextVirtualMethod()) { - mirror::AbstractMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), + mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, class_loader, NULL, it.GetMethodInvokeType(class_def)); if (method == NULL) { @@ -1562,14 +1564,14 @@ void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFil static void VerifyClass(const ParallelCompilationManager* manager, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { + ATRACE_CALL(); ScopedObjectAccess soa(Thread::Current()); const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())); - if (klass == NULL) { - CHECK(soa.Self()->IsExceptionPending()); + if (klass == NULL) { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); /* @@ -1600,6 +1602,7 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ soa.Self()->ClearException(); } + CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous()) << PrettyDescriptor(klass) << ": state=" << klass->GetStatus(); soa.Self()->AssertNoPendingException(); @@ -2067,10 +2070,10 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } } if (!is_black_listed) { - LOG(INFO) << "Initializing: " << descriptor; + VLOG(compiler) << "Initializing: " << descriptor; if (StringPiece(descriptor) == "Ljava/lang/Void;") { // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. - mirror::ObjectArray<mirror::Field>* fields = klass->GetSFields(); + mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields(); CHECK_EQ(fields->GetLength(), 1); fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V')); klass->SetStatus(mirror::Class::kStatusInitialized); @@ -2135,6 +2138,7 @@ void CompilerDriver::Compile(jobject class_loader, const std::vector<const DexFi } void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, size_t class_def_index) { + ATRACE_CALL(); jobject jclass_loader = manager->GetClassLoader(); const DexFile& dex_file = *manager->GetDexFile(); const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); @@ -2155,6 +2159,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz // empty class, probably a marker interface return; } + // Can we run DEX-to-DEX compiler on this class ? DexToDexCompilationLevel dex_to_dex_compilation_level = kDontDexToDexCompile; { @@ -2227,10 +2232,6 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t } else { bool compile = verifier::MethodVerifier::IsCandidateForCompilation(code_item, access_flags); if (compile) { - // If we're doing the image, override the compiler filter to force full compilation. - if ((image_classes_.get() != NULL) && (image_classes_->size() != 0)) { - Runtime::Current()->SetCompilerFilter(Runtime::kSpeed); - } CompilerFn compiler = compiler_; #ifdef ART_SEA_IR_MODE bool use_sea = Runtime::Current()->IsSeaIRMode(); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index b5222c99b8..21a44eaf12 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -99,7 +99,7 @@ class CompilerDriver { LOCKS_EXCLUDED(Locks::mutator_lock_); // Compile a single Method - void CompileOne(const mirror::AbstractMethod* method, base::TimingLogger& timings) + void CompileOne(const mirror::ArtMethod* method, base::TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); InstructionSet GetInstructionSet() const { @@ -301,7 +301,7 @@ class CompilerDriver { // Compute constant code and method pointers when possible void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, - mirror::AbstractMethod* method, + mirror::ArtMethod* method, uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -425,7 +425,7 @@ class CompilerDriver { CompilerEnableAutoElfLoadingFn compiler_enable_auto_elf_loading_; typedef const void* (*CompilerGetMethodCodeAddrFn) - (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::AbstractMethod* method); + (const CompilerDriver& driver, const CompiledMethod* cm, const mirror::ArtMethod* method); CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_; bool support_boot_image_fixup_; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 8ee9cf6442..c6687bb4aa 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -24,10 +24,10 @@ #include "common_test.h" #include "dex_file.h" #include "gc/heap.h" +#include "mirror/art_method-inl.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" -#include "mirror/abstract_method-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" @@ -115,7 +115,7 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { } EXPECT_EQ(dex->NumMethodIds(), dex_cache->NumResolvedMethods()); for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { - mirror::AbstractMethod* method = dex_cache->GetResolvedMethod(i); + mirror::ArtMethod* method = dex_cache->GetResolvedMethod(i); EXPECT_TRUE(method != NULL) << "method_idx=" << i << " " << dex->GetMethodDeclaringClassDescriptor(dex->GetMethodId(i)) << " " << dex->GetMethodName(dex->GetMethodId(i)); @@ -126,7 +126,7 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { } EXPECT_EQ(dex->NumFieldIds(), dex_cache->NumResolvedFields()); for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { - mirror::Field* field = dex_cache->GetResolvedField(i); + mirror::ArtField* field = dex_cache->GetResolvedField(i); EXPECT_TRUE(field != NULL) << "field_idx=" << i << " " << dex->GetFieldDeclaringClassDescriptor(dex->GetFieldId(i)) << " " << dex->GetFieldName(dex->GetFieldId(i)); diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc index 70d17de102..d3c13dd791 100644 --- a/compiler/elf_writer.cc +++ b/compiler/elf_writer.cc @@ -24,7 +24,7 @@ #include "elf_file.h" #include "invoke_type.h" #include "llvm/utils_llvm.h" -#include "mirror/abstract_method-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/object-inl.h" #include "oat.h" #include "scoped_thread_state_change.h" diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc index 2a9bc35559..e496ace27a 100644 --- a/compiler/elf_writer_mclinker.cc +++ b/compiler/elf_writer_mclinker.cc @@ -33,8 +33,8 @@ #include "driver/compiler_driver.h" #include "elf_file.h" #include "globals.h" -#include "mirror/abstract_method.h" -#include "mirror/abstract_method-inl.h" +#include "mirror/art_method.h" +#include "mirror/art_method-inl.h" #include "mirror/object-inl.h" #include "oat_writer.h" #include "scoped_thread_state_change.h" @@ -353,7 +353,7 @@ void ElfWriterMclinker::FixupOatMethodOffsets(const std::vector<const DexFile*>& const DexFile& dex_file = it.GetDexFile(); uint32_t method_idx = it.GetMemberIndex(); InvokeType invoke_type = it.GetInvokeType(); - mirror::AbstractMethod* method = NULL; + mirror::ArtMethod* method = NULL; if (compiler_driver_->IsImage()) { ClassLinker* linker = Runtime::Current()->GetClassLinker(); mirror::DexCache* dex_cache = linker->FindDexCache(dex_file); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 3432c8cbee..a40e3fc149 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -35,12 +35,12 @@ #include "globals.h" #include "image.h" #include "intern_table.h" +#include "mirror/art_field-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/array-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" -#include "mirror/field-inl.h" -#include "mirror/abstract_method-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "oat.h" @@ -52,11 +52,11 @@ #include "UniquePtr.h" #include "utils.h" -using ::art::mirror::AbstractMethod; +using ::art::mirror::ArtField; +using ::art::mirror::ArtMethod; using ::art::mirror::Class; using ::art::mirror::DexCache; using ::art::mirror::EntryPointFromInterpreter; -using ::art::mirror::Field; using ::art::mirror::Object; using ::art::mirror::ObjectArray; using ::art::mirror::String; @@ -257,7 +257,7 @@ void ImageWriter::PruneNonImageClasses() { } // Clear references to removed classes from the DexCaches. - AbstractMethod* resolution_method = runtime->GetResolutionMethod(); + ArtMethod* resolution_method = runtime->GetResolutionMethod(); typedef Set::const_iterator CacheIt; // TODO: C++0x auto for (CacheIt it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) { DexCache* dex_cache = *it; @@ -269,13 +269,13 @@ void ImageWriter::PruneNonImageClasses() { } } for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { - AbstractMethod* method = dex_cache->GetResolvedMethod(i); + ArtMethod* method = dex_cache->GetResolvedMethod(i); if (method != NULL && !IsImageClass(method->GetDeclaringClass())) { dex_cache->SetResolvedMethod(i, resolution_method); } } for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { - Field* field = dex_cache->GetResolvedField(i); + ArtField* field = dex_cache->GetResolvedField(i); if (field != NULL && !IsImageClass(field->GetDeclaringClass())) { dex_cache->SetResolvedField(i, NULL); } @@ -487,8 +487,8 @@ void ImageWriter::FixupObject(const Object* orig, Object* copy) { FixupClass(orig->AsClass(), down_cast<Class*>(copy)); } else if (orig->IsObjectArray()) { FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy)); - } else if (orig->IsMethod()) { - FixupMethod(orig->AsMethod(), down_cast<AbstractMethod*>(copy)); + } else if (orig->IsArtMethod()) { + FixupMethod(orig->AsArtMethod(), down_cast<ArtMethod*>(copy)); } else { FixupInstanceFields(orig, copy); } @@ -499,7 +499,7 @@ void ImageWriter::FixupClass(const Class* orig, Class* copy) { FixupStaticFields(orig, copy); } -void ImageWriter::FixupMethod(const AbstractMethod* orig, AbstractMethod* copy) { +void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { FixupInstanceFields(orig, copy); // OatWriter replaces the code_ with an offset value. Here we re-adjust to a pointer relative to @@ -614,9 +614,9 @@ void ImageWriter::FixupFields(const Object* orig, ? klass->NumReferenceStaticFields() : klass->NumReferenceInstanceFields()); for (size_t i = 0; i < num_reference_fields; ++i) { - Field* field = (is_static - ? klass->GetStaticField(i) - : klass->GetInstanceField(i)); + ArtField* field = (is_static + ? klass->GetStaticField(i) + : klass->GetInstanceField(i)); MemberOffset field_offset = field->GetOffset(); const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false); // Use SetFieldPtr to avoid card marking since we are writing to the image. @@ -626,7 +626,7 @@ void ImageWriter::FixupFields(const Object* orig, } if (!is_static && orig->IsReferenceInstance()) { // Fix-up referent, that isn't marked as an object field, for References. - Field* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;"); + ArtField* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;"); MemberOffset field_offset = field->GetOffset(); const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false); // Use SetFieldPtr to avoid card marking since we are writing to the image. @@ -634,16 +634,16 @@ void ImageWriter::FixupFields(const Object* orig, } } -static AbstractMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) +static ArtMethod* GetTargetMethod(const CompilerDriver::PatchInformation* patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); DexCache* dex_cache = class_linker->FindDexCache(patch->GetDexFile()); - AbstractMethod* method = class_linker->ResolveMethod(patch->GetDexFile(), - patch->GetTargetMethodIdx(), - dex_cache, - NULL, - NULL, - patch->GetTargetInvokeType()); + ArtMethod* method = class_linker->ResolveMethod(patch->GetDexFile(), + patch->GetTargetMethodIdx(), + dex_cache, + NULL, + NULL, + patch->GetTargetInvokeType()); CHECK(method != NULL) << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx(); CHECK(!method->IsRuntimeMethod()) @@ -664,7 +664,7 @@ void ImageWriter::PatchOatCodeAndMethods() { const Patches& code_to_patch = compiler_driver_.GetCodeToPatch(); for (size_t i = 0; i < code_to_patch.size(); i++) { const CompilerDriver::PatchInformation* patch = code_to_patch[i]; - AbstractMethod* target = GetTargetMethod(patch); + ArtMethod* target = GetTargetMethod(patch); uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target)); uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader()); uint32_t code_offset = code - code_base; @@ -674,7 +674,7 @@ void ImageWriter::PatchOatCodeAndMethods() { const Patches& methods_to_patch = compiler_driver_.GetMethodsToPatch(); for (size_t i = 0; i < methods_to_patch.size(); i++) { const CompilerDriver::PatchInformation* patch = methods_to_patch[i]; - AbstractMethod* target = GetTargetMethod(patch); + ArtMethod* target = GetTargetMethod(patch); SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target))); } diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 545534fff7..750109d1d9 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -152,7 +152,7 @@ class ImageWriter { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void FixupClass(const mirror::Class* orig, mirror::Class* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void FixupMethod(const mirror::AbstractMethod* orig, mirror::AbstractMethod* copy) + void FixupMethod(const mirror::ArtMethod* orig, mirror::ArtMethod* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void FixupObject(const mirror::Object* orig, mirror::Object* copy) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc index 4b6967faa0..a653ab42a9 100644 --- a/compiler/jni/jni_compiler_test.cc +++ b/compiler/jni/jni_compiler_test.cc @@ -21,9 +21,9 @@ #include "indirect_reference_table.h" #include "jni_internal.h" #include "mem_map.h" +#include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" -#include "mirror/abstract_method-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "mirror/stack_trace_element.h" @@ -51,7 +51,7 @@ class JniCompilerTest : public CommonTest { // Compile the native method before starting the runtime mirror::Class* c = class_linker_->FindClass("LMyClassNatives;", soa.Decode<mirror::ClassLoader*>(class_loader)); - mirror::AbstractMethod* method; + mirror::ArtMethod* method; if (direct) { method = c->FindDirectMethod(method_name, method_sig); } else { diff --git a/compiler/jni/portable/jni_compiler.cc b/compiler/jni/portable/jni_compiler.cc index e05f291a73..58ee1c1602 100644 --- a/compiler/jni/portable/jni_compiler.cc +++ b/compiler/jni/portable/jni_compiler.cc @@ -27,7 +27,7 @@ #include "llvm/llvm_compilation_unit.h" #include "llvm/runtime_support_llvm_func.h" #include "llvm/utils_llvm.h" -#include "mirror/abstract_method.h" +#include "mirror/art_method.h" #include "runtime.h" #include "stack.h" #include "thread.h" @@ -91,7 +91,7 @@ CompiledMethod* JniCompiler::Compile() { // Load class object this_object_or_class_object = irb_.LoadFromObjectOffset(method_object_addr, - mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + mirror::ArtMethod::DeclaringClassOffset().Int32Value(), irb_.getJObjectTy(), kTBAAConstJObject); } @@ -135,7 +135,7 @@ CompiledMethod* JniCompiler::Compile() { // Get callee code_addr ::llvm::Value* code_addr = irb_.LoadFromObjectOffset(method_object_addr, - mirror::AbstractMethod::NativeMethodOffset().Int32Value(), + mirror::ArtMethod::NativeMethodOffset().Int32Value(), GetFunctionType(dex_compilation_unit_->GetDexMethodIndex(), is_static, true)->getPointerTo(), kTBAARuntimeInfo); diff --git a/compiler/jni/portable/jni_compiler.h b/compiler/jni/portable/jni_compiler.h index 9bdf35ef10..49cc9f4abf 100644 --- a/compiler/jni/portable/jni_compiler.h +++ b/compiler/jni/portable/jni_compiler.h @@ -28,7 +28,7 @@ namespace art { class DexFile; class DexCompilationUnit; namespace mirror { - class AbstractMethod; + class ArtMethod; class ClassLoader; class DexCache; } // namespace mirror diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index 9713fe9da9..069def60f9 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -119,7 +119,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, // Check sirt offset is within frame CHECK_LT(sirt_offset.Uint32Value(), frame_size); __ LoadRef(main_jni_conv->InterproceduralScratchRegister(), - mr_conv->MethodRegister(), mirror::AbstractMethod::DeclaringClassOffset()); + mr_conv->MethodRegister(), mirror::ArtMethod::DeclaringClassOffset()); __ VerifyObject(main_jni_conv->InterproceduralScratchRegister(), false); __ StoreRef(sirt_offset, main_jni_conv->InterproceduralScratchRegister()); main_jni_conv->Next(); // in SIRT so move to next argument @@ -270,7 +270,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver& compiler, } // 9. Plant call to native code associated with method. - __ Call(main_jni_conv->MethodStackOffset(), mirror::AbstractMethod::NativeMethodOffset(), + __ Call(main_jni_conv->MethodStackOffset(), mirror::ArtMethod::NativeMethodOffset(), mr_conv->InterproceduralScratchRegister()); // 10. Fix differences in result widths. diff --git a/compiler/llvm/compiler_llvm.h b/compiler/llvm/compiler_llvm.h index 20934ab209..65bc16bcd8 100644 --- a/compiler/llvm/compiler_llvm.h +++ b/compiler/llvm/compiler_llvm.h @@ -34,7 +34,7 @@ namespace art { class CompilerDriver; class DexCompilationUnit; namespace mirror { - class AbstractMethod; + class ArtMethod; class ClassLoader; } // namespace mirror } // namespace art diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index a727d06cb2..4f6fa0a2df 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -20,7 +20,7 @@ #include "intrinsic_helper.h" #include "ir_builder.h" #include "method_reference.h" -#include "mirror/abstract_method.h" +#include "mirror/art_method.h" #include "mirror/array.h" #include "mirror/string.h" #include "thread.h" @@ -722,7 +722,7 @@ llvm::Value* GBCExpanderPass::EmitLoadDexCacheAddr(art::MemberOffset offset) { llvm::Value* GBCExpanderPass::EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx) { llvm::Value* static_storage_dex_cache_addr = - EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheInitializedStaticStorageOffset()); + EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheInitializedStaticStorageOffset()); llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx); @@ -732,7 +732,7 @@ GBCExpanderPass::EmitLoadDexCacheStaticStorageFieldAddr(uint32_t type_idx) { llvm::Value* GBCExpanderPass::EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx) { llvm::Value* resolved_type_dex_cache_addr = - EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheResolvedTypesOffset()); + EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheResolvedTypesOffset()); llvm::Value* type_idx_value = irb_.getPtrEquivInt(type_idx); @@ -742,7 +742,7 @@ GBCExpanderPass::EmitLoadDexCacheResolvedTypeFieldAddr(uint32_t type_idx) { llvm::Value* GBCExpanderPass:: EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx) { llvm::Value* resolved_method_dex_cache_addr = - EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheResolvedMethodsOffset()); + EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheResolvedMethodsOffset()); llvm::Value* method_idx_value = irb_.getPtrEquivInt(method_idx); @@ -752,7 +752,7 @@ EmitLoadDexCacheResolvedMethodFieldAddr(uint32_t method_idx) { llvm::Value* GBCExpanderPass:: EmitLoadDexCacheStringFieldAddr(uint32_t string_idx) { llvm::Value* string_dex_cache_addr = - EmitLoadDexCacheAddr(art::mirror::AbstractMethod::DexCacheStringsOffset()); + EmitLoadDexCacheAddr(art::mirror::ArtMethod::DexCacheStringsOffset()); llvm::Value* string_idx_value = irb_.getPtrEquivInt(string_idx); @@ -911,7 +911,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { } else { code_addr = irb_.LoadFromObjectOffset(callee_method_object_addr, - art::mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + art::mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), func_type->getPointerTo(), kTBAARuntimeInfo); } @@ -1207,7 +1207,7 @@ void GBCExpanderPass::Expand_SPutFast(llvm::Value* static_storage_addr, llvm::Value* GBCExpanderPass::Expand_LoadDeclaringClassSSB(llvm::Value* method_object_addr) { return irb_.LoadFromObjectOffset(method_object_addr, - art::mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(), irb_.getJObjectTy(), kTBAAConstJObject); } @@ -1259,7 +1259,7 @@ llvm::Value* GBCExpanderPass::Expand_Invoke(llvm::CallInst& call_inst) { llvm::Value* code_addr = irb_.LoadFromObjectOffset(callee_method_object_addr, - art::mirror::AbstractMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + art::mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), callee_method_type->getPointerTo(), kTBAARuntimeInfo); @@ -1938,7 +1938,7 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst, static_storage_addr = irb_.LoadFromObjectOffset(method_object_addr, - art::mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(), irb_.getJObjectTy(), kTBAAConstJObject); } else { @@ -2023,7 +2023,7 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst, static_storage_addr = irb_.LoadFromObjectOffset(method_object_addr, - art::mirror::AbstractMethod::DeclaringClassOffset().Int32Value(), + art::mirror::ArtMethod::DeclaringClassOffset().Int32Value(), irb_.getJObjectTy(), kTBAAConstJObject); } else { diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc index 7542b841a1..9296fc7050 100644 --- a/compiler/llvm/llvm_compilation_unit.cc +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -214,6 +214,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::llvm::TargetOptions target_options; target_options.FloatABIType = ::llvm::FloatABI::Soft; target_options.NoFramePointerElim = true; + target_options.NoFramePointerElimNonLeaf = true; target_options.UseSoftFloat = false; target_options.EnableFastISel = false; @@ -257,7 +258,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea ::llvm::OwningPtr< ::llvm::tool_output_file> out_file( new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg, - ::llvm::sys::fs::F_Binary)); + ::llvm::raw_fd_ostream::F_Binary)); if (!errmsg.empty()) { @@ -277,6 +278,7 @@ bool LlvmCompilationUnit::MaterializeToRawOStream(::llvm::raw_ostream& out_strea // pm_builder.Inliner = ::llvm::createAlwaysInlinerPass(); // pm_builder.Inliner = ::llvm::createPartialInliningPass(); pm_builder.OptLevel = 3; + pm_builder.DisableSimplifyLibCalls = 1; pm_builder.DisableUnitAtATime = 1; pm_builder.populateFunctionPassManager(fpm); pm_builder.populateModulePassManager(pm); diff --git a/compiler/llvm/runtime_support_builder_thumb2.cc b/compiler/llvm/runtime_support_builder_thumb2.cc index f0cb4a2d7b..eff29c8b04 100644 --- a/compiler/llvm/runtime_support_builder_thumb2.cc +++ b/compiler/llvm/runtime_support_builder_thumb2.cc @@ -51,8 +51,8 @@ void RuntimeSupportBuilderThumb2::EmitLockObject(Value* object) { // $2: temp // $3: temp std::string asms; - StringAppendF(&asms, "add $3, $1, #%"PRId32"\n", mirror::Object::MonitorOffset().Int32Value()); - StringAppendF(&asms, "ldr $2, [r9, #%"PRId32"]\n", Thread::ThinLockIdOffset().Int32Value()); + StringAppendF(&asms, "add $3, $1, #%" PRId32 "\n", mirror::Object::MonitorOffset().Int32Value()); + StringAppendF(&asms, "ldr $2, [r9, #%" PRId32 "]\n", Thread::ThinLockIdOffset().Int32Value()); StringAppendF(&asms, "ldrex $0, [$3]\n"); StringAppendF(&asms, "lsl $2, $2, %d\n", LW_LOCK_OWNER_SHIFT); StringAppendF(&asms, "bfi $2, $0, #0, #%d\n", LW_LOCK_OWNER_SHIFT - 1); diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index ce88cf6dd6..f9d6e4192d 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -23,7 +23,7 @@ #include "class_linker.h" #include "dex_file-inl.h" #include "gc/space/space.h" -#include "mirror/abstract_method-inl.h" +#include "mirror/art_method-inl.h" #include "mirror/array.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" @@ -400,7 +400,7 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); // Unchecked as we hold mutator_lock_ on entry. ScopedObjectAccessUnchecked soa(Thread::Current()); - mirror::AbstractMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, + mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, NULL, NULL, invoke_type); CHECK(method != NULL); method->SetFrameSizeInBytes(frame_size_in_bytes); @@ -464,7 +464,7 @@ bool OatWriter::Write(OutputStream& out) { if (kIsDebugBuild) { uint32_t size_total = 0; #define DO_STAT(x) \ - LOG(INFO) << #x "=" << PrettySize(x) << " (" << x << "B)"; \ + VLOG(compiler) << #x "=" << PrettySize(x) << " (" << x << "B)"; \ size_total += x; DO_STAT(size_dex_file_alignment_); @@ -495,7 +495,7 @@ bool OatWriter::Write(OutputStream& out) { DO_STAT(size_oat_class_method_offsets_); #undef DO_STAT - LOG(INFO) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \ + VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \ CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent))); CHECK_EQ(size_, size_total); } diff --git a/compiler/sea_ir/code_gen.cc b/compiler/sea_ir/code_gen/code_gen.cc index a513907b38..cb150e58fa 100644 --- a/compiler/sea_ir/code_gen.cc +++ b/compiler/sea_ir/code_gen/code_gen.cc @@ -15,8 +15,8 @@ */ #include <llvm/Support/raw_ostream.h> -#include "sea.h" -#include "code_gen.h" +#include "sea_ir/ir/sea.h" +#include "sea_ir/code_gen/code_gen.h" namespace sea_ir { @@ -114,6 +114,14 @@ void CodeGenVisitor::Visit(InstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); DCHECK(0); // This whole function is useful only during development. } + +void CodeGenVisitor::Visit(UnnamedConstInstructionNode* instruction) { + std::string instr = instruction->GetInstruction()->DumpString(NULL); + std::cout << "1.Instruction: " << instr << std::endl; + llvm_data_->AddValue(instruction, + llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, instruction->GetConstValue()))); +} + void CodeGenVisitor::Visit(ConstInstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); std::cout << "1.Instruction: " << instr << std::endl; @@ -123,14 +131,14 @@ void CodeGenVisitor::Visit(ConstInstructionNode* instruction) { void CodeGenVisitor::Visit(ReturnInstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); std::cout << "2.Instruction: " << instr << std::endl; - DCHECK_GT(instruction->GetSSAUses().size(), 0u); - llvm::Value* return_value = llvm_data_->GetValue(instruction->GetSSAUses().at(0)); + DCHECK_GT(instruction->GetSSAProducers().size(), 0u); + llvm::Value* return_value = llvm_data_->GetValue(instruction->GetSSAProducers().at(0)); llvm_data_->builder_.CreateRet(return_value); } void CodeGenVisitor::Visit(IfNeInstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); std::cout << "3.Instruction: " << instr << std::endl; - std::vector<InstructionNode*> ssa_uses = instruction->GetSSAUses(); + std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers(); DCHECK_GT(ssa_uses.size(), 1u); InstructionNode* use_l = ssa_uses.at(0); llvm::Value* left = llvm_data_->GetValue(use_l); @@ -171,7 +179,7 @@ void CodeGenVisitor::Visit(MoveResultInstructionNode* instruction) { // since their purpose of minimizing the number of opcodes in dex is // not relevant for the IR. (Will need to have different // instruction subclasses for functions and procedures.) - std::vector<InstructionNode*> ssa_uses = instruction->GetSSAUses(); + std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers(); InstructionNode* use_l = ssa_uses.at(0); llvm::Value* left = llvm_data_->GetValue(use_l); llvm::Value* right = llvm::ConstantInt::get(*llvm_data_->context_, llvm::APInt(32, 0)); @@ -187,7 +195,7 @@ void CodeGenVisitor::Visit(InvokeStaticInstructionNode* invoke) { // TODO: Add proper checking of the matching between formal and actual signature. DCHECK(NULL != callee); std::vector<llvm::Value*> parameter_values; - std::vector<InstructionNode*> parameter_sources = invoke->GetSSAUses(); + std::vector<InstructionNode*> parameter_sources = invoke->GetSSAProducers(); for (std::vector<InstructionNode*>::const_iterator cit = parameter_sources.begin(); cit != parameter_sources.end(); ++cit) { llvm::Value* parameter_value = llvm_data_->GetValue((*cit)); @@ -201,7 +209,7 @@ void CodeGenVisitor::Visit(InvokeStaticInstructionNode* invoke) { void CodeGenVisitor::Visit(AddIntInstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); std::cout << "7.Instruction: " << instr << std::endl; - std::vector<InstructionNode*> ssa_uses = instruction->GetSSAUses(); + std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers(); DCHECK_GT(ssa_uses.size(), 1u); InstructionNode* use_l = ssa_uses.at(0); InstructionNode* use_r = ssa_uses.at(1); @@ -221,7 +229,7 @@ void CodeGenVisitor::Visit(GotoInstructionNode* instruction) { void CodeGenVisitor::Visit(IfEqzInstructionNode* instruction) { std::string instr = instruction->GetInstruction()->DumpString(NULL); std::cout << "9. Instruction: " << instr << "; Id: " <<instruction << std::endl; - std::vector<InstructionNode*> ssa_uses = instruction->GetSSAUses(); + std::vector<InstructionNode*> ssa_uses = instruction->GetSSAProducers(); DCHECK_GT(ssa_uses.size(), 0u); InstructionNode* use_l = ssa_uses.at(0); llvm::Value* left = llvm_data_->GetValue(use_l); diff --git a/compiler/sea_ir/code_gen.h b/compiler/sea_ir/code_gen/code_gen.h index aba8d5c7f8..b1bc4dc2da 100644 --- a/compiler/sea_ir/code_gen.h +++ b/compiler/sea_ir/code_gen/code_gen.h @@ -14,14 +14,15 @@ * limitations under the License. */ -#ifndef ART_COMPILER_SEA_IR_CODE_GEN_H_ -#define ART_COMPILER_SEA_IR_CODE_GEN_H_ +#ifndef ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_ +#define ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_ +#include "llvm/Analysis/Verifier.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Analysis/Verifier.h" -#include "visitor.h" +#include "sea_ir/ir/visitor.h" namespace sea_ir { // Abstracts away the containers we use to map SEA IR objects to LLVM IR objects. @@ -100,6 +101,8 @@ class CodeGenPrepassVisitor: public CodeGenPassVisitor { void Visit(SignatureNode* region); void Visit(Region* region); void Visit(InstructionNode* instruction) { } + + void Visit(UnnamedConstInstructionNode* instruction) { } void Visit(ConstInstructionNode* instruction) { } void Visit(ReturnInstructionNode* instruction) { } void Visit(IfNeInstructionNode* instruction) { } @@ -119,6 +122,7 @@ class CodeGenPostpassVisitor: public CodeGenPassVisitor { void Visit(SignatureNode* region); void Visit(Region* region); void Visit(InstructionNode* region) { } + void Visit(UnnamedConstInstructionNode* instruction) { } void Visit(ConstInstructionNode* instruction) { } void Visit(ReturnInstructionNode* instruction) { } void Visit(IfNeInstructionNode* instruction) { } @@ -138,10 +142,10 @@ class CodeGenVisitor: public CodeGenPassVisitor { void Visit(SignatureNode* region); void Visit(Region* region); void Visit(InstructionNode* region); + void Visit(UnnamedConstInstructionNode* instruction); void Visit(ConstInstructionNode* instruction); void Visit(ReturnInstructionNode* instruction); void Visit(IfNeInstructionNode* instruction); - // void Visit(AddIntLitInstructionNode* instruction); void Visit(MoveResultInstructionNode* instruction); void Visit(InvokeStaticInstructionNode* instruction); void Visit(AddIntInstructionNode* instruction); @@ -150,4 +154,4 @@ class CodeGenVisitor: public CodeGenPassVisitor { void Visit(PhiInstructionNode* region) { } }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_CODE_GEN_H_ +#endif // ART_COMPILER_SEA_IR_CODE_GEN_CODE_GEN_H_ diff --git a/compiler/sea_ir/debug/dot_gen.cc b/compiler/sea_ir/debug/dot_gen.cc new file mode 100644 index 0000000000..9442684a52 --- /dev/null +++ b/compiler/sea_ir/debug/dot_gen.cc @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "scoped_thread_state_change.h" +#include "sea_ir/debug/dot_gen.h" + +namespace sea_ir { + +void DotGenerationVisitor::Initialize(SeaGraph* graph) { + graph_ = graph; + Region* root_region; + ordered_regions_.clear(); + for (std::vector<Region*>::const_iterator cit = graph->GetRegions()->begin(); + cit != graph->GetRegions()->end(); cit++ ) { + if ((*cit)->GetIDominator() == (*cit)) { + root_region = *cit; + } + } + ordered_regions_.push_back(root_region); + for (unsigned int id = 0; id < ordered_regions_.size(); id++) { + Region* current_region = ordered_regions_.at(id); + const std::set<Region*>* dominated_regions = current_region->GetIDominatedSet(); + for (std::set<Region*>::const_iterator cit = dominated_regions->begin(); + cit != dominated_regions->end(); cit++ ) { + ordered_regions_.push_back(*cit); + } + } +} + +void DotGenerationVisitor::ToDotSSAEdges(InstructionNode* instruction) { + std::map<int, InstructionNode*>* definition_edges = instruction->GetSSAProducersMap(); + // SSA definitions: + for (std::map<int, InstructionNode*>::const_iterator + def_it = definition_edges->begin(); + def_it != definition_edges->end(); def_it++) { + if (NULL != def_it->second) { + dot_text_ += def_it->second->StringId() + " -> "; + dot_text_ += instruction->StringId() + "[color=gray,label=\""; + dot_text_ += art::StringPrintf("vR = %d", def_it->first); + art::SafeMap<int, const Type*>::const_iterator type_it = types_->find(def_it->second->Id()); + if (type_it != types_->end()) { + art::ScopedObjectAccess soa(art::Thread::Current()); + dot_text_ += "(" + type_it->second->Dump() + ")"; + } else { + dot_text_ += "()"; + } + dot_text_ += "\"] ; // SSA edge\n"; + } + } + + // SSA used-by: + if (options_->WillSaveUseEdges()) { + std::vector<InstructionNode*>* used_in = instruction->GetSSAConsumers(); + for (std::vector<InstructionNode*>::const_iterator cit = used_in->begin(); + cit != used_in->end(); cit++) { + dot_text_ += (*cit)->StringId() + " -> " + instruction->StringId() + "[color=gray,label=\""; + dot_text_ += "\"] ; // SSA used-by edge\n"; + } + } +} + +void DotGenerationVisitor::ToDotSSAEdges(PhiInstructionNode* instruction) { + std::vector<InstructionNode*> definition_edges = instruction->GetSSAProducers(); + // SSA definitions: + for (std::vector<InstructionNode*>::const_iterator + def_it = definition_edges.begin(); + def_it != definition_edges.end(); def_it++) { + if (NULL != *def_it) { + dot_text_ += (*def_it)->StringId() + " -> "; + dot_text_ += instruction->StringId() + "[color=gray,label=\""; + dot_text_ += art::StringPrintf("vR = %d", instruction->GetRegisterNumber()); + art::SafeMap<int, const Type*>::const_iterator type_it = types_->find((*def_it)->Id()); + if (type_it != types_->end()) { + art::ScopedObjectAccess soa(art::Thread::Current()); + dot_text_ += "(" + type_it->second->Dump() + ")"; + } else { + dot_text_ += "()"; + } + dot_text_ += "\"] ; // SSA edge\n"; + } + } + + // SSA used-by: + if (options_->WillSaveUseEdges()) { + std::vector<InstructionNode*>* used_in = instruction->GetSSAConsumers(); + for (std::vector<InstructionNode*>::const_iterator cit = used_in->begin(); + cit != used_in->end(); cit++) { + dot_text_ += (*cit)->StringId() + " -> " + instruction->StringId() + "[color=gray,label=\""; + dot_text_ += "\"] ; // SSA used-by edge\n"; + } + } +} + +void DotGenerationVisitor::Visit(SignatureNode* parameter) { + dot_text_ += parameter->StringId() +" [label=\"[" + parameter->StringId() + "] signature:"; + dot_text_ += art::StringPrintf("r%d", parameter->GetResultRegister()); + dot_text_ += "\"] // signature node\n"; + ToDotSSAEdges(parameter); +} + +// Appends to @result a dot language formatted string representing the node and +// (by convention) outgoing edges, so that the composition of theToDot() of all nodes +// builds a complete dot graph (without prolog and epilog though). +void DotGenerationVisitor::Visit(Region* region) { + dot_text_ += "\n// Region: \nsubgraph " + region->StringId(); + dot_text_ += " { label=\"region " + region->StringId() + "(rpo="; + dot_text_ += art::StringPrintf("%d", region->GetRPO()); + if (NULL != region->GetIDominator()) { + dot_text_ += " dom=" + region->GetIDominator()->StringId(); + } + dot_text_ += ")\";\n"; + + std::vector<PhiInstructionNode*>* phi_instructions = region->GetPhiNodes(); + for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions->begin(); + cit != phi_instructions->end(); cit++) { + dot_text_ += (*cit)->StringId() +";\n"; + } + std::vector<InstructionNode*>* instructions = region->GetInstructions(); + for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin(); + cit != instructions->end(); cit++) { + dot_text_ += (*cit)->StringId() +";\n"; + } + + dot_text_ += "} // End Region.\n"; + std::vector<Region*>* successors = region->GetSuccessors(); + for (std::vector<Region*>::const_iterator cit = successors->begin(); cit != successors->end(); + cit++) { + DCHECK(NULL != *cit) << "Null successor found for SeaNode" << + region->GetLastChild()->StringId() << "."; + dot_text_ += region->GetLastChild()->StringId() + " -> " + + (*cit)->GetLastChild()->StringId() + + "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + region->StringId() + "];\n\n"; + } +} +void DotGenerationVisitor::Visit(InstructionNode* instruction) { + dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() + + " [label=\"[" + instruction->StringId() + "] " + + instruction->GetInstruction()->DumpString(graph_->GetDexFile()) + "\""; + dot_text_ += "];\n"; + ToDotSSAEdges(instruction); +} + +void DotGenerationVisitor::Visit(UnnamedConstInstructionNode* instruction) { + dot_text_ += "// Instruction ("+instruction->StringId()+"): \n" + instruction->StringId() + + " [label=\"[" + instruction->StringId() + "] const/x v-3, #" + + art::StringPrintf("%d", instruction->GetConstValue()) + "\""; + dot_text_ += "];\n"; + ToDotSSAEdges(instruction); +} + +void DotGenerationVisitor::Visit(PhiInstructionNode* phi) { + dot_text_ += "// PhiInstruction: \n" + phi->StringId() + + " [label=\"[" + phi->StringId() + "] PHI("; + dot_text_ += art::StringPrintf("%d", phi->GetRegisterNumber()); + dot_text_ += ")\""; + dot_text_ += "];\n"; + ToDotSSAEdges(phi); +} +} // namespace sea_ir diff --git a/compiler/sea_ir/debug/dot_gen.h b/compiler/sea_ir/debug/dot_gen.h new file mode 100644 index 0000000000..675d83d515 --- /dev/null +++ b/compiler/sea_ir/debug/dot_gen.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2013 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_SEA_IR_DEBUG_DOT_GEN_H_ +#define ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_ + +#include "safe_map.h" +#include "base/stringprintf.h" +#include "file_output_stream.h" +#include "sea_ir/ir/sea.h" +#include "sea_ir/types/type_inference.h" + +namespace sea_ir { + +class DotConversionOptions { + public: + DotConversionOptions(): save_use_edges_(false) { } + bool WillSaveUseEdges() const { + return save_use_edges_; + } + private: + bool save_use_edges_; +}; + +class DotGenerationVisitor: public IRVisitor { + public: + explicit DotGenerationVisitor(const DotConversionOptions* const options, + art::SafeMap<int, const Type*>* types): graph_(), types_(types), options_(options) { } + + virtual void Initialize(SeaGraph* graph); + // Saves the ssa def->use edges corresponding to @instruction. + void ToDotSSAEdges(InstructionNode* instruction); + void ToDotSSAEdges(PhiInstructionNode* instruction); + void Visit(SeaGraph* graph) { + dot_text_ += "digraph seaOfNodes {\ncompound=true\n"; + } + void Visit(SignatureNode* parameter); + + // Appends to @result a dot language formatted string representing the node and + // (by convention) outgoing edges, so that the composition of theToDot() of all nodes + // builds a complete dot graph (without prolog and epilog though). + void Visit(Region* region); + void Visit(InstructionNode* instruction); + void Visit(PhiInstructionNode* phi); + void Visit(UnnamedConstInstructionNode* instruction); + + void Visit(ConstInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(ReturnInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(IfNeInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(MoveResultInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(InvokeStaticInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(AddIntInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(GotoInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + void Visit(IfEqzInstructionNode* instruction) { + Visit(reinterpret_cast<InstructionNode*>(instruction)); + } + + std::string GetResult() const { + return dot_text_; + } + + private: + std::string dot_text_; + SeaGraph* graph_; + art::SafeMap<int, const Type*>* types_; + const DotConversionOptions* const options_; +}; + +// Stores options for turning a SEA IR graph to a .dot file. +class DotConversion { + public: + DotConversion(): options_() { } + // Saves to @filename the .dot representation of @graph with the options @options. + void DumpSea(SeaGraph* graph, std::string filename, + art::SafeMap<int, const Type*>* types) const { + LOG(INFO) << "Starting to write SEA string to file."; + DotGenerationVisitor dgv = DotGenerationVisitor(&options_, types); + graph->Accept(&dgv); + art::File* file = art::OS::OpenFile(filename.c_str(), true, true); + art::FileOutputStream fos(file); + std::string graph_as_string = dgv.GetResult(); + graph_as_string += "}"; + fos.WriteFully(graph_as_string.c_str(), graph_as_string.size()); + LOG(INFO) << "Written SEA string to file."; + } + + private: + DotConversionOptions options_; +}; + +} // namespace sea_ir +#endif // ART_COMPILER_SEA_IR_DEBUG_DOT_GEN_H_ diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc index 5843388c42..e24d07d50c 100644 --- a/compiler/sea_ir/frontend.cc +++ b/compiler/sea_ir/frontend.cc @@ -23,14 +23,17 @@ #include "llvm/llvm_compilation_unit.h" #include "mirror/object.h" #include "runtime.h" -#include "sea_ir/sea.h" +#include "safe_map.h" +#include "sea_ir/ir/sea.h" +#include "sea_ir/debug/dot_gen.h" +#include "sea_ir/types/types.h" namespace art { static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, - uint32_t access_flags, InvokeType invoke_type, + uint32_t method_access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) @@ -40,9 +43,11 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, // NOTE: Instead of keeping the convention from the Dalvik frontend.cc // and silencing the cpplint.py warning, I just corrected the formatting. VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "..."; - sea_ir::SeaGraph* sg = sea_ir::SeaGraph::GetCurrentGraph(dex_file); - sg->CompileMethod(code_item, class_def_idx, method_idx, dex_file); - sg->DumpSea("/tmp/temp.dot"); + sea_ir::SeaGraph* ir_graph = sea_ir::SeaGraph::GetGraph(dex_file); + ir_graph->CompileMethod(code_item, class_def_idx, method_idx, method_access_flags, dex_file); + sea_ir::DotConversion dc; + SafeMap<int, const sea_ir::Type*>* types = ir_graph->ti_->GetTypeMap(); + dc.DumpSea(ir_graph, "/tmp/temp.dot", types); CHECK(0 && "No SEA compiled function exists yet."); return NULL; } @@ -50,14 +55,14 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, const CompilerBackend backend, const DexFile::CodeItem* code_item, - uint32_t access_flags, + uint32_t method_access_flags, InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, llvm::LlvmCompilationUnit* llvm_compilation_unit) { - return CompileMethodWithSeaIr(compiler, backend, code_item, access_flags, invoke_type, + return CompileMethodWithSeaIr(compiler, backend, code_item, method_access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm_compilation_unit @@ -68,13 +73,13 @@ CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, - uint32_t access_flags, art::InvokeType invoke_type, + uint32_t method_access_flags, art::InvokeType invoke_type, uint32_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::CompilerBackend backend = compiler.GetCompilerBackend(); - return art::SeaIrCompileOneMethod(compiler, backend, code_item, access_flags, invoke_type, + return art::SeaIrCompileOneMethod(compiler, backend, code_item, method_access_flags, invoke_type, class_def_idx, method_idx, class_loader, dex_file, NULL /* use thread llvm_info */); } diff --git a/compiler/sea_ir/instruction_nodes.h b/compiler/sea_ir/ir/instruction_nodes.h index 6f9bdddf77..906a10fe27 100644 --- a/compiler/sea_ir/instruction_nodes.h +++ b/compiler/sea_ir/ir/instruction_nodes.h @@ -14,11 +14,12 @@ * limitations under the License. */ -#ifndef ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_ -#define ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_ -#include "sea_node.h" -#include "visitor.h" +#ifndef ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_ +#define ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_ #include "dex_instruction-inl.h" +#include "sea_ir/ir/sea_node.h" +#include "sea_ir/ir/visitor.h" + namespace sea_ir { @@ -48,9 +49,7 @@ class InstructionNode: public SeaNode { // Returns the set of registers defined by the current instruction. virtual std::vector<int> GetDefinitions() const; // Returns the set of register numbers that are used by the instruction. - virtual std::vector<int> GetUses(); - // Appends to @result the .dot string representation of the instruction. - virtual void ToDot(std::string& result, const art::DexFile& dex_file) const; + virtual std::vector<int> GetUses() const; // Mark the current instruction as a downward exposed definition. void MarkAsDEDef(); // Rename the use of @reg_no to refer to the instruction @definition, @@ -61,7 +60,7 @@ class InstructionNode: public SeaNode { } // Returns the ordered set of Instructions that define the input operands of this instruction. // Precondition: SeaGraph.ConvertToSSA(). - std::vector<InstructionNode*> GetSSAUses() { + virtual std::vector<InstructionNode*> GetSSAProducers() { std::vector<int> uses = GetUses(); std::vector<InstructionNode*> ssa_uses; for (std::vector<int>::const_iterator cit = uses.begin(); cit != uses.end(); cit++) { @@ -69,11 +68,15 @@ class InstructionNode: public SeaNode { } return ssa_uses; } - + std::map<int, InstructionNode* >* GetSSAProducersMap() { + return &definition_edges_; + } + std::vector<InstructionNode*>* GetSSAConsumers() { + return &used_in_; + } virtual void AddSSAUse(InstructionNode* use) { used_in_.push_back(use); } - void Accept(IRVisitor* v) { v->Visit(this); v->Traverse(this); @@ -91,11 +94,10 @@ class InstructionNode: public SeaNode { protected: explicit InstructionNode(const art::Instruction* in): SeaNode(), instruction_(in), used_in_(), de_def_(false), region_(NULL) { } - void ToDotSSAEdges(std::string& result) const; protected: const art::Instruction* const instruction_; - std::map<int, InstructionNode* > definition_edges_; + std::map<int, InstructionNode* > definition_edges_; // Maps used registers to their definitions. // Stores pointers to instructions that use the result of the current instruction. std::vector<InstructionNode*> used_in_; bool de_def_; @@ -121,6 +123,7 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { public: explicit UnnamedConstInstructionNode(const art::Instruction* inst, int32_t value): ConstInstructionNode(inst), value_(value) { } + void Accept(IRVisitor* v) { v->Visit(this); v->Traverse(this); @@ -134,19 +137,6 @@ class UnnamedConstInstructionNode: public ConstInstructionNode { return value_; } - void ToDot(std::string& result, const art::DexFile& dex_file) const { - std::ostringstream sstream; - sstream << GetConstValue(); - const std::string value_as_string(sstream.str()); - result += "// Instruction ("+StringId()+"): \n" + StringId() + - " [label=\"const/x v-3, #"+ value_as_string + "\""; - if (de_def_) { - result += "style=bold"; - } - result += "];\n"; - ToDotSSAEdges(result); - } - private: const int32_t value_; }; @@ -176,7 +166,7 @@ class IfNeInstructionNode: public InstructionNode { class MoveResultInstructionNode: public InstructionNode { public: explicit MoveResultInstructionNode(const art::Instruction* inst): InstructionNode(inst) { } - std::vector<int> GetUses() { + std::vector<int> GetUses() const { std::vector<int> uses; // Using vector<> instead of set<> because order matters. uses.push_back(RETURN_REGISTER); return uses; @@ -213,7 +203,7 @@ class AddIntLitInstructionNode: public AddIntInstructionNode { explicit AddIntLitInstructionNode(const art::Instruction* inst): AddIntInstructionNode(inst) { } - std::vector<int> GetUses() { + std::vector<int> GetUses() const { std::vector<int> uses = AddIntInstructionNode::GetUses(); uses.push_back(UNNAMED_CONST_REGISTER); return uses; @@ -245,4 +235,4 @@ class IfEqzInstructionNode: public InstructionNode { } }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_ +#endif // ART_COMPILER_SEA_IR_IR_INSTRUCTION_NODES_H_ diff --git a/compiler/sea_ir/instruction_tools.cc b/compiler/sea_ir/ir/instruction_tools.cc index 9627497805..143209de75 100644 --- a/compiler/sea_ir/instruction_tools.cc +++ b/compiler/sea_ir/ir/instruction_tools.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "instruction_tools.h" +#include "sea_ir/ir/instruction_tools.h" namespace sea_ir { diff --git a/compiler/sea_ir/instruction_tools.h b/compiler/sea_ir/ir/instruction_tools.h index d3871008a4..895e01732a 100644 --- a/compiler/sea_ir/instruction_tools.h +++ b/compiler/sea_ir/ir/instruction_tools.h @@ -17,8 +17,8 @@ #include "sea.h" #include "dex_instruction.h" -#ifndef ART_COMPILER_SEA_IR_INSTRUCTION_TOOLS_H_ -#define ART_COMPILER_SEA_IR_INSTRUCTION_TOOLS_H_ +#ifndef ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_ +#define ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_ // Note: This file has content cannibalized for SEA_IR from the MIR implementation, @@ -122,4 +122,4 @@ class InstructionTools { static const int instruction_attributes_[]; }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_INSTRUCTION_TOOLS_H_ +#endif // ART_COMPILER_SEA_IR_IR_INSTRUCTION_TOOLS_H_ diff --git a/compiler/sea_ir/ir/regions_test.cc b/compiler/sea_ir/ir/regions_test.cc new file mode 100644 index 0000000000..9813465db8 --- /dev/null +++ b/compiler/sea_ir/ir/regions_test.cc @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test.h" +#include "sea_ir/ir/sea.h" + +using utils::ScopedHashtable; + +namespace sea_ir { + +class RegionsTest : public art::CommonTest { +}; + +TEST_F(RegionsTest, Basics) { + sea_ir::SeaGraph sg(*java_lang_dex_file_); + sea_ir::Region* root = sg.GetNewRegion(); + sea_ir::Region* then_region = sg.GetNewRegion(); + sea_ir::Region* else_region = sg.GetNewRegion(); + std::vector<sea_ir::Region*>* regions = sg.GetRegions(); + // Test that regions have been registered correctly as children of the graph. + EXPECT_TRUE(std::find(regions->begin(), regions->end(), root) != regions->end()); + EXPECT_TRUE(std::find(regions->begin(), regions->end(), then_region) != regions->end()); + EXPECT_TRUE(std::find(regions->begin(), regions->end(), else_region) != regions->end()); + // Check that an edge recorded correctly in both the head and the tail. + sg.AddEdge(root, then_region); + std::vector<sea_ir::Region*>* succs = root->GetSuccessors(); + EXPECT_EQ(1U, succs->size()); + EXPECT_EQ(then_region, succs->at(0)); + std::vector<sea_ir::Region*>* preds = then_region->GetPredecessors(); + EXPECT_EQ(1U, preds->size()); + EXPECT_EQ(root, preds->at(0)); + // Check that two edges are recorded properly for both head and tail. + sg.AddEdge(root, else_region); + succs = root->GetSuccessors(); + EXPECT_EQ(2U, succs->size()); + EXPECT_TRUE(std::find(succs->begin(), succs->end(), then_region) != succs->end()); + EXPECT_TRUE(std::find(succs->begin(), succs->end(), else_region) != succs->end()); + preds = then_region->GetPredecessors(); + EXPECT_EQ(1U, preds->size()); + EXPECT_EQ(root, preds->at(0)); + preds = else_region->GetPredecessors(); + EXPECT_EQ(1U, preds->size()); + EXPECT_EQ(root, preds->at(0)); +} + +} // namespace art diff --git a/compiler/sea_ir/sea.cc b/compiler/sea_ir/ir/sea.cc index 99b21f8771..08fe0e1fac 100644 --- a/compiler/sea_ir/sea.cc +++ b/compiler/sea_ir/ir/sea.cc @@ -14,10 +14,10 @@ * limitations under the License. */ #include "base/stringprintf.h" -#include "file_output_stream.h" -#include "instruction_tools.h" -#include "sea.h" -#include "code_gen.h" +#include "sea_ir/ir/instruction_tools.h" +#include "sea_ir/ir/sea.h" +#include "sea_ir/code_gen/code_gen.h" +#include "sea_ir/types/type_inference.h" #define MAX_REACHING_DEF_ITERERATIONS (10) // TODO: When development is done, this define should not @@ -35,7 +35,6 @@ void IRVisitor::Traverse(Region* region) { cit != phis->end(); cit++) { (*cit)->Accept(this); } - std::vector<InstructionNode*>* instructions = region->GetInstructions(); for (std::vector<InstructionNode*>::const_iterator cit = instructions->begin(); cit != instructions->end(); cit++) { @@ -50,24 +49,10 @@ void IRVisitor::Traverse(SeaGraph* graph) { } } -SeaGraph* SeaGraph::GetCurrentGraph(const art::DexFile& dex_file) { +SeaGraph* SeaGraph::GetGraph(const art::DexFile& dex_file) { return new SeaGraph(dex_file); } -void SeaGraph::DumpSea(std::string filename) const { - LOG(INFO) << "Starting to write SEA string to file."; - std::string result; - result += "digraph seaOfNodes {\ncompound=true\n"; - for (std::vector<Region*>::const_iterator cit = regions_.begin(); cit != regions_.end(); cit++) { - (*cit)->ToDot(result, dex_file_); - } - result += "}\n"; - art::File* file = art::OS::OpenFile(filename.c_str(), true, true); - art::FileOutputStream fos(file); - fos.WriteFully(result.c_str(), result.size()); - LOG(INFO) << "Written SEA string to file."; -} - void SeaGraph::AddEdge(Region* src, Region* dst) const { src->AddSuccessor(dst); dst->AddPredecessor(src); @@ -191,10 +176,12 @@ void SeaGraph::ComputeReachingDefs() { void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, uint32_t method_idx) { + const art::DexFile& dex_file, uint32_t class_def_idx, + uint32_t method_idx, uint32_t method_access_flags) { + code_item_ = code_item; class_def_idx_ = class_def_idx; method_idx_ = method_idx; - + method_access_flags_ = method_access_flags; const uint16_t* code = code_item->insns_; const size_t size_in_code_units = code_item->insns_size_in_code_units_; // This maps target instruction pointers to their corresponding region objects. @@ -225,8 +212,9 @@ void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, // Insert one SignatureNode per function argument, // to serve as placeholder definitions in dataflow analysis. for (unsigned int crt_offset = 0; crt_offset < code_item->ins_size_; crt_offset++) { + int position = crt_offset; // TODO: Is this the correct offset in the signature? SignatureNode* parameter_def_node = - new sea_ir::SignatureNode(code_item->registers_size_ - 1 - crt_offset); + new sea_ir::SignatureNode(code_item->registers_size_ - 1 - crt_offset, position); AddParameterNode(parameter_def_node); r->AddChild(parameter_def_node); } @@ -260,12 +248,8 @@ void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, } r = nextRegion; } - bool definesRegister = (0 != InstructionTools::instruction_attributes_[inst->Opcode()] - && (1 << kDA)); - LOG(INFO)<< inst->GetDexPc(code) << "*** " << inst->DumpString(&dex_file) - << " region:" <<r->StringId() << "Definition?" << definesRegister << std::endl; r->AddChild(node); - } + } i += inst->SizeInCodeUnits(); } } @@ -417,10 +401,10 @@ void SeaGraph::GenerateLLVM() { code_gen_postpass_visitor.Write(std::string("my_file.llvm")); } -void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item, - uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file) { +void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file) { // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function. - BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx); + BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx, method_access_flags); // Pass: Compute reverse post-order of regions. ComputeRPO(); // Multiple passes: compute immediate dominators. @@ -433,6 +417,8 @@ void SeaGraph::CompileMethod(const art::DexFile::CodeItem* code_item, ComputeDominanceFrontier(); // Two Passes: Phi node insertion. ConvertToSSA(); + // Pass: type inference + ti_->ComputeTypes(this); // Pass: Generate LLVM IR. GenerateLLVM(); } @@ -465,18 +451,10 @@ void SeaGraph::AddRegion(Region* r) { regions_.push_back(r); } -/* -void SeaNode::AddSuccessor(Region* successor) { - DCHECK(successor) << "Tried to add NULL successor to SEA node."; - successors_.push_back(successor); - return; -} +SeaGraph::SeaGraph(const art::DexFile& df) + :ti_(new TypeInference()), class_def_idx_(0), method_idx_(0), method_access_flags_(), + regions_(), parameters_(), dex_file_(df), code_item_(NULL) { } -void SeaNode::AddPredecessor(Region* predecessor) { - DCHECK(predecessor) << "Tried to add NULL predecessor to SEA node."; - predecessors_.push_back(predecessor); -} -*/ void Region::AddChild(sea_ir::InstructionNode* instruction) { DCHECK(instruction) << "Tried to add NULL instruction to region node."; instructions_.push_back(instruction); @@ -490,46 +468,6 @@ SeaNode* Region::GetLastChild() const { return NULL; } -void Region::ToDot(std::string& result, const art::DexFile& dex_file) const { - result += "\n// Region: \nsubgraph " + StringId() + " { label=\"region " + StringId() + "(rpo="; - result += art::StringPrintf("%d", rpo_number_); - if (NULL != GetIDominator()) { - result += " dom=" + GetIDominator()->StringId(); - } - result += ")\";\n"; - - for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin(); - cit != phi_instructions_.end(); cit++) { - result += (*cit)->StringId() +";\n"; - } - - for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin(); - cit != instructions_.end(); cit++) { - result += (*cit)->StringId() +";\n"; - } - - result += "} // End Region.\n"; - - // Save phi-nodes. - for (std::vector<PhiInstructionNode*>::const_iterator cit = phi_instructions_.begin(); - cit != phi_instructions_.end(); cit++) { - (*cit)->ToDot(result, dex_file); - } - - // Save instruction nodes. - for (std::vector<InstructionNode*>::const_iterator cit = instructions_.begin(); - cit != instructions_.end(); cit++) { - (*cit)->ToDot(result, dex_file); - } - - for (std::vector<Region*>::const_iterator cit = successors_.begin(); cit != successors_.end(); - cit++) { - DCHECK(NULL != *cit) << "Null successor found for SeaNode" << GetLastChild()->StringId() << "."; - result += GetLastChild()->StringId() + " -> " + (*cit)->GetLastChild()->StringId() + - "[lhead=" + (*cit)->StringId() + ", " + "ltail=" + StringId() + "];\n\n"; - } -} - void Region::ComputeDownExposedDefs() { for (std::vector<InstructionNode*>::const_iterator inst_it = instructions_.begin(); inst_it != instructions_.end(); inst_it++) { @@ -692,38 +630,6 @@ std::vector<InstructionNode*> InstructionNode::Create(const art::Instruction* in return sea_instructions; } -void InstructionNode::ToDotSSAEdges(std::string& result) const { - // SSA definitions: - for (std::map<int, InstructionNode*>::const_iterator def_it = definition_edges_.begin(); - def_it != definition_edges_.end(); def_it++) { - if (NULL != def_it->second) { - result += def_it->second->StringId() + " -> " + StringId() + "[color=gray,label=\""; - result += art::StringPrintf("vR = %d", def_it->first); - result += "\"] ; // ssa edge\n"; - } - } - - // SSA used-by: - if (DotConversion::SaveUseEdges()) { - for (std::vector<InstructionNode*>::const_iterator cit = used_in_.begin(); - cit != used_in_.end(); cit++) { - result += (*cit)->StringId() + " -> " + StringId() + "[color=gray,label=\""; - result += "\"] ; // SSA used-by edge\n"; - } - } -} - -void InstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const { - result += "// Instruction ("+StringId()+"): \n" + StringId() + - " [label=\"" + instruction_->DumpString(&dex_file) + "\""; - if (de_def_) { - result += "style=bold"; - } - result += "];\n"; - - ToDotSSAEdges(result); -} - void InstructionNode::MarkAsDEDef() { de_def_ = true; } @@ -747,7 +653,7 @@ std::vector<int> InstructionNode::GetDefinitions() const { return definitions; } -std::vector<int> InstructionNode::GetUses() { +std::vector<int> InstructionNode::GetUses() const { std::vector<int> uses; // Using vector<> instead of set<> because order matters. if (!InstructionTools::IsDefinition(instruction_) && (instruction_->HasVRegA())) { int vA = instruction_->VRegA(); @@ -763,13 +669,4 @@ std::vector<int> InstructionNode::GetUses() { } return uses; } - -void PhiInstructionNode::ToDot(std::string& result, const art::DexFile& dex_file) const { - result += "// PhiInstruction: \n" + StringId() + - " [label=\"" + "PHI("; - result += art::StringPrintf("%d", register_no_); - result += ")\""; - result += "];\n"; - ToDotSSAEdges(result); -} } // namespace sea_ir diff --git a/compiler/sea_ir/sea.h b/compiler/sea_ir/ir/sea.h index 5cb84240ae..0b20ed7d74 100644 --- a/compiler/sea_ir/sea.h +++ b/compiler/sea_ir/ir/sea.h @@ -15,17 +15,18 @@ */ -#ifndef ART_COMPILER_SEA_IR_SEA_H_ -#define ART_COMPILER_SEA_IR_SEA_H_ +#ifndef ART_COMPILER_SEA_IR_IR_SEA_H_ +#define ART_COMPILER_SEA_IR_IR_SEA_H_ #include <set> #include <map> +#include "utils/scoped_hashtable.h" +#include "gtest/gtest_prod.h" #include "dex_file.h" #include "dex_instruction.h" -#include "instruction_tools.h" -#include "instruction_nodes.h" -#include "utils/scoped_hashtable.h" +#include "sea_ir/ir/instruction_tools.h" +#include "sea_ir/ir/instruction_nodes.h" namespace sea_ir { @@ -35,19 +36,9 @@ enum RegionNumbering { VISITING = -2 }; -// Stores options for turning a SEA IR graph to a .dot file. -class DotConversion { - public: - static bool SaveUseEdges() { - return save_use_edges_; - } - - private: - static const bool save_use_edges_ = false; // TODO: Enable per-sea graph configuration. -}; +class TypeInference; class Region; - class InstructionNode; class PhiInstructionNode; class SignatureNode; @@ -57,21 +48,20 @@ class SignatureNode; // can return from the GetSSAUses() calls, instead of having missing SSA edges. class SignatureNode: public InstructionNode { public: - explicit SignatureNode(unsigned int parameter_register):InstructionNode(NULL), - parameter_register_(parameter_register) { } - - void ToDot(std::string& result, const art::DexFile& dex_file) const { - result += StringId() +" [label=\"signature:"; - result += art::StringPrintf("r%d", GetResultRegister()); - result += "\"] // signature node\n"; - ToDotSSAEdges(result); - } + // Creates a new signature node representing the initial definition of the + // register @parameter_register which is the @position-th argument to the method. + explicit SignatureNode(unsigned int parameter_register, unsigned int position): + InstructionNode(NULL), parameter_register_(parameter_register), position_(position) { } int GetResultRegister() const { return parameter_register_; } - std::vector<int> GetUses() { + unsigned int GetPositionInSignature() const { + return position_; + } + + std::vector<int> GetUses() const { return std::vector<int>(); } @@ -81,15 +71,15 @@ class SignatureNode: public InstructionNode { } private: - unsigned int parameter_register_; + const unsigned int parameter_register_; + const unsigned int position_; // The position of this parameter node is + // in the function parameter list. }; class PhiInstructionNode: public InstructionNode { public: explicit PhiInstructionNode(int register_no): InstructionNode(NULL), register_no_(register_no), definition_edges_() {} - // Appends to @result the .dot string representation of the instruction. - void ToDot(std::string& result, const art::DexFile& dex_file) const; // Returns the register on which this phi-function is used. int GetRegisterNumber() const { return register_no_; @@ -113,6 +103,17 @@ class PhiInstructionNode: public InstructionNode { definition->AddSSAUse(this); } + // Returns the ordered set of Instructions that define the input operands of this instruction. + // Precondition: SeaGraph.ConvertToSSA(). + std::vector<InstructionNode*> GetSSAProducers() { + std::vector<InstructionNode*> producers; + for (std::vector<std::vector<InstructionNode*>*>::const_iterator + cit = definition_edges_.begin(); cit != definition_edges_.end(); cit++) { + producers.insert(producers.end(), (*cit)->begin(), (*cit)->end()); + } + return producers; + } + // Returns the instruction that defines the phi register from predecessor // on position @predecessor_pos. Note that the return value is vector<> just // for consistency with the return value of GetSSAUses() on regular instructions, @@ -128,6 +129,9 @@ class PhiInstructionNode: public InstructionNode { private: int register_no_; + // This vector has one entry for each predecessors, each with a single + // element, storing the id of the instruction that defines the register + // corresponding to this phi function. std::vector<std::vector<InstructionNode*>*> definition_edges_; }; @@ -150,10 +154,7 @@ class Region : public SeaNode { std::vector<InstructionNode*>* GetInstructions() { return &instructions_; } - // Appends to @result a dot language formatted string representing the node and - // (by convention) outgoing edges, so that the composition of theToDot() of all nodes - // builds a complete dot graph (without prolog and epilog though). - virtual void ToDot(std::string& result, const art::DexFile& dex_file) const; + // Computes Downward Exposed Definitions for the current node. void ComputeDownExposedDefs(); const std::map<int, sea_ir::InstructionNode*>* GetDownExposedDefs() const; @@ -257,16 +258,14 @@ class Region : public SeaNode { // and acts as starting point for visitors (ex: during code generation). class SeaGraph: IVisitable { public: - static SeaGraph* GetCurrentGraph(const art::DexFile&); + static SeaGraph* GetGraph(const art::DexFile&); - void CompileMethod(const art::DexFile::CodeItem* code_item, - uint32_t class_def_idx, uint32_t method_idx, const art::DexFile& dex_file); + void CompileMethod(const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file); // Returns all regions corresponding to this SeaGraph. std::vector<Region*>* GetRegions() { return ®ions_; } - // Returns a string representation of the region and its Instruction children. - void DumpSea(std::string filename) const; // Recursively computes the reverse postorder value for @crt_bb and successors. static void ComputeRPO(Region* crt_bb, int& crt_rpo); // Returns the "lowest common ancestor" of @i and @j in the dominator tree. @@ -275,13 +274,28 @@ class SeaGraph: IVisitable { std::vector<SignatureNode*>* GetParameterNodes() { return ¶meters_; } + + const art::DexFile* GetDexFile() const { + return &dex_file_; + } + + virtual void Accept(IRVisitor* visitor) { + visitor->Initialize(this); + visitor->Visit(this); + visitor->Traverse(this); + } + + TypeInference* ti_; uint32_t class_def_idx_; uint32_t method_idx_; + uint32_t method_access_flags_; + + protected: + explicit SeaGraph(const art::DexFile& df); + virtual ~SeaGraph() { } private: - explicit SeaGraph(const art::DexFile& df): - class_def_idx_(0), method_idx_(0), regions_(), parameters_(), dex_file_(df) { - } + FRIEND_TEST(RegionsTest, Basics); // Registers @childReg as a region belonging to the SeaGraph instance. void AddRegion(Region* childReg); // Returns new region and registers it with the SeaGraph instance. @@ -295,7 +309,8 @@ class SeaGraph: IVisitable { // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file // with class id @class_def_idx and method id @method_idx. void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, uint32_t method_idx); + const art::DexFile& dex_file, uint32_t class_def_idx, + uint32_t method_idx, uint32_t method_access_flags); // Computes immediate dominators for each region. // Precondition: ComputeMethodSeaGraph() void ComputeIDominators(); @@ -320,14 +335,6 @@ class SeaGraph: IVisitable { // Identifies the definitions corresponding to uses for region @node // by using the scoped hashtable of names @ scoped_table. void RenameAsSSA(Region* node, utils::ScopedHashtable<int, InstructionNode*>* scoped_table); - - virtual void Accept(IRVisitor* visitor) { - visitor->Initialize(this); - visitor->Visit(this); - visitor->Traverse(this); - } - - virtual ~SeaGraph() {} // Generate LLVM IR for the method. // Precondition: ConvertToSSA(). void GenerateLLVM(); @@ -336,6 +343,7 @@ class SeaGraph: IVisitable { std::vector<Region*> regions_; std::vector<SignatureNode*> parameters_; const art::DexFile& dex_file_; + const art::DexFile::CodeItem* code_item_; }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_SEA_H_ +#endif // ART_COMPILER_SEA_IR_IR_SEA_H_ diff --git a/compiler/sea_ir/sea_node.h b/compiler/sea_ir/ir/sea_node.h index c13e5d6aba..4dab5cba83 100644 --- a/compiler/sea_ir/sea_node.h +++ b/compiler/sea_ir/ir/sea_node.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_SEA_IR_SEA_NODE_H_ -#define ART_COMPILER_SEA_IR_SEA_NODE_H_ +#ifndef ART_COMPILER_SEA_IR_IR_SEA_NODE_H_ +#define ART_COMPILER_SEA_IR_IR_SEA_NODE_H_ #include "base/stringprintf.h" @@ -56,10 +56,6 @@ class SeaNode: public IVisitable { int Id() const { return id_; } - // Appends to @result a dot language formatted string representing the node and - // (by convention) outgoing edges, so that the composition of theToDot() of all nodes - // builds a complete dot graph, but without prolog ("digraph {") and epilog ("}"). - virtual void ToDot(std::string& result, const art::DexFile& dex_file) const = 0; virtual ~SeaNode() { } @@ -78,4 +74,4 @@ class SeaNode: public IVisitable { DISALLOW_COPY_AND_ASSIGN(SeaNode); }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_SEA_NODE_H_ +#endif // ART_COMPILER_SEA_IR_IR_SEA_NODE_H_ diff --git a/compiler/sea_ir/visitor.h b/compiler/sea_ir/ir/visitor.h index a4fec7b8a9..cc7b5d153f 100644 --- a/compiler/sea_ir/visitor.h +++ b/compiler/sea_ir/ir/visitor.h @@ -14,16 +14,8 @@ * limitations under the License. */ -#ifndef ART_COMPILER_SEA_IR_VISITOR_H_ -#define ART_COMPILER_SEA_IR_VISITOR_H_ - -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Analysis/Verifier.h" -// TODO: Separating the root visitor from the code_gen visitor -// would allow me to not include llvm headers here. - +#ifndef ART_COMPILER_SEA_IR_IR_VISITOR_H_ +#define ART_COMPILER_SEA_IR_IR_VISITOR_H_ namespace sea_ir { @@ -32,6 +24,7 @@ class Region; class InstructionNode; class PhiInstructionNode; class SignatureNode; +class UnnamedConstInstructionNode; class ConstInstructionNode; class ReturnInstructionNode; class IfNeInstructionNode; @@ -48,7 +41,7 @@ class IfEqzInstructionNode; class IRVisitor { public: - explicit IRVisitor():ordered_regions_() { } + explicit IRVisitor(): ordered_regions_() { } virtual void Initialize(SeaGraph* graph) = 0; virtual void Visit(SeaGraph* graph) = 0; virtual void Visit(Region* region) = 0; @@ -57,16 +50,16 @@ class IRVisitor { virtual void Visit(InstructionNode* region) = 0; virtual void Visit(ConstInstructionNode* instruction) = 0; + virtual void Visit(UnnamedConstInstructionNode* instruction) = 0; virtual void Visit(ReturnInstructionNode* instruction) = 0; virtual void Visit(IfNeInstructionNode* instruction) = 0; - // virtual void Visit(AddIntLitInstructionNode* instruction) = 0; virtual void Visit(MoveResultInstructionNode* instruction) = 0; virtual void Visit(InvokeStaticInstructionNode* instruction) = 0; virtual void Visit(AddIntInstructionNode* instruction) = 0; virtual void Visit(GotoInstructionNode* instruction) = 0; virtual void Visit(IfEqzInstructionNode* instruction) = 0; - // Note: This favor of visitor separates the traversal functions from the actual visiting part + // Note: This flavor of visitor separates the traversal functions from the actual visiting part // so that the Visitor subclasses don't duplicate code and can't get the traversal wrong. // The disadvantage is the increased number of functions (and calls). virtual void Traverse(SeaGraph* graph); @@ -91,4 +84,4 @@ class IRVisitor { std::vector<Region*> ordered_regions_; }; } // namespace sea_ir -#endif // ART_COMPILER_SEA_IR_VISITOR_H_ +#endif // ART_COMPILER_SEA_IR_IR_VISITOR_H_ diff --git a/compiler/sea_ir/types/type_data_test.cc b/compiler/sea_ir/types/type_data_test.cc new file mode 100644 index 0000000000..a66ebce38f --- /dev/null +++ b/compiler/sea_ir/types/type_data_test.cc @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test.h" +#include "sea_ir/types/types.h" + +namespace sea_ir { + +class TypeDataTest : public art::CommonTest { +}; + +TEST_F(TypeDataTest, Basics) { + TypeData td; + art::verifier::RegTypeCache type_cache(false); + int first_instruction_id = 1; + int second_instruction_id = 3; + EXPECT_TRUE(NULL == td.FindTypeOf(first_instruction_id)); + const Type* int_type = &type_cache.Integer(); + const Type* byte_type = &type_cache.Byte(); + td.SetTypeOf(first_instruction_id, int_type); + EXPECT_TRUE(int_type == td.FindTypeOf(first_instruction_id)); + EXPECT_TRUE(NULL == td.FindTypeOf(second_instruction_id)); + td.SetTypeOf(second_instruction_id, byte_type); + EXPECT_TRUE(int_type == td.FindTypeOf(first_instruction_id)); + EXPECT_TRUE(byte_type == td.FindTypeOf(second_instruction_id)); +} + +} // namespace art diff --git a/compiler/sea_ir/types/type_inference.cc b/compiler/sea_ir/types/type_inference.cc new file mode 100644 index 0000000000..31d7f0f8b6 --- /dev/null +++ b/compiler/sea_ir/types/type_inference.cc @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "scoped_thread_state_change.h" +#include "sea_ir/types/type_inference.h" +#include "sea_ir/types/type_inference_visitor.h" +#include "sea_ir/ir/sea.h" + +namespace sea_ir { + +bool TypeInference::IsPrimitiveDescriptor(char descriptor) { + switch (descriptor) { + case 'I': + case 'C': + case 'S': + case 'B': + case 'Z': + case 'F': + case 'D': + case 'J': + return true; + default: + return false; + } +} + +FunctionTypeInfo::FunctionTypeInfo(const SeaGraph* graph, art::verifier::RegTypeCache* types) + : dex_file_(graph->GetDexFile()), dex_method_idx_(graph->method_idx_), type_cache_(types), + method_access_flags_(graph->method_access_flags_) { + const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); + const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); + declaring_class_ = &(type_cache_->FromDescriptor(NULL, descriptor, false)); +} + +FunctionTypeInfo::FunctionTypeInfo(const SeaGraph* graph, InstructionNode* inst, + art::verifier::RegTypeCache* types): dex_file_(graph->GetDexFile()), + dex_method_idx_(inst->GetInstruction()->VRegB_35c()), type_cache_(types), + method_access_flags_(0) { + // TODO: Test that GetDeclaredArgumentTypes() works correctly when using this constructor. + const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); + const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); + declaring_class_ = &(type_cache_->FromDescriptor(NULL, descriptor, false)); +} + +const Type* FunctionTypeInfo::GetReturnValueType() { + const art::DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); + uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; + const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); + art::ScopedObjectAccess soa(art::Thread::Current()); + const Type& return_type = type_cache_->FromDescriptor(NULL, descriptor, false); + return &return_type; +} + + + +std::vector<const Type*> FunctionTypeInfo::GetDeclaredArgumentTypes() { + art::ScopedObjectAccess soa(art::Thread::Current()); + std::vector<const Type*> argument_types; + // Include the "this" pointer. + size_t cur_arg = 0; + if (!IsStatic()) { + // If this is a constructor for a class other than java.lang.Object, mark the first ("this") + // argument as uninitialized. This restricts field access until the superclass constructor is + // called. + const art::verifier::RegType& declaring_class = GetDeclaringClass(); + if (IsConstructor() && !declaring_class.IsJavaLangObject()) { + argument_types.push_back(&(type_cache_->UninitializedThisArgument(declaring_class))); + } else { + argument_types.push_back(&declaring_class); + } + cur_arg++; + } + + const art::DexFile::ProtoId& proto_id = + dex_file_->GetMethodPrototype(dex_file_->GetMethodId(dex_method_idx_)); + art::DexFileParameterIterator iterator(*dex_file_, proto_id); + + for (; iterator.HasNext(); iterator.Next()) { + const char* descriptor = iterator.GetDescriptor(); + if (descriptor == NULL) { + LOG(FATAL) << "Error: Encountered null type descriptor for function argument."; + } + switch (descriptor[0]) { + case 'L': + case '[': + // We assume that reference arguments are initialized. The only way it could be otherwise + // (assuming the caller was verified) is if the current method is <init>, but in that case + // it's effectively considered initialized the instant we reach here (in the sense that we + // can return without doing anything or call virtual methods). + { + const Type& reg_type = type_cache_->FromDescriptor(NULL, descriptor, false); + argument_types.push_back(®_type); + } + break; + case 'Z': + argument_types.push_back(&type_cache_->Boolean()); + break; + case 'C': + argument_types.push_back(&type_cache_->Char()); + break; + case 'B': + argument_types.push_back(&type_cache_->Byte()); + break; + case 'I': + argument_types.push_back(&type_cache_->Integer()); + break; + case 'S': + argument_types.push_back(&type_cache_->Short()); + break; + case 'F': + argument_types.push_back(&type_cache_->Float()); + break; + case 'J': + case 'D': { + // TODO: Figure out strategy for two-register operands (double, long) + LOG(FATAL) << "Error: Type inference for 64-bit variables has not been implemented."; + break; + } + default: + LOG(FATAL) << "Error: Unexpected signature encountered during type inference."; + } + cur_arg++; + } + return argument_types; +} + +// TODO: Lock is only used for dumping types (during development). Remove this for performance. +void TypeInference::ComputeTypes(SeaGraph* graph) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + std::vector<Region*>* regions = graph->GetRegions(); + std::list<InstructionNode*> worklist; + // Fill the work-list with all instructions. + for (std::vector<Region*>::const_iterator region_it = regions->begin(); + region_it != regions->end(); region_it++) { + std::vector<PhiInstructionNode*>* phi_instructions = (*region_it)->GetPhiNodes(); + std::copy(phi_instructions->begin(), phi_instructions->end(), std::back_inserter(worklist)); + std::vector<InstructionNode*>* instructions = (*region_it)->GetInstructions(); + std::copy(instructions->begin(), instructions->end(), std::back_inserter(worklist)); + } + TypeInferenceVisitor tiv(graph, &type_data_, type_cache_); + // Sparse (SSA) fixed-point algorithm that processes each instruction in the work-list, + // adding consumers of instructions whose result changed type back into the work-list. + // Note: According to [1] list iterators should not be invalidated on insertion, + // which simplifies the implementation; not 100% sure other STL implementations + // maintain this invariant, but they should. + // [1] http://www.sgi.com/tech/stl/List.html + // TODO: Making this conditional (as in sparse conditional constant propagation) would be good. + // TODO: Remove elements as I go. + for (std::list<InstructionNode*>::const_iterator instruction_it = worklist.begin(); + instruction_it != worklist.end(); instruction_it++) { + std::cout << "[TI] Instruction: " << (*instruction_it)->Id() << std::endl; + (*instruction_it)->Accept(&tiv); + const Type* old_type = type_data_.FindTypeOf((*instruction_it)->Id()); + const Type* new_type = tiv.GetType(); + bool type_changed = (old_type != new_type); + if (type_changed) { + std::cout << " New type:" << new_type->IsIntegralTypes() << std::endl; + std::cout << " Descrip:" << new_type->Dump()<< " on " << (*instruction_it)->Id() << std::endl; + type_data_.SetTypeOf((*instruction_it)->Id(), new_type); + // Add SSA consumers of the current instruction to the work-list. + std::vector<InstructionNode*>* consumers = (*instruction_it)->GetSSAConsumers(); + for (std::vector<InstructionNode*>::iterator consumer = consumers->begin(); + consumer != consumers->end(); consumer++) { + worklist.push_back(*consumer); + } + } + } +} +} // namespace sea_ir diff --git a/compiler/sea_ir/types/type_inference.h b/compiler/sea_ir/types/type_inference.h new file mode 100644 index 0000000000..d951d82071 --- /dev/null +++ b/compiler/sea_ir/types/type_inference.h @@ -0,0 +1,94 @@ +/* + * 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_SEA_IR_TYPES_TYPE_INFERENCE_H_ +#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_ + +#include "safe_map.h" +#include "dex_file-inl.h" +#include "sea_ir/types/types.h" + +namespace sea_ir { + +class SeaGraph; +class InstructionNode; + +// The type inference in SEA IR is different from the verifier in that it is concerned +// with a rich type hierarchy (TODO) usable in optimization and does not perform +// precise verification (which is the job of the verifier). +class TypeInference { + public: + TypeInference() { + type_cache_ = new art::verifier::RegTypeCache(false); + } + + // Computes the types for the method with SEA IR representation provided by @graph. + void ComputeTypes(SeaGraph* graph); + + art::SafeMap<int, const Type*>* GetTypeMap() { + return type_data_.GetTypeMap(); + } + // Returns true if @descriptor corresponds to a primitive type. + static bool IsPrimitiveDescriptor(char descriptor); + + protected: + art::verifier::RegTypeCache* type_cache_; + TypeData type_data_; +}; + +// Stores information about the exact type of a function. +class FunctionTypeInfo { + public: + // Finds method information about the method encoded by a SEA IR graph. + // @graph provides the input method SEA IR representation. + // @types provides the input cache of types from which the + // parameter types of the function are found. + FunctionTypeInfo(const SeaGraph* graph, art::verifier::RegTypeCache* types); + // Finds method information about the method encoded by + // an invocation instruction in a SEA IR graph. + // @graph provides the input method SEA IR representation. + // @inst is an invocation instruction for the desired method. + // @types provides the input cache of types from which the + // parameter types of the function are found. + FunctionTypeInfo(const SeaGraph* graph, InstructionNode* inst, + art::verifier::RegTypeCache* types); + // Returns the ordered vector of types corresponding to the function arguments. + std::vector<const Type*> GetDeclaredArgumentTypes(); + // Returns the declared return value type. + const Type* GetReturnValueType(); + // Returns the type corresponding to the class that declared the method. + const Type& GetDeclaringClass() { + return *declaring_class_; + } + + bool IsConstructor() const { + return (method_access_flags_ & kAccConstructor) != 0; + } + + bool IsStatic() const { + return (method_access_flags_ & kAccStatic) != 0; + } + + protected: + const Type* declaring_class_; + const art::DexFile* dex_file_; + const uint32_t dex_method_idx_; + art::verifier::RegTypeCache* type_cache_; + const uint32_t method_access_flags_; // Method's access flags. +}; +} // namespace sea_ir + +#endif // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_H_ diff --git a/compiler/sea_ir/types/type_inference_visitor.cc b/compiler/sea_ir/types/type_inference_visitor.cc new file mode 100644 index 0000000000..3da2fc1e2c --- /dev/null +++ b/compiler/sea_ir/types/type_inference_visitor.cc @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "scoped_thread_state_change.h" +#include "sea_ir/types/type_inference_visitor.h" +#include "sea_ir/types/type_inference.h" +#include "sea_ir/ir/sea.h" + +namespace sea_ir { + +void TypeInferenceVisitor::Visit(SignatureNode* parameter) { + FunctionTypeInfo fti(graph_, type_cache_); + std::vector<const Type*> arguments = fti.GetDeclaredArgumentTypes(); + DCHECK_LT(parameter->GetPositionInSignature(), arguments.size()) + << "Signature node position not present in signature."; + crt_type_.push_back(arguments.at(parameter->GetPositionInSignature())); +} + +void TypeInferenceVisitor::Visit(UnnamedConstInstructionNode* instruction) { + crt_type_.push_back(&type_cache_->Integer()); +} + +void TypeInferenceVisitor::Visit(PhiInstructionNode* instruction) { + std::vector<const Type*> types_to_merge = GetOperandTypes(instruction); + const Type* result_type = MergeTypes(types_to_merge); + crt_type_.push_back(result_type); +} + +void TypeInferenceVisitor::Visit(AddIntInstructionNode* instruction) { + std::vector<const Type*> operand_types = GetOperandTypes(instruction); + for (std::vector<const Type*>::const_iterator cit = operand_types.begin(); + cit != operand_types.end(); cit++) { + if (*cit != NULL) { + DCHECK((*cit)->IsInteger()); + } + } + crt_type_.push_back(&type_cache_->Integer()); +} + +void TypeInferenceVisitor::Visit(MoveResultInstructionNode* instruction) { + std::vector<const Type*> operand_types = GetOperandTypes(instruction); + const Type* operand_type = operand_types.at(0); + crt_type_.push_back(operand_type); +} + +void TypeInferenceVisitor::Visit(InvokeStaticInstructionNode* instruction) { + FunctionTypeInfo fti(graph_, instruction, type_cache_); + const Type* result_type = fti.GetReturnValueType(); + crt_type_.push_back(result_type); +} + +std::vector<const Type*> TypeInferenceVisitor::GetOperandTypes( + InstructionNode* instruction) const { + std::vector<InstructionNode*> sources = instruction->GetSSAProducers(); + std::vector<const Type*> types_to_merge; + for (std::vector<InstructionNode*>::const_iterator cit = sources.begin(); cit != sources.end(); + cit++) { + const Type* source_type = type_data_->FindTypeOf((*cit)->Id()); + if (source_type != NULL) { + types_to_merge.push_back(source_type); + } + } + return types_to_merge; +} + +const Type* TypeInferenceVisitor::MergeTypes(std::vector<const Type*>& types) const { + const Type* type = NULL; + if (types.size()>0) { + type = *(types.begin()); + if (types.size()>1) { + for (std::vector<const Type*>::const_iterator cit = types.begin(); + cit != types.end(); cit++) { + if (!type->Equals(**cit)) { + type = MergeTypes(type, *cit); + } + } + } + } + return type; +} + +const Type* TypeInferenceVisitor::MergeTypes(const Type* t1, const Type* t2) const { + DCHECK(t2 != NULL); + DCHECK(t1 != NULL); + art::ScopedObjectAccess soa(art::Thread::Current()); + const Type* result = &(t1->Merge(*t2, type_cache_)); + return result; +} + +} // namespace sea_ir diff --git a/compiler/sea_ir/types/type_inference_visitor.h b/compiler/sea_ir/types/type_inference_visitor.h new file mode 100644 index 0000000000..200b9f0253 --- /dev/null +++ b/compiler/sea_ir/types/type_inference_visitor.h @@ -0,0 +1,81 @@ +/* + * 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_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_ +#define ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_ + + +#include "dex_file-inl.h" +#include "sea_ir/ir/visitor.h" +#include "sea_ir/types/types.h" + +namespace sea_ir { + +// The TypeInferenceVisitor visits each instruction and computes its type taking into account +// the current type of the operands. The type is stored in the visitor. +// We may be better off by using a separate visitor type hierarchy that has return values +// or that passes data as parameters, than to use fields to store information that should +// in fact be returned after visiting each element. Ideally, I would prefer to use templates +// to specify the returned value type, but I am not aware of a possible implementation +// that does not horribly duplicate the visitor infrastructure code (version 1: no return value, +// version 2: with template return value). +class TypeInferenceVisitor: public IRVisitor { + public: + TypeInferenceVisitor(SeaGraph* graph, TypeData* type_data, + art::verifier::RegTypeCache* types): + graph_(graph), type_data_(type_data), type_cache_(types), crt_type_() { + } + // There are no type related actions to be performed on these classes. + void Initialize(SeaGraph* graph) { } + void Visit(SeaGraph* graph) { } + void Visit(Region* region) { } + + void Visit(PhiInstructionNode* instruction); + void Visit(SignatureNode* parameter); + void Visit(InstructionNode* instruction) { } + void Visit(UnnamedConstInstructionNode* instruction); + void Visit(ConstInstructionNode* instruction) { } + void Visit(ReturnInstructionNode* instruction) { } + void Visit(IfNeInstructionNode* instruction) { } + void Visit(MoveResultInstructionNode* instruction); + void Visit(InvokeStaticInstructionNode* instruction); + void Visit(AddIntInstructionNode* instruction); + void Visit(GotoInstructionNode* instruction) { } + void Visit(IfEqzInstructionNode* instruction) { } + + const Type* MergeTypes(std::vector<const Type*>& types) const; + const Type* MergeTypes(const Type* t1, const Type* t2) const; + std::vector<const Type*> GetOperandTypes(InstructionNode* instruction) const; + const Type* GetType() { + // TODO: Currently multiple defined types are not supported. + if (crt_type_.size()>0) { + const Type* single_type = crt_type_.at(0); + crt_type_.clear(); + return single_type; + } + return NULL; + } + + protected: + const SeaGraph* const graph_; + TypeData* type_data_; + art::verifier::RegTypeCache* type_cache_; + std::vector<const Type*> crt_type_; // Stored temporarily between two calls to Visit. +}; + +} // namespace sea_ir + +#endif // ART_COMPILER_SEA_IR_TYPES_TYPE_INFERENCE_VISITOR_H_ diff --git a/compiler/sea_ir/types/type_inference_visitor_test.cc b/compiler/sea_ir/types/type_inference_visitor_test.cc new file mode 100644 index 0000000000..8a249ebceb --- /dev/null +++ b/compiler/sea_ir/types/type_inference_visitor_test.cc @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_test.h" +#include "sea_ir/types/type_inference_visitor.h" +#include "sea_ir/ir/sea.h" + +namespace sea_ir { + +class TestInstructionNode:public InstructionNode { + public: + explicit TestInstructionNode(std::vector<InstructionNode*> prods): InstructionNode(NULL), + producers_(prods) { } + std::vector<InstructionNode*> GetSSAProducers() { + return producers_; + } + protected: + std::vector<InstructionNode*> producers_; +}; + +class TypeInferenceVisitorTest : public art::CommonTest { +}; + +TEST_F(TypeInferenceVisitorTest, MergeIntWithByte) { + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + const Type* int_type = &type_cache.Integer(); + const Type* byte_type = &type_cache.Byte(); + const Type* ib_type = tiv.MergeTypes(int_type, byte_type); + const Type* bi_type = tiv.MergeTypes(byte_type, int_type); + EXPECT_TRUE(ib_type == int_type); + EXPECT_TRUE(bi_type == int_type); +} + +TEST_F(TypeInferenceVisitorTest, MergeIntWithShort) { + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + const Type* int_type = &type_cache.Integer(); + const Type* short_type = &type_cache.Short(); + const Type* is_type = tiv.MergeTypes(int_type, short_type); + const Type* si_type = tiv.MergeTypes(short_type, int_type); + EXPECT_TRUE(is_type == int_type); + EXPECT_TRUE(si_type == int_type); +} + +TEST_F(TypeInferenceVisitorTest, MergeMultipleInts) { + int N = 10; // Number of types to merge. + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + std::vector<const Type*> types; + for (int i = 0; i < N; i++) { + const Type* new_type = &type_cache.Integer(); + types.push_back(new_type); + } + const Type* merged_type = tiv.MergeTypes(types); + EXPECT_TRUE(merged_type == &type_cache.Integer()); +} + +TEST_F(TypeInferenceVisitorTest, MergeMultipleShorts) { + int N = 10; // Number of types to merge. + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + std::vector<const Type*> types; + for (int i = 0; i < N; i++) { + const Type* new_type = &type_cache.Short(); + types.push_back(new_type); + } + const Type* merged_type = tiv.MergeTypes(types); + EXPECT_TRUE(merged_type == &type_cache.Short()); +} + +TEST_F(TypeInferenceVisitorTest, MergeMultipleIntsWithShorts) { + int N = 10; // Number of types to merge. + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + std::vector<const Type*> types; + for (int i = 0; i < N; i++) { + const Type* short_type = &type_cache.Short(); + const Type* int_type = &type_cache.Integer(); + types.push_back(short_type); + types.push_back(int_type); + } + const Type* merged_type = tiv.MergeTypes(types); + EXPECT_TRUE(merged_type == &type_cache.Integer()); +} + +TEST_F(TypeInferenceVisitorTest, GetOperandTypes) { + int N = 10; // Number of types to merge. + TypeData td; + art::verifier::RegTypeCache type_cache(false); + TypeInferenceVisitor tiv(NULL, &td, &type_cache); + std::vector<const Type*> types; + std::vector<InstructionNode*> preds; + for (int i = 0; i < N; i++) { + const Type* short_type = &type_cache.Short(); + const Type* int_type = &type_cache.Integer(); + TestInstructionNode* short_inst = + new TestInstructionNode(std::vector<InstructionNode*>()); + TestInstructionNode* int_inst = + new TestInstructionNode(std::vector<InstructionNode*>()); + preds.push_back(short_inst); + preds.push_back(int_inst); + td.SetTypeOf(short_inst->Id(), short_type); + td.SetTypeOf(int_inst->Id(), int_type); + types.push_back(short_type); + types.push_back(int_type); + } + TestInstructionNode* inst_to_test = new TestInstructionNode(preds); + std::vector<const Type*> result = tiv.GetOperandTypes(inst_to_test); + EXPECT_TRUE(result.size() == types.size()); + EXPECT_TRUE(true == std::equal(types.begin(), types.begin() + 2, result.begin())); +} + + +} // namespace art diff --git a/compiler/sea_ir/types/types.h b/compiler/sea_ir/types/types.h new file mode 100644 index 0000000000..64f25243d0 --- /dev/null +++ b/compiler/sea_ir/types/types.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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_SEA_IR_TYPES_TYPES_H_ +#define ART_COMPILER_SEA_IR_TYPES_TYPES_H_ + +#include "safe_map.h" +#include "verifier/reg_type.h" +#include "verifier/reg_type_cache.h" + +namespace sea_ir { + +// TODO: Replace typedef with an actual class implementation when we have more types. +typedef art::verifier::RegType Type; + +// Stores information about the result type of each instruction. +// Note: Main purpose is to encapsulate the map<instruction id, type*>, +// so that we can replace the underlying storage at any time. +class TypeData { + public: + art::SafeMap<int, const Type*>* GetTypeMap() { + return &type_map_; + } + // Returns the type associated with instruction with @instruction_id. + const Type* FindTypeOf(int instruction_id) { + art::SafeMap<int, const Type*>::const_iterator result_it = type_map_.find(instruction_id); + if (type_map_.end() != result_it) { + return result_it->second; + } + return NULL; + } + + // Saves the fact that instruction @instruction_id produces a value of type @type. + void SetTypeOf(int instruction_id, const Type* type) { + type_map_.Overwrite(instruction_id, type); + } + + private: + art::SafeMap<int, const Type*> type_map_; +}; + + + +} // namespace sea_ir +#endif // ART_COMPILER_SEA_IR_TYPES_TYPES_H_ diff --git a/compiler/utils/scoped_hashtable_test.cc b/compiler/utils/scoped_hashtable_test.cc index d5f9f7d035..68608f01d1 100644 --- a/compiler/utils/scoped_hashtable_test.cc +++ b/compiler/utils/scoped_hashtable_test.cc @@ -15,7 +15,7 @@ */ #include "common_test.h" -#include "scoped_hashtable.h" +#include "utils/scoped_hashtable.h" using utils::ScopedHashtable; |