/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EC: /* 0xec */
-/* File: x86-atom/OP_UNUSED_EC.S */
+.L_OP_BREAKPOINT: /* 0xec */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
/*
- * File: OP_UNUSED_EC.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_BREAKPOINT # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_EF: /* 0xef */
-/* File: x86-atom/OP_UNUSED_EF.S */
+.L_OP_EXECUTE_INLINE_RANGE: /* 0xef */
/* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
/*
- * File: OP_UNUSED_EF.S
+ * File: stub.S
*/
-/* File: x86-atom/unused.S */
- /* Copyright (C) 2008 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.
- */
-
- /*
- * File: unused.S
- *
- * Code: Common code for unused bytecodes. Uses no subtitutions.
- *
- * For: all unused bytecodes
- *
- * Description: aborts if executed.
- *
- * Format: ØØ|op (10x)
- *
- * Syntax: op
- */
-
- call common_abort
-
-
-
+ SAVE_PC_FP_TO_GLUE %edx # save program counter and frame pointer
+ pushl rGLUE # push parameter glue
+ call dvmMterp_OP_EXECUTE_INLINE_RANGE # call c-based implementation
+ lea 4(%esp), %esp
+ LOAD_PC_FP_FROM_GLUE # restore program counter and frame pointer
+ FINISH_A # jump to next instruction
/* ------------------------------ */
.balign 64
.L_OP_INVOKE_DIRECT_EMPTY: /* 0xf0 */
#define INST_INST(_inst) ((_inst) & 0xff)
/*
+ * Replace the opcode (used when handling breakpoints). _opcode is a u1.
+ */
+#define INST_REPLACE_OP(_inst, _opcode) (((_inst) & 0xff00) | _opcode)
+
+/*
* Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
*/
#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
#if defined(WITH_JIT)
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
- dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
- !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+ dvmJitDebuggerOrProfilerActive() : !dvmJitDebuggerOrProfilerActive() )
#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
# define CHECK_TRACKED_REFS() ((void)0)
+#if defined(WITH_JIT)
+#define CHECK_JIT() (0)
+#define ABORT_JIT_TSELECT() ((void)0)
+#endif
/*
* In the C mterp stubs, "goto" is a function call followed immediately
} \
}
-
/* File: c/opcommon.c */
/* forward declarations of goto targets */
GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
FINISH(2);
+/* File: c/OP_BREAKPOINT.c */
+HANDLE_OPCODE(OP_BREAKPOINT)
+#if (INTERP_TYPE == INTERP_DBG) && defined(WITH_DEBUGGER)
+ {
+ /*
+ * Restart this instruction with the original opcode. We do
+ * this by simply jumping to the handler.
+ *
+ * It's probably not necessary to update "inst", but we do it
+ * for the sake of anything that needs to do disambiguation in a
+ * common handler with INST_INST.
+ *
+ * The breakpoint itself is handled over in updateDebugger(),
+ * because we need to detect other events (method entry, single
+ * step) and report them in the same event packet, and we're not
+ * yet handling those through breakpoint instructions. By the
+ * time we get here, the breakpoint has already been handled and
+ * the thread resumed.
+ */
+ u1 originalOpCode = dvmGetOriginalOpCode(pc);
+ LOGV("+++ break 0x%02x (0x%04x -> 0x%04x)\n", originalOpCode, inst,
+ INST_REPLACE_OP(inst, originalOpCode));
+ inst = INST_REPLACE_OP(inst, originalOpCode);
+ FINISH_BKPT(originalOpCode);
+ }
+#else
+ LOGE("Breakpoint hit in non-debug interpreter\n");
+ dvmAbort();
+#endif
+OP_END
+
+/* File: c/OP_EXECUTE_INLINE_RANGE.c */
+HANDLE_OPCODE(OP_EXECUTE_INLINE_RANGE /*{vCCCC..v(CCCC+AA-1)}, inline@BBBB*/)
+ {
+ u4 arg0, arg1, arg2, arg3;
+ arg0 = arg1 = arg2 = arg3 = 0; /* placate gcc */
+
+ EXPORT_PC();
+
+ vsrc1 = INST_AA(inst); /* #of args */
+ ref = FETCH(1); /* inline call "ref" */
+ vdst = FETCH(2); /* range base */
+ ILOGV("|execute-inline-range args=%d @%d {regs=v%d-v%d}",
+ vsrc1, ref, vdst, vdst+vsrc1-1);
+
+ assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear
+ assert(vsrc1 <= 4);
+
+ switch (vsrc1) {
+ case 4:
+ arg3 = GET_REGISTER(vdst+3);
+ /* fall through */
+ case 3:
+ arg2 = GET_REGISTER(vdst+2);
+ /* fall through */
+ case 2:
+ arg1 = GET_REGISTER(vdst+1);
+ /* fall through */
+ case 1:
+ arg0 = GET_REGISTER(vdst+0);
+ /* fall through */
+ default: // case 0
+ ;
+ }
+
+#if INTERP_TYPE == INTERP_DBG
+ if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref))
+ GOTO_exceptionThrown();
+#else
+ if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref))
+ GOTO_exceptionThrown();
+#endif
+ }
+ FINISH(3);
+OP_END
+
/* File: c/gotoTargets.c */
/*
* C footer. This has some common code shared by the various targets.
if (dvmIsBreakFrame(fp)) {
/* bail without popping the method frame from stack */
LOGVV("+++ returned into break frame\n");
+#if defined(WITH_JIT)
+ /* Let the Jit know the return is terminating normally */
+ CHECK_JIT();
+#endif
GOTO_bail();
}
*/
PERIODIC_CHECKS(kInterpEntryThrow, 0);
+#if defined(WITH_JIT)
+ // Something threw during trace selection - abort the current trace
+ ABORT_JIT_TSELECT();
+#endif
/*
* We save off the exception and clear the exception status. While
* processing the exception we might need to load some Throwable
*
* If we do find a catch block, we want to transfer execution to
* that point.
+ *
+ * Note this can cause an exception while resolving classes in
+ * the "catch" blocks.
*/
catchRelPc = dvmFindCatchBlock(self, pc - curMethod->insns,
exception, false, (void*)&fp);
* Note we want to do this *after* the call to dvmFindCatchBlock,
* because that may need extra stack space to resolve exception
* classes (e.g. through a class loader).
+ *
+ * It's possible for the stack overflow handling to cause an
+ * exception (specifically, class resolution in a "catch" block
+ * during the call above), so we could see the thread's overflow
+ * flag raised but actually be running in a "nested" interpreter
+ * frame. We don't allow doubled-up StackOverflowErrors, so
+ * we can check for this by just looking at the exception type
+ * in the cleanup function. Also, we won't unroll past the SOE
+ * point because the more-recent exception will hit a break frame
+ * as it unrolls to here.
*/
if (self->stackOverflowed)
- dvmCleanupStackOverflow(self);
+ dvmCleanupStackOverflow(self, exception);
if (catchRelPc < 0) {
/* falling through to JNI code or off the bottom of the stack */
bottom = (u1*) newSaveArea - methodToCall->outsSize * sizeof(u4);
if (bottom < self->interpStackEnd) {
/* stack overflow */
- LOGV("Stack overflow on method call (start=%p end=%p newBot=%p size=%d '%s')\n",
+ LOGV("Stack overflow on method call (start=%p end=%p newBot=%p(%d) size=%d '%s')\n",
self->interpStackStart, self->interpStackEnd, bottom,
- self->interpStackSize, methodToCall->name);
- dvmHandleStackOverflow(self);
+ (u1*) fp - bottom, self->interpStackSize,
+ methodToCall->name);
+ dvmHandleStackOverflow(self, methodToCall);
assert(dvmCheckException(self));
GOTO_exceptionThrown();
}
ILOGD("> native <-- %s.%s %s", methodToCall->clazz->descriptor,
methodToCall->name, methodToCall->shorty);
+#if defined(WITH_JIT)
+ /* Allow the Jit to end any pending trace building */
+ CHECK_JIT();
+#endif
+
/*
* Jump through native call bridge. Because we leave no
* space for locals on native calls, "newFp" points directly