summaryrefslogtreecommitdiffstats
path: root/runtime/entrypoints/quick
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2014-03-05 16:11:04 -0800
committerIan Rogers <irogers@google.com>2014-03-05 22:32:53 -0800
commitbf6b92a158053c98b15f4393abb3b86344ec9a20 (patch)
tree93a28d1e01b045a8df23fe5279601496b62af3dd /runtime/entrypoints/quick
parent359597ee8c0667a7d2c0b74dcbb0f90bb6059bae (diff)
downloadart-bf6b92a158053c98b15f4393abb3b86344ec9a20.zip
art-bf6b92a158053c98b15f4393abb3b86344ec9a20.tar.gz
art-bf6b92a158053c98b15f4393abb3b86344ec9a20.tar.bz2
Generic JNI implementation for x86_64
Starting implementation for generic JNI on x86_64. Frames are of large static size (>4K) right now, should be compacted later. Passes the whole of jni_compiler_test. Change-Id: I88ac3e13a534afe7568d62a1ef97cb766e8260e4
Diffstat (limited to 'runtime/entrypoints/quick')
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc474
1 files changed, 418 insertions, 56 deletions
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 63e0d42..bf8b8ba 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -57,9 +57,9 @@ class QuickArgumentVisitor {
// | R1 | arg1
// | R0 | padding
// | Method* | <- sp
- static constexpr bool kSoftFloatAbi = true; // This is a soft float ABI.
- static constexpr size_t kNumGprArgs = 3; // 3 arguments passed in GPRs.
- static constexpr size_t kNumFprArgs = 0; // 0 arguments passed in FPRs.
+ static constexpr bool kQuickSoftFloatAbi = true; // This is a soft float ABI.
+ static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs.
+ static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs.
static constexpr size_t kBytesPerFprSpillLocation = 4; // FPR spill size is 4 bytes.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 8; // Offset of first GPR arg.
@@ -83,9 +83,9 @@ class QuickArgumentVisitor {
// | A2 | arg2
// | A1 | arg1
// | A0/Method* | <- sp
- static constexpr bool kSoftFloatAbi = true; // This is a soft float ABI.
- static constexpr size_t kNumGprArgs = 3; // 3 arguments passed in GPRs.
- static constexpr size_t kNumFprArgs = 0; // 0 arguments passed in FPRs.
+ static constexpr bool kQuickSoftFloatAbi = true; // This is a soft float ABI.
+ static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs.
+ static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs.
static constexpr size_t kBytesPerFprSpillLocation = 4; // FPR spill size is 4 bytes.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg.
@@ -109,9 +109,9 @@ class QuickArgumentVisitor {
// | EDX | arg2
// | ECX | arg1
// | EAX/Method* | <- sp
- static constexpr bool kSoftFloatAbi = true; // This is a soft float ABI.
- static constexpr size_t kNumGprArgs = 3; // 3 arguments passed in GPRs.
- static constexpr size_t kNumFprArgs = 0; // 0 arguments passed in FPRs.
+ static constexpr bool kQuickSoftFloatAbi = true; // This is a soft float ABI.
+ static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs.
+ static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs.
static constexpr size_t kBytesPerFprSpillLocation = 8; // FPR spill size is 8 bytes.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg.
@@ -148,9 +148,9 @@ class QuickArgumentVisitor {
// | XMM0 | float arg 1
// | Padding |
// | RDI/Method* | <- sp
- static constexpr bool kSoftFloatAbi = false; // This is a hard float ABI.
- static constexpr size_t kNumGprArgs = 5; // 3 arguments passed in GPRs.
- static constexpr size_t kNumFprArgs = 8; // 0 arguments passed in FPRs.
+ static constexpr bool kQuickSoftFloatAbi = false; // This is a hard float ABI.
+ static constexpr size_t kNumQuickGprArgs = 5; // 3 arguments passed in GPRs.
+ static constexpr size_t kNumQuickFprArgs = 8; // 0 arguments passed in FPRs.
static constexpr size_t kBytesPerFprSpillLocation = 8; // FPR spill size is 8 bytes.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16; // Offset of first FPR arg.
static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80; // Offset of first GPR arg.
@@ -211,15 +211,15 @@ class QuickArgumentVisitor {
}
byte* GetParamAddress() const {
- if (!kSoftFloatAbi) {
+ if (!kQuickSoftFloatAbi) {
Primitive::Type type = GetParamPrimitiveType();
if (UNLIKELY((type == Primitive::kPrimDouble) || (type == Primitive::kPrimFloat))) {
- if ((kNumFprArgs != 0) && (fpr_index_ + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
return fpr_args_ + (fpr_index_ * kBytesPerFprSpillLocation);
}
}
}
- if (gpr_index_ < kNumGprArgs) {
+ if (gpr_index_ < kNumQuickGprArgs) {
return gpr_args_ + GprIndexToGprOffset(gpr_index_);
}
return stack_args_ + (stack_index_ * kBytesStackArgLocation);
@@ -257,7 +257,7 @@ class QuickArgumentVisitor {
cur_type_ = Primitive::kPrimNot;
is_split_long_or_double_ = false;
Visit();
- if (kNumGprArgs > 0) {
+ if (kNumQuickGprArgs > 0) {
gpr_index_++;
} else {
stack_index_++;
@@ -274,7 +274,7 @@ class QuickArgumentVisitor {
case Primitive::kPrimInt:
is_split_long_or_double_ = false;
Visit();
- if (gpr_index_ < kNumGprArgs) {
+ if (gpr_index_ < kNumQuickGprArgs) {
gpr_index_++;
} else {
stack_index_++;
@@ -283,14 +283,14 @@ class QuickArgumentVisitor {
case Primitive::kPrimFloat:
is_split_long_or_double_ = false;
Visit();
- if (kSoftFloatAbi) {
- if (gpr_index_ < kNumGprArgs) {
+ if (kQuickSoftFloatAbi) {
+ if (gpr_index_ < kNumQuickGprArgs) {
gpr_index_++;
} else {
stack_index_++;
}
} else {
- if ((kNumFprArgs != 0) && (fpr_index_ + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
fpr_index_++;
} else {
stack_index_++;
@@ -299,14 +299,14 @@ class QuickArgumentVisitor {
break;
case Primitive::kPrimDouble:
case Primitive::kPrimLong:
- if (kSoftFloatAbi || (cur_type_ == Primitive::kPrimLong)) {
+ if (kQuickSoftFloatAbi || (cur_type_ == Primitive::kPrimLong)) {
is_split_long_or_double_ = (kBytesPerGprSpillLocation == 4) &&
- ((gpr_index_ + 1) == kNumGprArgs);
+ ((gpr_index_ + 1) == kNumQuickGprArgs);
Visit();
- if (gpr_index_ < kNumGprArgs) {
+ if (gpr_index_ < kNumQuickGprArgs) {
gpr_index_++;
if (kBytesPerGprSpillLocation == 4) {
- if (gpr_index_ < kNumGprArgs) {
+ if (gpr_index_ < kNumQuickGprArgs) {
gpr_index_++;
} else {
stack_index_++;
@@ -322,12 +322,12 @@ class QuickArgumentVisitor {
}
} else {
is_split_long_or_double_ = (kBytesPerFprSpillLocation == 4) &&
- ((fpr_index_ + 1) == kNumFprArgs);
+ ((fpr_index_ + 1) == kNumQuickFprArgs);
Visit();
- if ((kNumFprArgs != 0) && (fpr_index_ + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
fpr_index_++;
if (kBytesPerFprSpillLocation == 4) {
- if ((kNumFprArgs != 0) && (fpr_index_ + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fpr_index_ + 1 < kNumQuickFprArgs + 1)) {
fpr_index_++;
} else {
stack_index_++;
@@ -352,14 +352,14 @@ class QuickArgumentVisitor {
private:
static size_t StackArgumentStartFromShorty(bool is_static, const char* shorty,
uint32_t shorty_len) {
- if (kSoftFloatAbi) {
- CHECK_EQ(kNumFprArgs, 0U);
- return (kNumGprArgs * kBytesPerGprSpillLocation) + kBytesPerGprSpillLocation /* ArtMethod* */;
+ if (kQuickSoftFloatAbi) {
+ CHECK_EQ(kNumQuickFprArgs, 0U);
+ return (kNumQuickGprArgs * kBytesPerGprSpillLocation) + kBytesPerGprSpillLocation /* ArtMethod* */;
} else {
size_t offset = kBytesPerGprSpillLocation; // Skip Method*.
size_t gprs_seen = 0;
size_t fprs_seen = 0;
- if (!is_static && (gprs_seen < kNumGprArgs)) {
+ if (!is_static && (gprs_seen < kNumQuickGprArgs)) {
gprs_seen++;
offset += kBytesStackArgLocation;
}
@@ -371,34 +371,34 @@ class QuickArgumentVisitor {
case 'S':
case 'I':
case 'L':
- if (gprs_seen < kNumGprArgs) {
+ if (gprs_seen < kNumQuickGprArgs) {
gprs_seen++;
offset += kBytesStackArgLocation;
}
break;
case 'J':
- if (gprs_seen < kNumGprArgs) {
+ if (gprs_seen < kNumQuickGprArgs) {
gprs_seen++;
offset += 2 * kBytesStackArgLocation;
if (kBytesPerGprSpillLocation == 4) {
- if (gprs_seen < kNumGprArgs) {
+ if (gprs_seen < kNumQuickGprArgs) {
gprs_seen++;
}
}
}
break;
case 'F':
- if ((kNumFprArgs != 0) && (fprs_seen + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fprs_seen + 1 < kNumQuickFprArgs + 1)) {
fprs_seen++;
offset += kBytesStackArgLocation;
}
break;
case 'D':
- if ((kNumFprArgs != 0) && (fprs_seen + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fprs_seen + 1 < kNumQuickFprArgs + 1)) {
fprs_seen++;
offset += 2 * kBytesStackArgLocation;
if (kBytesPerFprSpillLocation == 4) {
- if ((kNumFprArgs != 0) && (fprs_seen + 1 < kNumFprArgs + 1)) {
+ if ((kNumQuickFprArgs != 0) && (fprs_seen + 1 < kNumQuickFprArgs + 1)) {
fprs_seen++;
}
}
@@ -428,13 +428,13 @@ class QuickArgumentVisitor {
};
// Visits arguments on the stack placing them into the shadow frame.
-class BuildQuickShadowFrameVisitor : public QuickArgumentVisitor {
+class BuildQuickShadowFrameVisitor FINAL : public QuickArgumentVisitor {
public:
BuildQuickShadowFrameVisitor(mirror::ArtMethod** sp, bool is_static, const char* shorty,
uint32_t shorty_len, ShadowFrame* sf, size_t first_arg_reg) :
QuickArgumentVisitor(sp, is_static, shorty, shorty_len), sf_(sf), cur_reg_(first_arg_reg) {}
- virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
Primitive::Type type = GetParamPrimitiveType();
switch (type) {
case Primitive::kPrimLong: // Fall-through.
@@ -525,14 +525,14 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa
// Visits arguments on the stack placing them into the args vector, Object* arguments are converted
// to jobjects.
-class BuildQuickArgumentVisitor : public QuickArgumentVisitor {
+class BuildQuickArgumentVisitor FINAL : public QuickArgumentVisitor {
public:
BuildQuickArgumentVisitor(mirror::ArtMethod** sp, bool is_static, const char* shorty,
uint32_t shorty_len, ScopedObjectAccessUnchecked* soa,
std::vector<jvalue>* args) :
QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa), args_(args) {}
- virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
jvalue val;
Primitive::Type type = GetParamPrimitiveType();
switch (type) {
@@ -638,13 +638,13 @@ extern "C" uint64_t artQuickProxyInvokeHandler(mirror::ArtMethod* proxy_method,
// Read object references held in arguments from quick frames and place in a JNI local references,
// so they don't get garbage collected.
-class RememberForGcArgumentVisitor : public QuickArgumentVisitor {
+class RememberForGcArgumentVisitor FINAL : public QuickArgumentVisitor {
public:
RememberForGcArgumentVisitor(mirror::ArtMethod** sp, bool is_static, const char* shorty,
uint32_t shorty_len, ScopedObjectAccessUnchecked* soa) :
QuickArgumentVisitor(sp, is_static, shorty, shorty_len), soa_(soa) {}
- virtual void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
if (IsParamAReference()) {
StackReference<mirror::Object>* stack_ref =
reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
@@ -671,14 +671,14 @@ class RememberForGcArgumentVisitor : public QuickArgumentVisitor {
// Lazily resolve a method for quick. Called by stub code.
extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
mirror::Object* receiver,
- Thread* thread, mirror::ArtMethod** sp)
+ Thread* self, mirror::ArtMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
// Start new JNI local reference state
- JNIEnvExt* env = thread->GetJniEnv();
+ JNIEnvExt* env = self->GetJniEnv();
ScopedObjectAccessUnchecked soa(env);
ScopedJniEnvLocalRefState env_state(env);
- const char* old_cause = thread->StartAssertNoThreadSuspension("Quick method resolution set up");
+ const char* old_cause = self->StartAssertNoThreadSuspension("Quick method resolution set up");
// Compute details about the called method (avoid GCs)
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -757,7 +757,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
dex_file->GetMethodShorty(dex_file->GetMethodId(dex_method_idx), &shorty_len);
RememberForGcArgumentVisitor visitor(sp, invoke_type == kStatic, shorty, shorty_len, &soa);
visitor.VisitArguments();
- thread->EndAssertNoThreadSuspension(old_cause);
+ self->EndAssertNoThreadSuspension(old_cause);
bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
// Resolve method filling in dex cache.
if (called->IsRuntimeMethod()) {
@@ -766,7 +766,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
receiver = sirt_receiver.get();
}
const void* code = NULL;
- if (LIKELY(!thread->IsExceptionPending())) {
+ if (LIKELY(!self->IsExceptionPending())) {
// Incompatible class change should have been handled in resolve method.
CHECK(!called->CheckIncompatibleClassChange(invoke_type))
<< PrettyMethod(called) << " " << invoke_type;
@@ -812,7 +812,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
DCHECK(called_class->IsErroneous());
}
}
- CHECK_EQ(code == NULL, thread->IsExceptionPending());
+ CHECK_EQ(code == NULL, self->IsExceptionPending());
// Fixup any locally saved objects may have moved during a GC.
visitor.FixupReferences();
// Place called method in callee-save frame to be placed as first argument to quick method.
@@ -820,13 +820,375 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called,
return code;
}
-extern "C" const void* artQuickGenericJniTrampoline(mirror::ArtMethod* called,
- mirror::Object* receiver,
- Thread* thread, mirror::ArtMethod** sp)
+// Visits arguments on the stack placing them into a region lower down the stack for the benefit
+// of transitioning into native code.
+class BuildGenericJniFrameVisitor FINAL : public QuickArgumentVisitor {
+#if defined(__arm__)
+ // TODO: These are all dummy values!
+ static constexpr bool kNativeSoftFloatAbi = false; // This is a hard float ABI.
+ static constexpr size_t kNumNativeGprArgs = 3; // 3 arguments passed in GPRs.
+ static constexpr size_t kNumNativeFprArgs = 0; // 0 arguments passed in FPRs.
+
+ static constexpr size_t kGprStackOffset = 4336;
+ static constexpr size_t kFprStackOffset = 4336 - 6*8;
+ static constexpr size_t kCallStackStackOffset = 4336 - 112;
+
+ static constexpr size_t kRegistersNeededForLong = 2;
+ static constexpr size_t kRegistersNeededForDouble = 2;
+#elif defined(__mips__)
+ // TODO: These are all dummy values!
+ static constexpr bool kNativeSoftFloatAbi = true; // This is a hard float ABI.
+ static constexpr size_t kNumNativeGprArgs = 0; // 6 arguments passed in GPRs.
+ static constexpr size_t kNumNativeFprArgs = 0; // 8 arguments passed in FPRs.
+
+ // update these
+ static constexpr size_t kGprStackOffset = 4336;
+ static constexpr size_t kFprStackOffset = 4336 - 6*8;
+ static constexpr size_t kCallStackStackOffset = 4336 - 112;
+
+ static constexpr size_t kRegistersNeededForLong = 2;
+ static constexpr size_t kRegistersNeededForDouble = 2;
+#elif defined(__i386__)
+ // TODO: Check these!
+ static constexpr bool kNativeSoftFloatAbi = true; // This is a soft float ABI.
+ static constexpr size_t kNumNativeGprArgs = 0; // 6 arguments passed in GPRs.
+ static constexpr size_t kNumNativeFprArgs = 0; // 8 arguments passed in FPRs.
+
+ // update these
+ static constexpr size_t kGprStackOffset = 4336;
+ static constexpr size_t kFprStackOffset = 4336 - 6*8;
+ static constexpr size_t kCallStackStackOffset = 4336 - 112;
+
+ static constexpr size_t kRegistersNeededForLong = 2;
+ static constexpr size_t kRegistersNeededForDouble = 2;
+#elif defined(__x86_64__)
+ static constexpr bool kNativeSoftFloatAbi = false; // This is a hard float ABI.
+ static constexpr size_t kNumNativeGprArgs = 6; // 6 arguments passed in GPRs.
+ static constexpr size_t kNumNativeFprArgs = 8; // 8 arguments passed in FPRs.
+
+ static constexpr size_t kGprStackOffset = 4336;
+ static constexpr size_t kFprStackOffset = 4336 - 6*8;
+ static constexpr size_t kCallStackStackOffset = 4336 - 112;
+
+ static constexpr size_t kRegistersNeededForLong = 1;
+ static constexpr size_t kRegistersNeededForDouble = 1;
+#else
+#error "Unsupported architecture"
+#endif
+
+
+ public:
+ BuildGenericJniFrameVisitor(mirror::ArtMethod** sp, bool is_static, const char* shorty,
+ uint32_t shorty_len, Thread* self) :
+ QuickArgumentVisitor(sp, is_static, shorty, shorty_len) {
+ // size of cookie plus padding
+ uint8_t* sp8 = reinterpret_cast<uint8_t*>(sp);
+ top_of_sirt_ = sp8 - 8;
+ cur_sirt_entry_ = reinterpret_cast<StackReference<mirror::Object>*>(top_of_sirt_) - 1;
+ sirt_number_of_references_ = 0;
+ gpr_index_ = kNumNativeGprArgs;
+ fpr_index_ = kNumNativeFprArgs;
+
+ cur_gpr_reg_ = reinterpret_cast<uintptr_t*>(sp8 - kGprStackOffset);
+ cur_fpr_reg_ = reinterpret_cast<uint32_t*>(sp8 - kFprStackOffset);
+ cur_stack_arg_ = reinterpret_cast<uintptr_t*>(sp8 - kCallStackStackOffset);
+
+ // jni environment is always first argument
+ PushPointer(self->GetJniEnv());
+
+ if (is_static) {
+ PushArgumentInSirt((*sp)->GetDeclaringClass());
+ }
+ }
+
+ void Visit() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) OVERRIDE {
+ Primitive::Type type = GetParamPrimitiveType();
+ switch (type) {
+ case Primitive::kPrimLong: {
+ jlong long_arg;
+ if (IsSplitLongOrDouble()) {
+ long_arg = ReadSplitLongParam();
+ } else {
+ long_arg = *reinterpret_cast<jlong*>(GetParamAddress());
+ }
+ PushLongArgument(long_arg);
+ break;
+ }
+ case Primitive::kPrimDouble: {
+ uint64_t double_arg;
+ if (IsSplitLongOrDouble()) {
+ // Read into union so that we don't case to a double.
+ double_arg = ReadSplitLongParam();
+ } else {
+ double_arg = *reinterpret_cast<uint64_t*>(GetParamAddress());
+ }
+ PushDoubleArgument(double_arg);
+ break;
+ }
+ case Primitive::kPrimNot: {
+ StackReference<mirror::Object>* stack_ref =
+ reinterpret_cast<StackReference<mirror::Object>*>(GetParamAddress());
+ PushArgumentInSirt(stack_ref->AsMirrorPtr());
+ break;
+ }
+ case Primitive::kPrimFloat:
+ PushFloatArgument(*reinterpret_cast<int32_t*>(GetParamAddress()));
+ break;
+ case Primitive::kPrimBoolean: // Fall-through.
+ case Primitive::kPrimByte: // Fall-through.
+ case Primitive::kPrimChar: // Fall-through.
+ case Primitive::kPrimShort: // Fall-through.
+ case Primitive::kPrimInt: // Fall-through.
+ PushIntArgument(*reinterpret_cast<jint*>(GetParamAddress()));
+ break;
+ case Primitive::kPrimVoid:
+ LOG(FATAL) << "UNREACHABLE";
+ break;
+ }
+ }
+
+ void FinalizeSirt(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (!IsAligned<8>(StackIndirectReferenceTable::SizeOf(sirt_number_of_references_))) {
+ sirt_number_of_references_++;
+ *cur_sirt_entry_ = StackReference<mirror::Object>();
+ cur_sirt_entry_--;
+ }
+ CHECK(IsAligned<8>(StackIndirectReferenceTable::SizeOf(sirt_number_of_references_)));
+ StackIndirectReferenceTable* sirt = reinterpret_cast<StackIndirectReferenceTable*>(
+ top_of_sirt_ - StackIndirectReferenceTable::SizeOf(sirt_number_of_references_));
+
+ sirt->SetNumberOfReferences(sirt_number_of_references_);
+ self->PushSirt(sirt);
+ }
+
+ jobject GetFirstSirtEntry() {
+ return reinterpret_cast<jobject>(reinterpret_cast<StackReference<mirror::Object>*>(top_of_sirt_) - 1);
+ }
+
+ private:
+ void PushArgumentInSirt(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Do something to push into the SIRT.
+ uintptr_t sirt_or_null;
+ if (obj != nullptr) {
+ sirt_number_of_references_++;
+ *cur_sirt_entry_ = StackReference<mirror::Object>::FromMirrorPtr(obj);
+ sirt_or_null = reinterpret_cast<uintptr_t>(cur_sirt_entry_);
+ cur_sirt_entry_--;
+ } else {
+ sirt_or_null = reinterpret_cast<uintptr_t>(nullptr);
+ }
+ // Push the GPR or stack arg.
+ if (gpr_index_ > 0) {
+ *cur_gpr_reg_ = sirt_or_null;
+ cur_gpr_reg_++;
+ gpr_index_--;
+ } else {
+ *cur_stack_arg_ = sirt_or_null;
+ cur_stack_arg_++;
+ }
+ }
+
+ void PushPointer(void* val) {
+ if (gpr_index_ > 0) {
+ *cur_gpr_reg_ = reinterpret_cast<uintptr_t>(val);
+ cur_gpr_reg_++;
+ gpr_index_--;
+ } else {
+ *cur_stack_arg_ = reinterpret_cast<uintptr_t>(val);
+ cur_stack_arg_++;
+ }
+ }
+
+ void PushIntArgument(jint val) {
+ if (gpr_index_ > 0) {
+ *cur_gpr_reg_ = val;
+ cur_gpr_reg_++;
+ gpr_index_--;
+ } else {
+ *cur_stack_arg_ = val;
+ cur_stack_arg_++;
+ }
+ }
+
+ void PushLongArgument(jlong val) {
+ // This is an ugly hack for the following problem:
+ // Assume odd number of 32b registers. Then having exactly kRegsNeeded left needs to spill!
+ if (gpr_index_ >= kRegistersNeededForLong + (kNumNativeGprArgs % kRegistersNeededForLong)) {
+ if (kRegistersNeededForLong > 1 && ((kNumNativeGprArgs - gpr_index_) & 1) == 1) {
+ // Pad.
+ gpr_index_--;
+ cur_gpr_reg_++;
+ }
+ uint64_t* tmp = reinterpret_cast<uint64_t*>(cur_gpr_reg_);
+ *tmp = val;
+ cur_gpr_reg_ += kRegistersNeededForLong;
+ gpr_index_ -= kRegistersNeededForLong;
+ } else {
+ uint64_t* tmp = reinterpret_cast<uint64_t*>(cur_stack_arg_);
+ *tmp = val;
+ cur_stack_arg_ += kRegistersNeededForLong;
+
+ gpr_index_ = 0; // can't use GPRs anymore
+ }
+ }
+
+ void PushFloatArgument(int32_t val) {
+ if (kNativeSoftFloatAbi) {
+ PushIntArgument(val);
+ } else {
+ if (fpr_index_ > 0) {
+ *cur_fpr_reg_ = val;
+ cur_fpr_reg_++;
+ if (kRegistersNeededForDouble == 1) {
+ // will pop 64 bits from the stack
+ // TODO: extend/clear bits???
+ cur_fpr_reg_++;
+ }
+ fpr_index_--;
+ } else {
+ // TODO: Check ABI for floats.
+ *cur_stack_arg_ = val;
+ cur_stack_arg_++;
+ }
+ }
+ }
+
+ void PushDoubleArgument(uint64_t val) {
+ // See PushLongArgument for explanation
+ if (fpr_index_ >= kRegistersNeededForDouble + (kNumNativeFprArgs % kRegistersNeededForDouble)) {
+ if (kRegistersNeededForDouble > 1 && ((kNumNativeFprArgs - fpr_index_) & 1) == 1) {
+ // Pad.
+ fpr_index_--;
+ cur_fpr_reg_++;
+ }
+ uint64_t* tmp = reinterpret_cast<uint64_t*>(cur_fpr_reg_);
+ *tmp = val;
+ // TODO: the whole thing doesn't make sense if we take uint32_t*...
+ cur_fpr_reg_ += 2; // kRegistersNeededForDouble;
+ fpr_index_ -= kRegistersNeededForDouble;
+ } else {
+ if (!IsAligned<8>(cur_stack_arg_)) {
+ cur_stack_arg_++; // Pad.
+ }
+ uint64_t* tmp = reinterpret_cast<uint64_t*>(cur_stack_arg_);
+ *tmp = val;
+ cur_stack_arg_ += kRegistersNeededForDouble;
+
+ fpr_index_ = 0; // can't use FPRs anymore
+ }
+ }
+
+ uint32_t sirt_number_of_references_;
+ StackReference<mirror::Object>* cur_sirt_entry_;
+ uint32_t gpr_index_; // should be uint, but gives error because on some archs no regs
+ uintptr_t* cur_gpr_reg_;
+ uint32_t fpr_index_; // ----- # -----
+ uint32_t* cur_fpr_reg_;
+ uintptr_t* cur_stack_arg_;
+ uint8_t* top_of_sirt_;
+
+ DISALLOW_COPY_AND_ASSIGN(BuildGenericJniFrameVisitor);
+};
+
+extern "C" const void* artQuickGenericJniTrampoline(Thread* self, mirror::ArtMethod** sp)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- LOG(FATAL) << "artQuickGenericJniTrampoline not implemented: "
- << PrettyMethod(called);
- return NULL;
+ uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
+ mirror::ArtMethod* called = *sp;
+ DCHECK(called->IsNative());
+
+ // run the visitor
+ MethodHelper mh(called);
+ BuildGenericJniFrameVisitor visitor(sp, called->IsStatic(), mh.GetShorty(), mh.GetShortyLength(),
+ self);
+ visitor.VisitArguments();
+ visitor.FinalizeSirt(self);
+
+ // fix up managed-stack things in Thread
+ self->SetTopOfStack(sp, 0);
+
+ // start JNI, save the cookie
+ uint32_t cookie;
+ if (called->IsSynchronized()) {
+ cookie = JniMethodStartSynchronized(visitor.GetFirstSirtEntry(), self);
+ // TODO: error checking.
+ if (self->IsExceptionPending()) {
+ self->PopSirt();
+ return nullptr;
+ }
+ } else {
+ cookie = JniMethodStart(self);
+ }
+ *(sp32-1) = cookie;
+
+ // retrieve native code
+ const void* nativeCode = called->GetNativeMethod();
+ if (nativeCode == nullptr) {
+ // TODO: is this really an error, or do we need to try to find native code?
+ LOG(FATAL) << "Finding native code not implemented yet.";
+ }
+
+ return nativeCode;
+}
+
+/*
+ * Is called after the native JNI code. Responsible for cleanup (SIRT, saved state) and
+ * unlocking.
+ */
+extern "C" uint64_t artQuickGenericJniEndTrampoline(Thread* self, mirror::ArtMethod** sp,
+ jvalue result, uint64_t result_f)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t* sp32 = reinterpret_cast<uint32_t*>(sp);
+ mirror::ArtMethod* called = *sp;
+ uint32_t cookie = *(sp32-1);
+
+ // TODO: synchronized.
+ MethodHelper mh(called);
+ char return_shorty_char = mh.GetShorty()[0];
+
+ if (return_shorty_char == 'L') {
+ // the only special ending call
+ if (called->IsSynchronized()) {
+ BuildGenericJniFrameVisitor visitor(sp, called->IsStatic(), mh.GetShorty(),
+ mh.GetShortyLength(), self);
+ return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceSynchronized(result.l, cookie,
+ visitor.GetFirstSirtEntry(),
+ self));
+ } else {
+ return reinterpret_cast<uint64_t>(JniMethodEndWithReference(result.l, cookie, self));
+ }
+ } else {
+ if (called->IsSynchronized()) {
+ // run the visitor
+ BuildGenericJniFrameVisitor visitor(sp, called->IsStatic(), mh.GetShorty(),
+ mh.GetShortyLength(), self);
+ JniMethodEndSynchronized(cookie, visitor.GetFirstSirtEntry(), self);
+ } else {
+ JniMethodEnd(cookie, self);
+ }
+
+ switch (return_shorty_char) {
+ case 'F': // Fall-through.
+ case 'D':
+ return result_f;
+ case 'Z':
+ return result.z;
+ case 'B':
+ return result.b;
+ case 'C':
+ return result.c;
+ case 'S':
+ return result.s;
+ case 'I':
+ return result.i;
+ case 'J':
+ return result.j;
+ case 'V':
+ return 0;
+ default:
+ LOG(FATAL) << "Unexpected return shorty character " << return_shorty_char;
+ return 0;
+ }
+ }
}
} // namespace art