Merge "Minor jfuzz improvements."
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index c902d28..e0abf19 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -277,39 +277,44 @@
return;
}
uint32_t method_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
- MethodReference target_method(&GetDexFile(), method_idx);
- InvokeType invoke_type = kVirtual;
- InvokeType original_invoke_type = invoke_type;
- int vtable_idx;
- uintptr_t direct_code;
- uintptr_t direct_method;
- // TODO: support devirtualization.
- const bool kEnableDevirtualization = false;
- bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc,
- false, kEnableDevirtualization,
- &invoke_type,
- &target_method, &vtable_idx,
- &direct_code, &direct_method);
- if (fast_path && original_invoke_type == invoke_type) {
- if (vtable_idx >= 0 && IsUint<16>(vtable_idx)) {
- VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
- << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
- << " to " << Instruction::Name(new_opcode)
- << " by replacing method index " << method_idx
- << " by vtable index " << vtable_idx
- << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
- << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
- // We are modifying 4 consecutive bytes.
- inst->SetOpcode(new_opcode);
- // Replace method index by vtable index.
- if (is_range) {
- inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
- } else {
- inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
- }
- quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
- }
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+ soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader())));
+
+ ClassLinker* class_linker = unit_.GetClassLinker();
+ ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
+ GetDexFile(),
+ method_idx,
+ unit_.GetDexCache(),
+ class_loader,
+ /* referrer */ nullptr,
+ kVirtual);
+
+ if (UNLIKELY(resolved_method == nullptr)) {
+ // Clean up any exception left by type resolution.
+ soa.Self()->ClearException();
+ return;
}
+
+ uint32_t vtable_idx = resolved_method->GetMethodIndex();
+ DCHECK(IsUint<16>(vtable_idx));
+ VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode())
+ << "(" << PrettyMethod(method_idx, GetDexFile(), true) << ")"
+ << " to " << Instruction::Name(new_opcode)
+ << " by replacing method index " << method_idx
+ << " by vtable index " << vtable_idx
+ << " at dex pc " << StringPrintf("0x%x", dex_pc) << " in method "
+ << PrettyMethod(unit_.GetDexMethodIndex(), GetDexFile(), true);
+ // We are modifying 4 consecutive bytes.
+ inst->SetOpcode(new_opcode);
+ // Replace method index by vtable index.
+ if (is_range) {
+ inst->SetVRegB_3rc(static_cast<uint16_t>(vtable_idx));
+ } else {
+ inst->SetVRegB_35c(static_cast<uint16_t>(vtable_idx));
+ }
+ quickened_info_.push_back(QuickenedInfo(dex_pc, method_idx));
}
CompiledMethod* ArtCompileDEX(
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 3a260f5..4b913f4 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -293,146 +293,6 @@
}
}
-inline int CompilerDriver::IsFastInvoke(
- ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
- mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type,
- MethodReference* target_method, const MethodReference* devirt_target,
- uintptr_t* direct_code, uintptr_t* direct_method) {
- // Don't try to fast-path if we don't understand the caller's class.
- // Referrer_class is the class that this invoke is contained in.
- if (UNLIKELY(referrer_class == nullptr)) {
- return 0;
- }
- StackHandleScope<2> hs(soa.Self());
- // Methods_class is the class refered to by the class_idx field of the methodId the method_idx is
- // pointing to.
- // For example in
- // .class LABC;
- // .super LDEF;
- // .method hi()V
- // ...
- // invoke-super {p0}, LDEF;->hi()V
- // ...
- // .end method
- // the referrer_class is 'ABC' and the methods_class is DEF. Note that the methods class is 'DEF'
- // even if 'DEF' inherits the method from it's superclass.
- Handle<mirror::Class> methods_class(hs.NewHandle(mUnit->GetClassLinker()->ResolveType(
- *target_method->dex_file,
- target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_,
- dex_cache,
- class_loader)));
- DCHECK(methods_class.Get() != nullptr);
- mirror::Class* methods_declaring_class = resolved_method->GetDeclaringClass();
- if (UNLIKELY(!referrer_class->CanAccessResolvedMethod(methods_declaring_class, resolved_method,
- dex_cache.Get(),
- target_method->dex_method_index))) {
- return 0;
- }
- // Sharpen a virtual call into a direct call when the target is known not to have been
- // overridden (ie is final).
- const bool same_dex_file = target_method->dex_file == mUnit->GetDexFile();
- bool can_sharpen_virtual_based_on_type = same_dex_file &&
- (*invoke_type == kVirtual) && (resolved_method->IsFinal() ||
- methods_declaring_class->IsFinal());
- // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of
- // the super class.
- const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
- // TODO We should be able to sharpen if we are going into the boot image as well.
- bool can_sharpen_super_based_on_type = same_dex_file &&
- (*invoke_type == kSuper) &&
- !methods_class->IsInterface() &&
- (referrer_class != methods_declaring_class) &&
- referrer_class->IsSubClass(methods_declaring_class) &&
- resolved_method->GetMethodIndex() < methods_declaring_class->GetVTableLength() &&
- (methods_declaring_class->GetVTableEntry(
- resolved_method->GetMethodIndex(), pointer_size) == resolved_method) &&
- resolved_method->IsInvokable();
- // TODO We should be able to sharpen if we are going into the boot image as well.
- bool can_sharpen_interface_super_based_on_type = same_dex_file &&
- (*invoke_type == kSuper) &&
- methods_class->IsInterface() &&
- methods_class->IsAssignableFrom(referrer_class) &&
- resolved_method->IsInvokable();
-
- if (can_sharpen_virtual_based_on_type ||
- can_sharpen_super_based_on_type ||
- can_sharpen_interface_super_based_on_type) {
- // Sharpen a virtual call into a direct call. The method_idx is into referrer's
- // dex cache, check that this resolved method is where we expect it.
- CHECK_EQ(target_method->dex_file, mUnit->GetDexFile());
- DCHECK_EQ(dex_cache.Get(), mUnit->GetClassLinker()->FindDexCache(
- soa.Self(), *mUnit->GetDexFile(), false));
- CHECK_EQ(referrer_class->GetDexCache()->GetResolvedMethod(
- target_method->dex_method_index, pointer_size),
- resolved_method) << PrettyMethod(resolved_method);
- int stats_flags = kFlagMethodResolved;
- GetCodeAndMethodForDirectCall(/*out*/invoke_type,
- kDirect, // Sharp type
- false, // The dex cache is guaranteed to be available
- referrer_class, resolved_method,
- /*out*/&stats_flags,
- target_method,
- /*out*/direct_code,
- /*out*/direct_method);
- DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method);
- if (*invoke_type == kDirect) {
- stats_flags |= kFlagsMethodResolvedVirtualMadeDirect;
- }
- return stats_flags;
- }
-
- if ((*invoke_type == kVirtual || *invoke_type == kInterface) && devirt_target != nullptr) {
- // Post-verification callback recorded a more precise invoke target based on its type info.
- ArtMethod* called_method;
- ClassLinker* class_linker = mUnit->GetClassLinker();
- if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
- called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- *devirt_target->dex_file, devirt_target->dex_method_index, dex_cache, class_loader,
- nullptr, kVirtual);
- } else {
- auto target_dex_cache(hs.NewHandle(class_linker->RegisterDexFile(*devirt_target->dex_file,
- class_loader.Get())));
- called_method = class_linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- *devirt_target->dex_file, devirt_target->dex_method_index, target_dex_cache,
- class_loader, nullptr, kVirtual);
- }
- CHECK(called_method != nullptr);
- CHECK(called_method->IsInvokable());
- int stats_flags = kFlagMethodResolved;
- GetCodeAndMethodForDirectCall(/*out*/invoke_type,
- kDirect, // Sharp type
- true, // The dex cache may not be available
- referrer_class, called_method,
- /*out*/&stats_flags,
- target_method,
- /*out*/direct_code,
- /*out*/direct_method);
- DCHECK_NE(*invoke_type, kSuper);
- if (*invoke_type == kDirect) {
- stats_flags |= kFlagsMethodResolvedPreciseTypeDevirtualization;
- }
- return stats_flags;
- }
-
- if (UNLIKELY(*invoke_type == kSuper)) {
- // Unsharpened super calls are suspicious so go slow-path.
- return 0;
- }
-
- // Sharpening failed so generate a regular resolved method dispatch.
- int stats_flags = kFlagMethodResolved;
- GetCodeAndMethodForDirectCall(/*out*/invoke_type,
- *invoke_type, // Sharp type
- false, // The dex cache is guaranteed to be available
- referrer_class, resolved_method,
- /*out*/&stats_flags,
- target_method,
- /*out*/direct_code,
- /*out*/direct_method);
- return stats_flags;
-}
-
inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class,
ArtMethod* resolved_method) {
if (!resolved_method->IsStatic()) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index a149c07..adbf9fd 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1654,12 +1654,8 @@
}
}
-void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type,
- bool no_guarantee_of_dex_cache_entry,
- const mirror::Class* referrer_class,
+void CompilerDriver::GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class,
ArtMethod* method,
- int* stats_flags,
- MethodReference* target_method,
uintptr_t* direct_code,
uintptr_t* direct_method) {
// For direct and static methods compute possible direct_code and direct_method values, ie
@@ -1671,15 +1667,11 @@
Runtime* const runtime = Runtime::Current();
gc::Heap* const heap = runtime->GetHeap();
auto* cl = runtime->GetClassLinker();
- const auto pointer_size = cl->GetImagePointerSize();
bool use_dex_cache = GetCompilerOptions().GetCompilePic(); // Off by default
const bool compiling_boot = heap->IsCompilingBoot();
// TODO This is somewhat hacky. We should refactor all of this invoke codepath.
const bool force_relocations = (compiling_boot ||
GetCompilerOptions().GetIncludePatchInformation());
- if (sharp_type != kStatic && sharp_type != kDirect) {
- return;
- }
// TODO: support patching on all architectures.
use_dex_cache = use_dex_cache || (force_relocations && !support_boot_image_fixup_);
mirror::Class* declaring_class = method->GetDeclaringClass();
@@ -1687,14 +1679,12 @@
if (!use_dex_cache) {
if (!method_code_in_boot) {
use_dex_cache = true;
- } else {
- bool has_clinit_trampoline =
- method->IsStatic() && !declaring_class->IsInitialized();
- if (has_clinit_trampoline && declaring_class != referrer_class) {
- // Ensure we run the clinit trampoline unless we are invoking a static method in the same
- // class.
- use_dex_cache = true;
- }
+ } else if (method->IsStatic() &&
+ declaring_class != referrer_class &&
+ !declaring_class->IsInitialized()) {
+ // Ensure we run the clinit trampoline unless we are invoking a static method in the same
+ // class.
+ use_dex_cache = true;
}
}
if (runtime->UseJitCompilation()) {
@@ -1705,9 +1695,7 @@
use_dex_cache = true;
}
}
- if (method_code_in_boot) {
- *stats_flags |= kFlagDirectCallToBoot | kFlagDirectMethodToBoot;
- }
+
if (!use_dex_cache && force_relocations) {
bool is_in_image;
if (IsBootImage()) {
@@ -1724,39 +1712,8 @@
use_dex_cache = true;
}
}
- // The method is defined not within this dex file. We need a dex cache slot within the current
- // dex file or direct pointers.
- bool must_use_direct_pointers = false;
- mirror::DexCache* dex_cache = declaring_class->GetDexCache();
- if (target_method->dex_file == dex_cache->GetDexFile() &&
- !(runtime->UseJitCompilation() && dex_cache->GetResolvedMethod(
- method->GetDexMethodIndex(), pointer_size) == nullptr)) {
- target_method->dex_method_index = method->GetDexMethodIndex();
- } else {
- if (no_guarantee_of_dex_cache_entry) {
- // See if the method is also declared in this dex cache.
- uint32_t dex_method_idx = method->FindDexMethodIndexInOtherDexFile(
- *target_method->dex_file, target_method->dex_method_index);
- if (dex_method_idx != DexFile::kDexNoIndex) {
- target_method->dex_method_index = dex_method_idx;
- } else {
- if (force_relocations && !use_dex_cache) {
- target_method->dex_method_index = method->GetDexMethodIndex();
- target_method->dex_file = dex_cache->GetDexFile();
- }
- must_use_direct_pointers = true;
- }
- }
- }
- if (use_dex_cache) {
- if (must_use_direct_pointers) {
- // Fail. Test above showed the only safe dispatch was via the dex cache, however, the direct
- // pointers are required as the dex cache lacks an appropriate entry.
- VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
- } else {
- *type = sharp_type;
- }
- } else {
+
+ if (!use_dex_cache) {
bool method_in_image = false;
const std::vector<gc::space::ImageSpace*> image_spaces = heap->GetBootImageSpaces();
for (gc::space::ImageSpace* image_space : image_spaces) {
@@ -1772,87 +1729,15 @@
// the method and its code are / will be. We don't sharpen to interpreter bridge since we
// check IsQuickToInterpreterBridge above.
CHECK(!method->IsAbstract());
- *type = sharp_type;
*direct_method = force_relocations ? -1 : reinterpret_cast<uintptr_t>(method);
*direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method);
- target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
- target_method->dex_method_index = method->GetDexMethodIndex();
- } else if (!must_use_direct_pointers) {
+ } else {
// Set the code and rely on the dex cache for the method.
- *type = sharp_type;
- if (force_relocations) {
- *direct_code = -1;
- target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
- target_method->dex_method_index = method->GetDexMethodIndex();
- } else {
- *direct_code = compiler_->GetEntryPointOf(method);
- }
- } else {
- // Direct pointers were required but none were available.
- VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
+ *direct_code = force_relocations ? -1 : compiler_->GetEntryPointOf(method);
}
}
}
-bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
- bool update_stats, bool enable_devirtualization,
- InvokeType* invoke_type, MethodReference* target_method,
- int* vtable_idx, uintptr_t* direct_code,
- uintptr_t* direct_method) {
- InvokeType orig_invoke_type = *invoke_type;
- int stats_flags = 0;
- ScopedObjectAccess soa(Thread::Current());
- // Try to resolve the method and compiling method's class.
- StackHandleScope<2> hs(soa.Self());
- Handle<mirror::DexCache> dex_cache(mUnit->GetDexCache());
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
- uint32_t method_idx = target_method->dex_method_index;
- ArtMethod* resolved_method = ResolveMethod(
- soa, dex_cache, class_loader, mUnit, method_idx, orig_invoke_type);
- auto h_referrer_class = hs.NewHandle(resolved_method != nullptr ?
- ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit) : nullptr);
- bool result = false;
- if (resolved_method != nullptr) {
- *vtable_idx = GetResolvedMethodVTableIndex(resolved_method, orig_invoke_type);
-
- if (enable_devirtualization && mUnit->GetVerifiedMethod() != nullptr) {
- const MethodReference* devirt_target = mUnit->GetVerifiedMethod()->GetDevirtTarget(dex_pc);
-
- stats_flags = IsFastInvoke(
- soa, dex_cache, class_loader, mUnit, h_referrer_class.Get(), resolved_method,
- invoke_type, target_method, devirt_target, direct_code, direct_method);
- result = stats_flags != 0;
- } else {
- // Devirtualization not enabled. Inline IsFastInvoke(), dropping the devirtualization parts.
- if (UNLIKELY(h_referrer_class.Get() == nullptr) ||
- UNLIKELY(!h_referrer_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(),
- resolved_method, dex_cache.Get(),
- target_method->dex_method_index)) ||
- *invoke_type == kSuper) {
- // Slow path. (Without devirtualization, all super calls go slow path as well.)
- } else {
- // Sharpening failed so generate a regular resolved method dispatch.
- stats_flags = kFlagMethodResolved;
- GetCodeAndMethodForDirectCall(
- invoke_type, *invoke_type, false, h_referrer_class.Get(), resolved_method, &stats_flags,
- target_method, direct_code, direct_method);
- result = true;
- }
- }
- }
- if (!result) {
- // Conservative defaults.
- *vtable_idx = -1;
- *direct_code = 0u;
- *direct_method = 0u;
- }
- if (update_stats) {
- ProcessedInvoke(orig_invoke_type, stats_flags);
- }
- return result;
-}
-
const VerifiedMethod* CompilerDriver::GetVerifiedMethod(const DexFile* dex_file,
uint32_t method_idx) const {
MethodReference ref(dex_file, method_idx);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ee21efa..1f4c3ac 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -328,16 +328,6 @@
ArtMethod* resolved_method, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Can we fast-path an INVOKE? If no, returns 0. If yes, returns a non-zero opaque flags value
- // for ProcessedInvoke() and computes the necessary lowering info.
- int IsFastInvoke(
- ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
- mirror::Class* referrer_class, ArtMethod* resolved_method, InvokeType* invoke_type,
- MethodReference* target_method, const MethodReference* devirt_target,
- uintptr_t* direct_code, uintptr_t* direct_method)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Is method's class initialized for an invoke?
// For static invokes to determine whether we need to consider potential call to <clinit>().
// For non-static invokes, assuming a non-null reference, the class is always initialized.
@@ -371,14 +361,6 @@
REQUIRES_SHARED(Locks::mutator_lock_);
- // Can we fastpath a interface, super class or virtual method call? Computes method's vtable
- // index.
- bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc,
- bool update_stats, bool enable_devirtualization,
- InvokeType* type, MethodReference* target_method, int* vtable_idx,
- uintptr_t* direct_code, uintptr_t* direct_method)
- REQUIRES(!Locks::mutator_lock_);
-
const VerifiedMethod* GetVerifiedMethod(const DexFile* dex_file, uint32_t method_idx) const;
bool IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc);
@@ -538,14 +520,10 @@
public: // TODO make private or eliminate.
// Compute constant code and method pointers when possible.
- void GetCodeAndMethodForDirectCall(/*out*/InvokeType* type,
- InvokeType sharp_type,
- bool no_guarantee_of_dex_cache_entry,
- const mirror::Class* referrer_class,
+ void GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class,
ArtMethod* method,
- /*out*/int* stats_flags,
- MethodReference* target_method,
- uintptr_t* direct_code, uintptr_t* direct_method)
+ /* out */ uintptr_t* direct_code,
+ /* out */ uintptr_t* direct_method)
REQUIRES_SHARED(Locks::mutator_lock_);
private:
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index cf633df..0f8cdbb 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -346,7 +346,7 @@
// Initialize to anything to silent compiler warnings.
QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
- switch (invoke->GetOriginalInvokeType()) {
+ switch (invoke->GetInvokeType()) {
case kStatic:
entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck;
break;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index c0c798d..8500204 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -515,7 +515,7 @@
// otherwise return a fall-back info that should be used instead.
virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) = 0;
+ HInvokeStaticOrDirect* invoke) = 0;
// Generate a call to a static or direct method.
virtual void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) = 0;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index a052873..6be458c 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6672,7 +6672,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) {
+ HInvokeStaticOrDirect* invoke) {
HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
// We disable pc-relative load when there is an irreducible loop, as the optimization
// is incompatible with it.
@@ -6686,7 +6686,7 @@
if (dispatch_info.code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative) {
const DexFile& outer_dex_file = GetGraph()->GetDexFile();
- if (&outer_dex_file != target_method.dex_file) {
+ if (&outer_dex_file != invoke->GetTargetMethod().dex_file) {
// Calls across dex files are more likely to exceed the available BL range,
// so use absolute patch with fixup if available and kCallArtMethod otherwise.
HInvokeStaticOrDirect::CodePtrLocation code_ptr_location =
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 424a1a1..6416d40 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -454,7 +454,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a29e9f3..7160607 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3544,7 +3544,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method ATTRIBUTE_UNUSED) {
+ HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
// On ARM64 we support all dispatch types.
return desired_dispatch_info;
}
@@ -3588,7 +3588,7 @@
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
// Add ADRP with its PC-relative DexCache access patch.
- const DexFile& dex_file = *invoke->GetTargetMethod().dex_file;
+ const DexFile& dex_file = invoke->GetDexFile();
uint32_t element_offset = invoke->GetDexCacheArrayOffset();
vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
{
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index f1dc7ee..a152245 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -522,7 +522,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index b06c84d..226f109 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -432,7 +432,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) {
+ HInvokeStaticOrDirect* invoke) {
TODO_VIXL32(FATAL);
return desired_dispatch_info;
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index d0c2c85..7b7118c 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -363,7 +363,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 2211ea3..f560207 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -4327,7 +4327,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method ATTRIBUTE_UNUSED) {
+ HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
// We disable PC-relative load when there is an irreducible loop, as the optimization
// is incompatible with it.
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 553a7e6..f943978 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -395,7 +395,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5039fad..a5e2351 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -2972,7 +2972,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method ATTRIBUTE_UNUSED) {
+ HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
switch (desired_dispatch_info.method_load_kind) {
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 2dd409a..690eccb 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -343,7 +343,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index cc9fe83..47dfb2e 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4217,7 +4217,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method ATTRIBUTE_UNUSED) {
+ HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
// We disable pc-relative load when there is an irreducible loop, as the optimization
@@ -4297,7 +4297,7 @@
__ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset));
// Bind a new fixup label at the end of the "movl" insn.
uint32_t offset = invoke->GetDexCacheArrayOffset();
- __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset));
+ __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
break;
}
case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 5866e65..1ae9af3 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -402,7 +402,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
// Generate a call to a static or direct method.
Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 1d87bf6..59c0ca4 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -733,7 +733,7 @@
HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method ATTRIBUTE_UNUSED) {
+ HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
switch (desired_dispatch_info.code_ptr_location) {
case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
@@ -775,7 +775,7 @@
Address::Absolute(kDummy32BitOffset, /* no_rip */ false));
// Bind a new fixup label at the end of the "movl" insn.
uint32_t offset = invoke->GetDexCacheArrayOffset();
- __ Bind(NewPcRelativeDexCacheArrayPatch(*invoke->GetTargetMethod().dex_file, offset));
+ __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFile(), offset));
break;
}
case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 7108676..594f051 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -399,7 +399,7 @@
// otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
- MethodReference target_method) OVERRIDE;
+ HInvokeStaticOrDirect* invoke) OVERRIDE;
Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc
index 6ad9b07..7010171 100644
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc
@@ -82,12 +82,10 @@
// we need to add the dex cache arrays base as the special input.
if (invoke->HasPcRelativeDexCache() &&
!IsCallFreeIntrinsic<IntrinsicLocationsBuilderARM>(invoke, codegen_)) {
- // Initialize base for target method dex file if needed.
- MethodReference target_method = invoke->GetTargetMethod();
- HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file);
+ HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
// Update the element offset in base.
- DexCacheArraysLayout layout(kArmPointerSize, target_method.dex_file);
- base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index));
+ DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFile());
+ base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
// Add the special argument base to the method.
DCHECK(!invoke->HasCurrentMethodInput());
invoke->AddSpecialInput(base);
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc
index 300284d..4456b49 100644
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_mips.cc
@@ -89,11 +89,10 @@
if (invoke->HasPcRelativeDexCache() &&
!IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) {
// Initialize base for target method dex file if needed.
- MethodReference target_method = invoke->GetTargetMethod();
- HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(*target_method.dex_file);
+ HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(invoke->GetDexFile());
// Update the element offset in base.
- DexCacheArraysLayout layout(kMipsPointerSize, target_method.dex_file);
- base->UpdateElementOffset(layout.MethodOffset(target_method.dex_method_index));
+ DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFile());
+ base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex()));
// Add the special argument base to the method.
DCHECK(!invoke->HasCurrentMethodInput());
invoke->AddSpecialInput(base);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index b3d5341..912ee29 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -447,7 +447,7 @@
void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE {
VisitInvoke(invoke);
- StartAttributeStream("invoke_type") << invoke->GetOriginalInvokeType();
+ StartAttributeStream("invoke_type") << invoke->GetInvokeType();
}
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index ce53134..f21dc0e 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -263,42 +263,24 @@
return false; // Don't bother to move further if we know the method is unresolved.
}
- uint32_t method_index = invoke_instruction->GetDexMethodIndex();
ScopedObjectAccess soa(Thread::Current());
+ uint32_t method_index = invoke_instruction->GetDexMethodIndex();
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, caller_dex_file);
- ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker();
// We can query the dex cache directly. The verifier has populated it already.
- ArtMethod* resolved_method;
+ ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod();
ArtMethod* actual_method = nullptr;
- 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 = IsSameDexFile(caller_dex_file, *ref.dex_file)
- ? caller_compilation_unit_.GetDexCache().Get()
- : class_linker->FindDexCache(soa.Self(), *ref.dex_file);
- resolved_method = dex_cache->GetResolvedMethod(
- ref.dex_method_index, class_linker->GetImagePointerSize());
- // actual_method == resolved_method for direct or static calls.
+ if (resolved_method == nullptr) {
+ DCHECK(invoke_instruction->IsInvokeStaticOrDirect());
+ DCHECK(invoke_instruction->AsInvokeStaticOrDirect()->IsStringInit());
+ VLOG(compiler) << "Not inlining a String.<init> method";
+ return false;
+ } else if (invoke_instruction->IsInvokeStaticOrDirect()) {
actual_method = resolved_method;
} else {
- resolved_method = caller_compilation_unit_.GetDexCache().Get()->GetResolvedMethod(
- method_index, class_linker->GetImagePointerSize());
- if (resolved_method != nullptr) {
- // Check if we can statically find the method.
- actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
- }
- }
-
- if (resolved_method == nullptr) {
- // TODO: Can this still happen?
- // Method cannot be resolved if it is in another dex file we do not have access to.
- VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, caller_dex_file);
- return false;
+ // Check if we can statically find the method.
+ actual_method = FindVirtualOrInterfaceTarget(invoke_instruction, resolved_method);
}
if (actual_method != nullptr) {
@@ -763,9 +745,9 @@
// 2) We will not go to the conflict trampoline with an invoke-virtual.
// TODO: Consider sharpening once it is not dependent on the compiler driver.
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
- uint32_t method_index = FindMethodIndexIn(
+ uint32_t dex_method_index = FindMethodIndexIn(
method, caller_dex_file, invoke_instruction->GetDexMethodIndex());
- if (method_index == DexFile::kDexNoIndex) {
+ if (dex_method_index == DexFile::kDexNoIndex) {
return false;
}
HInvokeVirtual* new_invoke = new (graph_->GetArena()) HInvokeVirtual(
@@ -773,7 +755,8 @@
invoke_instruction->GetNumberOfArguments(),
invoke_instruction->GetType(),
invoke_instruction->GetDexPc(),
- method_index,
+ dex_method_index,
+ method,
method->GetMethodIndex());
HInputsRef inputs = invoke_instruction->GetInputs();
for (size_t index = 0; index != inputs.size(); ++index) {
@@ -1122,7 +1105,7 @@
}
}
- InvokeType invoke_type = invoke_instruction->GetOriginalInvokeType();
+ InvokeType invoke_type = invoke_instruction->GetInvokeType();
if (invoke_type == kInterface) {
// We have statically resolved the dispatch. To please the class linker
// at runtime, we change this call as if it was a virtual call.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index d7e4c53..5a6a212 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -785,8 +785,6 @@
number_of_arguments++;
}
- MethodReference target_method(dex_file_, method_idx);
-
// Special handling for string init.
int32_t string_init_offset = 0;
bool is_string_init = compiler_driver_->IsStringInit(method_idx,
@@ -800,16 +798,17 @@
dchecked_integral_cast<uint64_t>(string_init_offset),
0U
};
+ MethodReference target_method(dex_file_, method_idx);
HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
arena_,
number_of_arguments - 1,
Primitive::kPrimNot /*return_type */,
dex_pc,
method_idx,
- target_method,
+ nullptr,
dispatch_info,
invoke_type,
- kStatic /* optimized_invoke_type */,
+ target_method,
HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
return HandleStringInit(invoke,
number_of_vreg_arguments,
@@ -853,10 +852,9 @@
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
+ // Update the method index 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);
}
}
@@ -866,15 +864,17 @@
0u,
0U
};
+ MethodReference target_method(resolved_method->GetDexFile(),
+ resolved_method->GetDexMethodIndex());
invoke = new (arena_) HInvokeStaticOrDirect(arena_,
number_of_arguments,
return_type,
dex_pc,
method_idx,
- target_method,
+ resolved_method,
dispatch_info,
invoke_type,
- invoke_type,
+ target_method,
clinit_check_requirement);
} else if (invoke_type == kVirtual) {
ScopedObjectAccess soa(Thread::Current()); // Needed for the method index
@@ -883,15 +883,17 @@
return_type,
dex_pc,
method_idx,
+ resolved_method,
resolved_method->GetMethodIndex());
} else {
DCHECK_EQ(invoke_type, kInterface);
- ScopedObjectAccess soa(Thread::Current()); // Needed for the method index
+ ScopedObjectAccess soa(Thread::Current()); // Needed for the IMT index.
invoke = new (arena_) HInvokeInterface(arena_,
number_of_arguments,
return_type,
dex_pc,
method_idx,
+ resolved_method,
resolved_method->GetImtIndex());
}
@@ -1103,7 +1105,7 @@
size_t start_index = 0;
size_t argument_index = 0;
- if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call.
+ if (invoke->GetInvokeType() != InvokeType::kStatic) { // Instance call.
uint32_t obj_reg = is_range ? register_index : args[0];
HInstruction* arg = is_unresolved
? LoadLocal(obj_reg, Primitive::kPrimNot)
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index b787888..ff829af 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -1657,7 +1657,7 @@
bool is_left,
Primitive::Type type) {
DCHECK(invoke->IsInvokeStaticOrDirect());
- DCHECK_EQ(invoke->GetOriginalInvokeType(), InvokeType::kStatic);
+ DCHECK_EQ(invoke->GetInvokeType(), InvokeType::kStatic);
HInstruction* value = invoke->InputAt(0);
HInstruction* distance = invoke->InputAt(1);
// Replace the invoke with an HRor.
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 418d59c..4d4bbcf 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -532,9 +532,7 @@
// inline. If the precise type is known, however, the instruction will be sharpened to an
// InvokeStaticOrDirect.
InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
- InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
- invoke->AsInvokeStaticOrDirect()->GetOptimizedInvokeType() :
- invoke->IsInvokeVirtual() ? kVirtual : kSuper;
+ InvokeType invoke_type = invoke->GetInvokeType();
switch (intrinsic_type) {
case kStatic:
return (invoke_type == kStatic);
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6d207765..57ae555 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -3742,8 +3742,8 @@
uint32_t GetDexMethodIndex() const { return dex_method_index_; }
const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
- InvokeType GetOriginalInvokeType() const {
- return GetPackedField<OriginalInvokeTypeField>();
+ InvokeType GetInvokeType() const {
+ return GetPackedField<InvokeTypeField>();
}
Intrinsics GetIntrinsic() const {
@@ -3777,21 +3777,22 @@
bool IsIntrinsic() const { return intrinsic_ != Intrinsics::kNone; }
+ ArtMethod* GetResolvedMethod() const { return resolved_method_; }
+
DECLARE_ABSTRACT_INSTRUCTION(Invoke);
protected:
- static constexpr size_t kFieldOriginalInvokeType = kNumberOfGenericPackedBits;
- static constexpr size_t kFieldOriginalInvokeTypeSize =
+ static constexpr size_t kFieldInvokeType = kNumberOfGenericPackedBits;
+ static constexpr size_t kFieldInvokeTypeSize =
MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
static constexpr size_t kFieldReturnType =
- kFieldOriginalInvokeType + kFieldOriginalInvokeTypeSize;
+ kFieldInvokeType + kFieldInvokeTypeSize;
static constexpr size_t kFieldReturnTypeSize =
MinimumBitsToStore(static_cast<size_t>(Primitive::kPrimLast));
static constexpr size_t kFlagCanThrow = kFieldReturnType + kFieldReturnTypeSize;
static constexpr size_t kNumberOfInvokePackedBits = kFlagCanThrow + 1;
static_assert(kNumberOfInvokePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
- using OriginalInvokeTypeField =
- BitField<InvokeType, kFieldOriginalInvokeType, kFieldOriginalInvokeTypeSize>;
+ using InvokeTypeField = BitField<InvokeType, kFieldInvokeType, kFieldInvokeTypeSize>;
using ReturnTypeField = BitField<Primitive::Type, kFieldReturnType, kFieldReturnTypeSize>;
HInvoke(ArenaAllocator* arena,
@@ -3800,23 +3801,26 @@
Primitive::Type return_type,
uint32_t dex_pc,
uint32_t dex_method_index,
- InvokeType original_invoke_type)
+ ArtMethod* resolved_method,
+ InvokeType invoke_type)
: HInstruction(
SideEffects::AllExceptGCDependency(), dex_pc), // Assume write/read on all fields/arrays.
number_of_arguments_(number_of_arguments),
+ resolved_method_(resolved_method),
inputs_(number_of_arguments + number_of_other_inputs,
arena->Adapter(kArenaAllocInvokeInputs)),
dex_method_index_(dex_method_index),
intrinsic_(Intrinsics::kNone),
intrinsic_optimizations_(0) {
SetPackedField<ReturnTypeField>(return_type);
- SetPackedField<OriginalInvokeTypeField>(original_invoke_type);
+ SetPackedField<InvokeTypeField>(invoke_type);
SetPackedFlag<kFlagCanThrow>(true);
}
void SetCanThrow(bool can_throw) { SetPackedFlag<kFlagCanThrow>(can_throw); }
uint32_t number_of_arguments_;
+ ArtMethod* const resolved_method_;
ArenaVector<HUserRecord<HInstruction*>> inputs_;
const uint32_t dex_method_index_;
Intrinsics intrinsic_;
@@ -3842,6 +3846,7 @@
return_type,
dex_pc,
dex_method_index,
+ nullptr,
invoke_type) {
}
@@ -3935,10 +3940,10 @@
Primitive::Type return_type,
uint32_t dex_pc,
uint32_t method_index,
- MethodReference target_method,
+ ArtMethod* resolved_method,
DispatchInfo dispatch_info,
- InvokeType original_invoke_type,
- InvokeType optimized_invoke_type,
+ InvokeType invoke_type,
+ MethodReference target_method,
ClinitCheckRequirement clinit_check_requirement)
: HInvoke(arena,
number_of_arguments,
@@ -3950,10 +3955,10 @@
return_type,
dex_pc,
method_index,
- original_invoke_type),
+ resolved_method,
+ invoke_type),
target_method_(target_method),
dispatch_info_(dispatch_info) {
- SetPackedField<OptimizedInvokeTypeField>(optimized_invoke_type);
SetPackedField<ClinitCheckRequirementField>(clinit_check_requirement);
}
@@ -4017,14 +4022,6 @@
uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); }
bool HasSpecialInput() const { return GetNumberOfArguments() != InputCount(); }
- InvokeType GetOptimizedInvokeType() const {
- return GetPackedField<OptimizedInvokeTypeField>();
- }
-
- void SetOptimizedInvokeType(InvokeType invoke_type) {
- SetPackedField<OptimizedInvokeTypeField>(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; }
@@ -4046,8 +4043,6 @@
}
}
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());
@@ -4075,7 +4070,11 @@
// Is this instruction a call to a static method?
bool IsStatic() const {
- return GetOriginalInvokeType() == kStatic;
+ return GetInvokeType() == kStatic;
+ }
+
+ MethodReference GetTargetMethod() const {
+ return target_method_;
}
// Remove the HClinitCheck or the replacement HLoadClass (set as last input by
@@ -4117,26 +4116,18 @@
void RemoveInputAt(size_t index);
private:
- static constexpr size_t kFieldOptimizedInvokeType = kNumberOfInvokePackedBits;
- static constexpr size_t kFieldOptimizedInvokeTypeSize =
- MinimumBitsToStore(static_cast<size_t>(kMaxInvokeType));
- static constexpr size_t kFieldClinitCheckRequirement =
- kFieldOptimizedInvokeType + kFieldOptimizedInvokeTypeSize;
+ static constexpr size_t kFieldClinitCheckRequirement = kNumberOfInvokePackedBits;
static constexpr size_t kFieldClinitCheckRequirementSize =
MinimumBitsToStore(static_cast<size_t>(ClinitCheckRequirement::kLast));
static constexpr size_t kNumberOfInvokeStaticOrDirectPackedBits =
kFieldClinitCheckRequirement + kFieldClinitCheckRequirementSize;
static_assert(kNumberOfInvokeStaticOrDirectPackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
- using OptimizedInvokeTypeField =
- BitField<InvokeType, kFieldOptimizedInvokeType, kFieldOptimizedInvokeTypeSize>;
using ClinitCheckRequirementField = BitField<ClinitCheckRequirement,
kFieldClinitCheckRequirement,
kFieldClinitCheckRequirementSize>;
- // 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
- // in derived class to increase visibility.
+ // Cached values of the resolved method, to avoid needing the mutator lock.
MethodReference target_method_;
DispatchInfo dispatch_info_;
@@ -4152,8 +4143,16 @@
Primitive::Type return_type,
uint32_t dex_pc,
uint32_t dex_method_index,
+ ArtMethod* resolved_method,
uint32_t vtable_index)
- : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kVirtual),
+ : HInvoke(arena,
+ number_of_arguments,
+ 0u,
+ return_type,
+ dex_pc,
+ dex_method_index,
+ resolved_method,
+ kVirtual),
vtable_index_(vtable_index) {}
bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -4166,6 +4165,7 @@
DECLARE_INSTRUCTION(InvokeVirtual);
private:
+ // Cached value of the resolved method, to avoid needing the mutator lock.
const uint32_t vtable_index_;
DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
@@ -4178,8 +4178,16 @@
Primitive::Type return_type,
uint32_t dex_pc,
uint32_t dex_method_index,
+ ArtMethod* resolved_method,
uint32_t imt_index)
- : HInvoke(arena, number_of_arguments, 0u, return_type, dex_pc, dex_method_index, kInterface),
+ : HInvoke(arena,
+ number_of_arguments,
+ 0u,
+ return_type,
+ dex_pc,
+ dex_method_index,
+ resolved_method,
+ kInterface),
imt_index_(imt_index) {}
bool CanDoImplicitNullCheckOn(HInstruction* obj) const OVERRIDE {
@@ -4193,6 +4201,7 @@
DECLARE_INSTRUCTION(InvokeInterface);
private:
+ // Cached value of the resolved method, to avoid needing the mutator lock.
const uint32_t imt_index_;
DISALLOW_COPY_AND_ASSIGN(HInvokeInterface);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index e64c005..abec55f 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -61,44 +61,28 @@
return;
}
- // TODO: Avoid CompilerDriver.
- InvokeType original_invoke_type = invoke->GetOriginalInvokeType();
- InvokeType optimized_invoke_type = original_invoke_type;
- MethodReference target_method(&graph_->GetDexFile(), invoke->GetDexMethodIndex());
- int vtable_idx;
- uintptr_t direct_code, direct_method;
- bool success = compiler_driver_->ComputeInvokeInfo(
- &compilation_unit_,
- invoke->GetDexPc(),
- false /* update_stats: already updated in builder */,
- true /* enable_devirtualization */,
- &optimized_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);
+ HGraph* outer_graph = codegen_->GetGraph();
+ ArtMethod* compiling_method = graph_->GetArtMethod();
HInvokeStaticOrDirect::MethodLoadKind method_load_kind;
HInvokeStaticOrDirect::CodePtrLocation code_ptr_location;
uint64_t method_load_data = 0u;
uint64_t direct_code_ptr = 0u;
- HGraph* outer_graph = codegen_->GetGraph();
- if (target_method.dex_file == &outer_graph->GetDexFile() &&
- target_method.dex_method_index == outer_graph->GetMethodIdx()) {
+ if (invoke->GetResolvedMethod() == outer_graph->GetArtMethod()) {
+ DCHECK(outer_graph->GetArtMethod() != nullptr);
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive;
code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf;
} else {
- bool use_pc_relative_instructions =
- ((direct_method == 0u || direct_code == static_cast<uintptr_t>(-1))) &&
- ContainsElement(compiler_driver_->GetDexFilesForOatFile(), target_method.dex_file);
+ uintptr_t direct_code, direct_method;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ compiler_driver_->GetCodeAndMethodForDirectCall(
+ (compiling_method == nullptr) ? nullptr : compiling_method->GetDeclaringClass(),
+ invoke->GetResolvedMethod(),
+ &direct_code,
+ &direct_method);
+ }
if (direct_method != 0u) { // Should we use a direct pointer to the method?
// Note: For JIT, kDirectAddressWithFixup doesn't make sense at all and while
// kDirectAddress would be fine for image methods, we don't support it at the moment.
@@ -110,13 +94,12 @@
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup;
}
} else { // Use dex cache.
- DCHECK_EQ(target_method.dex_file, &graph_->GetDexFile());
- if (use_pc_relative_instructions) { // Can we use PC-relative access to the dex cache arrays?
- DCHECK(!Runtime::Current()->UseJitCompilation());
+ if (!Runtime::Current()->UseJitCompilation()) {
+ // Use PC-relative access to the dex cache arrays.
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative;
DexCacheArraysLayout layout(GetInstructionSetPointerSize(codegen_->GetInstructionSet()),
&graph_->GetDexFile());
- method_load_data = layout.MethodOffset(target_method.dex_method_index);
+ method_load_data = layout.MethodOffset(invoke->GetDexMethodIndex());
} else { // We must go through the ArtMethod's pointer to resolved methods.
method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
}
@@ -125,10 +108,11 @@
// Note: For JIT, kCallPCRelative and kCallDirectWithFixup don't make sense at all and
// while kCallDirect would be fine for image methods, we don't support it at the moment.
DCHECK(!Runtime::Current()->UseJitCompilation());
+ const DexFile* dex_file_of_callee = invoke->GetTargetMethod().dex_file;
if (direct_code != static_cast<uintptr_t>(-1)) { // Is the code pointer known now?
code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirect;
direct_code_ptr = direct_code;
- } else if (use_pc_relative_instructions) {
+ } else if (ContainsElement(compiler_driver_->GetDexFilesForOatFile(), dex_file_of_callee)) {
// Use PC-relative calls for invokes within a multi-dex oat file.
code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative;
} else { // The direct pointer will be known at link time.
@@ -151,8 +135,7 @@
method_load_kind, code_ptr_location, method_load_data, direct_code_ptr
};
HInvokeStaticOrDirect::DispatchInfo dispatch_info =
- codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info,
- invoke->GetTargetMethod());
+ codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke);
invoke->SetDispatchInfo(dispatch_info);
}
diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build
deleted file mode 100644
index 92ddfc9..0000000
--- a/test/555-checker-regression-x86const/build
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-# Stop if something fails.
-set -e
-
-# We can't use src-ex testing infrastructure because src and src-ex are compiled
-# with javac independetely and can't share code (without reflection).
-
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-mv classes/UnresolvedClass.class classes-ex
-
-if [ ${USE_JACK} = "true" ]; then
- jar cf classes.jill.jar -C classes .
- jar cf classes-ex.jill.jar -C classes-ex .
-
- ${JACK} --import classes.jill.jar --output-dex .
- zip $TEST_NAME.jar classes.dex
- ${JACK} --import classes-ex.jill.jar --output-dex .
- zip ${TEST_NAME}-ex.jar classes.dex
-else
- if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
- zip $TEST_NAME.jar classes.dex
- ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
- zip ${TEST_NAME}-ex.jar classes.dex
- fi
-fi
diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/555-checker-regression-x86const/expected.txt
+++ /dev/null
diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt
deleted file mode 100644
index c4037fa..0000000
--- a/test/555-checker-regression-x86const/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Check that X86 FP constant-area handling handles intrinsics with CurrentMethod
-on the call.
diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run
deleted file mode 100644
index 63fdb8c..0000000
--- a/test/555-checker-regression-x86const/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-# Use secondary switch to add secondary dex file to class path.
-exec ${RUN} "${@}" --secondary
diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java
deleted file mode 100644
index 914cfde..0000000
--- a/test/555-checker-regression-x86const/src/Main.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-public class Main extends UnresolvedClass {
-
- /// CHECK-START: float Main.callAbs(float) register (before)
- /// CHECK: <<CurrentMethod:[ij]\d+>> CurrentMethod
- /// CHECK: <<ParamValue:f\d+>> ParameterValue
- /// CHECK: InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs
- static public float callAbs(float f) {
- // An intrinsic invoke in a method that has unresolved references will still
- // have a CurrentMethod as an argument. The X86 pc_relative_fixups_x86 pass
- // must be able to handle Math.abs invokes that have a CurrentMethod, as both
- // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask)
- // expect to be in the 'SpecialInputIndex' input index.
- return Math.abs(f);
- }
-
- static public void main(String[] args) {
- expectEquals(callAbs(-6.5f), 6.5f);
- }
-
- public static void expectEquals(float expected, float result) {
- if (expected != result) {
- throw new Error("Expected: " + expected + ", found: " + result);
- }
- }
-}
diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java
deleted file mode 100644
index e98bdbf..0000000
--- a/test/555-checker-regression-x86const/src/Unresolved.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2016 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 UnresolvedClass {
-}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0497735..211a69f 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -263,9 +263,12 @@
# 147-stripped-dex-fallback isn't supported on device because --strip-dex
# requires the zip command.
# 569-checker-pattern-replacement tests behaviour present only on host.
+# 902-hello-transformation isn't supported in current form due to linker
+# restrictions. See b/31681198
TEST_ART_BROKEN_TARGET_TESTS := \
147-stripped-dex-fallback \
- 569-checker-pattern-replacement
+ 569-checker-pattern-replacement \
+ 902-hello-transformation
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/run-test b/test/run-test
index 250263a..c50a9ca 100755
--- a/test/run-test
+++ b/test/run-test
@@ -476,7 +476,7 @@
run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}:${ANDROID_HOST_OUT}/nativetest${suffix64}"
else
guess_target_arch_name
- run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}:/system/lib${suffix64}"
+ run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}:${android_root}/lib${suffix64}"
run_args="${run_args} --boot /data/art-test/core${image_suffix}${pic_image_suffix}${multi_image_suffix}.art"
fi
if [ "$relocate" = "yes" ]; then
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 48ce295..3eb41cf 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -14,7 +14,7 @@
================
jfuzz [-s seed] [-d expr-depth] [-l stmt-length]
- [-i if-nest] [-n loop-nest]
+ [-i if-nest] [-n loop-nest] [-v] [-h]
where
@@ -28,6 +28,8 @@
(higher values yield deeper nested conditionals)
-n : defines a fuzzing nest for for/while/do-while loops
(higher values yield deeper nested loops)
+ -v : prints version number and exits
+ -h : prints help and exits
The current version of JFuzz sends all output to stdout, and uses
a fixed testing class named Test. So a typical test run looks as follows.
@@ -43,18 +45,22 @@
[--num_tests=NUM_TESTS]
[--device=DEVICE]
[--mode1=MODE] [--mode2=MODE]
+ [--report_script=SCRIPT]
+ [--jfuzz_arg=ARG]
where
- --num_tests : number of tests to run (10000 by default)
- --device : target device serial number (passed to adb -s)
- --mode1 : m1
- --mode2 : m2, with m1 != m2, and values one of
+ --num_tests : number of tests to run (10000 by default)
+ --device : target device serial number (passed to adb -s)
+ --mode1 : m1
+ --mode2 : m2, with m1 != m2, and values one of
ri = reference implementation on host (default for m1)
hint = Art interpreter on host
hopt = Art optimizing on host (default for m2)
tint = Art interpreter on target
topt = Art optimizing on target
+ --report_script : path to script called for each divergence
+ --jfuzz_arg : argument for jfuzz
How to start J/DexFuzz testing (multi-layered)
==============================================
diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc
index fabfc69..82683f2 100644
--- a/tools/jfuzz/jfuzz.cc
+++ b/tools/jfuzz/jfuzz.cc
@@ -1145,7 +1145,7 @@
// Parse options.
while (1) {
- int32_t option = getopt(argc, argv, "s:d:l:i:n:h");
+ int32_t option = getopt(argc, argv, "s:d:l:i:n:vh");
if (option < 0) {
break; // done
}
@@ -1165,12 +1165,15 @@
case 'n':
loop_nest = strtoul(optarg, nullptr, 0);
break;
+ case 'v':
+ fprintf(stderr, "jfuzz version %s\n", VERSION);
+ return 0;
case 'h':
default:
fprintf(stderr,
"usage: %s [-s seed] "
"[-d expr-depth] [-l stmt-length] "
- "[-i if-nest] [-n loop-nest] [-h]\n",
+ "[-i if-nest] [-n loop-nest] [-v] [-h]\n",
argv[0]);
return 1;
}
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index cf2364b..05e8daf 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -20,9 +20,11 @@
import os
import shlex
import shutil
+import subprocess
import sys
from glob import glob
+from subprocess import DEVNULL
from tempfile import mkdtemp
sys.path.append(os.path.dirname(os.path.dirname(
@@ -34,6 +36,7 @@
from common.common import GetJackClassPath
from common.common import GetEnvVariableOrError
from common.common import RunCommand
+from common.common import RunCommandForOutput
from common.common import DeviceTestEnv
# Return codes supported by bisection bug search.
@@ -302,7 +305,8 @@
class JFuzzTester(object):
"""Tester that runs JFuzz many times and report divergences."""
- def __init__(self, num_tests, device, mode1, mode2):
+ def __init__(self, num_tests, device, mode1, mode2, jfuzz_args,
+ report_script):
"""Constructor for the tester.
Args:
@@ -310,11 +314,15 @@
device: string, target device serial number (or None)
mode1: string, execution mode for first runner
mode2: string, execution mode for second runner
+ jfuzz_args: list of strings, additional arguments for jfuzz
+ report_script: string, path to script called for each divergence
"""
self._num_tests = num_tests
self._device = device
self._runner1 = GetExecutionModeRunner(device, mode1)
self._runner2 = GetExecutionModeRunner(device, mode2)
+ self._jfuzz_args = jfuzz_args
+ self._report_script = report_script
self._save_dir = None
self._results_dir = None
self._jfuzz_dir = None
@@ -392,7 +400,8 @@
Raises:
FatalError: error when jfuzz fails
"""
- if RunCommand(['jfuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
+ if (RunCommand(['jfuzz'] + self._jfuzz_args, out='Test.java', err=None)
+ != RetCode.SUCCESS):
raise FatalError('Unexpected error while running JFuzz')
def CheckForDivergence(self, retc1, retc2):
@@ -442,6 +451,44 @@
# Maybe run bisection bug search.
if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
+ # Call reporting script.
+ if self._report_script:
+ self.RunReportScript(retc1, retc2, is_output_divergence)
+
+ def RunReportScript(self, retc1, retc2, is_output_divergence):
+ """Runs report script."""
+ try:
+ title = "Divergence between {0} and {1} (found with fuzz testing)".format(
+ self._runner1.description, self._runner2.description)
+ # Prepare divergence comment.
+ jfuzz_cmd_and_version = subprocess.check_output(
+ ['grep', '-o', 'jfuzz.*', 'Test.java'], universal_newlines=True)
+ (jfuzz_cmd_str, jfuzz_ver) = jfuzz_cmd_and_version.split('(')
+ # Strip right parenthesis and new line.
+ jfuzz_ver = jfuzz_ver[:-2]
+ jfuzz_args = ['\'-{0}\''.format(arg)
+ for arg in jfuzz_cmd_str.strip().split(' -')][1:]
+ wrapped_args = ['--jfuzz_arg={0}'.format(opt) for opt in jfuzz_args]
+ repro_cmd_str = (os.path.basename(__file__) + ' --num_tests 1 ' +
+ ' '.join(wrapped_args))
+ comment = 'jfuzz {0}\nReproduce test:\n{1}\nReproduce divergence:\n{2}\n'.format(
+ jfuzz_ver, jfuzz_cmd_str, repro_cmd_str)
+ if is_output_divergence:
+ (output, _, _) = RunCommandForOutput(
+ ['diff', self._runner1.output_file, self._runner2.output_file],
+ None, subprocess.PIPE, subprocess.STDOUT)
+ comment += 'Diff:\n' + output
+ else:
+ comment += '{0} vs {1}\n'.format(retc1, retc2)
+ # Prepare report script command.
+ script_cmd = [self._report_script, title, comment]
+ ddir = self.GetCurrentDivergenceDir()
+ bisection_out_files = glob(ddir + '/*_bisection_out.txt')
+ if bisection_out_files:
+ script_cmd += ['--bisection_out', bisection_out_files[0]]
+ subprocess.check_call(script_cmd, stdout=DEVNULL, stderr=DEVNULL)
+ except subprocess.CalledProcessError as err:
+ print('Failed to run report script.\n', err)
def RunBisectionSearch(self, args, expected_retcode, expected_output,
runner_id):
@@ -495,12 +542,16 @@
help='execution mode 1 (default: ri)')
parser.add_argument('--mode2', default='hopt',
help='execution mode 2 (default: hopt)')
+ parser.add_argument('--report_script', help='script called for each'
+ 'divergence')
+ parser.add_argument('--jfuzz_arg', default=[], dest='jfuzz_args',
+ action='append', help='argument for jfuzz')
args = parser.parse_args()
if args.mode1 == args.mode2:
raise FatalError('Identical execution modes given')
# Run the JFuzz tester.
- with JFuzzTester(args.num_tests, args.device,
- args.mode1, args.mode2) as fuzzer:
+ with JFuzzTester(args.num_tests, args.device, args.mode1, args.mode2,
+ args.jfuzz_args, args.report_script) as fuzzer:
fuzzer.Run()
if __name__ == '__main__':