diff options
27 files changed, 88 insertions, 412 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 8e75bdcdc9..d7754e8ea9 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -735,79 +735,6 @@ static InvokeType GetInvokeTypeFromOpCode(Instruction::Code opcode) { } } -ArtMethod* HGraphBuilder::ResolveMethod(uint16_t method_idx, InvokeType invoke_type) { - ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<2> hs(soa.Self()); - - ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker(); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle( - soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); - Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); - - ArtMethod* resolved_method = class_linker->ResolveMethod( - *dex_compilation_unit_->GetDexFile(), - method_idx, - dex_compilation_unit_->GetDexCache(), - class_loader, - /* referrer */ nullptr, - invoke_type); - - if (UNLIKELY(resolved_method == nullptr)) { - // Clean up any exception left by type resolution. - soa.Self()->ClearException(); - return nullptr; - } - - // Check access. The class linker has a fast path for looking into the dex cache - // and does not check the access if it hits it. - if (compiling_class.Get() == nullptr) { - if (!resolved_method->IsPublic()) { - return nullptr; - } - } else if (!compiling_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(), - resolved_method, - dex_compilation_unit_->GetDexCache().Get(), - method_idx)) { - return nullptr; - } - - // We have to special case the invoke-super case, as ClassLinker::ResolveMethod does not. - // We need to look at the referrer's super class vtable. - if (invoke_type == kSuper) { - if (compiling_class.Get() == nullptr) { - // Invoking a super method requires knowing the actual super class. If we did not resolve - // the compiling method's declaring class (which only happens for ahead of time compilation), - // bail out. - DCHECK(Runtime::Current()->IsAotCompiler()); - return nullptr; - } - uint16_t vtable_index = resolved_method->GetMethodIndex(); - ArtMethod* actual_method = compiling_class->GetSuperClass()->GetVTableEntry( - vtable_index, class_linker->GetImagePointerSize()); - if (actual_method != resolved_method && - !IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // TODO: The actual method could still be referenced in the current dex file, so we - // could try locating it. - // TODO: Remove the dex_file restriction. - return nullptr; - } - if (!actual_method->IsInvokable()) { - // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub - // could resolve the callee to the wrong method. - return nullptr; - } - resolved_method = actual_method; - } - - // Check for incompatible class changes. The class linker has a fast path for - // looking into the dex cache and does not check incompatible class changes if it hits it. - if (resolved_method->CheckIncompatibleClassChange(invoke_type)) { - return nullptr; - } - - return resolved_method; -} - bool HGraphBuilder::BuildInvoke(const Instruction& instruction, uint32_t dex_pc, uint32_t method_idx, @@ -815,18 +742,22 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, bool is_range, uint32_t* args, uint32_t register_index) { - InvokeType invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode()); + InvokeType original_invoke_type = GetInvokeTypeFromOpCode(instruction.Opcode()); + InvokeType optimized_invoke_type = original_invoke_type; const char* descriptor = dex_file_->GetMethodShorty(method_idx); Primitive::Type return_type = Primitive::GetType(descriptor[0]); // Remove the return type from the 'proto'. size_t number_of_arguments = strlen(descriptor) - 1; - if (invoke_type != kStatic) { // instance call + if (original_invoke_type != kStatic) { // instance call // One extra argument for 'this'. number_of_arguments++; } MethodReference target_method(dex_file_, method_idx); + int32_t table_index = 0; + uintptr_t direct_code = 0; + uintptr_t direct_method = 0; // Special handling for string init. int32_t string_init_offset = 0; @@ -849,7 +780,7 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, method_idx, target_method, dispatch_info, - invoke_type, + original_invoke_type, kStatic /* optimized_invoke_type */, HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit); return HandleStringInit(invoke, @@ -860,16 +791,23 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, descriptor); } - ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type); - - if (resolved_method == nullptr) { + // Handle unresolved methods. + if (!compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, + dex_pc, + true /* update_stats */, + true /* enable_devirtualization */, + &optimized_invoke_type, + &target_method, + &table_index, + &direct_code, + &direct_method)) { MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, number_of_arguments, return_type, dex_pc, method_idx, - invoke_type); + original_invoke_type); return HandleInvoke(invoke, number_of_vreg_arguments, args, @@ -879,26 +817,21 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, nullptr /* clinit_check */); } + // Handle resolved methods (non string init). + + DCHECK(optimized_invoke_type != kSuper); + // Potential class initialization check, in the case of a static method call. HClinitCheck* clinit_check = nullptr; HInvoke* invoke = nullptr; - if (invoke_type == kDirect || invoke_type == kStatic || invoke_type == kSuper) { + if (optimized_invoke_type == kDirect || optimized_invoke_type == kStatic) { // By default, consider that the called method implicitly requires // an initialization check of its declaring method. HInvokeStaticOrDirect::ClinitCheckRequirement clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit; - ScopedObjectAccess soa(Thread::Current()); - if (invoke_type == kStatic) { - clinit_check = ProcessClinitCheckForInvoke( - dex_pc, resolved_method, method_idx, &clinit_check_requirement); - } else if (invoke_type == kSuper) { - if (IsSameDexFile(*resolved_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // Update the target method to the one resolved. Note that this may be a no-op if - // we resolved to the method referenced by the instruction. - method_idx = resolved_method->GetDexMethodIndex(); - target_method = MethodReference(dex_file_, method_idx); - } + if (optimized_invoke_type == kStatic) { + clinit_check = ProcessClinitCheckForInvoke(dex_pc, method_idx, &clinit_check_requirement); } HInvokeStaticOrDirect::DispatchInfo dispatch_info = { @@ -914,26 +847,24 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, method_idx, target_method, dispatch_info, - invoke_type, - invoke_type, + original_invoke_type, + optimized_invoke_type, clinit_check_requirement); - } else if (invoke_type == kVirtual) { - ScopedObjectAccess soa(Thread::Current()); // Needed for the method index + } else if (optimized_invoke_type == kVirtual) { invoke = new (arena_) HInvokeVirtual(arena_, number_of_arguments, return_type, dex_pc, method_idx, - resolved_method->GetMethodIndex()); + table_index); } else { - DCHECK_EQ(invoke_type, kInterface); - ScopedObjectAccess soa(Thread::Current()); // Needed for the method index + DCHECK_EQ(optimized_invoke_type, kInterface); invoke = new (arena_) HInvokeInterface(arena_, number_of_arguments, return_type, dex_pc, method_idx, - resolved_method->GetDexMethodIndex()); + table_index); } return HandleInvoke(invoke, @@ -1031,18 +962,23 @@ bool HGraphBuilder::IsInitialized(Handle<mirror::Class> cls) const { HClinitCheck* HGraphBuilder::ProcessClinitCheckForInvoke( uint32_t dex_pc, - ArtMethod* resolved_method, uint32_t method_idx, HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) { - const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); - Thread* self = Thread::Current(); - StackHandleScope<4> hs(self); + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<5> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( dex_compilation_unit_->GetClassLinker()->FindDexCache( - self, *dex_compilation_unit_->GetDexFile()))); + soa.Self(), *dex_compilation_unit_->GetDexFile()))); + Handle<mirror::ClassLoader> class_loader(hs.NewHandle( + soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); + ArtMethod* resolved_method = compiler_driver_->ResolveMethod( + soa, dex_cache, class_loader, dex_compilation_unit_, method_idx, InvokeType::kStatic); + + DCHECK(resolved_method != nullptr); + + const DexFile& outer_dex_file = *outer_compilation_unit_->GetDexFile(); Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( - outer_compilation_unit_->GetClassLinker()->FindDexCache( - self, outer_dex_file))); + outer_compilation_unit_->GetClassLinker()->FindDexCache(soa.Self(), outer_dex_file))); Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass())); Handle<mirror::Class> resolved_method_class(hs.NewHandle(resolved_method->GetDeclaringClass())); diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index c3979f3dd1..5ada93f684 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -305,10 +305,8 @@ class HGraphBuilder : public ValueObject { HClinitCheck* ProcessClinitCheckForInvoke( uint32_t dex_pc, - ArtMethod* method, uint32_t method_idx, - HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement) - SHARED_REQUIRES(Locks::mutator_lock_); + HInvokeStaticOrDirect::ClinitCheckRequirement* clinit_check_requirement); // Build a HNewInstance instruction. bool BuildNewInstance(uint16_t type_index, uint32_t dex_pc); @@ -317,10 +315,6 @@ class HGraphBuilder : public ValueObject { bool IsInitialized(Handle<mirror::Class> cls) const SHARED_REQUIRES(Locks::mutator_lock_); - // Try to resolve a method using the class linker. Return null if a method could - // not be resolved. - ArtMethod* ResolveMethod(uint16_t method_idx, InvokeType invoke_type); - ArenaAllocator* const arena_; // A list of the size of the dex code holding block information for diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 0063aefb1a..a98d9c68b7 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -5943,16 +5943,12 @@ void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp Register temp = temp_location.AsRegister<Register>(); uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kArmPointerSize).Uint32Value(); - - // Use the calling convention instead of the location of the receiver, as - // intrinsics may have put the receiver in a different register. In the intrinsics - // slow path, the arguments have been moved to the right place, so here we are - // guaranteed that the receiver is the first register of the calling convention. - InvokeDexCallingConvention calling_convention; - Register receiver = calling_convention.GetRegisterAt(0); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + DCHECK(receiver.IsRegister()); // /* HeapReference<Class> */ temp = receiver->klass_ - __ LoadFromOffset(kLoadWord, temp, receiver, class_offset); + __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset); MaybeRecordImplicitNullCheck(invoke); // Instead of simply (possibly) unpoisoning `temp` here, we should // emit a read barrier for the previous class reference load. diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 04acd9d32c..ac16268834 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3618,12 +3618,8 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok } void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) { - // Use the calling convention instead of the location of the receiver, as - // intrinsics may have put the receiver in a different register. In the intrinsics - // slow path, the arguments have been moved to the right place, so here we are - // guaranteed that the receiver is the first register of the calling convention. - InvokeDexCallingConvention calling_convention; - Register receiver = calling_convention.GetRegisterAt(0); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); Register temp = XRegisterFrom(temp_in); size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kArm64PointerSize).SizeValue(); @@ -3634,10 +3630,11 @@ void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location te DCHECK(receiver.IsRegister()); // /* HeapReference<Class> */ temp = receiver->klass_ - __ Ldr(temp.W(), HeapOperandFrom(LocationFrom(receiver), class_offset)); + __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset)); MaybeRecordImplicitNullCheck(invoke); // Instead of simply (possibly) unpoisoning `temp` here, we should // emit a read barrier for the previous class reference load. + // However this is not required in practice, as this is an // intermediate/temporary reference and because the current // concurrent copying collector keeps the from-space memory // intact/accessible until the end of the marking phase (the diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index bc5eb31405..934f24bfb0 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -2986,13 +2986,8 @@ void InstructionCodeGeneratorMIPS64::VisitInvokeStaticOrDirect(HInvokeStaticOrDi } void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) { - // Use the calling convention instead of the location of the receiver, as - // intrinsics may have put the receiver in a different register. In the intrinsics - // slow path, the arguments have been moved to the right place, so here we are - // guaranteed that the receiver is the first register of the calling convention. - InvokeDexCallingConvention calling_convention; - GpuRegister receiver = calling_convention.GetRegisterAt(0); - + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); GpuRegister temp = temp_location.AsRegister<GpuRegister>(); size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kMips64PointerSize).SizeValue(); @@ -3000,7 +2995,8 @@ void CodeGeneratorMIPS64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMips64WordSize); // temp = object->GetClass(); - __ LoadFromOffset(kLoadUnsignedWord, temp, receiver, class_offset); + DCHECK(receiver.IsRegister()); + __ LoadFromOffset(kLoadUnsignedWord, temp, receiver.AsRegister<GpuRegister>(), class_offset); MaybeRecordImplicitNullCheck(invoke); // temp = temp->GetMethodAt(method_offset); __ LoadFromOffset(kLoadDoubleword, temp, temp, method_offset); diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index a8ed06c22c..1fc09a81bc 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1970,11 +1970,6 @@ void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirec } void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { - IntrinsicLocationsBuilderX86 intrinsic(codegen_); - if (intrinsic.TryDispatch(invoke)) { - return; - } - HandleInvoke(invoke); } @@ -4156,16 +4151,12 @@ void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp Register temp = temp_in.AsRegister<Register>(); uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kX86PointerSize).Uint32Value(); - - // Use the calling convention instead of the location of the receiver, as - // intrinsics may have put the receiver in a different register. In the intrinsics - // slow path, the arguments have been moved to the right place, so here we are - // guaranteed that the receiver is the first register of the calling convention. - InvokeDexCallingConvention calling_convention; - Register receiver = calling_convention.GetRegisterAt(0); + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + DCHECK(receiver.IsRegister()); // /* HeapReference<Class> */ temp = receiver->klass_ - __ movl(temp, Address(receiver, class_offset)); + __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset)); MaybeRecordImplicitNullCheck(invoke); // Instead of simply (possibly) unpoisoning `temp` here, we should // emit a read barrier for the previous class reference load. diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 4618be9cc3..534ee1c5ab 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -802,17 +802,12 @@ void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location t CpuRegister temp = temp_in.AsRegister<CpuRegister>(); size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue(); - - // Use the calling convention instead of the location of the receiver, as - // intrinsics may have put the receiver in a different register. In the intrinsics - // slow path, the arguments have been moved to the right place, so here we are - // guaranteed that the receiver is the first register of the calling convention. - InvokeDexCallingConvention calling_convention; - Register receiver = calling_convention.GetRegisterAt(0); - + LocationSummary* locations = invoke->GetLocations(); + Location receiver = locations->InAt(0); size_t class_offset = mirror::Object::ClassOffset().SizeValue(); + DCHECK(receiver.IsRegister()); // /* HeapReference<Class> */ temp = receiver->klass_ - __ movl(temp, Address(CpuRegister(receiver), class_offset)); + __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset)); MaybeRecordImplicitNullCheck(invoke); // Instead of simply (possibly) unpoisoning `temp` here, we should // emit a read barrier for the previous class reference load. diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 2bff21375e..48bcd10b10 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -402,11 +402,6 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } } - void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE { - VisitInvoke(invoke); - StartAttributeStream("intrinsic") << invoke->GetIntrinsic(); - } - void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* field_access) OVERRIDE { StartAttributeStream("field_type") << field_access->GetFieldType(); } diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 6d93be37a7..0363f203b2 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -192,10 +192,6 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { // We can query the dex cache directly. The verifier has populated it already. ArtMethod* resolved_method; if (invoke_instruction->IsInvokeStaticOrDirect()) { - if (invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit()) { - VLOG(compiler) << "Not inlining a String.<init> method"; - return false; - } MethodReference ref = invoke_instruction->AsInvokeStaticOrDirect()->GetTargetMethod(); mirror::DexCache* const dex_cache = (&caller_dex_file == ref.dex_file) ? caller_compilation_unit_.GetDexCache().Get() diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 834081188b..b01324ec3b 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -384,7 +384,7 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile // InvokeStaticOrDirect. InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic); InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ? - invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() : + invoke->AsInvokeStaticOrDirect()->GetInvokeType() : invoke->IsInvokeVirtual() ? kVirtual : kSuper; switch (intrinsic_type) { case kStatic: diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 2c2fc8cb2a..d5110a7172 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3418,7 +3418,7 @@ class HInvokeStaticOrDirect : public HInvoke { MethodReference target_method, DispatchInfo dispatch_info, InvokeType original_invoke_type, - InvokeType optimized_invoke_type, + InvokeType invoke_type, ClinitCheckRequirement clinit_check_requirement) : HInvoke(arena, number_of_arguments, @@ -3432,7 +3432,7 @@ class HInvokeStaticOrDirect : public HInvoke { dex_pc, method_index, original_invoke_type), - optimized_invoke_type_(optimized_invoke_type), + invoke_type_(invoke_type), clinit_check_requirement_(clinit_check_requirement), target_method_(target_method), dispatch_info_(dispatch_info) { } @@ -3478,11 +3478,7 @@ class HInvokeStaticOrDirect : public HInvoke { // platform-specific special input, such as PC-relative addressing base. uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); } - InvokeType GetOptimizedInvokeType() const { return optimized_invoke_type_; } - void SetOptimizedInvokeType(InvokeType invoke_type) { - optimized_invoke_type_ = invoke_type; - } - + InvokeType GetInvokeType() const { return invoke_type_; } MethodLoadKind GetMethodLoadKind() const { return dispatch_info_.method_load_kind; } CodePtrLocation GetCodePtrLocation() const { return dispatch_info_.code_ptr_location; } bool IsRecursive() const { return GetMethodLoadKind() == MethodLoadKind::kRecursive; } @@ -3505,7 +3501,6 @@ class HInvokeStaticOrDirect : public HInvoke { } bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; } MethodReference GetTargetMethod() const { return target_method_; } - void SetTargetMethod(MethodReference method) { target_method_ = method; } int32_t GetStringInitOffset() const { DCHECK(IsStringInit()); @@ -3531,7 +3526,7 @@ class HInvokeStaticOrDirect : public HInvoke { // Is this instruction a call to a static method? bool IsStatic() const { - return GetOriginalInvokeType() == kStatic; + return GetInvokeType() == kStatic; } // Remove the HClinitCheck or the replacement HLoadClass (set as last input by @@ -3604,7 +3599,7 @@ class HInvokeStaticOrDirect : public HInvoke { void RemoveInputAt(size_t index); private: - InvokeType optimized_invoke_type_; + const InvokeType invoke_type_; ClinitCheckRequirement clinit_check_requirement_; // The target method may refer to different dex file or method index than the original // invoke. This happens for sharpened calls and for calls where a method was redeclared diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 5e1d1d9954..a128079cdb 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -49,8 +49,7 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { } // TODO: Avoid CompilerDriver. - InvokeType original_invoke_type = invoke->GetOriginalInvokeType(); - InvokeType optimized_invoke_type = original_invoke_type; + InvokeType invoke_type = invoke->GetOriginalInvokeType(); MethodReference target_method(&graph_->GetDexFile(), invoke->GetDexMethodIndex()); int vtable_idx; uintptr_t direct_code, direct_method; @@ -59,18 +58,15 @@ void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { invoke->GetDexPc(), false /* update_stats: already updated in builder */, true /* enable_devirtualization */, - &optimized_invoke_type, + &invoke_type, &target_method, &vtable_idx, &direct_code, &direct_method); - if (!success) { - // TODO: try using kDexCachePcRelative. It's always a valid method load - // kind as long as it's supported by the codegen - return; - } - invoke->SetOptimizedInvokeType(optimized_invoke_type); - invoke->SetTargetMethod(target_method); + DCHECK(success); + DCHECK_EQ(invoke_type, invoke->GetInvokeType()); + DCHECK_EQ(target_method.dex_file, invoke->GetTargetMethod().dex_file); + DCHECK_EQ(target_method.dex_method_index, invoke->GetTargetMethod().dex_method_index); HInvokeStaticOrDirect::MethodLoadKind method_load_kind; HInvokeStaticOrDirect::CodePtrLocation code_ptr_location; diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index dccb1dad3b..21e4e445e6 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -598,12 +598,8 @@ inline ArtMethod* FindMethodFast(uint32_t method_idx, mirror::Object* this_objec } else if (type == kStatic || type == kDirect) { return resolved_method; } else if (type == kSuper) { - mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass(); - if (resolved_method->GetMethodIndex() >= super_class->GetVTableLength()) { - // The super class does not have the method. - return nullptr; - } - return super_class->GetVTableEntry(resolved_method->GetMethodIndex(), sizeof(void*)); + return referrer->GetDeclaringClass()->GetSuperClass()->GetVTableEntry( + resolved_method->GetMethodIndex(), sizeof(void*)); } else { DCHECK(type == kVirtual); return this_object->GetClass()->GetVTableEntry( diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java index 5080f142b1..6dce96c9ca 100644 --- a/test/464-checker-inline-sharpen-calls/src/Main.java +++ b/test/464-checker-inline-sharpen-calls/src/Main.java @@ -19,25 +19,23 @@ public final class Main { public void invokeVirtual() { } - /// CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) builder (after) - /// CHECK-DAG: <<Invoke:v\d+>> InvokeVirtual + /// CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (before) + /// CHECK-DAG: <<Invoke:v\d+>> InvokeStaticOrDirect /// CHECK-DAG: ReturnVoid /// CHECK-START: void Main.inlineSharpenInvokeVirtual(Main) inliner (after) - /// CHECK-NOT: InvokeVirtual /// CHECK-NOT: InvokeStaticOrDirect public static void inlineSharpenInvokeVirtual(Main m) { m.invokeVirtual(); } - /// CHECK-START: int Main.inlineSharpenStringInvoke() ssa_builder (after) - /// CHECK-DAG: <<Invoke:i\d+>> InvokeVirtual + /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (before) + /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect /// CHECK-DAG: Return [<<Invoke>>] /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after) /// CHECK-NOT: InvokeStaticOrDirect - /// CHECK-NOT: InvokeVirtual /// CHECK-START: int Main.inlineSharpenStringInvoke() inliner (after) /// CHECK-DAG: <<Field:i\d+>> InstanceFieldGet diff --git a/test/492-checker-inline-invoke-interface/expected.txt b/test/492-checker-inline-invoke-interface/expected.txt index 42b331f722..b0014d7529 100644 --- a/test/492-checker-inline-invoke-interface/expected.txt +++ b/test/492-checker-inline-invoke-interface/expected.txt @@ -2,4 +2,4 @@ Hello from clinit java.lang.Exception at ForceStatic.<clinit>(Main.java:24) at Main.$inline$foo(Main.java:31) - at Main.main(Main.java:50) + at Main.main(Main.java:48) diff --git a/test/492-checker-inline-invoke-interface/src/Main.java b/test/492-checker-inline-invoke-interface/src/Main.java index a8b63075be..9a4548542b 100644 --- a/test/492-checker-inline-invoke-interface/src/Main.java +++ b/test/492-checker-inline-invoke-interface/src/Main.java @@ -31,17 +31,15 @@ public class Main implements Itf { int a = ForceStatic.field; } - /// CHECK-START: void Main.main(java.lang.String[]) ssa_builder (after) + /// CHECK-START: void Main.main(java.lang.String[]) inliner (before) + /// CHECK: InvokeStaticOrDirect /// CHECK: InvokeStaticOrDirect - /// CHECK: InvokeInterface /// CHECK-START: void Main.main(java.lang.String[]) inliner (before) /// CHECK-NOT: ClinitCheck /// CHECK-START: void Main.main(java.lang.String[]) inliner (after) /// CHECK-NOT: InvokeStaticOrDirect - /// CHECK-NOT: InvokeVirtual - /// CHECK-NOT: InvokeInterface /// CHECK-START: void Main.main(java.lang.String[]) inliner (after) /// CHECK: ClinitCheck diff --git a/test/536-checker-intrinsic-optimization/src/Main.java b/test/536-checker-intrinsic-optimization/src/Main.java index 3f65d5a312..1b784ae367 100644 --- a/test/536-checker-intrinsic-optimization/src/Main.java +++ b/test/536-checker-intrinsic-optimization/src/Main.java @@ -35,7 +35,7 @@ public class Main { } /// CHECK-START: boolean Main.stringEqualsNull() register (after) - /// CHECK: <<Invoke:z\d+>> InvokeVirtual + /// CHECK: <<Invoke:z\d+>> InvokeStaticOrDirect /// CHECK: Return [<<Invoke>>] public static boolean stringEqualsNull() { String o = (String)myObject; @@ -47,7 +47,7 @@ public class Main { } /// CHECK-START-X86: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after) - /// CHECK: InvokeVirtual + /// CHECK: InvokeStaticOrDirect /// CHECK-NOT: test public static boolean stringArgumentNotNull(Object obj) { obj.getClass(); @@ -56,7 +56,7 @@ public class Main { // Test is very brittle as it depends on the order we emit instructions. /// CHECK-START-X86: boolean Main.stringArgumentIsString() disassembly (after) - /// CHECK: InvokeVirtual + /// CHECK: InvokeStaticOrDirect /// CHECK: test /// CHECK: jz/eq // Check that we don't try to compare the classes. diff --git a/test/551-invoke-super/expected.txt b/test/551-invoke-super/expected.txt deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/551-invoke-super/expected.txt +++ /dev/null diff --git a/test/551-invoke-super/info.txt b/test/551-invoke-super/info.txt deleted file mode 100644 index 864ddfecb6..0000000000 --- a/test/551-invoke-super/info.txt +++ /dev/null @@ -1 +0,0 @@ -Tests the invoke-super opcode when resolving to an abstract method. diff --git a/test/551-invoke-super/smali/invokesuper.smali b/test/551-invoke-super/smali/invokesuper.smali deleted file mode 100644 index ad3c218fae..0000000000 --- a/test/551-invoke-super/smali/invokesuper.smali +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (C) 2015 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. - - -.class public LInvokeSuper; -.super LSuperClass; - -.method public constructor <init>()V -.registers 1 - invoke-direct {v0}, LSuperClass;-><init>()V - return-void -.end method - - -.method public run()I -.registers 2 - # Do an invoke super on a non-super class to force complex resolution. - invoke-super {v1}, LInvokeSuper;->returnInt()I - move-result v0 - return v0 -.end method - - -.method public returnInt()I -.registers 2 - const v0, 777 - return v0 -.end method diff --git a/test/551-invoke-super/smali/superclass.smali b/test/551-invoke-super/smali/superclass.smali deleted file mode 100644 index 47fbee7cdb..0000000000 --- a/test/551-invoke-super/smali/superclass.smali +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (C) 2015 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. - -.class abstract public LSuperClass; -.super Ljava/lang/Object; - -.method public constructor <init>()V -.registers 1 - invoke-direct {v0}, Ljava/lang/Object;-><init>()V - return-void -.end method - -.method abstract public returnInt()I -.end method diff --git a/test/551-invoke-super/src/Main.java b/test/551-invoke-super/src/Main.java deleted file mode 100644 index 3a301847d3..0000000000 --- a/test/551-invoke-super/src/Main.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class Main { - // Workaround for b/18051191. - class InnerClass {} - - public static void main(String[] args) throws Exception { - Class<?> c = Class.forName("InvokeSuper"); - try { - Method m = c.getMethod("run"); - m.invoke(c.newInstance(), new Object[0]); - throw new Error("Expected AbstractMethodError"); - } catch (InvocationTargetException e) { - if (!(e.getCause() instanceof AbstractMethodError)) { - throw new Error("Expected AbstractMethodError"); - } - } - } -} diff --git a/test/552-invoke-non-existent-super/expected.txt b/test/552-invoke-non-existent-super/expected.txt deleted file mode 100644 index e69de29bb2..0000000000 --- a/test/552-invoke-non-existent-super/expected.txt +++ /dev/null diff --git a/test/552-invoke-non-existent-super/info.txt b/test/552-invoke-non-existent-super/info.txt deleted file mode 100644 index c5428d49be..0000000000 --- a/test/552-invoke-non-existent-super/info.txt +++ /dev/null @@ -1 +0,0 @@ -Tests the invoke-super opcode when the super class does not have the method. diff --git a/test/552-invoke-non-existent-super/smali/invokesuper.smali b/test/552-invoke-non-existent-super/smali/invokesuper.smali deleted file mode 100644 index ad3c218fae..0000000000 --- a/test/552-invoke-non-existent-super/smali/invokesuper.smali +++ /dev/null @@ -1,40 +0,0 @@ -# -# Copyright (C) 2015 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. - - -.class public LInvokeSuper; -.super LSuperClass; - -.method public constructor <init>()V -.registers 1 - invoke-direct {v0}, LSuperClass;-><init>()V - return-void -.end method - - -.method public run()I -.registers 2 - # Do an invoke super on a non-super class to force complex resolution. - invoke-super {v1}, LInvokeSuper;->returnInt()I - move-result v0 - return v0 -.end method - - -.method public returnInt()I -.registers 2 - const v0, 777 - return v0 -.end method diff --git a/test/552-invoke-non-existent-super/smali/superclass.smali b/test/552-invoke-non-existent-super/smali/superclass.smali deleted file mode 100644 index 21d961ea6a..0000000000 --- a/test/552-invoke-non-existent-super/smali/superclass.smali +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2015 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. - -.class abstract public LSuperClass; -.super Ljava/lang/Object; - -.method public constructor <init>()V -.registers 1 - invoke-direct {v0}, Ljava/lang/Object;-><init>()V - return-void -.end method diff --git a/test/552-invoke-non-existent-super/src/Main.java b/test/552-invoke-non-existent-super/src/Main.java deleted file mode 100644 index c2644711a1..0000000000 --- a/test/552-invoke-non-existent-super/src/Main.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class Main { - // Workaround for b/18051191. - class InnerClass {} - - public static void main(String[] args) throws Exception { - Class<?> c = Class.forName("InvokeSuper"); - try { - Method m = c.getMethod("run"); - m.invoke(c.newInstance(), new Object[0]); - throw new Error("Expected NoSuchMethodError"); - } catch (InvocationTargetException e) { - if (!(e.getCause() instanceof NoSuchMethodError)) { - throw new Error("Expected NoSuchMethodError"); - } - } - } -} |