From a2c211ca97cce4d900a6b2047049ffbe46fd5890 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Thu, 1 Nov 2018 09:50:52 +0000 Subject: Add compiling class to the DexCompilationUnit. Use it to simplify HInstructionBuilder and reduce the number of class resolution calls. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Test: Pixel 2 XL boots. Change-Id: Ib4f9b4ea61235841e653a03a40755a39c7de7504 --- compiler/optimizing/inliner.cc | 4 +- compiler/optimizing/instruction_builder.cc | 123 +++++++++-------------------- compiler/optimizing/instruction_builder.h | 19 +---- compiler/optimizing/optimizing_compiler.cc | 38 +++++---- 4 files changed, 67 insertions(+), 117 deletions(-) (limited to 'compiler/optimizing') diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index dd781c288f..f9e9abbdfd 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1757,6 +1757,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, caller_compilation_unit_.GetClassLoader(), handles_); + Handle compiling_class = handles_->NewHandle(resolved_method->GetDeclaringClass()); DexCompilationUnit dex_compilation_unit( class_loader, class_linker, @@ -1766,7 +1767,8 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, method_index, resolved_method->GetAccessFlags(), /* verified_method */ nullptr, - dex_cache); + dex_cache, + compiling_class); InvokeType invoke_type = invoke_instruction->GetInvokeType(); if (invoke_type == kInterface) { diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 63b2705b43..3747d8224b 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -849,7 +849,7 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in // make this an invoke-unresolved to handle cross-dex invokes or abstract super methods, both of // which require runtime handling. if (invoke_type == kSuper) { - ObjPtr compiling_class = ResolveCompilingClass(soa); + ObjPtr compiling_class = dex_compilation_unit_->GetCompilingClass().Get(); if (compiling_class == nullptr) { // We could not determine the method's class we need to wait until runtime. DCHECK(Runtime::Current()->IsAotCompiler()); @@ -969,7 +969,7 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, ScopedObjectAccess soa(Thread::Current()); if (invoke_type == kStatic) { clinit_check = - ProcessClinitCheckForInvoke(soa, dex_pc, resolved_method, &clinit_check_requirement); + ProcessClinitCheckForInvoke(dex_pc, resolved_method, &clinit_check_requirement); } else if (invoke_type == kSuper) { if (IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { // Update the method index to the one resolved. Note that this may be a no-op if @@ -1055,7 +1055,7 @@ HNewInstance* HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, u HInstruction* cls = load_class; Handle klass = load_class->GetClass(); - if (!IsInitialized(soa, klass)) { + if (!IsInitialized(klass)) { cls = new (allocator_) HClinitCheck(load_class, dex_pc); AppendInstruction(cls); } @@ -1284,7 +1284,7 @@ static bool HasTrivialInitialization(ObjPtr cls, return true; } -bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle cls) const { +bool HInstructionBuilder::IsInitialized(Handle cls) const { if (cls == nullptr) { return false; } @@ -1312,29 +1312,20 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle outermost_cls = ResolveOutermostCompilingClass(soa); - bool is_outer_static_or_constructor = - (outer_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u; - if (is_outer_static_or_constructor && outermost_cls == cls.Get()) { + auto is_static_method_or_constructor_of_cls = [cls](const DexCompilationUnit& compilation_unit) + REQUIRES_SHARED(Locks::mutator_lock_) { + return (compilation_unit.GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u && + compilation_unit.GetCompilingClass().Get() == cls.Get(); + }; + if (is_static_method_or_constructor_of_cls(*outer_compilation_unit_) || + // Check also the innermost method. Though excessive copies of ClinitCheck can be + // eliminated by GVN, that happens only after the decision whether to inline the + // graph or not and that may depend on the presence of the ClinitCheck. + // TODO: We should walk over the entire inlined method chain, but we don't pass that + // information to the builder. + is_static_method_or_constructor_of_cls(*dex_compilation_unit_)) { return true; } - // Remember if the compiled class is a subclass of `cls`. By the time this is used - // below the `outermost_cls` may be invalidated by calling ResolveCompilingClass(). - bool is_subclass = IsSubClass(outermost_cls, cls.Get()); - if (dex_compilation_unit_ != outer_compilation_unit_) { - // Check also the innermost method. Though excessive copies of ClinitCheck can be - // eliminated by GVN, that happens only after the decision whether to inline the - // graph or not and that may depend on the presence of the ClinitCheck. - // TODO: We should walk over the entire inlined method chain, but we don't pass that - // information to the builder. - ObjPtr innermost_cls = ResolveCompilingClass(soa); - bool is_inner_static_or_constructor = - (dex_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u; - if (is_inner_static_or_constructor && innermost_cls == cls.Get()) { - return true; - } - is_subclass = is_subclass || IsSubClass(innermost_cls, cls.Get()); - } // Otherwise, we may be able to avoid the check if `cls` is a superclass of a method being // compiled here (anywhere in the inlining chain) as the `cls` must have started initializing @@ -1355,6 +1346,11 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, HandleGetCompilingClass().Get(), cls.Get()); + if (dex_compilation_unit_ != outer_compilation_unit_) { + is_subclass = is_subclass || + IsSubClass(dex_compilation_unit_->GetCompilingClass().Get(), cls.Get()); + } if (is_subclass && HasTrivialInitialization(cls.Get(), compiler_driver_->GetCompilerOptions())) { return true; } @@ -1363,18 +1359,16 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle klass = handles_->NewHandle(resolved_method->GetDeclaringClass()); HClinitCheck* clinit_check = nullptr; - if (IsInitialized(soa, klass)) { + if (IsInitialized(klass)) { *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone; } else { - HLoadClass* cls = BuildLoadClass(soa, - klass->GetDexTypeIndex(), + HLoadClass* cls = BuildLoadClass(klass->GetDexTypeIndex(), klass->GetDexFile(), klass, dex_pc, @@ -1610,43 +1604,6 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio return true; } -static ObjPtr ResolveClassFrom(ScopedObjectAccess& soa, - CompilerDriver* driver, - const DexCompilationUnit& compilation_unit) - REQUIRES_SHARED(Locks::mutator_lock_) { - Handle class_loader = compilation_unit.GetClassLoader(); - Handle dex_cache = compilation_unit.GetDexCache(); - - return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit); -} - -ObjPtr HInstructionBuilder::ResolveOutermostCompilingClass( - ScopedObjectAccess& soa) const { - return ResolveClassFrom(soa, compiler_driver_, *outer_compilation_unit_); -} - -ObjPtr HInstructionBuilder::ResolveCompilingClass(ScopedObjectAccess& soa) const { - return ResolveClassFrom(soa, compiler_driver_, *dex_compilation_unit_); -} - -bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const { - ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); - Handle dex_cache = dex_compilation_unit_->GetDexCache(); - Handle class_loader = dex_compilation_unit_->GetClassLoader(); - Handle cls(hs.NewHandle(compiler_driver_->ResolveClass( - soa, dex_cache, class_loader, type_index, dex_compilation_unit_))); - Handle outer_class(hs.NewHandle(ResolveOutermostCompilingClass(soa))); - - // GetOutermostCompilingClass returns null when the class is unresolved - // (e.g. if it derives from an unresolved class). This is bogus knowing that - // we are compiling it. - // When this happens we cannot establish a direct relation between the current - // class and the outer class, so we return false. - // (Note that this is only used for optimizing invokes and field accesses) - return (cls != nullptr) && (outer_class.Get() == cls.Get()); -} - void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put, @@ -1666,18 +1623,17 @@ void HInstructionBuilder::BuildUnresolvedStaticFieldAccess(const Instruction& in ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, bool is_put) { ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); Handle class_loader = dex_compilation_unit_->GetClassLoader(); - Handle compiling_class(hs.NewHandle(ResolveCompilingClass(soa))); ArtField* resolved_field = class_linker->ResolveField(field_idx, dex_compilation_unit_->GetDexCache(), class_loader, is_static); + DCHECK_EQ(resolved_field == nullptr, soa.Self()->IsExceptionPending()); if (UNLIKELY(resolved_field == nullptr)) { - // Clean up any exception left by type resolution. + // Clean up any exception left by field resolution. soa.Self()->ClearException(); return nullptr; } @@ -1689,6 +1645,7 @@ ArtField* HInstructionBuilder::ResolveField(uint16_t field_idx, bool is_static, } // Check access. + Handle compiling_class = dex_compilation_unit_->GetCompilingClass(); if (compiling_class == nullptr) { if (!resolved_field->IsPublic()) { return nullptr; @@ -1731,8 +1688,7 @@ void HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, DataType::Type field_type = GetFieldAccessType(*dex_file_, field_index); Handle klass = handles_->NewHandle(resolved_field->GetDeclaringClass()); - HLoadClass* constant = BuildLoadClass(soa, - klass->GetDexTypeIndex(), + HLoadClass* constant = BuildLoadClass(klass->GetDexTypeIndex(), klass->GetDexFile(), klass, dex_pc, @@ -1748,7 +1704,7 @@ void HInstructionBuilder::BuildStaticFieldAccess(const Instruction& instruction, } HInstruction* cls = constant; - if (!IsInitialized(soa, klass)) { + if (!IsInitialized(klass)) { cls = new (allocator_) HClinitCheck(constant, dex_pc); AppendInstruction(cls); } @@ -1989,12 +1945,11 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, uint3 ScopedObjectAccess soa(Thread::Current()); const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); Handle klass = ResolveClass(soa, type_index); - bool needs_access_check = LoadClassNeedsAccessCheck(soa, klass); - return BuildLoadClass(soa, type_index, dex_file, klass, dex_pc, needs_access_check); + bool needs_access_check = LoadClassNeedsAccessCheck(klass); + return BuildLoadClass(type_index, dex_file, klass, dex_pc, needs_access_check); } -HLoadClass* HInstructionBuilder::BuildLoadClass(ScopedObjectAccess& soa, - dex::TypeIndex type_index, +HLoadClass* HInstructionBuilder::BuildLoadClass(dex::TypeIndex type_index, const DexFile& dex_file, Handle klass, uint32_t dex_pc, @@ -2011,11 +1966,8 @@ HLoadClass* HInstructionBuilder::BuildLoadClass(ScopedObjectAccess& soa, } // Note: `klass` must be from `handles_`. - bool is_referrers_class = false; - if (klass != nullptr) { - ObjPtr outermost_cls = ResolveOutermostCompilingClass(soa); - is_referrers_class = (outermost_cls == klass.Get()); - } + bool is_referrers_class = + (klass != nullptr) && (outer_compilation_unit_->GetCompilingClass().Get() == klass.Get()); HLoadClass* load_class = new (allocator_) HLoadClass( graph_->GetCurrentMethod(), type_index, @@ -2049,14 +2001,13 @@ Handle HInstructionBuilder::ResolveClass(ScopedObjectAccess& soa, return handles_->NewHandle(klass); } -bool HInstructionBuilder::LoadClassNeedsAccessCheck(ScopedObjectAccess& soa, - Handle klass) { +bool HInstructionBuilder::LoadClassNeedsAccessCheck(Handle klass) { if (klass == nullptr) { return true; } else if (klass->IsPublic()) { return false; } else { - ObjPtr compiling_class = ResolveCompilingClass(soa); + ObjPtr compiling_class = dex_compilation_unit_->GetCompilingClass().Get(); return compiling_class == nullptr || !compiling_class->CanAccess(klass.Get()); } } @@ -2085,7 +2036,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, ScopedObjectAccess soa(Thread::Current()); const DexFile& dex_file = *dex_compilation_unit_->GetDexFile(); Handle klass = ResolveClass(soa, type_index); - bool needs_access_check = LoadClassNeedsAccessCheck(soa, klass); + bool needs_access_check = LoadClassNeedsAccessCheck(klass); TypeCheckKind check_kind = HSharpening::ComputeTypeCheckKind( klass.Get(), code_generator_, needs_access_check); @@ -2103,7 +2054,7 @@ void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction, bitstring_path_to_root = graph_->GetIntConstant(static_cast(path_to_root), dex_pc); bitstring_mask = graph_->GetIntConstant(static_cast(mask), dex_pc); } else { - class_or_null = BuildLoadClass(soa, type_index, dex_file, klass, dex_pc, needs_access_check); + class_or_null = BuildLoadClass(type_index, dex_file, klass, dex_pc, needs_access_check); } DCHECK(class_or_null != nullptr); diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 2ab2139216..0ee026af23 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -222,8 +222,7 @@ class HInstructionBuilder : public ValueObject { // Builds a `HLoadClass` loading the given `type_index`. HLoadClass* BuildLoadClass(dex::TypeIndex type_index, uint32_t dex_pc); - HLoadClass* BuildLoadClass(ScopedObjectAccess& soa, - dex::TypeIndex type_index, + HLoadClass* BuildLoadClass(dex::TypeIndex type_index, const DexFile& dex_file, Handle klass, uint32_t dex_pc, @@ -233,7 +232,7 @@ class HInstructionBuilder : public ValueObject { Handle ResolveClass(ScopedObjectAccess& soa, dex::TypeIndex type_index) REQUIRES_SHARED(Locks::mutator_lock_); - bool LoadClassNeedsAccessCheck(ScopedObjectAccess& soa, Handle klass) + bool LoadClassNeedsAccessCheck(Handle klass) REQUIRES_SHARED(Locks::mutator_lock_); // Builds a `HLoadMethodHandle` loading the given `method_handle_index`. @@ -242,17 +241,6 @@ class HInstructionBuilder : public ValueObject { // Builds a `HLoadMethodType` loading the given `proto_index`. void BuildLoadMethodType(dex::ProtoIndex proto_index, uint32_t dex_pc); - // Returns the outer-most compiling method's class. - ObjPtr ResolveOutermostCompilingClass(ScopedObjectAccess& soa) const - REQUIRES_SHARED(Locks::mutator_lock_); - - // Returns the class whose method is being compiled. - ObjPtr ResolveCompilingClass(ScopedObjectAccess& soa) const - REQUIRES_SHARED(Locks::mutator_lock_); - - // Returns whether `type_index` points to the outer-most compiling method's class. - bool IsOutermostCompilingClass(dex::TypeIndex type_index) const; - void PotentiallySimplifyFakeString(uint16_t original_dex_register, uint32_t dex_pc, HInvoke* invoke); @@ -275,7 +263,6 @@ class HInstructionBuilder : public ValueObject { void HandleStringInitResult(HInvokeStaticOrDirect* invoke); HClinitCheck* ProcessClinitCheckForInvoke( - ScopedObjectAccess& soa, uint32_t dex_pc, ArtMethod* method, HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) @@ -289,7 +276,7 @@ class HInstructionBuilder : public ValueObject { void BuildConstructorFenceForAllocation(HInstruction* allocation); // Return whether the compiler can assume `cls` is initialized. - bool IsInitialized(ScopedObjectAccess& soa, Handle cls) const + bool IsInitialized(Handle cls) const REQUIRES_SHARED(Locks::mutator_lock_); // Try to resolve a method using the class linker. Return null if a method could diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index a95ddff188..38daaaa31c 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1056,6 +1056,15 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, std::unique_ptr codegen; bool compiled_intrinsic = false; { + ScopedObjectAccess soa(Thread::Current()); + ArtMethod* method = + runtime->GetClassLinker()->ResolveMethod( + method_idx, dex_cache, jclass_loader, /*referrer=*/ nullptr, invoke_type); + DCHECK_EQ(method == nullptr, soa.Self()->IsExceptionPending()); + soa.Self()->ClearException(); // Suppress exception if any. + VariableSizedHandleScope handles(soa.Self()); + Handle compiling_class = + handles.NewHandle(method != nullptr ? method->GetDeclaringClass() : nullptr); DexCompilationUnit dex_compilation_unit( jclass_loader, runtime->GetClassLinker(), @@ -1064,12 +1073,9 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, class_def_idx, method_idx, access_flags, - /* verified_method */ nullptr, // Not needed by the Optimizing compiler. - dex_cache); - ScopedObjectAccess soa(Thread::Current()); - ArtMethod* method = compiler_driver->ResolveMethod( - soa, dex_cache, jclass_loader, &dex_compilation_unit, method_idx, invoke_type); - VariableSizedHandleScope handles(soa.Self()); + /*verified_method=*/ nullptr, // Not needed by the Optimizing compiler. + dex_cache, + compiling_class); // Go to native so that we don't block GC during compilation. ScopedThreadSuspension sts(soa.Self(), kNative); if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { @@ -1171,21 +1177,23 @@ CompiledMethod* OptimizingCompiler::JniCompile(uint32_t access_flags, if (compiler_options.IsBootImage()) { ScopedObjectAccess soa(Thread::Current()); ArtMethod* method = runtime->GetClassLinker()->LookupResolvedMethod( - method_idx, dex_cache.Get(), /* class_loader */ nullptr); + method_idx, dex_cache.Get(), /*class_loader=*/ nullptr); if (method != nullptr && UNLIKELY(method->IsIntrinsic())) { + VariableSizedHandleScope handles(soa.Self()); ScopedNullHandle class_loader; // null means boot class path loader. + Handle compiling_class = handles.NewHandle(method->GetDeclaringClass()); DexCompilationUnit dex_compilation_unit( class_loader, runtime->GetClassLinker(), dex_file, - /* code_item */ nullptr, - /* class_def_idx */ DexFile::kDexNoIndex16, + /*code_item=*/ nullptr, + /*class_def_idx=*/ DexFile::kDexNoIndex16, method_idx, access_flags, - /* verified_method */ nullptr, - dex_cache); + /*verified_method=*/ nullptr, + dex_cache, + compiling_class); CodeVectorAllocator code_allocator(&allocator); - VariableSizedHandleScope handles(soa.Self()); // Go to native so that we don't block GC during compilation. ScopedThreadSuspension sts(soa.Self(), kNative); std::unique_ptr codegen( @@ -1349,6 +1357,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, std::unique_ptr codegen; { + Handle compiling_class = handles.NewHandle(method->GetDeclaringClass()); DexCompilationUnit dex_compilation_unit( class_loader, runtime->GetClassLinker(), @@ -1357,8 +1366,9 @@ bool OptimizingCompiler::JitCompile(Thread* self, class_def_idx, method_idx, access_flags, - /* verified_method */ nullptr, - dex_cache); + /*verified_method=*/ nullptr, + dex_cache, + compiling_class); // Go to native so that we don't block GC during compilation. ScopedThreadSuspension sts(self, kNative); -- cgit v1.2.3-59-g8ed1b