}
}
-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,
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;
method_idx,
target_method,
dispatch_info,
- invoke_type,
+ original_invoke_type,
kStatic /* optimized_invoke_type */,
HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
return HandleStringInit(invoke,
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,
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 = {
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,
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()));
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);
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
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.
}
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();
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
}
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();
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);
}
void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
- IntrinsicLocationsBuilderX86 intrinsic(codegen_);
- if (intrinsic.TryDispatch(invoke)) {
- return;
- }
-
HandleInvoke(invoke);
}
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.
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.
}
}
- void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
- VisitInvoke(invoke);
- StartAttributeStream("intrinsic") << invoke->GetIntrinsic();
- }
-
void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* field_access) OVERRIDE {
StartAttributeStream("field_type") << field_access->GetFieldType();
}
// 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()
// 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:
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,
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) { }
// 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; }
}
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());
// 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
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
}
// 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;
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;
} 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(
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
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)
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
}
/// 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;
}
/// 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();
// 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.
+++ /dev/null
-Tests the invoke-super opcode when resolving to an abstract method.
+++ /dev/null
-#
-# 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
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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");
- }
- }
- }
-}
+++ /dev/null
-Tests the invoke-super opcode when the super class does not have the method.
+++ /dev/null
-#
-# 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
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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");
- }
- }
- }
-}