From 912d0bce3d42e6b3a06e2b2f9f2165abbf786a98 Mon Sep 17 00:00:00 2001 From: tromey Date: Mon, 15 Aug 2005 21:26:35 +0000 Subject: * Make-lang.in (JAVA_OBJS): Removed verify.o (java/verify.o): Removed. * verify.c: Removed. * lang.c (flag_new_verifier): Removed. (java_post_options): Updated. * java-tree.h (flag_new_verifier): Removed. (verify_jvm_instructions): Removed. * expr.c (pop_type_0): Assume flag_new_verifier is true. (build_java_check_indexed_type): Likewise. (expand_java_arraystore): Likewise. (expand_java_arrayload): Likewise. (pop_arguments): Likewise. (expand_byte_code): Likewise. (process_jvm_instruction): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@103126 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/java/ChangeLog | 17 + gcc/java/Make-lang.in | 5 +- gcc/java/expr.c | 126 ++-- gcc/java/java-tree.h | 4 - gcc/java/lang.c | 9 - gcc/java/verify.c | 1574 ------------------------------------------------- 6 files changed, 53 insertions(+), 1682 deletions(-) delete mode 100644 gcc/java/verify.c diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 17999a0d520..dea76f53a17 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,20 @@ +2005-08-15 Tom Tromey + + * Make-lang.in (JAVA_OBJS): Removed verify.o + (java/verify.o): Removed. + * verify.c: Removed. + * lang.c (flag_new_verifier): Removed. + (java_post_options): Updated. + * java-tree.h (flag_new_verifier): Removed. + (verify_jvm_instructions): Removed. + * expr.c (pop_type_0): Assume flag_new_verifier is true. + (build_java_check_indexed_type): Likewise. + (expand_java_arraystore): Likewise. + (expand_java_arrayload): Likewise. + (pop_arguments): Likewise. + (expand_byte_code): Likewise. + (process_jvm_instruction): Likewise. + 2005-08-10 Andrew Haley * java-gimplify.c (java_gimplify_modify_expr): Fix any pointer diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in index ddeb12d8e3c..458d65b80eb 100644 --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -102,7 +102,7 @@ gt-java-builtins.h gtype-java.h gt-java-resource.h : s-gtype ; @true # Executables built by this Makefile: JAVA_OBJS = java/parse.o java/class.o java/decl.o java/expr.o \ - java/constants.o java/lang.o java/typeck.o java/except.o java/verify.o \ + java/constants.o java/lang.o java/typeck.o java/except.o \ java/verify-glue.o java/verify-impl.o \ java/zextract.o java/jcf-io.o java/win32-host.o java/jcf-parse.o java/mangle.o \ java/mangle_name.o java/builtins.o java/resource.o \ @@ -349,9 +349,6 @@ java/resource.o: java/resource.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ java/typeck.o: java/typeck.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h \ java/convert.h toplev.h $(SYSTEM_H) coretypes.h $(TM_H) $(GGC_H) real.h java/win32-host.o: java/win32-host.c $(CONFIG_H) $(SYSTEM_H) coretypes.h java/jcf.h -java/verify.o: java/verify.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h \ - java/javaop.h java/java-opcodes.h java/java-except.h toplev.h $(SYSTEM_H) \ - coretypes.h $(TM_H) java/verify-glue.o: java/verify-glue.c $(CONFIG_H) $(SYSTEM_H) $(JAVA_TREE_H) \ coretypes.h $(TM_H) java/verify.h toplev.h java/verify-impl.o: java/verify-impl.c $(CONFIG_H) java/verify.h $(SYSTEM_H) \ diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 165aea70980..c5e48a8406d 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -350,29 +350,12 @@ pop_type_0 (tree type, char **messagep) return t; if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE) { - if (flag_new_verifier) - { - /* Since the verifier has already run, we know that any - types we see will be compatible. In BC mode, this fact - may be checked at runtime, but if that is so then we can - assume its truth here as well. So, we always succeed - here, with the expected type. */ - return type; - } - else - { - if (type == ptr_type_node || type == object_ptr_type_node) - return t; - else if (t == ptr_type_node) /* Special case for null reference. */ - return type; - /* This is a kludge, but matches what Sun's verifier does. - It can be tricked, but is safe as long as type errors - (i.e. interface method calls) are caught at run-time. */ - else if (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (type)))) - return object_ptr_type_node; - else if (can_widen_reference_to (t, type)) - return t; - } + /* Since the verifier has already run, we know that any + types we see will be compatible. In BC mode, this fact + may be checked at runtime, but if that is so then we can + assume its truth here as well. So, we always succeed + here, with the expected type. */ + return type; } if (! flag_verify_invocations && flag_indirect_dispatch @@ -1022,33 +1005,14 @@ build_java_arraystore_check (tree array, tree object) return unchanged. */ static tree -build_java_check_indexed_type (tree array_node, tree indexed_type) +build_java_check_indexed_type (tree array_node ATTRIBUTE_UNUSED, + tree indexed_type) { - tree elt_type; - /* We used to check to see if ARRAY_NODE really had array type. However, with the new verifier, this is not necessary, as we know that the object will be an array of the appropriate type. */ - if (flag_new_verifier) - return indexed_type; - - if (!is_array_type_p (TREE_TYPE (array_node))) - abort (); - - elt_type = (TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (array_node)))); - - if (indexed_type == ptr_type_node) - return promote_type (elt_type); - - /* BYTE/BOOLEAN store and load are used for both type */ - if (indexed_type == byte_type_node && elt_type == boolean_type_node) - return boolean_type_node; - - if (indexed_type != elt_type ) - abort (); - else - return indexed_type; + return indexed_type; } /* newarray triggers a call to _Jv_NewPrimArray. This function should be @@ -1155,23 +1119,18 @@ expand_java_arraystore (tree rhs_type_node) tree index = pop_value (int_type_node); tree array_type, array; - if (flag_new_verifier) + /* If we're processing an `aaload' we might as well just pick + `Object'. */ + if (TREE_CODE (rhs_type_node) == POINTER_TYPE) { - /* If we're processing an `aaload' we might as well just pick - `Object'. */ - if (TREE_CODE (rhs_type_node) == POINTER_TYPE) - { - array_type = build_java_array_type (object_ptr_type_node, -1); - rhs_type_node = object_ptr_type_node; - } - else - array_type = build_java_array_type (rhs_type_node, -1); + array_type = build_java_array_type (object_ptr_type_node, -1); + rhs_type_node = object_ptr_type_node; } else - array_type = ptr_type_node; + array_type = build_java_array_type (rhs_type_node, -1); + array = pop_value (array_type); - if (flag_new_verifier) - array = build1 (NOP_EXPR, promote_type (array_type), array); + array = build1 (NOP_EXPR, promote_type (array_type), array); rhs_type_node = build_java_check_indexed_type (array, rhs_type_node); @@ -1205,23 +1164,17 @@ expand_java_arrayload (tree lhs_type_node) tree array_type; tree array_node; - if (flag_new_verifier) + /* If we're processing an `aaload' we might as well just pick + `Object'. */ + if (TREE_CODE (lhs_type_node) == POINTER_TYPE) { - /* If we're processing an `aaload' we might as well just pick - `Object'. */ - if (TREE_CODE (lhs_type_node) == POINTER_TYPE) - { - array_type = build_java_array_type (object_ptr_type_node, -1); - lhs_type_node = object_ptr_type_node; - } - else - array_type = build_java_array_type (lhs_type_node, -1); + array_type = build_java_array_type (object_ptr_type_node, -1); + lhs_type_node = object_ptr_type_node; } else - array_type = ptr_type_node; + array_type = build_java_array_type (lhs_type_node, -1); array_node = pop_value (array_type); - if (flag_new_verifier) - array_node = build1 (NOP_EXPR, promote_type (array_type), array_node); + array_node = build1 (NOP_EXPR, promote_type (array_type), array_node); index_node = save_expr (index_node); array_node = save_expr (array_node); @@ -1916,12 +1869,11 @@ pop_arguments (tree arg_types) tree type = TREE_VALUE (arg_types); tree arg = pop_value (type); - /* With the new verifier we simply cast each argument to its - proper type. This is needed since we lose type information - coming out of the verifier. We also have to do this with the - old verifier when we pop an integer type that must be - promoted for the function call. */ - if (flag_new_verifier && TREE_CODE (type) == POINTER_TYPE) + /* We simply cast each argument to its proper type. This is + needed since we lose type information coming out of the + verifier. We also have to do this when we pop an integer + type that must be promoted for the function call. */ + if (TREE_CODE (type) == POINTER_TYPE) arg = build1 (NOP_EXPR, type, arg); else if (targetm.calls.promote_prototypes (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node) @@ -2943,16 +2895,8 @@ expand_byte_code (JCF *jcf, tree method) } } - if (flag_new_verifier) - { - if (! verify_jvm_instructions_new (jcf, byte_ops, length)) - return; - } - else - { - if (! verify_jvm_instructions (jcf, byte_ops, length)) - return; - } + if (! verify_jvm_instructions_new (jcf, byte_ops, length)) + return; promote_arguments (); @@ -3065,10 +3009,10 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, replace the top of the stack with the thrown object reference */ if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET) { - /* Note that the new verifier will not emit a type map at all - for dead exception handlers. In this case we just ignore - the situation. */ - if (! flag_new_verifier || (instruction_bits[PC] & BCODE_VERIFIED) != 0) + /* Note that the verifier will not emit a type map at all for + dead exception handlers. In this case we just ignore the + situation. */ + if ((instruction_bits[PC] & BCODE_VERIFIED) != 0) { tree type = pop_type (promote_type (throwable_type_node)); push_value (build_exception_object_ref (type)); diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index ab6157b7c61..b96e818584a 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -219,9 +219,6 @@ extern int flag_indirect_dispatch; /* When zero, don't generate runtime array store checks. */ extern int flag_store_check; -/* When nonzero, use the new bytecode verifier. */ -extern int flag_new_verifier; - /* Encoding used for source files. */ extern const char *current_encoding; @@ -1328,7 +1325,6 @@ extern void init_class_processing (void); extern void add_type_assertion (tree, int, tree, tree); extern int can_widen_reference_to (tree, tree); extern int class_depth (tree); -extern int verify_jvm_instructions (struct JCF *, const unsigned char *, long); extern int verify_jvm_instructions_new (struct JCF *, const unsigned char *, long); extern void maybe_pushlevels (int); diff --git a/gcc/java/lang.c b/gcc/java/lang.c index 053bd1b5c0c..4b7902f2825 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -133,9 +133,6 @@ int flag_deprecated = 1; /* Don't attempt to verify invocations. */ int flag_verify_invocations = 0; -/* True if the new bytecode verifier should be used. */ -int flag_new_verifier = 1; - /* When nonzero, print extra version information. */ static int v_flag = 0; @@ -606,12 +603,6 @@ java_post_options (const char **pfilename) must always verify everything. */ if (! flag_indirect_dispatch) flag_verify_invocations = true; - else - { - /* If we are using indirect dispatch, then we want the new - verifier as well. */ - flag_new_verifier = 1; - } /* Open input file. */ diff --git a/gcc/java/verify.c b/gcc/java/verify.c deleted file mode 100644 index 5b544b86f1f..00000000000 --- a/gcc/java/verify.c +++ /dev/null @@ -1,1574 +0,0 @@ -/* Handle verification of bytecoded methods for the GNU compiler for - the Java(TM) language. - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. - -Java and all Java-based marks are trademarks or registered trademarks -of Sun Microsystems, Inc. in the United States and other countries. -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 "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "java-tree.h" -#include "javaop.h" -#include "java-opcodes.h" -#include "jcf.h" -#include "java-except.h" -#include "toplev.h" - -static void push_pending_label (tree); -static tree merge_types (tree, tree); -static const char *check_pending_block (tree); -static void type_stack_dup (int, int); -static int start_pc_cmp (const void *, const void *); -static char *pop_argument_types (tree); - -extern int stack_pointer; - -/* During verification, start of the current subroutine (jsr target). */ -tree current_subr; - -/* A list of pending blocks, chained using LABEL_PENDING_CHAIN. - A pending block is one that has LABEL_CHANGED set, which means - it requires (re-) verification. */ -tree pending_blocks; - -/* Append TARGET_LABEL to the pending_block stack unless already in it. */ - -static void -push_pending_label (tree target_label) -{ - if (! LABEL_CHANGED (target_label)) - { - LABEL_PENDING_CHAIN (target_label) = pending_blocks; - pending_blocks = target_label; - LABEL_CHANGED (target_label) = 1; - } -} - -/* Note that TARGET_LABEL is a possible successor instruction. - Merge the type state etc. - Return NULL on success, or an error message on failure. */ - -static const char * -check_pending_block (tree target_label) -{ - int changed = merge_type_state (target_label); - - if (changed) - { - if (changed < 0) - return "types could not be merged"; - push_pending_label (target_label); - } - - if (current_subr == NULL_TREE) - { - if (LABEL_IN_SUBR (target_label)) - return "might transfer control into subroutine"; - } - else - { - if (LABEL_IN_SUBR (target_label)) - { - if (LABEL_SUBR_START (target_label) != current_subr) - return "transfer out of subroutine"; - } - else if (! LABEL_VERIFIED (target_label)) - { - LABEL_IN_SUBR (target_label) = 1; - LABEL_SUBR_START (target_label) = current_subr; - } - else - return "transfer out of subroutine"; - } - return NULL; -} - -/* Count the number of nested jsr calls needed to reach LABEL. */ - -static int -subroutine_nesting (tree label) -{ - int nesting = 0; - while (label != NULL_TREE && LABEL_IN_SUBR (label)) - { - if (! LABEL_IS_SUBR_START (label)) - label = LABEL_SUBR_START (label); - label = LABEL_SUBR_CONTEXT (label); - nesting++; - } - return nesting; -} - -/* Return the "merged" types of TYPE1 and TYPE2. - If either is primitive, the other must match (after promotion to int). - For reference types, return the common super-class. - Return TYPE_UNKNOWN if the types cannot be merged. */ - -static tree -merge_types (tree type1, tree type2) -{ - if (type1 == type2) - return type1; - if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN - || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR) - return TYPE_UNKNOWN; - if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE) - { - int depth1, depth2; - tree tt1, tt2; - /* ptr_type_node is only used for a null reference, - which is compatible with any reference type. */ - if (type1 == ptr_type_node || type2 == object_ptr_type_node) - return type2; - if (type2 == ptr_type_node || type1 == object_ptr_type_node) - return type1; - - tt1 = TREE_TYPE (type1); - tt2 = TREE_TYPE (type2); - - /* If tt{1,2} haven't been properly loaded, now is a good time - to do it. */ - if (!TYPE_SIZE (tt1)) - { - load_class (tt1, 1); - safe_layout_class (tt1); - } - - if (!TYPE_SIZE (tt2)) - { - load_class (tt2, 1); - safe_layout_class (tt2); - } - - if (TYPE_ARRAY_P (tt1) || TYPE_ARRAY_P (tt2)) - { - if (TYPE_ARRAY_P (tt1) == TYPE_ARRAY_P (tt2)) - { - tree el_type1 = TYPE_ARRAY_ELEMENT (tt1); - tree el_type2 = TYPE_ARRAY_ELEMENT (tt2); - tree el_type = NULL_TREE; - if (el_type1 == el_type2) - el_type = el_type1; - else if (TREE_CODE (el_type1) == POINTER_TYPE - && TREE_CODE (el_type2) == POINTER_TYPE) - el_type = merge_types (el_type1, el_type2); - if (el_type != NULL_TREE) - { - HOST_WIDE_INT len1 = java_array_type_length (tt1); - HOST_WIDE_INT len2 = java_array_type_length (tt2); - if (len1 != len2) - len1 = -1; - else if (el_type1 == el_type2) - return type1; - return promote_type (build_java_array_type (el_type, len1)); - } - } - return object_ptr_type_node; - } - - if (CLASS_INTERFACE (TYPE_NAME (tt1))) - { - /* FIXME: should see if two interfaces have a common - superinterface. */ - if (CLASS_INTERFACE (TYPE_NAME (tt2))) - { - /* This is a kludge, but matches what Sun's verifier does. - It can be tricked, but is safe as long as type errors - (i.e. interface method calls) are caught at run-time. */ - return object_ptr_type_node; - } - else - { - if (can_widen_reference_to (tt2, tt1)) - return type1; - else - return object_ptr_type_node; - } - } - else if (CLASS_INTERFACE (TYPE_NAME (tt2))) - { - if (can_widen_reference_to (tt1, tt2)) - return type2; - else - return object_ptr_type_node; - } - - type1 = tt1; - type2 = tt2; - - depth1 = class_depth (type1); - depth2 = class_depth (type2); - for ( ; depth1 > depth2; depth1--) - type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0)); - for ( ; depth2 > depth1; depth2--) - type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0)); - while (type1 != type2) - { - type1 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type1), 0)); - type2 = BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (type2), 0)); - } - return promote_type (type1); - } - if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2) - && TYPE_PRECISION (type1) <= 32 && TYPE_PRECISION (type2) <= 32) - return int_type_node; - return TYPE_UNKNOWN; -} - -/* Merge the current type state with that at LABEL. - Return -1 if the states are incompatible (i.e. on error), - 0 if there was no change, and 1 if there was a change. */ - -int -merge_type_state (tree label) -{ - int nlocals = DECL_MAX_LOCALS (current_function_decl); - int cur_length = stack_pointer + nlocals; - tree vec = LABEL_TYPE_STATE (label); - tree return_map; - if (vec == NULL_TREE) - { - vec = make_tree_vec (cur_length); - LABEL_TYPE_STATE (label) = vec; - - while (--cur_length >= 0) - TREE_VEC_ELT (vec, cur_length) = type_map[cur_length]; - return 1; - } - else - { - int i; - int changed = 0; - if (LABEL_IS_SUBR_START (label) && LABEL_VERIFIED (label) - && current_subr != label) - return_map = LABEL_RETURN_TYPE_STATE (label); - else - return_map = NULL_TREE; - if (TREE_VEC_LENGTH (vec) != cur_length) - { - return -1; - } - for (i = 0; i < cur_length; i++) - { - tree old_type = TREE_VEC_ELT (vec, i); - tree new_type = merge_types (old_type, type_map[i]); - if (TREE_VEC_ELT (vec, i) != new_type) - { - /* If there has been a change, note that since we must re-verify. - However, if the label is the start of a subroutine, - we don't care about local variables that are neither - set nor used in the subroutine. */ - if (return_map == NULL_TREE || i >= nlocals - || TREE_VEC_ELT (return_map, i) != TYPE_UNUSED - || (TYPE_IS_WIDE (new_type) - && TREE_VEC_ELT (return_map, i+1) != TYPE_UNUSED)) - changed = 1; - } - TREE_VEC_ELT (vec, i) = new_type; - if (new_type == TYPE_UNKNOWN) - { - if (i >= nlocals) - return -1; - } - else if (TYPE_IS_WIDE (new_type)) - i++; - } - return changed; - } -} - -/* Handle dup-like operations. */ - -static void -type_stack_dup (int size, int offset) -{ - tree type[4]; - int index; - for (index = 0; index < size + offset; index++) - { - type[index] = stack_type_map[stack_pointer - 1]; - if (type[index] == void_type_node) - { - index++; - type[index] = stack_type_map[stack_pointer - 2]; - if (! TYPE_IS_WIDE (type[index])) - abort (); - if (index == size || index == size + offset) - /* Dup operation splits 64-bit number. */ - abort (); - } - pop_type (type[index]); - } - for (index = size; --index >= 0; ) - { - if (type[index] != void_type_node) - push_type (type[index]); - } - - for (index = size + offset; --index >= 0; ) - { - if (type[index] != void_type_node) - push_type (type[index]); - } -} - -/* This keeps track of a start PC and corresponding initial index. */ -struct pc_index -{ - int start_pc; - int index; -}; - -/* A helper that is used when sorting exception ranges. */ -static int -start_pc_cmp (const void *xp, const void *yp) -{ - const struct pc_index *x = (const struct pc_index *) xp; - const struct pc_index *y = (const struct pc_index *) yp; - return x->start_pc - y->start_pc; -} - -/* This causes the next iteration to ignore the next instruction - and look for some other unhandled instruction. */ -#define INVALIDATE_PC (prevpc = -1, oldpc = PC, PC = INVALID_PC) -#define INVALID_PC (-1) - -#define VERIFICATION_ERROR(MESSAGE) \ - do { message = MESSAGE; goto verify_error; } while (0) - -#define VERIFICATION_ERROR_WITH_INDEX(MESSAGE) \ - do { message = MESSAGE; goto error_with_index; } while (0) - -/* Recursive helper function to pop argument types during verification. - ARG_TYPES is the list of formal parameter types. - Return NULL on success and a freshly malloc'd error message on failure. */ - -static char * -pop_argument_types (tree arg_types) -{ - if (arg_types == end_params_node) - return NULL; - if (TREE_CODE (arg_types) == TREE_LIST) - { - char *message = pop_argument_types (TREE_CHAIN (arg_types)); - if (message == NULL) - pop_type_0 (TREE_VALUE (arg_types), &message); - return message; - } - abort (); -} - -#define POP_TYPE(TYPE, MESSAGE) \ - do { pmessage = NULL; pop_type_0 (TYPE, &pmessage); \ - if (pmessage != NULL) goto pop_type_error; \ - } while (0) - -#define POP_TYPE_CONV(TYPE, POPPED_TYPE, MESSAGE) \ - do { pmessage = NULL; POPPED_TYPE = pop_type_0 (TYPE, &pmessage); \ - if (pmessage != NULL) goto pop_type_error; \ - } while (0) - -#define PUSH_TYPE(TYPE) \ - do { if (! push_type_0 (TYPE)) { goto stack_overflow; }} while (0) - -#define PUSH_PENDING(LABEL) \ - do { tree tmplab = LABEL; \ - if ((message = check_pending_block (tmplab)) != NULL) \ - { oldpc = LABEL_PC (tmplab); goto verify_error; }} while (0) - -#ifdef __GNUC__ -#define CHECK_PC_IN_RANGE(PC) __extension__ \ - ({if (PC < 0 || PC > length) goto bad_pc; (void)1;}) -#else -#define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > length ? (abort (), 0) : 1) -#endif - -#define BCODE byte_ops - - -/* Verify the bytecodes of the current method, with the instructions - starting at BYTE_OPS and LENGTH in number, from the class file pointed to - by JCF. - Return 1 on success, 0 on failure. */ -int -verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) -{ - tree label; - int wide = 0; - int op_code; - int PC; - int oldpc = 0; /* PC of start of instruction. */ - int prevpc = 0; /* If >= 0, PC of previous instruction. */ - const char *message = 0; - char *pmessage; - int i; - int index; - unsigned char *p; - struct eh_range *prev_eh_ranges = NULL_EH_RANGE; - struct eh_range *eh_ranges; - tree return_type = TREE_TYPE (TREE_TYPE (current_function_decl)); - struct pc_index *starts; - int eh_count; - - jint int_value = -1; - - pending_blocks = NULL_TREE; - - current_subr = NULL_TREE; - - /* Handle the exception table. */ - method_init_exceptions (); - JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length); - eh_count = JCF_readu2 (jcf); - - /* We read the exception handlers in order of increasing start PC. - To do this we first read and sort the start PCs. */ - starts = xmalloc (eh_count * sizeof (struct pc_index)); - for (i = 0; i < eh_count; ++i) - { - starts[i].start_pc = GET_u2 (jcf->read_ptr + 8 * i); - starts[i].index = i; - } - qsort (starts, eh_count, sizeof (struct pc_index), start_pc_cmp); - - for (i = 0; i < eh_count; ++i) - { - int start_pc, end_pc, handler_pc, catch_type; - - p = jcf->read_ptr + 8 * starts[i].index; - - start_pc = GET_u2 (p); - end_pc = GET_u2 (p+2); - handler_pc = GET_u2 (p+4); - catch_type = GET_u2 (p+6); - - if (start_pc < 0 || start_pc >= length - || end_pc < 0 || end_pc > length || start_pc >= end_pc - || handler_pc < 0 || handler_pc >= length - || ! (instruction_bits[start_pc] & BCODE_INSTRUCTION_START) - || (end_pc < length && - ! (instruction_bits[end_pc] & BCODE_INSTRUCTION_START)) - || ! (instruction_bits[handler_pc] & BCODE_INSTRUCTION_START)) - { - error ("bad pc in exception_table"); - free (starts); - return 0; - } - - add_handler (start_pc, end_pc, - lookup_label (handler_pc), - catch_type == 0 ? NULL_TREE - : get_class_constant (jcf, catch_type)); - - instruction_bits[handler_pc] |= BCODE_EXCEPTION_TARGET; - } - - free (starts); - - for (PC = 0;;) - { - tree type, tmp; - - if (((PC != INVALID_PC - && instruction_bits[PC] & BCODE_TARGET) != 0) - || PC == 0) - { - PUSH_PENDING (lookup_label (PC)); - INVALIDATE_PC; - } - - /* Check if there are any more pending blocks in the current - subroutine. Because we push pending blocks in a - last-in-first-out order, and because we don't push anything - from our caller until we are done with this subroutine or - 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 - caller. */ - if (current_subr && PC == INVALID_PC) - { - if (pending_blocks == NULL_TREE - || (subroutine_nesting (pending_blocks) - < subroutine_nesting (current_subr))) - { - int size - = DECL_MAX_LOCALS (current_function_decl) + stack_pointer; - - tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); - tmp = LABEL_RETURN_LABELS (current_subr); - - /* FIXME: If we exit a subroutine via a throw, we might - have returned to an earlier caller. Obviously a - "ret" can only return one level, but a throw may - return many levels. */ - current_subr = LABEL_SUBR_CONTEXT (current_subr); - - if (RETURN_MAP_ADJUSTED (ret_map)) - { - /* Since we are done with this subroutine, set up - the (so far known) return address as pending - - with the merged type state. */ - for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp)) - { - tree return_label = TREE_VALUE (tmp); - tree return_state = LABEL_TYPE_STATE (return_label); - if (return_state == NULL_TREE) - { - /* This means we had not verified the subroutine - earlier, so this is the first jsr to call it. - In this case, the type_map of the return - address is just the current type_map - and that - is handled by the following PUSH_PENDING. */ - } - else - { - /* In this case we have to do a merge. But first - restore the type_map for unused slots to those - that were in effect at the jsr. */ - for (index = size; --index >= 0; ) - { - type_map[index] - = TREE_VEC_ELT (ret_map, index); - - if (type_map[index] == TYPE_UNUSED) - type_map[index] - = TREE_VEC_ELT (return_state, index); - } - } - PUSH_PENDING (return_label); - } - } - } - } - - if (PC == INVALID_PC) - { - label = pending_blocks; - - if (label == NULL_TREE) - break; /* We're done! */ - - pending_blocks = LABEL_PENDING_CHAIN (label); - LABEL_CHANGED (label) = 0; - - if (LABEL_IN_SUBR (label)) - current_subr = LABEL_SUBR_START (label); - else - current_subr = NULL_TREE; - - /* Restore type_map and stack_pointer from - LABEL_TYPE_STATE (label), and continue - compiling from there. */ - load_type_state (label); - - PC = LABEL_PC (label); - } - else if (PC >= length) - VERIFICATION_ERROR ("falling through the end of the method"); - - - oldpc = PC; - - if (! (instruction_bits[PC] & BCODE_INSTRUCTION_START) && ! wide) - VERIFICATION_ERROR ("PC not at instruction start"); - - instruction_bits[PC] |= BCODE_VERIFIED; - - eh_ranges = find_handler (oldpc); - - op_code = byte_ops[PC++]; - switch (op_code) - { - int is_static, is_putting; - - case OPCODE_nop: - break; - - case OPCODE_iconst_m1: - case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_2: - case OPCODE_iconst_3: case OPCODE_iconst_4: case OPCODE_iconst_5: - i = op_code - OPCODE_iconst_0; - goto push_int; - push_int: - if (byte_ops[PC] == OPCODE_newarray - || byte_ops[PC] == OPCODE_anewarray) - int_value = i; - PUSH_TYPE (int_type_node); break; - - case OPCODE_lconst_0: case OPCODE_lconst_1: - PUSH_TYPE (long_type_node); break; - - case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2: - PUSH_TYPE (float_type_node); break; - - case OPCODE_dconst_0: case OPCODE_dconst_1: - PUSH_TYPE (double_type_node); break; - - case OPCODE_bipush: - i = IMMEDIATE_s1; - goto push_int; - - case OPCODE_sipush: - i = IMMEDIATE_s2; - goto push_int; - - case OPCODE_iload: type = int_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_dload: type = double_type_node; goto general_load; - case OPCODE_aload: type = ptr_type_node; goto general_load; - general_load: - index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; - wide = 0; - goto load; - case OPCODE_iload_0: type = int_type_node; index = 0; goto load; - case OPCODE_iload_1: type = int_type_node; index = 1; goto load; - case OPCODE_iload_2: type = int_type_node; index = 2; goto load; - case OPCODE_iload_3: type = int_type_node; index = 3; goto load; - case OPCODE_lload_0: type = long_type_node; index = 0; goto load; - case OPCODE_lload_1: type = long_type_node; index = 1; goto load; - case OPCODE_lload_2: type = long_type_node; index = 2; goto load; - case OPCODE_lload_3: type = long_type_node; index = 3; goto load; - case OPCODE_fload_0: type = float_type_node; index = 0; goto load; - case OPCODE_fload_1: type = float_type_node; index = 1; goto load; - case OPCODE_fload_2: type = float_type_node; index = 2; goto load; - case OPCODE_fload_3: type = float_type_node; index = 3; goto load; - case OPCODE_dload_0: type = double_type_node; index = 0; goto load; - case OPCODE_dload_1: type = double_type_node; index = 1; goto load; - case OPCODE_dload_2: type = double_type_node; index = 2; goto load; - case OPCODE_dload_3: type = double_type_node; index = 3; goto load; - case OPCODE_aload_0: type = ptr_type_node; index = 0; goto load; - case OPCODE_aload_1: type = ptr_type_node; index = 1; goto load; - case OPCODE_aload_2: type = ptr_type_node; index = 2; goto load; - case OPCODE_aload_3: type = ptr_type_node; index = 3; goto load; - load: - if (index < 0 - || (index + TYPE_IS_WIDE (type) - >= DECL_MAX_LOCALS (current_function_decl))) - VERIFICATION_ERROR_WITH_INDEX - ("invalid local variable index %d in load"); - tmp = type_map[index]; - if (tmp == TYPE_UNKNOWN) - VERIFICATION_ERROR_WITH_INDEX - ("loading local variable %d which has unknown type"); - else if (tmp == TYPE_SECOND - || (TYPE_IS_WIDE (type) - && type_map[index+1] != void_type_node) - || (type == ptr_type_node - ? TREE_CODE (tmp) != POINTER_TYPE - : type == int_type_node - ? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) - : type != tmp)) - VERIFICATION_ERROR_WITH_INDEX - ("loading local variable %d which has invalid type"); - PUSH_TYPE (tmp); - goto note_used; - case OPCODE_istore: type = int_type_node; goto general_store; - case OPCODE_lstore: type = long_type_node; goto general_store; - case OPCODE_fstore: type = float_type_node; goto general_store; - case OPCODE_dstore: type = double_type_node; goto general_store; - case OPCODE_astore: type = object_ptr_type_node; goto general_store; - general_store: - index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; - wide = 0; - goto store; - case OPCODE_istore_0: type = int_type_node; index = 0; goto store; - case OPCODE_istore_1: type = int_type_node; index = 1; goto store; - case OPCODE_istore_2: type = int_type_node; index = 2; goto store; - case OPCODE_istore_3: type = int_type_node; index = 3; goto store; - case OPCODE_lstore_0: type = long_type_node; index=0; goto store; - case OPCODE_lstore_1: type = long_type_node; index=1; goto store; - case OPCODE_lstore_2: type = long_type_node; index=2; goto store; - case OPCODE_lstore_3: type = long_type_node; index=3; goto store; - case OPCODE_fstore_0: type=float_type_node; index=0; goto store; - case OPCODE_fstore_1: type=float_type_node; index=1; goto store; - case OPCODE_fstore_2: type=float_type_node; index=2; goto store; - case OPCODE_fstore_3: type=float_type_node; index=3; goto store; - case OPCODE_dstore_0: type=double_type_node; index=0; goto store; - case OPCODE_dstore_1: type=double_type_node; index=1; goto store; - case OPCODE_dstore_2: type=double_type_node; index=2; goto store; - case OPCODE_dstore_3: type=double_type_node; index=3; goto store; - case OPCODE_astore_0: type = ptr_type_node; index = 0; goto store; - case OPCODE_astore_1: type = ptr_type_node; index = 1; goto store; - case OPCODE_astore_2: type = ptr_type_node; index = 2; goto store; - case OPCODE_astore_3: type = ptr_type_node; index = 3; goto store; - store: - if (index < 0 - || (index + TYPE_IS_WIDE (type) - >= DECL_MAX_LOCALS (current_function_decl))) - { - VERIFICATION_ERROR_WITH_INDEX - ("invalid local variable index %d in store"); - return 0; - } - POP_TYPE_CONV (type, type, NULL); - type_map[index] = type; - - /* If a local variable has changed, we need to reconsider exception - handlers. */ - prev_eh_ranges = NULL_EH_RANGE; - - /* Allocate decl for this variable now, so we get a temporary -! that survives the whole method. */ - find_local_variable (index, type, oldpc); - - if (TYPE_IS_WIDE (type)) - type_map[index+1] = TYPE_SECOND; - - /* ... fall through to note_used ... */ - note_used: - /* For store or load, note that local variable INDEX is used. - This is needed to verify try-finally subroutines. */ - if (current_subr) - { - tree vec = LABEL_RETURN_TYPE_STATE (current_subr); - tree subr_vec = LABEL_TYPE_STATE (current_subr); - int len = 1 + TYPE_IS_WIDE (type); - while (--len >= 0) - { - if (TREE_VEC_ELT (vec, index) == TYPE_UNUSED) - TREE_VEC_ELT (vec, index) = TREE_VEC_ELT (subr_vec, index); - } - } - break; - case OPCODE_iadd: - case OPCODE_iand: - case OPCODE_idiv: - case OPCODE_imul: - case OPCODE_ior: - case OPCODE_irem: - case OPCODE_ishl: - case OPCODE_ishr: - case OPCODE_isub: - case OPCODE_iushr: - case OPCODE_ixor: - type = int_type_node; goto binop; - case OPCODE_ineg: - case OPCODE_i2c: - case OPCODE_i2b: - case OPCODE_i2s: - type = int_type_node; goto unop; - case OPCODE_ladd: - case OPCODE_land: - case OPCODE_ldiv: - case OPCODE_lsub: - case OPCODE_lmul: - case OPCODE_lrem: - case OPCODE_lor: - case OPCODE_lxor: - type = long_type_node; goto binop; - case OPCODE_lneg: - type = long_type_node; goto unop; - case OPCODE_fadd: case OPCODE_fsub: - case OPCODE_fmul: case OPCODE_fdiv: case OPCODE_frem: - type = float_type_node; goto binop; - case OPCODE_fneg: - type = float_type_node; goto unop; - case OPCODE_dadd: case OPCODE_dsub: - case OPCODE_dmul: case OPCODE_ddiv: case OPCODE_drem: - type = double_type_node; goto binop; - case OPCODE_dneg: - type = double_type_node; goto unop; - - unop: - pop_type (type); - PUSH_TYPE (type); - break; - - binop: - pop_type (type); - pop_type (type); - PUSH_TYPE (type); - break; - - case OPCODE_lshl: - case OPCODE_lshr: - case OPCODE_lushr: - pop_type (int_type_node); - pop_type (long_type_node); - PUSH_TYPE (long_type_node); - break; - - case OPCODE_iinc: - index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; - PC += wide + 1; - wide = 0; - if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)) - VERIFICATION_ERROR ("invalid local variable index in iinc"); - tmp = type_map[index]; - if (tmp == NULL_TREE - || ! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) - VERIFICATION_ERROR ("invalid local variable type in iinc"); - break; - - case OPCODE_i2l: - pop_type (int_type_node); PUSH_TYPE (long_type_node); break; - case OPCODE_i2f: - pop_type (int_type_node); PUSH_TYPE (float_type_node); break; - case OPCODE_i2d: - pop_type (int_type_node); PUSH_TYPE (double_type_node); break; - case OPCODE_l2i: - pop_type (long_type_node); PUSH_TYPE (int_type_node); break; - case OPCODE_l2f: - pop_type (long_type_node); PUSH_TYPE (float_type_node); break; - case OPCODE_l2d: - pop_type (long_type_node); PUSH_TYPE (double_type_node); break; - case OPCODE_f2i: - pop_type (float_type_node); PUSH_TYPE (int_type_node); break; - case OPCODE_f2l: - pop_type (float_type_node); PUSH_TYPE (long_type_node); break; - case OPCODE_f2d: - pop_type (float_type_node); PUSH_TYPE (double_type_node); break; - case OPCODE_d2i: - pop_type (double_type_node); PUSH_TYPE (int_type_node); break; - case OPCODE_d2l: - pop_type (double_type_node); PUSH_TYPE (long_type_node); break; - case OPCODE_d2f: - pop_type (double_type_node); PUSH_TYPE (float_type_node); break; - - case OPCODE_lcmp: - type = long_type_node; goto compare; - case OPCODE_fcmpl: - case OPCODE_fcmpg: - type = float_type_node; goto compare; - case OPCODE_dcmpl: - case OPCODE_dcmpg: - type = double_type_node; goto compare; - compare: - pop_type (type); pop_type (type); - PUSH_TYPE (int_type_node); break; - - case OPCODE_ifeq: - case OPCODE_ifne: - case OPCODE_iflt: - case OPCODE_ifge: - case OPCODE_ifgt: - case OPCODE_ifle: - pop_type (int_type_node); goto cond; - case OPCODE_ifnull: - case OPCODE_ifnonnull: - pop_type (ptr_type_node ); goto cond; - case OPCODE_if_icmpeq: - case OPCODE_if_icmpne: - case OPCODE_if_icmplt: - case OPCODE_if_icmpge: - case OPCODE_if_icmpgt: - case OPCODE_if_icmple: - pop_type (int_type_node); pop_type (int_type_node); goto cond; - case OPCODE_if_acmpeq: - case OPCODE_if_acmpne: - pop_type (object_ptr_type_node); pop_type (object_ptr_type_node); - goto cond; - - cond: - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); - break; - - case OPCODE_goto: - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); - INVALIDATE_PC; - break; - - case OPCODE_wide: - switch (byte_ops[PC]) - { - case OPCODE_iload: case OPCODE_lload: - case OPCODE_fload: case OPCODE_dload: case OPCODE_aload: - case OPCODE_istore: case OPCODE_lstore: - case OPCODE_fstore: case OPCODE_dstore: case OPCODE_astore: - case OPCODE_iinc: - case OPCODE_ret: - wide = 1; - break; - default: - VERIFICATION_ERROR ("invalid use of wide instruction"); - } - break; - - case OPCODE_return: type = void_type_node; goto ret; - case OPCODE_ireturn: - if ((TREE_CODE (return_type) == BOOLEAN_TYPE - || TREE_CODE (return_type) == CHAR_TYPE - || TREE_CODE (return_type) == INTEGER_TYPE) - && TYPE_PRECISION (return_type) <= 32) - type = return_type; - else - type = NULL_TREE; - goto ret; - case OPCODE_lreturn: type = long_type_node; goto ret; - case OPCODE_freturn: type = float_type_node; goto ret; - case OPCODE_dreturn: type = double_type_node; goto ret; - case OPCODE_areturn: - if (TREE_CODE (return_type) == POINTER_TYPE) - type = return_type; - else - type = NULL_TREE; - goto ret; - - ret: - if (type != return_type) - VERIFICATION_ERROR ("incorrect ?return opcode"); - if (type != void_type_node) - POP_TYPE (type, "return value has wrong type"); - INVALIDATE_PC; - break; - - case OPCODE_getstatic: is_putting = 0; 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_putfield: is_putting = 1; is_static = 0; goto field; - field: - { - tree field_signature, field_type; - index = IMMEDIATE_u2; - - if (index <= 0 || index >= JPOOL_SIZE (current_jcf)) - VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d"); - - if (JPOOL_TAG (current_jcf, index) != CONSTANT_Fieldref) - VERIFICATION_ERROR - ("field instruction does not reference a Fieldref"); - - field_signature - = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, index); - - field_type = get_type_from_signature (field_signature); - - if (is_putting) - POP_TYPE (field_type, "incorrect type for field"); - - if (! is_static) - { - int clindex - = COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, index); - - tree self_type = get_class_constant (current_jcf, clindex); - - /* Defer actual checking until next pass. */ - POP_TYPE (self_type, "incorrect type for field reference"); - } - - if (! is_putting) - PUSH_TYPE (field_type); - break; - } - - case OPCODE_new: - PUSH_TYPE (get_class_constant (jcf, IMMEDIATE_u2)); - break; - - case OPCODE_dup: wide = 1; index = 0; goto dup; - case OPCODE_dup_x1: wide = 1; index = 1; goto dup; - case OPCODE_dup_x2: wide = 1; index = 2; goto dup; - case OPCODE_dup2: wide = 2; index = 0; goto dup; - case OPCODE_dup2_x1: wide = 2; index = 1; goto dup; - case OPCODE_dup2_x2: wide = 2; index = 2; goto dup; - - dup: - if (wide + index > stack_pointer) - VERIFICATION_ERROR ("stack underflow - dup* operation"); - type_stack_dup (wide, index); - wide = 0; - break; - - case OPCODE_pop: index = 1; goto pop; - case OPCODE_pop2: index = 2; goto pop; - - pop: - if (stack_pointer < index) - VERIFICATION_ERROR ("stack underflow"); - stack_pointer -= index; - break; - - case OPCODE_swap: - if (stack_pointer < 2) - VERIFICATION_ERROR ("stack underflow (in swap)"); - else - { - tree type1 = stack_type_map[stack_pointer - 1]; - tree type2 = stack_type_map[stack_pointer - 2]; - - if (type1 == void_type_node || type2 == void_type_node) - VERIFICATION_ERROR ("verifier (swap): double or long value"); - - stack_type_map[stack_pointer - 2] = type1; - stack_type_map[stack_pointer - 1] = type2; - } - break; - - case OPCODE_ldc: index = IMMEDIATE_u1; goto ldc; - case OPCODE_ldc2_w: - case OPCODE_ldc_w: - index = IMMEDIATE_u2; goto ldc; - - ldc: - if (index <= 0 || index >= JPOOL_SIZE (current_jcf)) - VERIFICATION_ERROR_WITH_INDEX ("bad constant pool index %d in ldc"); - - int_value = -1; - switch (JPOOL_TAG (current_jcf, index) & ~CONSTANT_ResolvedFlag) - { - case CONSTANT_Integer: type = int_type_node; goto check_ldc; - case CONSTANT_Float: type = float_type_node; goto check_ldc; - case CONSTANT_String: type = string_type_node; goto check_ldc; - case CONSTANT_Long: type = long_type_node; goto check_ldc; - case CONSTANT_Double: type = double_type_node; goto check_ldc; - check_ldc: - if (TYPE_IS_WIDE (type) == (op_code == OPCODE_ldc2_w)) - break; - /* ... else fall through ... */ - default: - VERIFICATION_ERROR ("bad constant pool tag in ldc"); - } - if (type == int_type_node) - { - i = TREE_INT_CST_LOW (get_constant (current_jcf, index)); - goto push_int; - } - PUSH_TYPE (type); - break; - - case OPCODE_invokevirtual: - case OPCODE_invokespecial: - case OPCODE_invokestatic: - case OPCODE_invokeinterface: - { - tree sig, method_name, method_type, self_type; - int self_is_interface, tag; - index = IMMEDIATE_u2; - - if (index <= 0 || index >= JPOOL_SIZE (current_jcf)) - VERIFICATION_ERROR_WITH_INDEX - ("bad constant pool index %d for invoke"); - - tag = JPOOL_TAG (current_jcf, index); - - if (op_code == OPCODE_invokeinterface) - { - if (tag != CONSTANT_InterfaceMethodref) - VERIFICATION_ERROR - ("invokeinterface does not reference an InterfaceMethodref"); - } - else - { - if (tag != CONSTANT_Methodref) - VERIFICATION_ERROR ("invoke does not reference a Methodref"); - } - - sig = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, index); - - self_type - = get_class_constant (current_jcf, - COMPONENT_REF_CLASS_INDEX - (¤t_jcf->cpool, index)); - - if (! CLASS_LOADED_P (self_type)) - load_class (self_type, 1); - - self_is_interface = CLASS_INTERFACE (TYPE_NAME (self_type)); - method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, index); - method_type = parse_signature_string ((const unsigned char *) IDENTIFIER_POINTER (sig), - IDENTIFIER_LENGTH (sig)); - - if (TREE_CODE (method_type) != FUNCTION_TYPE) - VERIFICATION_ERROR ("bad method signature"); - - pmessage = pop_argument_types (TYPE_ARG_TYPES (method_type)); - if (pmessage != NULL) - { - message = "invalid argument type"; - goto pop_type_error; - } - - /* Can't invoke . */ - if (ID_CLINIT_P (method_name)) - VERIFICATION_ERROR ("invoke opcode can't invoke "); - - /* Apart from invokespecial, can't invoke . */ - if (op_code != OPCODE_invokespecial && ID_INIT_P (method_name)) - VERIFICATION_ERROR ("invoke opcode can't invoke "); - - if (op_code != OPCODE_invokestatic) - POP_TYPE (self_type, - "stack type not subclass of invoked method's class"); - - switch (op_code) - { - case OPCODE_invokeinterface: - { - int nargs = IMMEDIATE_u1; - int notZero = IMMEDIATE_u1; - - if (!nargs || notZero) - VERIFICATION_ERROR - ("invalid argument number in invokeinterface"); - - /* If we verify/resolve the constant pool, as we should, - this test (and the one just following) are redundant. */ - if (! self_is_interface) - VERIFICATION_ERROR - ("invokeinterface calls method not in interface"); - break; - - default: - if (self_is_interface) - VERIFICATION_ERROR ("method in interface called"); - } - } - - if (TREE_TYPE (method_type) != void_type_node) - PUSH_TYPE (TREE_TYPE (method_type)); - break; - } - - case OPCODE_arraylength: - /* Type checking actually made during code generation. */ - pop_type (ptr_type_node); - PUSH_TYPE (int_type_node); - break; - - /* Q&D verification *or* more checking done during code generation - for byte/boolean/char/short, the value popped is a int coerced - into the right type before being stored. */ - case OPCODE_iastore: type = int_type_node; goto astore; - case OPCODE_lastore: type = long_type_node; goto astore; - case OPCODE_fastore: type = float_type_node; goto astore; - case OPCODE_dastore: type = double_type_node; goto astore; - case OPCODE_aastore: type = ptr_type_node; goto astore; - case OPCODE_bastore: type = int_type_node; goto astore; - case OPCODE_castore: type = int_type_node; goto astore; - case OPCODE_sastore: type = int_type_node; goto astore; - - astore: - /* FIXME - need better verification here. */ - pop_type (type); /* new value */ - pop_type (int_type_node); /* index */ - pop_type (ptr_type_node); /* array */ - break; - - /* Q&D verification *or* more checking done during code generation - for byte/boolean/char/short, the value pushed is a int. */ - case OPCODE_iaload: type = int_type_node; goto aload; - case OPCODE_laload: type = long_type_node; goto aload; - case OPCODE_faload: type = float_type_node; goto aload; - case OPCODE_daload: type = double_type_node; goto aload; - case OPCODE_aaload: type = ptr_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_saload: type = promote_type (short_type_node); goto aload; - - aload: - pop_type (int_type_node); - tmp = pop_type (ptr_type_node); - if (is_array_type_p (tmp)) - type = TYPE_ARRAY_ELEMENT (TREE_TYPE (tmp)); - else if (tmp != TYPE_NULL) - VERIFICATION_ERROR ("array load from non-array type"); - PUSH_TYPE (type); - break; - - case OPCODE_anewarray: - type = get_class_constant (current_jcf, IMMEDIATE_u2); - type = promote_type (type); - goto newarray; - - case OPCODE_newarray: - index = IMMEDIATE_u1; - type = decode_newarray_type (index); - if (type == NULL_TREE) - VERIFICATION_ERROR ("invalid type code in newarray opcode"); - goto newarray; - - newarray: - if (int_value >= 0 && prevpc >= 0) - { - /* If the previous instruction pushed an int constant, - we want to use it. */ - switch (byte_ops[prevpc]) - { - 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_bipush: case OPCODE_sipush: - case OPCODE_ldc: case OPCODE_ldc_w: - break; - default: - int_value = -1; - } - } - else - int_value = -1; - - type = build_java_array_type (type, int_value); - pop_type (int_type_node); - PUSH_TYPE (type); - break; - - case OPCODE_multianewarray: - { - int ndim, i; - index = IMMEDIATE_u2; - ndim = IMMEDIATE_u1; - - if (ndim < 1) - VERIFICATION_ERROR - ("number of dimension lower that 1 in multianewarray" ); - - for (i = 0; i < ndim; i++) - pop_type (int_type_node); - - PUSH_TYPE (get_class_constant (current_jcf, index)); - break; - } - - case OPCODE_aconst_null: - PUSH_TYPE (ptr_type_node); - break; - - case OPCODE_athrow: - /* FIXME: athrow also empties the stack. */ - POP_TYPE (throwable_type_node, "missing throwable at athrow" ); - INVALIDATE_PC; - break; - - case OPCODE_checkcast: - POP_TYPE (object_ptr_type_node, - "checkcast operand is not a pointer"); - type = get_class_constant (current_jcf, IMMEDIATE_u2); - PUSH_TYPE (type); - break; - - case OPCODE_instanceof: - POP_TYPE (object_ptr_type_node, - "instanceof operand is not a pointer"); - get_class_constant (current_jcf, IMMEDIATE_u2); - PUSH_TYPE (int_type_node); - break; - - case OPCODE_tableswitch: - { - jint low, high; - - POP_TYPE (int_type_node, "missing int for tableswitch"); - - while (PC%4) - { - if (byte_ops[PC++]) - VERIFICATION_ERROR ("bad alignment in tableswitch pad"); - } - - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); - low = IMMEDIATE_s4; - high = IMMEDIATE_s4; - - if (low > high) - VERIFICATION_ERROR ("unsorted low/high value in tableswitch"); - - while (low++ <= high) - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); - - INVALIDATE_PC; - break; - } - - case OPCODE_lookupswitch: - { - jint npairs, last = 0, not_registered = 1; - - POP_TYPE (int_type_node, "missing int for lookupswitch"); - - while (PC%4) - { - if (byte_ops[PC++]) - VERIFICATION_ERROR ("bad alignment in lookupswitch pad"); - } - - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); - npairs = IMMEDIATE_s4; - - if (npairs < 0) - VERIFICATION_ERROR ("invalid number of targets in lookupswitch"); - - while (npairs--) - { - int match = IMMEDIATE_s4; - - if (not_registered) - not_registered = 0; - else if (last >= match) - VERIFICATION_ERROR ("unsorted match value in lookupswitch"); - - last = match; - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); - } - INVALIDATE_PC; - break; - } - - case OPCODE_monitorenter: - /* fall thru */ - case OPCODE_monitorexit: - pop_type (ptr_type_node); - break; - - case OPCODE_goto_w: - PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); - INVALIDATE_PC; - break; - - case OPCODE_jsr: - { - tree target = lookup_label (oldpc + IMMEDIATE_s2); - tree return_label = lookup_label (PC); - PUSH_TYPE (return_address_type_node); - /* The return label chain will be null if this is the first - time we've seen this jsr target. */ - if (LABEL_RETURN_LABEL (target) == NULL_TREE) - { - tree return_type_map; - int nlocals = DECL_MAX_LOCALS (current_function_decl); - index = nlocals + DECL_MAX_STACK (current_function_decl); - return_type_map = make_tree_vec (index); - - while (index > nlocals) - TREE_VEC_ELT (return_type_map, --index) = TYPE_UNKNOWN; - - while (index > 0) - TREE_VEC_ELT (return_type_map, --index) = TYPE_UNUSED; - - LABEL_RETURN_LABEL (target) - = build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target)); - LABEL_PC (LABEL_RETURN_LABEL (target)) = INVALID_PC; - LABEL_RETURN_TYPE_STATE (target) = return_type_map; - LABEL_IS_SUBR_START (target) = 1; - LABEL_IN_SUBR (target) = 1; - LABEL_SUBR_START (target) = target; - LABEL_SUBR_CONTEXT (target) = current_subr; - } - else if (! LABEL_IS_SUBR_START (target) - || LABEL_SUBR_CONTEXT (target) != current_subr) - VERIFICATION_ERROR ("label part of different subroutines"); - - i = merge_type_state (target); - if (i != 0) - { - if (i < 0) - VERIFICATION_ERROR ("types could not be merged at jsr"); - push_pending_label (target); - } - current_subr = target; - - /* Chain return_pc onto LABEL_RETURN_LABELS (target) if needed. */ - if (! value_member (return_label, LABEL_RETURN_LABELS (target))) - { - LABEL_RETURN_LABELS (target) - = tree_cons (NULL_TREE, return_label, - LABEL_RETURN_LABELS (target)); - } - - if (LABEL_VERIFIED (target)) - { - tree return_map = LABEL_RETURN_TYPE_STATE (target); - int len = TREE_VEC_LENGTH (return_map); - stack_pointer = len - DECL_MAX_LOCALS (current_function_decl); - while (--len >= 0) - { - if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED) - type_map[len] = TREE_VEC_ELT (return_map, len); - } - current_subr = LABEL_SUBR_CONTEXT (target); - if (RETURN_MAP_ADJUSTED (return_map)) - PUSH_PENDING (return_label); - } - - INVALIDATE_PC; - } - break; - - case OPCODE_ret: - if (current_subr == NULL_TREE) - VERIFICATION_ERROR ("ret instruction not in a jsr subroutine"); - else - { - tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); - int size - = DECL_MAX_LOCALS (current_function_decl) + stack_pointer; - index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; - wide = 0; - INVALIDATE_PC; - if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl) - || type_map[index] != TYPE_RETURN_ADDR) - VERIFICATION_ERROR ("invalid ret index"); - - /* The next chunk of code is similar to an inlined version of - merge_type_state (LABEL_RETURN_LABEL (current_subr)). - The main differences are that LABEL_RETURN_LABEL is - pre-allocated by the jsr (but we don't know the size then); - and that we have to handle TYPE_UNUSED. */ - - if (! RETURN_MAP_ADJUSTED (ret_map)) - { - /* First return from this subroutine - fix stack - pointer. */ - TREE_VEC_LENGTH (ret_map) = size; - for (index = size; --index >= 0; ) - { - if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED) - TREE_VEC_ELT (ret_map, index) = type_map[index]; - } - RETURN_MAP_ADJUSTED (ret_map) = 1; - } - else - { - if (TREE_VEC_LENGTH (ret_map) != size) - VERIFICATION_ERROR ("inconsistent stack size on ret"); - for (index = 0; index < size; index++) - { - tree type = TREE_VEC_ELT (ret_map, index); - if (type != TYPE_UNUSED) - { - type = merge_types (type, type_map[index]); - TREE_VEC_ELT (ret_map, index) = type; - if (type == TYPE_UNKNOWN) - { - if (index >= size - stack_pointer) - VERIFICATION_ERROR - ("inconsistent types on ret from jsr"); - } - else if (TYPE_IS_WIDE (type)) - index++; - } - } - } - } - break; - - case OPCODE_jsr_w: - case OPCODE_ret_w: - default: - error ("unknown opcode %d@pc=%d during verification", op_code, PC-1); - return 0; - } - - prevpc = oldpc; - - /* 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. - In either case we need to consider any exception handlers that - might "follow" this instruction. */ - - if (eh_ranges != prev_eh_ranges) - { - int save_stack_pointer = stack_pointer; - int index = DECL_MAX_LOCALS (current_function_decl); - tree save_type = type_map[index]; - tree save_current_subr = current_subr; - struct eh_range *ranges = find_handler (oldpc); - stack_pointer = 1; - - for ( ; ranges != NULL_EH_RANGE; ranges = ranges->outer) - { - tree chain = ranges->handlers; - - /* We need to determine if the handler is part of current_subr. - The are two cases: (1) The exception catch range - is entirely within current_subr. In that case the handler - is also part of current_subr. - (2) Some of the catch range is not in current_subr. - In that case, the handler is *not* part of current_subr. - - Figuring out which is the case is not necessarily obvious, - in the presence of clever code generators (and obfuscators). - We make a simplifying assumption that in case (2) we - 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 - a subroutine is within the catch range, then the handler is - *not* part of the subroutine, and vice versa. */ - - current_subr = save_current_subr; - for ( ; current_subr != NULL_TREE; - current_subr = LABEL_SUBR_CONTEXT (current_subr)) - { - tree return_labels = LABEL_RETURN_LABELS (current_subr); - /* There could be multiple return_labels, but - we only need to check one. */ - int return_pc = LABEL_PC (TREE_VALUE (return_labels)); - if (return_pc <= ranges->start_pc - || return_pc > ranges->end_pc) - break; - } - - for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain)) - { - tree handler = TREE_VALUE (chain); - tree type = TREE_PURPOSE (chain); - - if (type == NULL_TREE) /* a finally handler */ - type = throwable_type_node; - - type_map[index] = promote_type (type); - - PUSH_PENDING (handler); - } - } - stack_pointer = save_stack_pointer; - current_subr = save_current_subr; - type_map[index] = save_type; - prev_eh_ranges = eh_ranges; - } - } - - return 1; - - pop_type_error: - error ("verification error at PC=%d", oldpc); - if (message != NULL) - error ("%s", message); - error ("%s", pmessage); - free (pmessage); - return 0; - - stack_overflow: - message = "stack overflow"; - goto verify_error; - - bad_pc: - message = "program counter out of range"; - goto verify_error; - - error_with_index: - error ("verification error at PC=%d", oldpc); - error (message, index); - return 0; - - verify_error: - error ("verification error at PC=%d", oldpc); - error ("%s", message); - return 0; -} -- cgit v1.2.3