Commit c516c1ff by Ranjit Mathew Committed by Ranjit Mathew

verify.c: Insert a short blurb at the start referring to the JVMS.

	* verify.c: Insert a short blurb at the start referring to the JVMS.
	Minor formatting fixes all over the place.
	(merge_type_state): Remove redundant nested if statement.
	(verify_jvm_instructions): Ensure current_subr is initialised to
	NULL_TREE.

Cii: Enter Log.  Lines beginning with `CVS:' are removed automaticalli

From-SVN: r84084
parent b75941cb
2004-07-04 Ranjit Mathew <rmathew@hotmail.com>
* verify.c: Insert a short blurb at the start referring to the JVMS.
(merge_type_state): Remove redundant nested if statement.
(verify_jvm_instructions): Ensure current_subr is initialised to
NULL_TREE.
Minor formatting fixes all over the place.
2004-07-02 Richard Henderson <rth@redhat.com> 2004-07-02 Richard Henderson <rth@redhat.com>
* jcf-write.c (generate_bytecode_insns <case SAVE_EXPR>): Rewrite. * jcf-write.c (generate_bytecode_insns <case SAVE_EXPR>): Rewrite.
......
...@@ -24,6 +24,11 @@ Java and all Java-based marks are trademarks or registered trademarks ...@@ -24,6 +24,11 @@ Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries. of Sun Microsystems, Inc. in the United States and other countries.
The Free Software Foundation is independent of Sun Microsystems, Inc. */ The Free Software Foundation is independent of Sun Microsystems, Inc. */
/* This bytecode verifier is an implementation of the bytecode
verification process described in section 4.9 of "The Java(TM) Virtual
Machine Specification", Second Edition, by Tim Lindholm and Frank Yellin,
published by Addison-Wesley in 1999. */
#include "config.h" #include "config.h"
#include "system.h" #include "system.h"
#include "coretypes.h" #include "coretypes.h"
...@@ -82,7 +87,7 @@ check_pending_block (tree target_label) ...@@ -82,7 +87,7 @@ check_pending_block (tree target_label)
push_pending_label (target_label); push_pending_label (target_label);
} }
if (current_subr == NULL) if (current_subr == NULL_TREE)
{ {
if (LABEL_IN_SUBR (target_label)) if (LABEL_IN_SUBR (target_label))
return "might transfer control into subroutine"; return "might transfer control into subroutine";
...@@ -113,7 +118,7 @@ subroutine_nesting (tree label) ...@@ -113,7 +118,7 @@ subroutine_nesting (tree label)
int nesting = 0; int nesting = 0;
while (label != NULL_TREE && LABEL_IN_SUBR (label)) while (label != NULL_TREE && LABEL_IN_SUBR (label))
{ {
if (! LABEL_IS_SUBR_START(label)) if (! LABEL_IS_SUBR_START (label))
label = LABEL_SUBR_START (label); label = LABEL_SUBR_START (label);
label = LABEL_SUBR_CONTEXT (label); label = LABEL_SUBR_CONTEXT (label);
nesting++; nesting++;
...@@ -250,11 +255,9 @@ merge_type_state (tree label) ...@@ -250,11 +255,9 @@ merge_type_state (tree label)
tree return_map; tree return_map;
if (vec == NULL_TREE) if (vec == NULL_TREE)
{ {
if (!vec) vec = make_tree_vec (cur_length);
{ LABEL_TYPE_STATE (label) = vec;
vec = make_tree_vec (cur_length);
LABEL_TYPE_STATE (label) = vec;
}
while (--cur_length >= 0) while (--cur_length >= 0)
TREE_VEC_ELT (vec, cur_length) = type_map [cur_length]; TREE_VEC_ELT (vec, cur_length) = type_map [cur_length];
return 1; return 1;
...@@ -281,7 +284,7 @@ merge_type_state (tree label) ...@@ -281,7 +284,7 @@ merge_type_state (tree label)
/* If there has been a change, note that since we must re-verify. /* If there has been a change, note that since we must re-verify.
However, if the label is the start of a subroutine, However, if the label is the start of a subroutine,
we don't care about local variables that are neither we don't care about local variables that are neither
set nor used in the sub-routine. */ set nor used in the subroutine. */
if (return_map == NULL_TREE || i >= nlocals if (return_map == NULL_TREE || i >= nlocals
|| TREE_VEC_ELT (return_map, i) != TYPE_UNUSED || TREE_VEC_ELT (return_map, i) != TYPE_UNUSED
|| (TYPE_IS_WIDE (new_type) || (TYPE_IS_WIDE (new_type)
...@@ -306,33 +309,33 @@ merge_type_state (tree label) ...@@ -306,33 +309,33 @@ merge_type_state (tree label)
static void static void
type_stack_dup (int size, int offset) type_stack_dup (int size, int offset)
{ {
tree type[4]; tree type [4];
int index; int index;
for (index = 0; index < size + offset; index++) for (index = 0; index < size + offset; index++)
{ {
type[index] = stack_type_map[stack_pointer - 1]; type [index] = stack_type_map [stack_pointer - 1];
if (type[index] == void_type_node) if (type [index] == void_type_node)
{ {
index++; index++;
type[index] = stack_type_map[stack_pointer - 2]; type [index] = stack_type_map [stack_pointer - 2];
if (! TYPE_IS_WIDE (type[index])) if (! TYPE_IS_WIDE (type [index]))
abort (); abort ();
if (index == size || index == size + offset) if (index == size || index == size + offset)
/* Dup operation splits 64-bit number. */ /* Dup operation splits 64-bit number. */
abort (); abort ();
} }
pop_type (type[index]); pop_type (type [index]);
} }
for (index = size; --index >= 0; ) for (index = size; --index >= 0; )
{ {
if (type[index] != void_type_node) if (type [index] != void_type_node)
push_type (type[index]); push_type (type [index]);
} }
for (index = size + offset; --index >= 0; ) for (index = size + offset; --index >= 0; )
{ {
if (type[index] != void_type_node) if (type [index] != void_type_node)
push_type (type[index]); push_type (type [index]);
} }
} }
...@@ -437,7 +440,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -437,7 +440,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
pending_blocks = NULL_TREE; pending_blocks = NULL_TREE;
/* Handle the exception table. */ current_subr = NULL_TREE;
/* Handle the exception table. */
method_init_exceptions (); method_init_exceptions ();
JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length); JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length);
eh_count = JCF_readu2 (jcf); eh_count = JCF_readu2 (jcf);
...@@ -447,8 +452,8 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -447,8 +452,8 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
starts = xmalloc (eh_count * sizeof (struct pc_index)); starts = xmalloc (eh_count * sizeof (struct pc_index));
for (i = 0; i < eh_count; ++i) for (i = 0; i < eh_count; ++i)
{ {
starts[i].start_pc = GET_u2 (jcf->read_ptr + 8 * i); starts [i].start_pc = GET_u2 (jcf->read_ptr + 8 * i);
starts[i].index = i; starts [i].index = i;
} }
qsort (starts, eh_count, sizeof (struct pc_index), start_pc_cmp); qsort (starts, eh_count, sizeof (struct pc_index), start_pc_cmp);
...@@ -456,7 +461,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -456,7 +461,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
{ {
int start_pc, end_pc, handler_pc, catch_type; int start_pc, end_pc, handler_pc, catch_type;
p = jcf->read_ptr + 8 * starts[i].index; p = jcf->read_ptr + 8 * starts [i].index;
start_pc = GET_u2 (p); start_pc = GET_u2 (p);
end_pc = GET_u2 (p+2); end_pc = GET_u2 (p+2);
...@@ -490,6 +495,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -490,6 +495,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
for (PC = 0;;) for (PC = 0;;)
{ {
tree type, tmp; tree type, tmp;
if (((PC != INVALID_PC if (((PC != INVALID_PC
&& instruction_bits [PC] & BCODE_TARGET) != 0) && instruction_bits [PC] & BCODE_TARGET) != 0)
|| PC == 0) || PC == 0)
...@@ -497,57 +503,61 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -497,57 +503,61 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
PUSH_PENDING (lookup_label (PC)); PUSH_PENDING (lookup_label (PC));
INVALIDATE_PC; INVALIDATE_PC;
} }
/* Check if there are any more pending blocks in the current /* Check if there are any more pending blocks in the current
subroutine. Because we push pending blocks in a subroutine. Because we push pending blocks in a
last-in-first-out order, and because we don't push anything last-in-first-out order, and because we don't push anything
from our caller until we are done with this subroutine or from our caller until we are done with this subroutine or
anything nested in it, then we are done if the top of the anything nested in it, we are done if the top of the
pending_blocks stack is not in a subroutine, or it is in our pending_blocks stack is not in a subroutine, or it is in our
caller. */ caller. */
if (current_subr if (current_subr && PC == INVALID_PC)
&& PC == INVALID_PC)
{ {
if (pending_blocks == NULL_TREE if (pending_blocks == NULL_TREE
|| (subroutine_nesting (pending_blocks) || (subroutine_nesting (pending_blocks)
< subroutine_nesting (current_subr))) < subroutine_nesting (current_subr)))
{ {
int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer; int size
= DECL_MAX_LOCALS (current_function_decl) + stack_pointer;
tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
tmp = LABEL_RETURN_LABELS (current_subr); tmp = LABEL_RETURN_LABELS (current_subr);
/* FIXME: If we exit a subroutine via a throw, we might /* FIXME: If we exit a subroutine via a throw, we might
have returned to an earlier caller. Obviously a have returned to an earlier caller. Obviously a
"ret" can only return one level, but a throw may "ret" can only return one level, but a throw may
return many levels.*/ return many levels. */
current_subr = LABEL_SUBR_CONTEXT (current_subr); current_subr = LABEL_SUBR_CONTEXT (current_subr);
if (RETURN_MAP_ADJUSTED (ret_map)) if (RETURN_MAP_ADJUSTED (ret_map))
{ {
/* Since we are done with this subroutine , set up /* Since we are done with this subroutine, set up
the (so far known) return address as pending - the (so far known) return address as pending -
with the merged type state. */ with the merged type state. */
for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp)) for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
{ {
tree return_label = TREE_VALUE (tmp); tree return_label = TREE_VALUE (tmp);
tree return_state = LABEL_TYPE_STATE (return_label); tree return_state = LABEL_TYPE_STATE (return_label);
if (return_state == NULL_TREE) if (return_state == NULL_TREE)
{ {
/* This means means we had not verified the /* This means we had not verified the subroutine
subroutine earlier, so this is the first jsr to earlier, so this is the first jsr to call it.
call it. In this case, the type_map of the return In this case, the type_map of the return
address is just the current type_map - and that address is just the current type_map - and that
is handled by the following PUSH_PENDING. */ is handled by the following PUSH_PENDING. */
} }
else else
{ {
/* In this case we have to do a merge. But first /* In this case we have to do a merge. But first
restore the type_map for unused slots to those restore the type_map for unused slots to those
that were in effect at the jsr. */ that were in effect at the jsr. */
for (index = size; --index >= 0; ) for (index = size; --index >= 0; )
{ {
type_map[index] = TREE_VEC_ELT (ret_map, index); type_map [index]
if (type_map[index] == TYPE_UNUSED) = TREE_VEC_ELT (ret_map, index);
type_map[index]
if (type_map [index] == TYPE_UNUSED)
type_map [index]
= TREE_VEC_ELT (return_state, index); = TREE_VEC_ELT (return_state, index);
} }
} }
...@@ -556,11 +566,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -556,11 +566,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
} }
} }
} }
if (PC == INVALID_PC) if (PC == INVALID_PC)
{ {
label = pending_blocks; label = pending_blocks;
if (label == NULL_TREE) if (label == NULL_TREE)
break; /* We're done! */ break; /* We're done! */
pending_blocks = LABEL_PENDING_CHAIN (label); pending_blocks = LABEL_PENDING_CHAIN (label);
LABEL_CHANGED (label) = 0; LABEL_CHANGED (label) = 0;
...@@ -571,52 +584,60 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -571,52 +584,60 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
/* Restore type_map and stack_pointer from /* Restore type_map and stack_pointer from
LABEL_TYPE_STATE (label), and continue LABEL_TYPE_STATE (label), and continue
compiling from there. */ compiling from there. */
load_type_state (label); load_type_state (label);
PC = LABEL_PC (label); PC = LABEL_PC (label);
} }
else if (PC >= length) else if (PC >= length)
VERIFICATION_ERROR ("falling through end of method"); VERIFICATION_ERROR ("falling through the end of the method");
/* fprintf (stderr, "** %d\n", PC); */
oldpc = PC; oldpc = PC;
if (!(instruction_bits [PC] & BCODE_INSTRUCTION_START) && ! wide) if (! (instruction_bits [PC] & BCODE_INSTRUCTION_START) && ! wide)
VERIFICATION_ERROR ("PC not at instruction start"); VERIFICATION_ERROR ("PC not at instruction start");
instruction_bits[PC] |= BCODE_VERIFIED; instruction_bits [PC] |= BCODE_VERIFIED;
eh_ranges = find_handler (oldpc); eh_ranges = find_handler (oldpc);
op_code = byte_ops[PC++]; op_code = byte_ops [PC++];
switch (op_code) switch (op_code)
{ {
int is_static, is_putting; int is_static, is_putting;
case OPCODE_nop: case OPCODE_nop:
break; break;
case OPCODE_iconst_m1: case OPCODE_iconst_m1:
case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_2: case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_2:
case OPCODE_iconst_3: case OPCODE_iconst_4: case OPCODE_iconst_5: case OPCODE_iconst_3: case OPCODE_iconst_4: case OPCODE_iconst_5:
i = op_code - OPCODE_iconst_0; i = op_code - OPCODE_iconst_0;
goto push_int; goto push_int;
push_int: push_int:
if (byte_ops[PC] == OPCODE_newarray if (byte_ops [PC] == OPCODE_newarray
|| byte_ops[PC] == OPCODE_anewarray) || byte_ops [PC] == OPCODE_anewarray)
int_value = i; int_value = i;
PUSH_TYPE (int_type_node); break; PUSH_TYPE (int_type_node); break;
case OPCODE_lconst_0: case OPCODE_lconst_1: case OPCODE_lconst_0: case OPCODE_lconst_1:
PUSH_TYPE (long_type_node); break; PUSH_TYPE (long_type_node); break;
case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2: case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2:
PUSH_TYPE (float_type_node); break; PUSH_TYPE (float_type_node); break;
case OPCODE_dconst_0: case OPCODE_dconst_1: case OPCODE_dconst_0: case OPCODE_dconst_1:
PUSH_TYPE (double_type_node); break; PUSH_TYPE (double_type_node); break;
case OPCODE_bipush: case OPCODE_bipush:
i = IMMEDIATE_s1; i = IMMEDIATE_s1;
goto push_int; goto push_int;
case OPCODE_sipush: case OPCODE_sipush:
i = IMMEDIATE_s2; i = IMMEDIATE_s2;
goto push_int; goto push_int;
case OPCODE_iload: type = int_type_node; goto general_load; case OPCODE_iload: type = int_type_node; goto general_load;
case OPCODE_lload: type = long_type_node; goto general_load; case OPCODE_lload: type = long_type_node; goto general_load;
case OPCODE_fload: type = float_type_node; goto general_load; case OPCODE_fload: type = float_type_node; goto general_load;
...@@ -652,13 +673,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -652,13 +673,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
>= DECL_MAX_LOCALS (current_function_decl))) >= DECL_MAX_LOCALS (current_function_decl)))
VERIFICATION_ERROR_WITH_INDEX VERIFICATION_ERROR_WITH_INDEX
("invalid local variable index %d in load"); ("invalid local variable index %d in load");
tmp = type_map[index]; tmp = type_map [index];
if (tmp == TYPE_UNKNOWN) if (tmp == TYPE_UNKNOWN)
VERIFICATION_ERROR_WITH_INDEX VERIFICATION_ERROR_WITH_INDEX
("loading local variable %d which has unknown type"); ("loading local variable %d which has unknown type");
else if (tmp == TYPE_SECOND else if (tmp == TYPE_SECOND
|| (TYPE_IS_WIDE (type) || (TYPE_IS_WIDE (type)
&& type_map[index+1] != void_type_node) && type_map [index+1] != void_type_node)
|| (type == ptr_type_node || (type == ptr_type_node
? TREE_CODE (tmp) != POINTER_TYPE ? TREE_CODE (tmp) != POINTER_TYPE
: type == int_type_node : type == int_type_node
...@@ -707,21 +728,23 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -707,21 +728,23 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
return 0; return 0;
} }
POP_TYPE_CONV (type, type, NULL); POP_TYPE_CONV (type, type, NULL);
type_map[index] = type; type_map [index] = type;
/* If local variable changed, we need to reconsider eh handlers. */ /* If a local variable has changed, we need to reconsider exception
handlers. */
prev_eh_ranges = NULL_EH_RANGE; prev_eh_ranges = NULL_EH_RANGE;
/* Allocate decl and rtx for this variable now, so if we're not /* Allocate decl and rtx for this variable now, so if we're not
optimizing, we get a temporary that survives the whole method. */ optimizing, we get a temporary that survives the whole method. */
find_local_variable (index, type, oldpc); find_local_variable (index, type, oldpc);
if (TYPE_IS_WIDE (type)) if (TYPE_IS_WIDE (type))
type_map[index+1] = TYPE_SECOND; type_map [index+1] = TYPE_SECOND;
/* ... fall through to note_used ... */ /* ... fall through to note_used ... */
note_used: note_used:
/* For store or load, note that local variable INDEX is used. /* For store or load, note that local variable INDEX is used.
This is needed to verify try-finally sub-routines. */ This is needed to verify try-finally subroutines. */
if (current_subr) if (current_subr)
{ {
tree vec = LABEL_RETURN_TYPE_STATE (current_subr); tree vec = LABEL_RETURN_TYPE_STATE (current_subr);
...@@ -772,15 +795,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -772,15 +795,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
type = double_type_node; goto binop; type = double_type_node; goto binop;
case OPCODE_dneg: case OPCODE_dneg:
type = double_type_node; goto unop; type = double_type_node; goto unop;
unop: unop:
pop_type (type); pop_type (type);
PUSH_TYPE (type); PUSH_TYPE (type);
break; break;
binop: binop:
pop_type (type); pop_type (type);
pop_type (type); pop_type (type);
PUSH_TYPE (type); PUSH_TYPE (type);
break; break;
case OPCODE_lshl: case OPCODE_lshl:
case OPCODE_lshr: case OPCODE_lshr:
case OPCODE_lushr: case OPCODE_lushr:
...@@ -788,17 +814,19 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -788,17 +814,19 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
pop_type (long_type_node); pop_type (long_type_node);
PUSH_TYPE (long_type_node); PUSH_TYPE (long_type_node);
break; break;
case OPCODE_iinc: case OPCODE_iinc:
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
PC += wide + 1; PC += wide + 1;
wide = 0; wide = 0;
if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)) if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl))
VERIFICATION_ERROR ("invalid local variable index in iinc"); VERIFICATION_ERROR ("invalid local variable index in iinc");
tmp = type_map[index]; tmp = type_map [index];
if (tmp == NULL_TREE if (tmp == NULL_TREE
|| ! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) || ! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32)
VERIFICATION_ERROR ("invalid local variable type in iinc"); VERIFICATION_ERROR ("invalid local variable type in iinc");
break; break;
case OPCODE_i2l: case OPCODE_i2l:
pop_type (int_type_node); PUSH_TYPE (long_type_node); break; pop_type (int_type_node); PUSH_TYPE (long_type_node); break;
case OPCODE_i2f: case OPCODE_i2f:
...@@ -823,6 +851,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -823,6 +851,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
pop_type (double_type_node); PUSH_TYPE (long_type_node); break; pop_type (double_type_node); PUSH_TYPE (long_type_node); break;
case OPCODE_d2f: case OPCODE_d2f:
pop_type (double_type_node); PUSH_TYPE (float_type_node); break; pop_type (double_type_node); PUSH_TYPE (float_type_node); break;
case OPCODE_lcmp: case OPCODE_lcmp:
type = long_type_node; goto compare; type = long_type_node; goto compare;
case OPCODE_fcmpl: case OPCODE_fcmpl:
...@@ -834,6 +863,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -834,6 +863,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
compare: compare:
pop_type (type); pop_type (type); pop_type (type); pop_type (type);
PUSH_TYPE (int_type_node); break; PUSH_TYPE (int_type_node); break;
case OPCODE_ifeq: case OPCODE_ifeq:
case OPCODE_ifne: case OPCODE_ifne:
case OPCODE_iflt: case OPCODE_iflt:
...@@ -855,15 +885,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -855,15 +885,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
case OPCODE_if_acmpne: case OPCODE_if_acmpne:
pop_type (object_ptr_type_node); pop_type (object_ptr_type_node); pop_type (object_ptr_type_node); pop_type (object_ptr_type_node);
goto cond; goto cond;
cond: cond:
PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2));
break; break;
case OPCODE_goto: case OPCODE_goto:
PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2));
INVALIDATE_PC; INVALIDATE_PC;
break; break;
case OPCODE_wide: case OPCODE_wide:
switch (byte_ops[PC]) switch (byte_ops [PC])
{ {
case OPCODE_iload: case OPCODE_lload: case OPCODE_iload: case OPCODE_lload:
case OPCODE_fload: case OPCODE_dload: case OPCODE_aload: case OPCODE_fload: case OPCODE_dload: case OPCODE_aload:
...@@ -877,6 +910,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -877,6 +910,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
VERIFICATION_ERROR ("invalid use of wide instruction"); VERIFICATION_ERROR ("invalid use of wide instruction");
} }
break; break;
case OPCODE_return: type = void_type_node; goto ret; case OPCODE_return: type = void_type_node; goto ret;
case OPCODE_ireturn: case OPCODE_ireturn:
if ((TREE_CODE (return_type) == BOOLEAN_TYPE if ((TREE_CODE (return_type) == BOOLEAN_TYPE
...@@ -896,13 +930,15 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -896,13 +930,15 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
else else
type = NULL_TREE; type = NULL_TREE;
goto ret; goto ret;
ret: ret:
if (type != return_type) if (type != return_type)
VERIFICATION_ERROR ("incorrect ?return opcode"); VERIFICATION_ERROR ("incorrect ?return opcode");
if (type != void_type_node) if (type != void_type_node)
POP_TYPE(type, "return value has wrong type"); POP_TYPE (type, "return value has wrong type");
INVALIDATE_PC; INVALIDATE_PC;
break; break;
case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field; case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field;
case OPCODE_putstatic: is_putting = 1; is_static = 1; goto field; case OPCODE_putstatic: is_putting = 1; is_static = 1; goto field;
case OPCODE_getfield: is_putting = 0; is_static = 0; goto field; case OPCODE_getfield: is_putting = 0; is_static = 0; goto field;
...@@ -911,69 +947,90 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -911,69 +947,90 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
{ {
tree field_signature, field_type; tree field_signature, field_type;
index = IMMEDIATE_u2; index = IMMEDIATE_u2;
if (index <= 0 || index >= JPOOL_SIZE(current_jcf))
if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d"); VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d");
if (JPOOL_TAG (current_jcf, index) != CONSTANT_Fieldref) if (JPOOL_TAG (current_jcf, index) != CONSTANT_Fieldref)
VERIFICATION_ERROR VERIFICATION_ERROR
("field instruction does not reference a Fieldref"); ("field instruction does not reference a Fieldref");
field_signature = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);
field_signature
= COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);
field_type = get_type_from_signature (field_signature); field_type = get_type_from_signature (field_signature);
if (is_putting) if (is_putting)
POP_TYPE (field_type, "incorrect type for field"); POP_TYPE (field_type, "incorrect type for field");
if (! is_static) if (! is_static)
{ {
int clindex = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool, int clindex
index); = COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool, index);
tree self_type = get_class_constant (current_jcf, clindex); tree self_type = get_class_constant (current_jcf, clindex);
/* Defer actual checking until next pass. */ /* Defer actual checking until next pass. */
POP_TYPE(self_type, "incorrect type for field reference"); POP_TYPE (self_type, "incorrect type for field reference");
} }
if (! is_putting) if (! is_putting)
PUSH_TYPE (field_type); PUSH_TYPE (field_type);
break; break;
} }
case OPCODE_new: case OPCODE_new:
PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2)); PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2));
break; break;
case OPCODE_dup: wide = 1; index = 0; goto dup; case OPCODE_dup: wide = 1; index = 0; goto dup;
case OPCODE_dup_x1: wide = 1; index = 1; goto dup; case OPCODE_dup_x1: wide = 1; index = 1; goto dup;
case OPCODE_dup_x2: wide = 1; index = 2; goto dup; case OPCODE_dup_x2: wide = 1; index = 2; goto dup;
case OPCODE_dup2: wide = 2; index = 0; goto dup; case OPCODE_dup2: wide = 2; index = 0; goto dup;
case OPCODE_dup2_x1: wide = 2; index = 1; goto dup; case OPCODE_dup2_x1: wide = 2; index = 1; goto dup;
case OPCODE_dup2_x2: wide = 2; index = 2; goto dup; case OPCODE_dup2_x2: wide = 2; index = 2; goto dup;
dup: dup:
if (wide + index > stack_pointer) if (wide + index > stack_pointer)
VERIFICATION_ERROR ("stack underflow - dup* operation"); VERIFICATION_ERROR ("stack underflow - dup* operation");
type_stack_dup (wide, index); type_stack_dup (wide, index);
wide = 0; wide = 0;
break; break;
case OPCODE_pop: index = 1; goto pop; case OPCODE_pop: index = 1; goto pop;
case OPCODE_pop2: index = 2; goto pop; case OPCODE_pop2: index = 2; goto pop;
pop: pop:
if (stack_pointer < index) if (stack_pointer < index)
VERIFICATION_ERROR ("stack underflow"); VERIFICATION_ERROR ("stack underflow");
stack_pointer -= index; stack_pointer -= index;
break; break;
case OPCODE_swap: case OPCODE_swap:
if (stack_pointer < 2) if (stack_pointer < 2)
VERIFICATION_ERROR ("stack underflow (in swap)"); VERIFICATION_ERROR ("stack underflow (in swap)");
else else
{ {
tree type1 = stack_type_map[stack_pointer - 1]; tree type1 = stack_type_map [stack_pointer - 1];
tree type2 = stack_type_map[stack_pointer - 2]; tree type2 = stack_type_map [stack_pointer - 2];
if (type1 == void_type_node || type2 == void_type_node) if (type1 == void_type_node || type2 == void_type_node)
VERIFICATION_ERROR ("verifier (swap): double or long value"); VERIFICATION_ERROR ("verifier (swap): double or long value");
stack_type_map[stack_pointer - 2] = type1;
stack_type_map[stack_pointer - 1] = type2; stack_type_map [stack_pointer - 2] = type1;
stack_type_map [stack_pointer - 1] = type2;
} }
break; break;
case OPCODE_ldc: index = IMMEDIATE_u1; goto ldc; case OPCODE_ldc: index = IMMEDIATE_u1; goto ldc;
case OPCODE_ldc2_w: case OPCODE_ldc2_w:
case OPCODE_ldc_w: case OPCODE_ldc_w:
index = IMMEDIATE_u2; goto ldc; index = IMMEDIATE_u2; goto ldc;
ldc: ldc:
if (index <= 0 || index >= JPOOL_SIZE(current_jcf)) if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d in ldc"); VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d in ldc");
int_value = -1; int_value = -1;
switch (JPOOL_TAG (current_jcf, index) & ~CONSTANT_ResolvedFlag) switch (JPOOL_TAG (current_jcf, index) & ~CONSTANT_ResolvedFlag)
{ {
...@@ -1005,10 +1062,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1005,10 +1062,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
tree sig, method_name, method_type, self_type; tree sig, method_name, method_type, self_type;
int self_is_interface, tag; int self_is_interface, tag;
index = IMMEDIATE_u2; index = IMMEDIATE_u2;
if (index <= 0 || index >= JPOOL_SIZE(current_jcf))
if (index <= 0 || index >= JPOOL_SIZE (current_jcf))
VERIFICATION_ERROR_WITH_INDEX VERIFICATION_ERROR_WITH_INDEX
("bad constant pool index %d for invoke"); ("bad constant pool index %d for invoke");
tag = JPOOL_TAG (current_jcf, index); tag = JPOOL_TAG (current_jcf, index);
if (op_code == OPCODE_invokeinterface) if (op_code == OPCODE_invokeinterface)
{ {
if (tag != CONSTANT_InterfaceMethodref) if (tag != CONSTANT_InterfaceMethodref)
...@@ -1020,18 +1080,25 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1020,18 +1080,25 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
if (tag != CONSTANT_Methodref) if (tag != CONSTANT_Methodref)
VERIFICATION_ERROR ("invoke does not reference a Methodref"); VERIFICATION_ERROR ("invoke does not reference a Methodref");
} }
sig = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index); sig = COMPONENT_REF_SIGNATURE (&current_jcf->cpool, index);
self_type = get_class_constant
(current_jcf, COMPONENT_REF_CLASS_INDEX (&current_jcf->cpool, self_type
index)); = get_class_constant (current_jcf,
COMPONENT_REF_CLASS_INDEX
(&current_jcf->cpool, index));
if (! CLASS_LOADED_P (self_type)) if (! CLASS_LOADED_P (self_type))
load_class (self_type, 1); load_class (self_type, 1);
self_is_interface = CLASS_INTERFACE (TYPE_NAME (self_type)); self_is_interface = CLASS_INTERFACE (TYPE_NAME (self_type));
method_name = COMPONENT_REF_NAME (&current_jcf->cpool, index); method_name = COMPONENT_REF_NAME (&current_jcf->cpool, index);
method_type = parse_signature_string (IDENTIFIER_POINTER (sig), method_type = parse_signature_string (IDENTIFIER_POINTER (sig),
IDENTIFIER_LENGTH (sig)); IDENTIFIER_LENGTH (sig));
if (TREE_CODE (method_type) != FUNCTION_TYPE) if (TREE_CODE (method_type) != FUNCTION_TYPE)
VERIFICATION_ERROR ("bad method signature"); VERIFICATION_ERROR ("bad method signature");
pmessage = pop_argument_types (TYPE_ARG_TYPES (method_type)); pmessage = pop_argument_types (TYPE_ARG_TYPES (method_type));
if (pmessage != NULL) if (pmessage != NULL)
{ {
...@@ -1039,10 +1106,11 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1039,10 +1106,11 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
goto pop_type_error; goto pop_type_error;
} }
/* Can't invoke <clinit> */ /* Can't invoke <clinit>. */
if (ID_CLINIT_P (method_name)) if (ID_CLINIT_P (method_name))
VERIFICATION_ERROR ("invoke opcode can't invoke <clinit>"); VERIFICATION_ERROR ("invoke opcode can't invoke <clinit>");
/* Apart invokespecial, can't invoke <init> */
/* Apart from invokespecial, can't invoke <init>. */
if (op_code != OPCODE_invokespecial && ID_INIT_P (method_name)) if (op_code != OPCODE_invokespecial && ID_INIT_P (method_name))
VERIFICATION_ERROR ("invoke opcode can't invoke <init>"); VERIFICATION_ERROR ("invoke opcode can't invoke <init>");
...@@ -1060,11 +1128,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1060,11 +1128,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
if (!nargs || notZero) if (!nargs || notZero)
VERIFICATION_ERROR VERIFICATION_ERROR
("invalid argument number in invokeinterface"); ("invalid argument number in invokeinterface");
/* If we verify/resolve the constant pool, as we should, /* If we verify/resolve the constant pool, as we should,
this test (and the one just following) are redundant. */ this test (and the one just following) are redundant. */
if (! self_is_interface) if (! self_is_interface)
VERIFICATION_ERROR ("invokeinterface calls method not in interface"); VERIFICATION_ERROR
("invokeinterface calls method not in interface");
break; break;
default: default:
if (self_is_interface) if (self_is_interface)
VERIFICATION_ERROR ("method in interface called"); VERIFICATION_ERROR ("method in interface called");
...@@ -1077,9 +1148,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1077,9 +1148,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
} }
case OPCODE_arraylength: case OPCODE_arraylength:
/* Type checking actually made during code generation */ /* Type checking actually made during code generation. */
pop_type( ptr_type_node ); pop_type (ptr_type_node);
PUSH_TYPE( int_type_node ); PUSH_TYPE (int_type_node);
break; break;
/* Q&D verification *or* more checking done during code generation /* Q&D verification *or* more checking done during code generation
...@@ -1093,8 +1164,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1093,8 +1164,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
case OPCODE_bastore: type = int_type_node; goto astore; case OPCODE_bastore: type = int_type_node; goto astore;
case OPCODE_castore: type = int_type_node; goto astore; case OPCODE_castore: type = int_type_node; goto astore;
case OPCODE_sastore: type = int_type_node; goto astore; case OPCODE_sastore: type = int_type_node; goto astore;
astore: astore:
/* FIXME - need better verification here */ /* FIXME - need better verification here. */
pop_type (type); /* new value */ pop_type (type); /* new value */
pop_type (int_type_node); /* index */ pop_type (int_type_node); /* index */
pop_type (ptr_type_node); /* array */ pop_type (ptr_type_node); /* array */
...@@ -1110,6 +1182,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1110,6 +1182,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
case OPCODE_baload: type = promote_type (byte_type_node); goto aload; case OPCODE_baload: type = promote_type (byte_type_node); goto aload;
case OPCODE_caload: type = promote_type (char_type_node); goto aload; case OPCODE_caload: type = promote_type (char_type_node); goto aload;
case OPCODE_saload: type = promote_type (short_type_node); goto aload; case OPCODE_saload: type = promote_type (short_type_node); goto aload;
aload: aload:
pop_type (int_type_node); pop_type (int_type_node);
tmp = pop_type (ptr_type_node); tmp = pop_type (ptr_type_node);
...@@ -1135,9 +1208,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1135,9 +1208,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
newarray: newarray:
if (int_value >= 0 && prevpc >= 0) if (int_value >= 0 && prevpc >= 0)
{ {
/* If previous instruction pushed int constant, /* If the previous instruction pushed an int constant,
we want to use it. */ we want to use it. */
switch (byte_ops[prevpc]) switch (byte_ops [prevpc])
{ {
case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_0: case OPCODE_iconst_1:
case OPCODE_iconst_2: case OPCODE_iconst_3: case OPCODE_iconst_2: case OPCODE_iconst_3:
...@@ -1151,6 +1224,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1151,6 +1224,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
} }
else else
int_value = -1; int_value = -1;
type = build_java_array_type (type, int_value); type = build_java_array_type (type, int_value);
pop_type (int_type_node); pop_type (int_type_node);
PUSH_TYPE (type); PUSH_TYPE (type);
...@@ -1162,11 +1236,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1162,11 +1236,13 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
index = IMMEDIATE_u2; index = IMMEDIATE_u2;
ndim = IMMEDIATE_u1; ndim = IMMEDIATE_u1;
if( ndim < 1 ) if (ndim < 1)
VERIFICATION_ERROR ("number of dimension lower that 1 in multianewarray" ); VERIFICATION_ERROR
("number of dimension lower that 1 in multianewarray" );
for( i = 0; i < ndim; i++ ) for (i = 0; i < ndim; i++)
pop_type (int_type_node); pop_type (int_type_node);
PUSH_TYPE (get_class_constant (current_jcf, index)); PUSH_TYPE (get_class_constant (current_jcf, index));
break; break;
} }
...@@ -1176,7 +1252,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1176,7 +1252,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
break; break;
case OPCODE_athrow: case OPCODE_athrow:
/* FIXME: athrow also empties the stack. */ /* FIXME: athrow also empties the stack. */
POP_TYPE (throwable_type_node, "missing throwable at athrow" ); POP_TYPE (throwable_type_node, "missing throwable at athrow" );
INVALIDATE_PC; INVALIDATE_PC;
break; break;
...@@ -1187,6 +1263,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1187,6 +1263,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
type = get_class_constant (current_jcf, IMMEDIATE_u2); type = get_class_constant (current_jcf, IMMEDIATE_u2);
PUSH_TYPE (type); PUSH_TYPE (type);
break; break;
case OPCODE_instanceof: case OPCODE_instanceof:
POP_TYPE (object_ptr_type_node, POP_TYPE (object_ptr_type_node,
"instanceof operand is not a pointer"); "instanceof operand is not a pointer");
...@@ -1199,12 +1276,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1199,12 +1276,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
jint low, high; jint low, high;
POP_TYPE (int_type_node, "missing int for tableswitch"); POP_TYPE (int_type_node, "missing int for tableswitch");
while (PC%4) while (PC%4)
{ {
if (byte_ops[PC++]) if (byte_ops [PC++])
VERIFICATION_ERROR ("bad alignment in tableswitch pad"); VERIFICATION_ERROR ("bad alignment in tableswitch pad");
} }
PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4));
PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
low = IMMEDIATE_s4; low = IMMEDIATE_s4;
high = IMMEDIATE_s4; high = IMMEDIATE_s4;
...@@ -1213,6 +1292,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1213,6 +1292,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
while (low++ <= high) while (low++ <= high)
PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
INVALIDATE_PC; INVALIDATE_PC;
break; break;
} }
...@@ -1222,13 +1302,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1222,13 +1302,14 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
jint npairs, last = 0, not_registered = 1; jint npairs, last = 0, not_registered = 1;
POP_TYPE (int_type_node, "missing int for lookupswitch"); POP_TYPE (int_type_node, "missing int for lookupswitch");
while (PC%4) while (PC%4)
{ {
if (byte_ops[PC++]) if (byte_ops [PC++])
VERIFICATION_ERROR ("bad alignment in lookupswitch pad"); VERIFICATION_ERROR ("bad alignment in lookupswitch pad");
} }
PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4)); PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4));
npairs = IMMEDIATE_s4; npairs = IMMEDIATE_s4;
if (npairs < 0) if (npairs < 0)
...@@ -1237,6 +1318,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1237,6 +1318,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
while (npairs--) while (npairs--)
{ {
int match = IMMEDIATE_s4; int match = IMMEDIATE_s4;
if (not_registered) if (not_registered)
not_registered = 0; not_registered = 0;
else if (last >= match) else if (last >= match)
...@@ -1273,13 +1355,16 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1273,13 +1355,16 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
int nlocals = DECL_MAX_LOCALS (current_function_decl); int nlocals = DECL_MAX_LOCALS (current_function_decl);
index = nlocals + DECL_MAX_STACK (current_function_decl); index = nlocals + DECL_MAX_STACK (current_function_decl);
return_type_map = make_tree_vec (index); return_type_map = make_tree_vec (index);
while (index > nlocals) while (index > nlocals)
TREE_VEC_ELT (return_type_map, --index) = TYPE_UNKNOWN; TREE_VEC_ELT (return_type_map, --index) = TYPE_UNKNOWN;
while (index > 0) while (index > 0)
TREE_VEC_ELT (return_type_map, --index) = TYPE_UNUSED; TREE_VEC_ELT (return_type_map, --index) = TYPE_UNUSED;
LABEL_RETURN_LABEL (target) LABEL_RETURN_LABEL (target)
= build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target)); = build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target));
LABEL_PC (LABEL_RETURN_LABEL (target)) = -1; LABEL_PC (LABEL_RETURN_LABEL (target)) = INVALID_PC;
LABEL_RETURN_TYPE_STATE (target) = return_type_map; LABEL_RETURN_TYPE_STATE (target) = return_type_map;
LABEL_IS_SUBR_START (target) = 1; LABEL_IS_SUBR_START (target) = 1;
LABEL_IN_SUBR (target) = 1; LABEL_IN_SUBR (target) = 1;
...@@ -1315,7 +1400,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1315,7 +1400,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
while (--len >= 0) while (--len >= 0)
{ {
if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED) if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED)
type_map[len] = TREE_VEC_ELT (return_map, len); type_map [len] = TREE_VEC_ELT (return_map, len);
} }
current_subr = LABEL_SUBR_CONTEXT (target); current_subr = LABEL_SUBR_CONTEXT (target);
if (RETURN_MAP_ADJUSTED (return_map)) if (RETURN_MAP_ADJUSTED (return_map))
...@@ -1325,33 +1410,37 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1325,33 +1410,37 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
INVALIDATE_PC; INVALIDATE_PC;
} }
break; break;
case OPCODE_ret: case OPCODE_ret:
if (current_subr == NULL) if (current_subr == NULL_TREE)
VERIFICATION_ERROR ("ret instruction not in a jsr subroutine"); VERIFICATION_ERROR ("ret instruction not in a jsr subroutine");
else else
{ {
tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr);
int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer; int size
= DECL_MAX_LOCALS (current_function_decl) + stack_pointer;
index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1;
wide = 0; wide = 0;
INVALIDATE_PC; INVALIDATE_PC;
if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl) if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)
|| type_map[index] != TYPE_RETURN_ADDR) || type_map [index] != TYPE_RETURN_ADDR)
VERIFICATION_ERROR ("invalid ret index"); VERIFICATION_ERROR ("invalid ret index");
/* The next chunk of code is similar to an inlined version of /* The next chunk of code is similar to an inlined version of
* merge_type_state (LABEL_RETURN_LABEL (current_subr)). merge_type_state (LABEL_RETURN_LABEL (current_subr)).
* The main differences are that LABEL_RETURN_LABEL is The main differences are that LABEL_RETURN_LABEL is
* pre-allocated by the jsr (but we don't know the size then); pre-allocated by the jsr (but we don't know the size then);
* and that we have to handle TYPE_UNUSED. */ and that we have to handle TYPE_UNUSED. */
if (! RETURN_MAP_ADJUSTED (ret_map)) if (! RETURN_MAP_ADJUSTED (ret_map))
{ /* First return from this subroutine - fix stack pointer. */ {
/* First return from this subroutine - fix stack
pointer. */
TREE_VEC_LENGTH (ret_map) = size; TREE_VEC_LENGTH (ret_map) = size;
for (index = size; --index >= 0; ) for (index = size; --index >= 0; )
{ {
if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED) if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED)
TREE_VEC_ELT (ret_map, index) = type_map[index]; TREE_VEC_ELT (ret_map, index) = type_map [index];
} }
RETURN_MAP_ADJUSTED (ret_map) = 1; RETURN_MAP_ADJUSTED (ret_map) = 1;
} }
...@@ -1377,10 +1466,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1377,10 +1466,9 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
} }
} }
} }
} }
break; break;
case OPCODE_jsr_w: case OPCODE_jsr_w:
case OPCODE_ret_w: case OPCODE_ret_w:
default: default:
...@@ -1393,17 +1481,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1393,17 +1481,18 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
/* The following test is true if we have entered or exited an exception /* The following test is true if we have entered or exited an exception
handler range *or* we have done a store to a local variable. handler range *or* we have done a store to a local variable.
In either case we need to consider any exception handlers that In either case we need to consider any exception handlers that
might "follow" this instruction. */ might "follow" this instruction. */
if (eh_ranges != prev_eh_ranges) if (eh_ranges != prev_eh_ranges)
{ {
int save_stack_pointer = stack_pointer; int save_stack_pointer = stack_pointer;
int index = DECL_MAX_LOCALS (current_function_decl); int index = DECL_MAX_LOCALS (current_function_decl);
tree save_type = type_map[index]; tree save_type = type_map [index];
tree save_current_subr = current_subr; tree save_current_subr = current_subr;
struct eh_range *ranges = find_handler (oldpc); struct eh_range *ranges = find_handler (oldpc);
stack_pointer = 1; stack_pointer = 1;
for (; ranges != NULL_EH_RANGE; ranges = ranges->outer)
for ( ; ranges != NULL_EH_RANGE; ranges = ranges->outer)
{ {
tree chain = ranges->handlers; tree chain = ranges->handlers;
...@@ -1420,7 +1509,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1420,7 +1509,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
have that the current_subr is entirely within the catch range. have that the current_subr is entirely within the catch range.
In that case we can assume if that if a caller (the jsr) of In that case we can assume if that if a caller (the jsr) of
a subroutine is within the catch range, then the handler is a subroutine is within the catch range, then the handler is
*not* part of the subroutine, and vice versa. */ *not* part of the subroutine, and vice versa. */
current_subr = save_current_subr; current_subr = save_current_subr;
for ( ; current_subr != NULL_TREE; for ( ; current_subr != NULL_TREE;
...@@ -1428,31 +1517,35 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1428,31 +1517,35 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
{ {
tree return_labels = LABEL_RETURN_LABELS (current_subr); tree return_labels = LABEL_RETURN_LABELS (current_subr);
/* There could be multiple return_labels, but /* There could be multiple return_labels, but
we only need to check one. */ we only need to check one. */
int return_pc = LABEL_PC (TREE_VALUE (return_labels)); int return_pc = LABEL_PC (TREE_VALUE (return_labels));
if (return_pc <= ranges->start_pc if (return_pc <= ranges->start_pc
|| return_pc > ranges->end_pc) || return_pc > ranges->end_pc)
break; break;
} }
for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain)) for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain))
{ {
tree handler = TREE_VALUE (chain); tree handler = TREE_VALUE (chain);
tree type = TREE_PURPOSE (chain); tree type = TREE_PURPOSE (chain);
if (type == NULL_TREE) /* a finally handler */ if (type == NULL_TREE) /* a finally handler */
type = throwable_type_node; type = throwable_type_node;
type_map[index] = promote_type (type);
type_map [index] = promote_type (type);
PUSH_PENDING (handler); PUSH_PENDING (handler);
} }
} }
stack_pointer = save_stack_pointer; stack_pointer = save_stack_pointer;
current_subr = save_current_subr; current_subr = save_current_subr;
type_map[index] = save_type; type_map [index] = save_type;
prev_eh_ranges = eh_ranges; prev_eh_ranges = eh_ranges;
} }
} }
return 1; return 1;
pop_type_error: pop_type_error:
error ("verification error at PC=%d", oldpc); error ("verification error at PC=%d", oldpc);
if (message != NULL) if (message != NULL)
...@@ -1460,16 +1553,20 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) ...@@ -1460,16 +1553,20 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length)
error ("%s", pmessage); error ("%s", pmessage);
free (pmessage); free (pmessage);
return 0; return 0;
stack_overflow: stack_overflow:
message = "stack overflow"; message = "stack overflow";
goto verify_error; goto verify_error;
bad_pc: bad_pc:
message = "program counter out of range"; message = "program counter out of range";
goto verify_error; goto verify_error;
error_with_index: error_with_index:
error ("verification error at PC=%d", oldpc); error ("verification error at PC=%d", oldpc);
error (message, index); error (message, index);
return 0; return 0;
verify_error: verify_error:
error ("verification error at PC=%d", oldpc); error ("verification error at PC=%d", oldpc);
error ("%s", message); error ("%s", message);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment