Run time illegal access checks on static and direct methods
Fixes test 075.
Change-Id: I28b20451dcae8000dc0e2cb9068dfa5166659d43
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 853c4d2..dd8a483 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -60,7 +60,7 @@
dalvik/libdex
art_cflags := \
- -O2 \
+ -O0 \
-ggdb3 \
-Wall \
-Werror \
@@ -127,6 +127,7 @@
src/calling_convention_arm.cc \
src/calling_convention_x86.cc \
src/card_table.cc \
+ src/constants.cc \
src/context.cc \
src/context_arm.cc.arm \
src/context_x86.cc \
diff --git a/src/class_linker.cc b/src/class_linker.cc
index d8bf664..449bb53 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -83,7 +83,7 @@
const StringPiece& signature) {
ClassHelper kh(c);
std::ostringstream msg;
- msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << "." << signature
+ msg << "no " << (is_direct ? "direct" : "virtual") << " method " << name << signature
<< " in class " << kh.GetDescriptor() << " or its superclasses";
std::string location(kh.GetLocation());
if (!location.empty()) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 35108bb..08c6cc4 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -71,19 +71,36 @@
LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases";
}
-void AOTCompilationStats::Dump() {
- DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
- DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
- DumpStat(resolved_types_, unresolved_types_, "types resolved");
- DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
- DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
- "static fields resolved");
- DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
- "static fields local to a class");
- DumpStat(resolved_virtual_methods_, unresolved_virtual_methods_, "resolved virtual methods");
- DumpStat(resolved_super_methods_, unresolved_super_methods_, "resolved super-class methods");
- DumpStat(resolved_interface_methods_, unresolved_interface_methods_, "resolved interface methods");
-}
+class AOTCompilationStats {
+ public:
+ AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"),
+ types_in_dex_cache_(0), types_not_in_dex_cache_(0),
+ strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
+ resolved_types_(0), unresolved_types_(0),
+ resolved_instance_fields_(0), unresolved_instance_fields_(0),
+ resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0) {
+ for (size_t i = 0; i < kMaxInvokeType; i++) {
+ resolved_methods_[i] = 0;
+ unresolved_methods_[i] = 0;
+ }
+ }
+
+ void Dump() {
+ DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache");
+ DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache");
+ DumpStat(resolved_types_, unresolved_types_, "types resolved");
+ DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved");
+ DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_,
+ "static fields resolved");
+ DumpStat(resolved_local_static_fields_, resolved_static_fields_ + unresolved_static_fields_,
+ "static fields local to a class");
+
+ for (size_t i = 0; i < kMaxInvokeType; i++) {
+ std::ostringstream oss;
+ oss << "resolved " << static_cast<InvokeType>(i) << " methods";
+ DumpStat(resolved_methods_[i], unresolved_methods_[i], oss.str().c_str());
+ }
+ }
// Allow lossy statistics in non-debug builds
#ifndef NDEBUG
@@ -92,82 +109,97 @@
#define STATS_LOCK()
#endif
-void AOTCompilationStats::TypeInDexCache() {
- STATS_LOCK();
- types_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeNotInDexCache() {
- STATS_LOCK();
- types_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringInDexCache() {
- STATS_LOCK();
- strings_in_dex_cache_++;
-}
-
-void AOTCompilationStats::StringNotInDexCache() {
- STATS_LOCK();
- strings_not_in_dex_cache_++;
-}
-
-void AOTCompilationStats::TypeDoesntNeedAccessCheck() {
- STATS_LOCK();
- resolved_types_++;
-}
-
-void AOTCompilationStats::TypeNeedsAccessCheck() {
- STATS_LOCK();
- unresolved_types_++;
-}
-
-void AOTCompilationStats::ResolvedInstanceField() {
- STATS_LOCK();
- resolved_instance_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedInstanceField(){
- STATS_LOCK();
- unresolved_instance_fields_++;
-}
-
-void AOTCompilationStats::ResolvedLocalStaticField() {
- STATS_LOCK();
- resolved_local_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedStaticField() {
- STATS_LOCK();
- resolved_static_fields_++;
-}
-
-void AOTCompilationStats::UnresolvedStaticField() {
- STATS_LOCK();
- unresolved_static_fields_++;
-}
-
-void AOTCompilationStats::ResolvedMethod(bool is_interface, bool is_super) {
- STATS_LOCK();
- if (is_interface) {
- resolved_interface_methods_++;
- } else if (is_super) {
- resolved_super_methods_++;
- } else {
- resolved_virtual_methods_++;
+ void TypeInDexCache() {
+ STATS_LOCK();
+ types_in_dex_cache_++;
}
-}
-void AOTCompilationStats::UnresolvedMethod(bool is_interface, bool is_super) {
- STATS_LOCK();
- if (is_interface) {
- unresolved_interface_methods_++;
- } else if (is_super) {
- unresolved_super_methods_++;
- } else {
- unresolved_virtual_methods_++;
+ void TypeNotInDexCache() {
+ STATS_LOCK();
+ types_not_in_dex_cache_++;
}
-}
+
+ void StringInDexCache() {
+ STATS_LOCK();
+ strings_in_dex_cache_++;
+ }
+
+ void StringNotInDexCache() {
+ STATS_LOCK();
+ strings_not_in_dex_cache_++;
+ }
+
+ void TypeDoesntNeedAccessCheck() {
+ STATS_LOCK();
+ resolved_types_++;
+ }
+
+ void TypeNeedsAccessCheck() {
+ STATS_LOCK();
+ unresolved_types_++;
+ }
+
+ void ResolvedInstanceField() {
+ STATS_LOCK();
+ resolved_instance_fields_++;
+ }
+
+ void UnresolvedInstanceField(){
+ STATS_LOCK();
+ unresolved_instance_fields_++;
+ }
+
+ void ResolvedLocalStaticField() {
+ STATS_LOCK();
+ resolved_local_static_fields_++;
+ }
+
+ void ResolvedStaticField() {
+ STATS_LOCK();
+ resolved_static_fields_++;
+ }
+
+ void UnresolvedStaticField() {
+ STATS_LOCK();
+ unresolved_static_fields_++;
+ }
+
+ void ResolvedMethod(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ resolved_methods_[type]++;
+ }
+
+ void UnresolvedMethod(InvokeType type) {
+ DCHECK_LE(type, kMaxInvokeType);
+ STATS_LOCK();
+ unresolved_methods_[type]++;
+ }
+
+ private:
+ Mutex stats_lock_;
+
+ size_t types_in_dex_cache_;
+ size_t types_not_in_dex_cache_;
+
+ size_t strings_in_dex_cache_;
+ size_t strings_not_in_dex_cache_;
+
+ size_t resolved_types_;
+ size_t unresolved_types_;
+
+ size_t resolved_instance_fields_;
+ size_t unresolved_instance_fields_;
+
+ size_t resolved_local_static_fields_;
+ size_t resolved_static_fields_;
+ size_t unresolved_static_fields_;
+
+ size_t resolved_methods_[kMaxInvokeType + 1];
+ size_t unresolved_methods_[kMaxInvokeType + 1];
+
+ DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
+};
Compiler::Compiler(InstructionSet instruction_set, bool image, size_t thread_count,
const std::set<std::string>* image_classes)
@@ -178,6 +210,7 @@
compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
image_(image),
thread_count_(thread_count),
+ stats_(new AOTCompilationStats),
image_classes_(image_classes)
#if defined(ART_USE_LLVM_COMPILER)
,
@@ -257,7 +290,7 @@
timings.Dump();
}
- stats_.Dump();
+ stats_->Dump();
}
void Compiler::CompileOne(const Method* method) {
@@ -320,19 +353,19 @@
bool Compiler::CanAssumeTypeIsPresentInDexCache(const DexCache* dex_cache,
uint32_t type_idx) {
if (!IsImage()) {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
return false;
}
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
return false;
}
bool result = IsImageClass(ClassHelper(resolved_class).GetDescriptor());
if (result) {
- stats_.TypeInDexCache();
+ stats_->TypeInDexCache();
} else {
- stats_.TypeNotInDexCache();
+ stats_->TypeNotInDexCache();
}
return result;
}
@@ -346,9 +379,9 @@
// image classes then we can assume the string is present in the dex cache if it is there now
bool result = IsImage() && image_classes_ == NULL && dex_cache->GetResolvedString(string_idx) != NULL;
if (result) {
- stats_.StringInDexCache();
+ stats_->StringInDexCache();
} else {
- stats_.StringNotInDexCache();
+ stats_->StringNotInDexCache();
}
return result;
}
@@ -358,22 +391,22 @@
// Get type from dex cache assuming it was populated by the verifier
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
if (referrer_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
// Perform access check, will return true if access is ok or false if we're going to have to
// check this at runtime (for example for class loaders).
bool result = referrer_class->CanAccess(resolved_class);
if (result) {
- stats_.TypeDoesntNeedAccessCheck();
+ stats_->TypeDoesntNeedAccessCheck();
} else {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
}
return result;
}
@@ -385,22 +418,22 @@
// Get type from dex cache assuming it was populated by the verifier.
Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Unknown class needs access checks.
}
const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
if (referrer_class == NULL) {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
return false; // Incomplete referrer knowledge needs access check.
}
// Perform access and instantiable checks, will return true if access is ok or false if we're
// going to have to check this at runtime (for example for class loaders).
bool result = referrer_class->CanAccess(resolved_class) && resolved_class->IsInstantiable();
if (result) {
- stats_.TypeDoesntNeedAccessCheck();
+ stats_->TypeDoesntNeedAccessCheck();
} else {
- stats_.TypeNeedsAccessCheck();
+ stats_->TypeNeedsAccessCheck();
}
return result;
}
@@ -439,7 +472,7 @@
resolved_field->GetAccessFlags())) {
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedInstanceField();
+ stats_->ResolvedInstanceField();
return true; // Fast path.
}
}
@@ -448,7 +481,7 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedInstanceField();
+ stats_->UnresolvedInstanceField();
return false; // Incomplete knowledge needs slow path.
}
@@ -470,7 +503,7 @@
is_referrers_class = true; // implies no worrying about class initialization
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedLocalStaticField();
+ stats_->ResolvedLocalStaticField();
return true; // fast path
} else {
Class* fields_class = resolved_field->GetDeclaringClass();
@@ -487,7 +520,7 @@
ssb_index = fields_class->GetDexTypeIndex();
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedStaticField();
+ stats_->ResolvedStaticField();
return true;
}
// Search dex file for localized ssb index
@@ -502,7 +535,7 @@
ssb_index = cUnit->dex_file->GetIndexForTypeId(*type_id);
field_offset = resolved_field->GetOffset().Int32Value();
is_volatile = resolved_field->IsVolatile();
- stats_.ResolvedStaticField();
+ stats_->ResolvedStaticField();
return true;
}
}
@@ -515,12 +548,11 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedStaticField();
+ stats_->UnresolvedStaticField();
return false; // Incomplete knowledge needs slow path.
}
-bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit,
- bool is_interface, bool is_super,
+bool Compiler::ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
int& vtable_idx) {
vtable_idx = -1;
Method* resolved_method = ComputeReferrerMethod(cUnit, method_idx);
@@ -545,15 +577,15 @@
referrer_class->CanAccessMember(methods_class,
resolved_method->GetAccessFlags())) {
vtable_idx = resolved_method->GetMethodIndex();
- if (is_interface || !is_super) {
- // nothing left to do for virtual/interface dispatch
- stats_.ResolvedMethod(is_interface, is_super);
+ if (type != kSuper) {
+ // nothing left to do for static/direct/virtual/interface dispatch
+ stats_->ResolvedMethod(type);
return true;
} else {
// ensure the vtable index will be correct to dispatch in the vtable of the super class
if (referrer_class->IsSubClass(methods_class) &&
vtable_idx < methods_class->GetVTable()->GetLength()) {
- stats_.ResolvedMethod(is_interface, is_super);
+ stats_->ResolvedMethod(type);
return true;
}
}
@@ -565,7 +597,7 @@
if (thread->IsExceptionPending()) {
thread->ClearException();
}
- stats_.UnresolvedMethod(is_interface, is_super);
+ stats_->UnresolvedMethod(type);
return false; // Incomplete knowledge needs slow path.
}
diff --git a/src/compiler.h b/src/compiler.h
index 186d433..0c6b2bf 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -37,72 +37,11 @@
namespace art {
+class AOTCompilationStats;
class Context;
class TimingLogger;
typedef struct CompilationUnit CompilationUnit;
-class AOTCompilationStats {
- public:
- AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"),
- types_in_dex_cache_(0), types_not_in_dex_cache_(0),
- strings_in_dex_cache_(0), strings_not_in_dex_cache_(0),
- resolved_types_(0), unresolved_types_(0),
- resolved_instance_fields_(0), unresolved_instance_fields_(0),
- resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0),
- resolved_virtual_methods_(0), unresolved_virtual_methods_(0),
- resolved_super_methods_(0), unresolved_super_methods_(0),
- resolved_interface_methods_(0), unresolved_interface_methods_(0) {}
- void Dump();
-
- void TypeInDexCache();
- void TypeNotInDexCache();
-
- void StringInDexCache();
- void StringNotInDexCache();
-
- void TypeDoesntNeedAccessCheck();
- void TypeNeedsAccessCheck();
-
- void ResolvedInstanceField();
- void UnresolvedInstanceField();
-
- void ResolvedLocalStaticField();
- void ResolvedStaticField();
- void UnresolvedStaticField();
-
- void ResolvedMethod(bool is_interface, bool is_super);
- void UnresolvedMethod(bool is_interface, bool is_super);
-
- private:
- Mutex stats_lock_;
-
- size_t types_in_dex_cache_;
- size_t types_not_in_dex_cache_;
-
- size_t strings_in_dex_cache_;
- size_t strings_not_in_dex_cache_;
-
- size_t resolved_types_;
- size_t unresolved_types_;
-
- size_t resolved_instance_fields_;
- size_t unresolved_instance_fields_;
-
- size_t resolved_local_static_fields_;
- size_t resolved_static_fields_;
- size_t unresolved_static_fields_;
-
- size_t resolved_virtual_methods_;
- size_t unresolved_virtual_methods_;
-
- size_t resolved_super_methods_;
- size_t unresolved_super_methods_;
-
- size_t resolved_interface_methods_;
- size_t unresolved_interface_methods_;
-
- DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);;
-};
class Compiler {
public:
@@ -177,8 +116,8 @@
bool& is_referrers_class, bool& is_volatile);
// Can we fastpath a interface, super class or virtual method call? Computes method's vtable index
- bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, bool is_interface,
- bool is_super, int& vtable_idx);
+ bool ComputeInvokeInfo(uint32_t method_idx, CompilationUnit* cUnit, InvokeType type,
+ int& vtable_idx);
#if defined(ART_USE_LLVM_COMPILER)
compiler_llvm::CompilerLLVM* GetCompilerLLVM() const {
@@ -250,11 +189,10 @@
size_t thread_count_;
uint64_t start_ns_;
- AOTCompilationStats stats_;
+ UniquePtr<AOTCompilationStats> stats_;
const std::set<std::string>* image_classes_;
-
#if defined(ART_USE_LLVM_COMPILER)
UniquePtr<compiler_llvm::CompilerLLVM> compiler_llvm_;
#endif
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index cbf5867..a1793e0 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -469,29 +469,14 @@
return state + 1;
}
-STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir,
- bool accessCheck, bool isInterface,
- bool isSuper, int state, uint32_t dexIdx,
- uint32_t methodIdx)
+STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir, int trampoline,
+ int state, uint32_t dexIdx, uint32_t methodIdx)
{
/*
* This handles the case in which the base method is not fully
* resolved at compile time, we bail to a runtime helper.
*/
if (state == 0) {
- int trampoline;
- if (!accessCheck) {
- DCHECK(isInterface);
- trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
- } else {
- if (isInterface) {
- trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
- } else if (isSuper) {
- trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
- } else {
- trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
- }
- }
// Load trampoline target
loadWordDisp(cUnit, rSELF, trampoline, rLR);
// Load r0 with method index
@@ -501,18 +486,32 @@
return -1;
}
+STATIC int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
+STATIC int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ int state, uint32_t dexIdx, uint32_t methodIdx)
+{
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
+}
+
STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t methodIdx)
{
- return nextInvokeInsnSP(cUnit, mir, true, false, true, state, dexIdx,
- methodIdx);
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t methodIdx)
{
- return nextInvokeInsnSP(cUnit, mir, true, false, false, state, dexIdx,
- methodIdx);
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
/*
@@ -522,7 +521,8 @@
STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t unused)
{
- return nextInvokeInsnSP(cUnit, mir, false, true, false, state, dexIdx, 0);
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
@@ -530,7 +530,8 @@
uint32_t dexIdx,
uint32_t unused)
{
- return nextInvokeInsnSP(cUnit, mir, true, true, false, state, dexIdx, 0);
+ int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
+ return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
}
STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
@@ -569,9 +570,9 @@
*/
STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int callState,
- ArmLIR** pcrLabel, bool isRange,
- NextCallInsn nextCallInsn, uint32_t dexIdx,
- uint32_t methodIdx, bool skipThis)
+ ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
+ uint32_t dexIdx, uint32_t methodIdx,
+ bool skipThis)
{
RegLocation rlArg;
@@ -676,7 +677,7 @@
// If we can treat it as non-range (Jumbo ops will use range form)
if (numArgs <= 5)
return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
- true, nextCallInsn, dexIdx, methodIdx,
+ nextCallInsn, dexIdx, methodIdx,
skipThis);
/*
* Make sure range list doesn't span the break between in normal
@@ -766,45 +767,13 @@
branchOver->generic.target = (LIR*)target;
}
-STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
- bool direct, bool range)
+STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir,
+ InvokeType type, bool isRange)
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
- ArmLIR** pNullCk = direct ? &nullCk : NULL;
- NextCallInsn nextCallInsn = nextSDCallInsn;
- oatFlushAllRegs(cUnit); /* Everything to home location */
-
- // Explicit register usage
- oatLockCallTemps(cUnit);
-
- uint32_t dexMethodIdx = mir->dalvikInsn.vB;
-
- if (range) {
- callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
- nextCallInsn, dexMethodIdx, 0, false);
- } else {
- callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
- false, nextCallInsn, dexMethodIdx,
- 0, false);
- }
- // Finish up any of the call sequence not interleaved in arg loading
- while (callState >= 0) {
- callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx, 0);
- }
- if (DISPLAY_MISSING_TARGETS) {
- genShowTarget(cUnit);
- }
- opReg(cUnit, kOpBlx, rLR);
- oatClobberCalleeSave(cUnit);
-}
-
-STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir, bool isInterface,
- bool isSuper, bool isRange)
-{
- DecodedInstruction* dInsn = &mir->dalvikInsn;
- int callState = 0;
+ ArmLIR** pNullCk = NULL;
NextCallInsn nextCallInsn;
oatFlushAllRegs(cUnit); /* Everything to home location */
// Explicit register usage
@@ -812,25 +781,38 @@
uint32_t dexMethodIdx = dInsn->vB;
int vtableIdx;
+ bool skipThis;
bool fastPath =
- cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit,
- isInterface, isSuper, vtableIdx)
+ cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit, type,
+ vtableIdx)
&& !SLOW_INVOKE_PATH;
- if (isInterface) {
+ if (type == kInterface) {
nextCallInsn = fastPath ? nextInterfaceCallInsn
: nextInterfaceCallInsnWithAccessCheck;
- } else if (isSuper) {
+ skipThis = false;
+ } else if (type == kDirect) {
+ if (fastPath) {
+ pNullCk = &nullCk;
+ }
+ nextCallInsn = fastPath ? nextSDCallInsn : nextDirectCallInsnSP;
+ skipThis = false;
+ } else if (type == kStatic) {
+ nextCallInsn = fastPath ? nextSDCallInsn : nextStaticCallInsnSP;
+ skipThis = false;
+ } else if (type == kSuper) {
nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
+ skipThis = fastPath;
} else {
+ DCHECK_EQ(type, kVirtual);
nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+ skipThis = fastPath;
}
- bool skipThis = fastPath && !isInterface;
if (!isRange) {
- callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
- false, nextCallInsn, dexMethodIdx,
+ callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
+ nextCallInsn, dexMethodIdx,
vtableIdx, skipThis);
} else {
- callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
+ callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
nextCallInsn, dexMethodIdx, vtableIdx,
skipThis);
}
@@ -1296,48 +1278,38 @@
break;
case OP_INVOKE_STATIC_RANGE:
- genInvokeStaticDirect(cUnit, mir, false /*direct*/,
- true /*range*/);
+ genInvoke(cUnit, mir, kStatic, true /*range*/);
break;
case OP_INVOKE_STATIC:
- genInvokeStaticDirect(cUnit, mir, false /*direct*/,
- false /*range*/);
+ genInvoke(cUnit, mir, kStatic, false /*range*/);
break;
case OP_INVOKE_DIRECT:
- genInvokeStaticDirect(cUnit, mir, true /*direct*/,
- false /*range*/);
+ genInvoke(cUnit, mir, kDirect, false /*range*/);
break;
case OP_INVOKE_DIRECT_RANGE:
- genInvokeStaticDirect(cUnit, mir, true /*direct*/,
- true /*range*/);
+ genInvoke(cUnit, mir, kDirect, true /*range*/);
break;
case OP_INVOKE_VIRTUAL:
- genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
- false /*range*/);
+ genInvoke(cUnit, mir, kVirtual, false /*range*/);
break;
case OP_INVOKE_VIRTUAL_RANGE:
- genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
- true /*range*/);
+ genInvoke(cUnit, mir, kVirtual, true /*range*/);
break;
case OP_INVOKE_SUPER:
- genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
- false /*range*/);
+ genInvoke(cUnit, mir, kSuper, false /*range*/);
break;
case OP_INVOKE_SUPER_RANGE:
- genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
- true /*range*/);
+ genInvoke(cUnit, mir, kSuper, true /*range*/);
break;
case OP_INVOKE_INTERFACE:
- genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
- false /*range*/);
+ genInvoke(cUnit, mir, kInterface, false /*range*/);
break;
case OP_INVOKE_INTERFACE_RANGE:
- genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
- true /*range*/);
+ genInvoke(cUnit, mir, kInterface, true /*range*/);
break;
case OP_NEG_INT:
diff --git a/src/constants.cc b/src/constants.cc
new file mode 100644
index 0000000..c32f136
--- /dev/null
+++ b/src/constants.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "constants.h"
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& os, const InvokeType& rhs) {
+ switch (rhs) {
+ case kStatic: os << "static"; break;
+ case kDirect: os << "direct"; break;
+ case kVirtual: os << "virtual"; break;
+ case kSuper: os << "super"; break;
+ case kInterface: os << "interface"; break;
+ default: os << "InvokeType[" << static_cast<int>(rhs) << "]"; break;
+ }
+ return os;
+}
+
+} // namespace art
diff --git a/src/constants.h b/src/constants.h
index 778d646..5c1323f 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -17,6 +17,8 @@
#ifndef ART_SRC_CONSTANTS_H_
#define ART_SRC_CONSTANTS_H_
+#include <iosfwd>
+
namespace art {
enum InstructionSet {
@@ -26,6 +28,13 @@
kX86
};
+enum InvokeType {
+ kStatic, kDirect, kVirtual, kSuper, kInterface,
+ kMaxInvokeType = kInterface
+};
+
+std::ostream& operator<<(std::ostream& os, const InvokeType& rhs);
+
} // namespace art
#include "constants_x86.h"
diff --git a/src/object.cc b/src/object.cc
index 27b85b0..3aba5c8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1506,7 +1506,7 @@
}
}
Throwable* cause = GetFieldObject<Throwable*>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), false);
- if (cause != NULL) {
+ if (cause != NULL && cause != this) { // Constructor makes cause == this by default.
result += "Caused by: ";
result += cause->Dump();
}
diff --git a/src/object.h b/src/object.h
index a7e012f..f9c8eb7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1016,7 +1016,12 @@
template<class T>
ObjectArray<T>* ObjectArray<T>::Alloc(Class* object_array_class, int32_t length) {
- return Array::Alloc(object_array_class, length, sizeof(uint32_t))->AsObjectArray<T>();
+ Array* array = Array::Alloc(object_array_class, length, sizeof(uint32_t));
+ if (UNLIKELY(array == NULL)) {
+ return NULL;
+ } else {
+ return array->AsObjectArray<T>();
+ }
}
template<class T>
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 670049a..f158680 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -45,13 +45,15 @@
static void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
Class* accessed, const Method* caller,
const Method* called,
- bool is_interface, bool is_super) {
+ InvokeType type) {
+ std::ostringstream type_stream;
+ type_stream << type;
self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"illegal class access ('%s' -> '%s')"
"in attempt to invoke %s method '%s' from '%s'",
PrettyDescriptor(referrer).c_str(),
PrettyDescriptor(accessed).c_str(),
- (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+ type_stream.str().c_str(),
PrettyMethod(called).c_str(),
PrettyMethod(caller).c_str());
}
@@ -89,13 +91,14 @@
}
static void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller,
- uint32_t method_idx, bool is_interface,
- bool is_super) {
+ uint32_t method_idx, InvokeType type) {
const DexFile& dex_file =
Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
+ std::ostringstream type_stream;
+ type_stream << type;
self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
"Attempt to invoke %s method '%s' from '%s' on a null object reference",
- (is_interface ? "interface" : (is_super ? "super class" : "virtual")),
+ type_stream.str().c_str(),
PrettyMethod(method_idx, dex_file, true).c_str(),
PrettyMethod(caller).c_str());
}
@@ -540,40 +543,46 @@
bool is_static, bool is_primitive, size_t expected_size) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
- if (LIKELY(resolved_field != NULL)) {
+ if (UNLIKELY(resolved_field == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ } else {
Class* fields_class = resolved_field->GetDeclaringClass();
Class* referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
+ return NULL; // failure
} else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
resolved_field->GetAccessFlags()))) {
ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
return NULL; // failure
- }
- FieldHelper fh(resolved_field);
- if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
- fh.FieldSize() != expected_size)) {
- self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
- "Attempted read of %zd-bit %s on field '%s'",
- expected_size * (32 / sizeof(int32_t)),
- is_primitive ? "primitive" : "non-primitive",
- PrettyField(resolved_field, true).c_str());
- }
- if (!is_static) {
- // instance fields must be being accessed on an initialized class
- return resolved_field;
} else {
- // If the class is already initializing, we must be inside <clinit>, or
- // we'd still be waiting for the lock.
- if (fields_class->IsInitializing()) {
+ FieldHelper fh(resolved_field);
+ if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+ fh.FieldSize() != expected_size)) {
+ self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
+ "Attempted read of %zd-bit %s on field '%s'",
+ expected_size * (32 / sizeof(int32_t)),
+ is_primitive ? "primitive" : "non-primitive",
+ PrettyField(resolved_field, true).c_str());
+ return NULL; // failure
+ } else if (!is_static) {
+ // instance fields must be being accessed on an initialized class
return resolved_field;
- } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
- return resolved_field;
+ } else {
+ // If the class is already initializing, we must be inside <clinit>, or
+ // we'd still be waiting for the lock.
+ if (fields_class->IsInitializing()) {
+ return resolved_field;
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
+ return resolved_field;
+ } else {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ }
}
}
}
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL;
}
extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
@@ -1118,8 +1127,9 @@
// Fast path method resolution that can't throw exceptions
static Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
- bool access_check, bool is_interface, bool is_super) {
- if (UNLIKELY(this_object == NULL)) {
+ bool access_check, InvokeType type) {
+ bool is_direct = type == kStatic || type == kDirect;
+ if (UNLIKELY(this_object == NULL && !is_direct)) {
return NULL;
}
Method* resolved_method =
@@ -1137,38 +1147,46 @@
return NULL;
}
}
- if (is_interface) {
+ if (type == kInterface) { // Most common form of slow path dispatch.
return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
- } else if (is_super) {
+ } else if (is_direct) {
+ return resolved_method;
+ } else if (type == kSuper) {
return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
} else {
+ DCHECK(type == kVirtual);
return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
}
}
// Slow path method resolution
static Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
- Thread* self, bool access_check, bool is_interface,
- bool is_super) {
+ Thread* self, bool access_check, InvokeType type) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, false);
- if (LIKELY(resolved_method != NULL)) {
+ bool is_direct = type == kStatic || type == kDirect;
+ Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
+ if (UNLIKELY(resolved_method == NULL)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind
+ return NULL; // failure
+ } else {
if (!access_check) {
- if (is_interface) {
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
Method* interface_method =
this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
if (UNLIKELY(interface_method == NULL)) {
ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
resolved_method,
this_object);
- return NULL;
+ return NULL; // failure
} else {
return interface_method;
}
} else {
ObjectArray<Method>* vtable;
uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (is_super) {
+ if (type == kSuper) {
vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
} else {
vtable = this_object->GetClass()->GetVTable();
@@ -1191,8 +1209,7 @@
referring_class);
if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
- referrer, resolved_method, is_interface,
- is_super);
+ referrer, resolved_method, type);
return NULL; // failure
} else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
resolved_method->GetAccessFlags()))) {
@@ -1200,21 +1217,23 @@
return NULL; // failure
}
}
- if (is_interface) {
+ if (is_direct) {
+ return resolved_method;
+ } else if (type == kInterface) {
Method* interface_method =
this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
if (UNLIKELY(interface_method == NULL)) {
ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
resolved_method,
this_object);
- return NULL;
+ return NULL; // failure
} else {
return interface_method;
}
} else {
ObjectArray<Method>* vtable;
uint16_t vtable_index = resolved_method->GetMethodIndex();
- if (is_super) {
+ if (type == kSuper) {
Class* super_class = referring_class->GetSuperClass();
if (LIKELY(super_class != NULL)) {
vtable = referring_class->GetSuperClass()->GetVTable();
@@ -1232,32 +1251,26 @@
self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
"attempt to invoke %s method '%s' from '%s'"
" using incorrect form of method dispatch",
- (is_super ? "super class" : "virtual"),
+ (type == kSuper ? "super class" : "virtual"),
PrettyMethod(resolved_method).c_str(),
PrettyMethod(referrer).c_str());
- return NULL;
+ return NULL; // failure
}
}
}
}
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind
- return NULL;
}
static uint64_t artInvokeCommon(uint32_t method_idx, Object* this_object, Method* caller_method,
- Thread* self, Method** sp, bool access_check, bool is_interface,
- bool is_super){
- Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
- is_interface, is_super);
+ Thread* self, Method** sp, bool access_check, InvokeType type){
+ Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
if (UNLIKELY(method == NULL)) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
- if (UNLIKELY(this_object == NULL)) {
- ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, is_interface,
- is_super);
+ if (UNLIKELY(this_object == NULL && type != kDirect && type != kStatic)) {
+ ThrowNullPointerExceptionForMethodAccess(self, caller_method, method_idx, type);
return 0; // failure
}
- method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check,
- is_interface, is_super);
+ method = FindMethodFromCode(method_idx, this_object, caller_method, self, access_check, type);
if (UNLIKELY(method == NULL)) {
CHECK(self->IsExceptionPending());
return 0; // failure
@@ -1277,28 +1290,43 @@
extern "C" uint64_t artInvokeInterfaceTrampoline(uint32_t method_idx, Object* this_object,
Method* caller_method, Thread* self,
Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, true, false);
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, false, kInterface);
}
extern "C" uint64_t artInvokeInterfaceTrampolineWithAccessCheck(uint32_t method_idx,
Object* this_object,
Method* caller_method, Thread* self,
Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, true, false);
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kInterface);
+}
+
+
+extern "C" uint64_t artInvokeDirectTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kDirect);
+}
+
+extern "C" uint64_t artInvokeStaticTrampolineWithAccessCheck(uint32_t method_idx,
+ Object* this_object,
+ Method* caller_method, Thread* self,
+ Method** sp) {
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kStatic);
}
extern "C" uint64_t artInvokeSuperTrampolineWithAccessCheck(uint32_t method_idx,
Object* this_object,
Method* caller_method, Thread* self,
Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, false, true);
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kSuper);
}
extern "C" uint64_t artInvokeVirtualTrampolineWithAccessCheck(uint32_t method_idx,
Object* this_object,
Method* caller_method, Thread* self,
Method** sp) {
- return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, false, false);
+ return artInvokeCommon(method_idx, this_object, caller_method, self, sp, true, kVirtual);
}
static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index a5e4c87..305bbf6 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -69,8 +69,10 @@
extern "C" void art_check_cast_from_code(void*, void*);
extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
extern "C" void art_handle_fill_data_from_code(void*, void*);
+ extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+ extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
extern "C" void art_lock_object_from_code(void*);
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index 69e908d..b337ebc 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -170,77 +170,45 @@
mov r3, sp @ pass SP
b artThrowVerificationErrorFromCode @ artThrowVerificationErrorFromCode(kind, ref, Thread*, SP)
- .global art_invoke_interface_trampoline
- .extern artInvokeInterfaceTrampoline
/*
- * All generated callsites for interface invokes will load arguments as usual - except instead
- * of loading arg0/r0 with the target Method*, arg0/r0 will contain the method_idx. This
- * wrapper will save arg1-arg3, load the caller's Method*, align the stack and call the helper
- * artFindInterfaceMethodInCacheFromCode(idx, this, method);
+ * All generated callsites for interface invokes and invocation slow paths will load arguments
+ * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
+ * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the
+ * stack and call the appropriate C helper.
* NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
*
- * artInvokeInterfaceTrampoline will attempt to locate the target and return a 64-bit
- * result in r0/r1 consisting of the target Method* in r0 and method->code_ in r1.
+ * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
+ * of the target Method* in r0 and method->code_ in r1.
*
- * If unsuccessful, artInvokeInterfaceTrampoline will return NULL/NULL. There will be
- * a pending exception in the thread and we branch to another stub to deliver it.
+ * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
+ * thread and we branch to another stub to deliver it.
*
* On success this wrapper will restore arguments and *jump* to the target, leaving the lr
* pointing back to the original caller.
*/
-art_invoke_interface_trampoline:
+.macro INVOKE_TRAMPOLINE c_name, cxx_name
+ .global \c_name
+ .extern \cxx_name
+\c_name:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- ldr r2, [sp, #48] @ pass caller Method*
- mov r3, r9 @ pass Thread::Current
- str sp, [sp, #0] @ pass SP
- bl artInvokeInterfaceTrampoline @ (method_idx, this, caller, Thread*, SP)
- mov r12, r1 @ save r0->code_
+ ldr r2, [sp, #48] @ pass caller Method*
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ bl \cxx_name @ (method_idx, this, caller, Thread*, SP)
+ mov r12, r1 @ save r0->code_
RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
- cmp r0, #0 @ did we find the target?
- bxne r12 @ tail call to target if so
+ cmp r0, #0 @ did we find the target?
+ bxne r12 @ tail call to target if so
DELIVER_PENDING_EXCEPTION
+.endm
- .global art_invoke_interface_trampoline_with_access_check
- .extern artInvokeInterfaceTrampolineWithAccessCheck
-art_invoke_interface_trampoline_with_access_check:
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- ldr r2, [sp, #48] @ pass caller Method*
- mov r3, r9 @ pass Thread::Current
- str sp, [sp, #0] @ pass SP
- bl artInvokeInterfaceTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
- mov r12, r1 @ save r0->code_
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
- cmp r0, #0 @ did we find the target?
- bxne r12 @ tail call to target if so
- DELIVER_PENDING_EXCEPTION
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline, artInvokeInterfaceTrampoline
+INVOKE_TRAMPOLINE art_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
- .global art_invoke_super_trampoline_with_access_check
- .extern artInvokeSuperTrampolineWithAccessCheck
-art_invoke_super_trampoline_with_access_check:
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- ldr r2, [sp, #48] @ pass caller Method*
- mov r3, r9 @ pass Thread::Current
- str sp, [sp, #0] @ pass SP
- bl artInvokeSuperTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
- mov r12, r1 @ save r0->code_
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
- cmp r0, #0 @ did we find the target?
- bxne r12 @ tail call to target if so
- DELIVER_PENDING_EXCEPTION
-
- .global art_invoke_virtual_trampoline_with_access_check
- .extern artInvokeVirtualTrampolineWithAccessCheck
-art_invoke_virtual_trampoline_with_access_check:
- SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- ldr r2, [sp, #48] @ pass caller Method*
- mov r3, r9 @ pass Thread::Current
- str sp, [sp, #0] @ pass SP
- bl artInvokeVirtualTrampolineWithAccessCheck @ (method_idx, this, caller, Thread*, SP)
- mov r12, r1 @ save r0->code_
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
- cmp r0, #0 @ did we find the target?
- bxne r12 @ tail call to target if so
- DELIVER_PENDING_EXCEPTION
+INVOKE_TRAMPOLINE art_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
+INVOKE_TRAMPOLINE art_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
.global art_handle_fill_data_from_code
.extern artHandleFillArrayDataFromCode
diff --git a/src/thread.cc b/src/thread.cc
index 2fd3a5a..661e3bb 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -115,8 +115,10 @@
pInitializeStaticStorage = art_initialize_static_storage_from_code;
pInitializeTypeFromCode = art_initialize_type_from_code;
pInitializeTypeAndVerifyAccessFromCode = art_initialize_type_and_verify_access_from_code;
+ pInvokeDirectTrampolineWithAccessCheck = art_invoke_direct_trampoline_with_access_check;
pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
pInvokeInterfaceTrampolineWithAccessCheck = art_invoke_interface_trampoline_with_access_check;
+ pInvokeStaticTrampolineWithAccessCheck = art_invoke_static_trampoline_with_access_check;
pInvokeSuperTrampolineWithAccessCheck = art_invoke_super_trampoline_with_access_check;
pInvokeVirtualTrampolineWithAccessCheck = art_invoke_virtual_trampoline_with_access_check;
pLockObjectFromCode = art_lock_object_from_code;
diff --git a/src/thread.h b/src/thread.h
index 4bfc5cf..cd39794 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -617,8 +617,10 @@
void (*pHandleFillArrayDataFromCode)(void*, void*);
void* (*pInitializeStaticStorage)(uint32_t, void*);
uint32_t (*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
+ void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeInterfaceTrampoline)(uint32_t, void*);
void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*);
+ void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*);
void (*pInvokeVirtualTrampolineWithAccessCheck)(uint32_t, void*);
void* (*pInitializeTypeFromCode)(uint32_t, void*);