Implement interpreter packed-switch.
Don't enter interpreter for native methods. Fix ScopedObjectAccess use
when in native state.
Change-Id: I7575a4f2701215009226dde05022213d044fb56d
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 388eb85..757639e 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -190,8 +190,12 @@
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
- result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get())));
+ jobject jresult;
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ jresult = fn(soa.Env(), klass.get());
+ }
+ result->SetL(soa.Decode<Object*>(jresult));
} else if (shorty == "V") {
typedef void (fnptr)(JNIEnv*, jclass);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
@@ -227,8 +231,12 @@
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
soa.AddLocalReference<jobject>(args[0].GetL()));
- ScopedThreadStateChange tsc(self, kNative);
- result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get(), arg0.get())));
+ jobject jresult;
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ jresult = fn(soa.Env(), klass.get(), arg0.get());
+ }
+ result->SetL(soa.Decode<Object*>(jresult));
} else if (shorty == "IIZ") {
typedef jint (fnptr)(JNIEnv*, jclass, jint, jboolean);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
@@ -312,8 +320,12 @@
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
ScopedLocalRef<jobject> rcvr(soa.Env(),
soa.AddLocalReference<jobject>(receiver));
- ScopedThreadStateChange tsc(self, kNative);
- result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get())));
+ jobject jresult;
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ jresult = fn(soa.Env(), rcvr.get());
+ }
+ result->SetL(soa.Decode<Object*>(jresult));
} else if (shorty == "LL") {
typedef jobject (fnptr)(JNIEnv*, jobject, jobject);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
@@ -321,8 +333,14 @@
soa.AddLocalReference<jobject>(receiver));
ScopedLocalRef<jobject> arg0(soa.Env(),
soa.AddLocalReference<jobject>(args[0].GetL()));
+ jobject jresult;
+ {
+ ScopedThreadStateChange tsc(self, kNative);
+ jresult = fn(soa.Env(), rcvr.get(), arg0.get());
+
+ }
+ result->SetL(soa.Decode<Object*>(jresult));
ScopedThreadStateChange tsc(self, kNative);
- result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get(), arg0.get())));
} else if (shorty == "III") {
typedef jint (fnptr)(JNIEnv*, jobject, jint, jint);
fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
@@ -780,17 +798,32 @@
next_inst = Instruction::At(insns + dex_pc + dec_insn.vA);
break;
}
- case Instruction::PACKED_SWITCH:
- UNIMPLEMENTED(FATAL) << inst->DumpString(&mh.GetDexFile());
+ case Instruction::PACKED_SWITCH: {
+ uint32_t dex_pc = inst->GetDexPc(insns);
+ const uint16_t* switch_data = insns + dex_pc + dec_insn.vB;
+ int32_t test_val = shadow_frame.GetVReg(dec_insn.vA);
+ CHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
+ uint16_t size = switch_data[1];
+ CHECK_GT(size, 0);
+ const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
+ CHECK(IsAligned<4>(keys));
+ int32_t first_key = keys[0];
+ const int32_t* targets = reinterpret_cast<const int32_t*>(&switch_data[4]);
+ CHECK(IsAligned<4>(targets));
+ int32_t index = test_val - first_key;
+ if (index >= 0 && index < size) {
+ next_inst = Instruction::At(insns + dex_pc + targets[index]);
+ }
break;
+ }
case Instruction::SPARSE_SWITCH: {
uint32_t dex_pc = inst->GetDexPc(insns);
- const uint16_t* switchData = insns + dex_pc + dec_insn.vB;
- int32_t testVal = shadow_frame.GetVReg(dec_insn.vA);
- CHECK_EQ(switchData[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
- uint16_t size = switchData[1];
+ const uint16_t* switch_data = insns + dex_pc + dec_insn.vB;
+ int32_t test_val = shadow_frame.GetVReg(dec_insn.vA);
+ CHECK_EQ(switch_data[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+ uint16_t size = switch_data[1];
CHECK_GT(size, 0);
- const int32_t* keys = reinterpret_cast<const int32_t*>(&switchData[2]);
+ const int32_t* keys = reinterpret_cast<const int32_t*>(&switch_data[2]);
CHECK(IsAligned<4>(keys));
const int32_t* entries = keys + size;
CHECK(IsAligned<4>(entries));
@@ -799,9 +832,9 @@
while (lo <= hi) {
int mid = (lo + hi) / 2;
int32_t foundVal = keys[mid];
- if (testVal < foundVal) {
+ if (test_val < foundVal) {
hi = mid - 1;
- } else if (testVal > foundVal) {
+ } else if (test_val > foundVal) {
lo = mid + 1;
} else {
next_inst = Instruction::At(insns + dex_pc + entries[mid]);
diff --git a/src/object.cc b/src/object.cc
index 4eb5066..dce475f 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -663,7 +663,7 @@
result->SetJ(0);
}
} else {
- bool interpret = self->ReadFlag(kEnterInterpreter);
+ bool interpret = self->ReadFlag(kEnterInterpreter) && !IsNative();
const bool kLogInvocationStartAndReturn = false;
if (!interpret && GetCode() != NULL && stub != NULL) {
if (kLogInvocationStartAndReturn) {