Changes: Edwin Steiner
- $Id: stack.c 803 2003-12-17 14:11:00Z edwin $
+ $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
*/
#include <string.h>
#include "stack.h"
#include "global.h"
+#include "main.h"
#include "jit.h"
#include "builtin.h"
#include "disass.h"
#define REQUIRE_4 REQUIRE(4)
/* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX we allow ACONST instructions inserted as arguments to builtin
+ * functions to exceed the maximum stack depth. Maybe we should check
+ * against maximum stack depth only at block boundaries?
*/
#define CHECKOVERFLOW \
do { \
if (stackdepth > maxstack) { \
- if (iptr[0].opc != ICMD_ACONST) \
+ if (iptr[0].opc != ICMD_ACONST \
+ || iptr[0].op1 == 0) \
{OVERFLOW;} \
} \
} while(0)
*
* These macros check the input stackdepth and they set the output
* stackdepth and the output stack of the instruction (iptr->dst).
+ *
+ * These macros do *not* check for stack overflows!
*/
#define PUSHCONST(s){NEWSTACKn(s,stackdepth);SETDST;stackdepth++;}
new[2].prev=new+1;new[3].prev=new+2;\
new[4].prev=new+3;new[5].prev=new+4;\
curstack=new+5;new+=6;SETDST;stackdepth+=2;}
-/******************************/
+
+/*--------------------------------------------------*/
+/* MACROS FOR HANDLING BASIC BLOCKS */
+/*--------------------------------------------------*/
/* COPYCURSTACK makes a copy of the current operand stack (curstack)
* and returns it in the variable copy.
copy=NULL;\
}
+/* BBEND is called at the end of each basic block (after the last
+ * instruction of the block has been processed).
+ */
#define BBEND(s,i){\
i=stackdepth-1;\
}
+/**********************************************************************/
+/* analyse_stack */
+/**********************************************************************/
+
+/* analyse_stack uses the intermediate code created by parse.c to
+ * build a model of the JVM operand stack for the current method.
+ *
+ * The following checks are performed:
+ * - check for operand stack underflow (before each instruction)
+ * - check for operand stack overflow (after[1] each instruction)
+ * - check for matching stack depth at merging points
+ * - check for matching basic types[2] at merging points
+ * - check basic types for instruction input (except for BUILTIN*
+ * opcodes, INVOKE* opcodes and MULTIANEWARRAY)
+ *
+ * [1]) XXX Checking this after the instruction should be ok. parse.c
+ * counts the number of required stack slots in such a way that it is
+ * only vital that we don't exceed `maxstack` at basic block
+ * boundaries.
+ *
+ * [2]) 'basic types' means the distinction between INT, LONG, FLOAT,
+ * DOUBLE and ADDRESS types. Subtypes of INT and different ADDRESS
+ * types are not discerned.
+ */
+
void analyse_stack()
{
int b_count;
/* pop 1 push 0 */
case ICMD_POP:
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_1;
+ if (IS_2_WORD_TYPE(curstack->type))
+ panic("Illegal instruction: POP on category 2 type");
+ }
+#endif
OP1_0ANY;
break;
case ICMD_POP2:
REQUIRE_1;
if (! IS_2_WORD_TYPE(curstack->type)) {
+ /* ..., cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_2;
+ if (IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: POP2 on cat2, cat1 types");
+ }
+#endif
OP1_0ANY; /* second pop */
}
else
/* pop 0 push 1 dup */
case ICMD_DUP:
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_1;
+ if (IS_2_WORD_TYPE(curstack->type))
+ panic("Illegal instruction: DUP on category 2 type");
+ }
+#endif
COUNT(count_dup_instruction);
DUP;
break;
case ICMD_DUP2:
REQUIRE_1;
if (IS_2_WORD_TYPE(curstack->type)) {
+ /* ..., cat2 */
iptr->opc = ICMD_DUP;
DUP;
}
else {
REQUIRE_2;
+ /* ..., ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ if (IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: DUP2 on cat2, cat1 types");
+ }
+#endif
copy = curstack;
NEWSTACK(copy->prev->type, copy->prev->varkind,
copy->prev->varnum);
/* pop 2 push 3 dup */
case ICMD_DUP_X1:
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_2;
+ if (IS_2_WORD_TYPE(curstack->type) ||
+ IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: DUP_X1 on cat 2 type");
+ }
+#endif
DUP_X1;
break;
case ICMD_DUP2_X1:
REQUIRE_2;
if (IS_2_WORD_TYPE(curstack->type)) {
+ /* ..., ????, cat2 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ if (IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: DUP2_X1 on cat2, cat2 types");
+ }
+#endif
iptr->opc = ICMD_DUP_X1;
DUP_X1;
}
else {
+ /* ..., ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_3;
+ if (IS_2_WORD_TYPE(curstack->prev->type)
+ || IS_2_WORD_TYPE(curstack->prev->prev->type))
+ panic("Illegal instruction: DUP2_X1 on invalid types");
+ }
+#endif
DUP2_X1;
}
break;
case ICMD_DUP_X2:
REQUIRE_2;
if (IS_2_WORD_TYPE(curstack->prev->type)) {
+ /* ..., cat2, ???? */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ if (IS_2_WORD_TYPE(curstack->type))
+ panic("Illegal instruction: DUP_X2 on cat2, cat2 types");
+ }
+#endif
iptr->opc = ICMD_DUP_X1;
DUP_X1;
}
else {
+ /* ..., cat1, ???? */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_3;
+ if (IS_2_WORD_TYPE(curstack->type)
+ || IS_2_WORD_TYPE(curstack->prev->prev->type))
+ panic("Illegal instruction: DUP_X2 on invalid types");
+ }
+#endif
DUP_X2;
}
break;
case ICMD_DUP2_X2:
REQUIRE_2;
if (IS_2_WORD_TYPE(curstack->type)) {
+ /* ..., ????, cat2 */
if (IS_2_WORD_TYPE(curstack->prev->type)) {
+ /* ..., cat2, cat2 */
iptr->opc = ICMD_DUP_X1;
DUP_X1;
}
else {
+ /* ..., cat1, cat2 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_3;
+ if (IS_2_WORD_TYPE(curstack->prev->prev->type))
+ panic("Illegal instruction: DUP2_X2 on invalid types");
+ }
+#endif
iptr->opc = ICMD_DUP_X2;
DUP_X2;
}
}
else {
REQUIRE_3;
+ /* ..., ????, ????, cat1 */
if (IS_2_WORD_TYPE(curstack->prev->prev->type)) {
+ /* ..., cat2, ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ if (IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: DUP2_X2 on invalid types");
+ }
+#endif
iptr->opc = ICMD_DUP2_X1;
DUP2_X1;
}
else {
+ /* ..., cat1, ????, cat1 */
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_4;
+ if (IS_2_WORD_TYPE(curstack->prev->type)
+ || IS_2_WORD_TYPE(curstack->prev->prev->prev->type))
+ panic("Illegal instruction: DUP2_X2 on invalid types");
+ }
+#endif
DUP2_X2;
}
}
/* pop 2 push 2 swap */
case ICMD_SWAP:
+#ifdef TYPECHECK_STACK_COMPCAT
+ if (opt_verify) {
+ REQUIRE_2;
+ if (IS_2_WORD_TYPE(curstack->type)
+ || IS_2_WORD_TYPE(curstack->prev->type))
+ panic("Illegal instruction: SWAP on category 2 type");
+ }
+#endif
SWAP;
break;
* needs it because the OP1_0ANY below
* overwrites iptr->dst.
*/
- iptr->val.a = (void*) iptr->dst;
+ iptr->val.a = (void *) iptr->dst;
+
+ tbptr->type = BBTYPE_SBR;
- tbptr->type=BBTYPE_SBR;
+ /* We need to check for overflow right here because
+ * the pushed value is poped after MARKREACHED. */
CHECKOVERFLOW;
MARKREACHED(tbptr, copy);
OP1_0ANY;
arguments_num = i + intreg_argnum;
copy = curstack;
while (--i >= 0) {
+ /* XXX check INT type here? Currently typecheck does this. */
if (! (copy->flags & SAVEDVAR)) {
copy->varkind = ARGVAR;
copy->varnum = i + intreg_argnum;
}
+/**********************************************************************/
+/* DEBUGGING HELPERS */
+/**********************************************************************/
+
void icmd_print_stack(stackptr s)
{
int i, j;
case ICMD_PUTSTATIC:
case ICMD_GETSTATIC:
printf(" ");
- utf_fprint(stdout,
- ((fieldinfo *) iptr->val.a)->class->name);
+ utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->class->name);
printf(".");
- utf_fprint(stdout,
- ((fieldinfo *) iptr->val.a)->name);
+ utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->name);
printf(" (type ");
- utf_fprint(stdout,
- ((fieldinfo *) iptr->val.a)->descriptor);
+ utf_fprint(stdout, ((fieldinfo *) iptr->val.a)->descriptor);
printf(")");
break;