Fixed the trace builder to correctly handle excpetion throwing instruction.
Added a new unit test 081-hot-exceptions to target this problem.
diff --git a/tests/081-hot-exceptions/expected.txt b/tests/081-hot-exceptions/expected.txt
new file mode 100644
index 0000000..2432ff4
--- /dev/null
+++ b/tests/081-hot-exceptions/expected.txt
@@ -0,0 +1,2 @@
+sum = 0
+exception = 1024
diff --git a/tests/081-hot-exceptions/info.txt b/tests/081-hot-exceptions/info.txt
new file mode 100644
index 0000000..cc514f3
--- /dev/null
+++ b/tests/081-hot-exceptions/info.txt
@@ -0,0 +1,3 @@
+Make a hot exception-throwing path to stress test how the trace builder handles
+exceptions encountered during trace selection. The existence of exceptions will
+cause a control flow change to deviate from the current method.
diff --git a/tests/081-hot-exceptions/src/Main.java b/tests/081-hot-exceptions/src/Main.java
new file mode 100644
index 0000000..90e7af2
--- /dev/null
+++ b/tests/081-hot-exceptions/src/Main.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 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 {
+ static class ArrayObj {
+ int[] array;
+
+ int getArrayElement(int i) throws NullPointerException {
+ return array[i];
+ }
+ }
+
+ public static void main(String[] args) {
+ ArrayObj arrayObj2 = new ArrayObj();
+ int sum = 0;
+ int exception = 0;
+
+ for (int i = 0; i < 1024; i++) {
+ try {
+ // A hot method invocation that always encounters exceptions
+ sum += arrayObj2.getArrayElement(i);
+ } catch (NullPointerException npe) {
+ exception++;
+ }
+ }
+ System.out.println("sum = " + sum);
+ System.out.println("exception = " + exception);
+ }
+}
diff --git a/vm/compiler/codegen/arm/Codegen.c b/vm/compiler/codegen/arm/Codegen.c
index 30a7b1b..2e735fa 100644
--- a/vm/compiler/codegen/arm/Codegen.c
+++ b/vm/compiler/codegen/arm/Codegen.c
@@ -2316,11 +2316,11 @@
(cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
assert(classPtr != NULL);
assert(classPtr->status & CLASS_INITIALIZED);
- if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
- /* It's going to throw, just let the interp. deal with it. */
- genInterpSingleStep(cUnit, mir);
- return false;
- }
+ /*
+ * If it is going to throw, it should not make to the trace to begin
+ * with.
+ */
+ assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
loadConstant(cUnit, r4PC, (int)dvmAllocObject);
loadConstant(cUnit, r0, (int) classPtr);
genExportPC(cUnit, mir, r2, r3 );
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 928ca09..28994b7 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -161,10 +161,11 @@
int currTraceRun;
int totalTraceLen; // Number of Dalvik insts in trace
- const u2* currTraceHead; // Start of the trace we're building
- const u2* currRunHead; // Start of run we're building
+ const u2* currTraceHead; // Start of the trace we're building
+ const u2* currRunHead; // Start of run we're building
int currRunLen; // Length of run in 16-bit words
int lastThreshFilter;
+ const u2* lastPC; // Stage the PC first for the threaded interpreter
#if defined(WITH_SELF_VERIFICATION)
struct HeapArgSpace heapArgSpace;
#endif
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index f1ac1c2..aca5fff 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -515,25 +515,38 @@
#endif
);
+ /* First instruction - just remember the PC and exit */
+ if (interpState->lastPC == NULL) {
+ interpState->lastPC = pc;
+ return switchInterp;
+ }
+
+ /* Prepare to handle last PC and stage the current PC */
+ const u2 *lastPC = interpState->lastPC;
+ interpState->lastPC = pc;
+
switch (interpState->jitState) {
char* nopStr;
int target;
int offset;
DecodedInstruction decInsn;
case kJitTSelect:
- dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
+ /* Grow the trace around the last PC if jitState is kJitTSelect */
+ dexDecodeInstruction(gDvm.instrFormat, lastPC, &decInsn);
#if defined(SHOW_TRACE)
LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
#endif
flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
- len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
- offset = pc - interpState->method->insns;
- if (pc != interpState->currRunHead + interpState->currRunLen) {
+ len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, lastPC);
+ offset = lastPC - interpState->method->insns;
+ assert((unsigned) offset <
+ dvmGetMethodInsnsSize(interpState->method));
+ if (lastPC != interpState->currRunHead + interpState->currRunLen) {
int currTraceRun;
/* We need to start a new trace run */
currTraceRun = ++interpState->currTraceRun;
interpState->currRunLen = 0;
- interpState->currRunHead = (u2*)pc;
+ interpState->currRunHead = (u2*)lastPC;
interpState->trace[currTraceRun].frag.startOffset = offset;
interpState->trace[currTraceRun].frag.numInsts = 0;
interpState->trace[currTraceRun].frag.runEnd = false;
@@ -542,6 +555,12 @@
interpState->trace[interpState->currTraceRun].frag.numInsts++;
interpState->totalTraceLen++;
interpState->currRunLen += len;
+
+ /* Will probably never hit this with the current trace buildier */
+ if (interpState->currTraceRun == (MAX_JIT_RUN_LEN - 1)) {
+ interpState->jitState = kJitTSelectEnd;
+ }
+
if ( ((flags & kInstrUnconditional) == 0) &&
/* don't end trace on INVOKE_DIRECT_EMPTY */
(decInsn.opCode != OP_INVOKE_DIRECT_EMPTY) &&
@@ -880,6 +899,7 @@
interpState->trace[0].frag.numInsts = 0;
interpState->trace[0].frag.runEnd = false;
interpState->trace[0].frag.hint = kJitHintNone;
+ interpState->lastPC = 0;
break;
case kJitTSelect:
case kJitTSelectAbort:
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index f20c0f1..c34d6c4 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -576,6 +576,10 @@
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ interpState->jitState = kJitTSelectEnd;
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 4b0a17d..81e7165 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -3609,6 +3609,10 @@
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ interpState->jitState = kJitTSelectEnd;
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index a336a95..45a18da 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -3909,6 +3909,10 @@
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ interpState->jitState = kJitTSelectEnd;
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 7e03400..3576608 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -3623,6 +3623,10 @@
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ interpState->jitState = kJitTSelectEnd;
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index f8792bd..6492daf 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -1764,6 +1764,10 @@
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ interpState->jitState = kJitTSelectEnd;
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
diff --git a/vm/native/java_lang_Runtime.c b/vm/native/java_lang_Runtime.c
index 1278f03..b5c0aee 100644
--- a/vm/native/java_lang_Runtime.c
+++ b/vm/native/java_lang_Runtime.c
@@ -53,6 +53,9 @@
LOGW("JNI exit hook returned\n");
}
LOGD("Calling exit(%d)\n", status);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+ dvmCompilerDumpStats();
+#endif
exit(status);
}
@@ -161,4 +164,3 @@
Dalvik_java_lang_Runtime_totalMemory },
{ NULL, NULL, NULL },
};
-