aboutsummaryrefslogtreecommitdiff
path: root/gcc/java/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/java/expr.c')
-rw-r--r--gcc/java/expr.c539
1 files changed, 415 insertions, 124 deletions
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index deb75a9..305ab5b 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -323,26 +323,63 @@ pop_type_0 (tree type, char **messagep)
t = stack_type_map[--stack_pointer];
if (type == NULL_TREE || t == type)
return t;
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ do
+ {
+ tree tt = TREE_PURPOSE (t);
+ if (! can_widen_reference_to (tt, type))
+ {
+ t = tt;
+ goto fail;
+ }
+ t = TREE_CHAIN (t);
+ }
+ while (t);
+ return t;
+ }
if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t)
&& TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32)
- return t;
+ return t;
if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE)
{
- 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;
- else if (can_widen_reference_to (t, type))
- return t;
- /* 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;
+ 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;
+ }
+ }
+
+ if (! flag_verify_invocations && flag_indirect_dispatch
+ && t == object_ptr_type_node)
+ {
+ if (type != ptr_type_node)
+ warning ("need to insert runtime check for %s",
+ xstrdup (lang_printable_name (type, 0)));
+ return type;
}
/* lang_printable_name uses a static buffer, so we must save the result
from calling it the first time. */
+ fail:
{
char *temp = xstrdup (lang_printable_name (type, 0));
*messagep = concat ("expected type '", temp,
@@ -370,6 +407,68 @@ pop_type (tree type)
return type;
}
+
+/* Return true if two type assertions are equal. */
+
+static int
+type_assertion_eq (const void * k1_p, const void * k2_p)
+{
+ type_assertion k1 = *(type_assertion *)k1_p;
+ type_assertion k2 = *(type_assertion *)k2_p;
+ return (k1.assertion_code == k2.assertion_code
+ && k1.op1 == k2.op1
+ && k1.op2 == k2.op2);
+}
+
+/* Hash a type assertion. */
+
+static hashval_t
+type_assertion_hash (const void *p)
+{
+ const type_assertion *k_p = p;
+ hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
+ k_p->assertion_code, 0);
+ hash = iterative_hash (&k_p->op1, sizeof k_p->op1, hash);
+ return iterative_hash (&k_p->op2, sizeof k_p->op2, hash);
+}
+
+/* Add an entry to the type assertion table for the given class.
+ CLASS is the class for which this assertion will be evaluated by the
+ runtime during loading/initialization.
+ ASSERTION_CODE is the 'opcode' or type of this assertion: see java-tree.h.
+ OP1 and OP2 are the operands. The tree type of these arguments may be
+ specific to each assertion_code. */
+
+void
+add_type_assertion (tree class, int assertion_code, tree op1, tree op2)
+{
+ htab_t assertions_htab;
+ type_assertion as;
+ void **as_pp;
+
+ assertions_htab = TYPE_ASSERTIONS (class);
+ if (assertions_htab == NULL)
+ {
+ assertions_htab = htab_create_ggc (7, type_assertion_hash,
+ type_assertion_eq, NULL);
+ TYPE_ASSERTIONS (current_class) = assertions_htab;
+ }
+
+ as.assertion_code = assertion_code;
+ as.op1 = op1;
+ as.op2 = op2;
+
+ as_pp = htab_find_slot (assertions_htab, &as, true);
+
+ /* Don't add the same assertion twice. */
+ if (*as_pp)
+ return;
+
+ *as_pp = ggc_alloc (sizeof (type_assertion));
+ **(type_assertion **)as_pp = as;
+}
+
+
/* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE.
Handles array types and interfaces. */
@@ -387,6 +486,28 @@ can_widen_reference_to (tree source_type, tree target_type)
if (source_type == target_type)
return 1;
+
+ /* FIXME: This is very pessimistic, in that it checks everything,
+ even if we already know that the types are compatible. If we're
+ to support full Java class loader semantics, we need this.
+ However, we could do something more optimal. */
+ if (! flag_verify_invocations)
+ {
+ add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE,
+ source_type, target_type);
+
+ if (!quiet_flag)
+ warning ("assert: %s is assign compatible with %s",
+ xstrdup (lang_printable_name (target_type, 0)),
+ xstrdup (lang_printable_name (source_type, 0)));
+ /* Punt everything to runtime. */
+ return 1;
+ }
+
+ if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
+ {
+ return 1;
+ }
else
{
if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type))
@@ -420,7 +541,16 @@ can_widen_reference_to (tree source_type, tree target_type)
int source_depth = class_depth (source_type);
int target_depth = class_depth (target_type);
- /* class_depth can return a negative depth if an error occurred */
+ if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
+ {
+ if (! quiet_flag)
+ warning ("assert: %s is assign compatible with %s",
+ xstrdup (lang_printable_name (target_type, 0)),
+ xstrdup (lang_printable_name (source_type, 0)));
+ return 1;
+ }
+
+ /* class_depth can return a negative depth if an error occurred */
if (source_depth < 0 || target_depth < 0)
return 0;
@@ -687,13 +817,18 @@ build_java_array_length_access (tree node)
throws a NullPointerException. The only way we could get a node
of type ptr_type_node at this point is `aconst_null; arraylength'
or something equivalent. */
- if (type == ptr_type_node)
+ if (!flag_new_verifier && type == ptr_type_node)
return build3 (CALL_EXPR, int_type_node,
build_address_of (soft_nullpointer_node),
NULL_TREE, NULL_TREE);
if (!is_array_type_p (type))
- abort ();
+ {
+ /* With the new verifier, we will see an ordinary pointer type
+ here. In this case, we just use an arbitrary array type. */
+ array_type = build_java_array_type (object_ptr_type_node, -1);
+ type = promote_type (array_type);
+ }
length = java_array_type_length (type);
if (length >= 0)
@@ -754,6 +889,13 @@ build_java_arrayaccess (tree array, tree type, tree index)
tree ref;
tree array_type = TREE_TYPE (TREE_TYPE (array));
+ if (!is_array_type_p (TREE_TYPE (array)))
+ {
+ /* With the new verifier, we will see an ordinary pointer type
+ here. In this case, we just use the correct array type. */
+ array_type = build_java_array_type (type, -1);
+ }
+
if (flag_bounds_check)
{
/* Generate:
@@ -803,11 +945,21 @@ build_java_arraystore_check (tree array, tree object)
tree array_type_p = TREE_TYPE (array);
tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object)));
- if (! is_array_type_p (array_type_p))
- abort ();
+ if (! flag_verify_invocations)
+ {
+ /* With the new verifier, we don't track precise types. FIXME:
+ performance regression here. */
+ element_type = TYPE_NAME (object_type_node);
+ }
+ else
+ {
+ if (! is_array_type_p (array_type_p))
+ abort ();
- /* Get the TYPE_DECL for ARRAY's element type. */
- element_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
+ /* Get the TYPE_DECL for ARRAY's element type. */
+ element_type
+ = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p))));
+ }
if (TREE_CODE (element_type) != TYPE_DECL
|| TREE_CODE (object_type) != TYPE_DECL)
@@ -816,13 +968,14 @@ build_java_arraystore_check (tree array, tree object)
if (!flag_store_check)
return build1 (NOP_EXPR, array_type_p, array);
- /* No check is needed if the element type is final or is itself an array.
- Also check that element_type matches object_type, since in the bytecode
- compilation case element_type may be the actual element type of the array
- rather than its declared type. */
+ /* No check is needed if the element type is final. Also check that
+ element_type matches object_type, since in the bytecode
+ compilation case element_type may be the actual element type of
+ the array rather than its declared type. However, if we're doing
+ indirect dispatch, we can't do the `final' optimization. */
if (element_type == object_type
- && (TYPE_ARRAY_P (TREE_TYPE (element_type))
- || CLASS_FINAL (element_type)))
+ && ! flag_indirect_dispatch
+ && CLASS_FINAL (element_type))
return build1 (NOP_EXPR, array_type_p, array);
/* OBJECT might be wrapped by a SAVE_EXPR. */
@@ -864,24 +1017,30 @@ build_java_arraystore_check (tree array, tree object)
ARRAY_NODE. This function is used to retrieve something less vague than
a pointer type when indexing the first dimension of something like [[<t>.
May return a corrected type, if necessary, otherwise INDEXED_TYPE is
- return unchanged.
- As a side effect, it also makes sure that ARRAY_NODE is an array. */
+ return unchanged. */
static tree
build_java_check_indexed_type (tree array_node, 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);
+ 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 )
+ if (indexed_type == byte_type_node && elt_type == boolean_type_node)
return boolean_type_node;
if (indexed_type != elt_type )
@@ -992,7 +1151,25 @@ expand_java_arraystore (tree rhs_type_node)
&& TYPE_PRECISION (rhs_type_node) <= 32) ?
int_type_node : rhs_type_node);
tree index = pop_value (int_type_node);
- tree array = pop_value (ptr_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)
+ {
+ 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);
+ }
+ else
+ array_type = ptr_type_node;
+ array = pop_value (array_type);
+ if (flag_new_verifier)
+ array = build1 (NOP_EXPR, promote_type (array_type), array);
rhs_type_node = build_java_check_indexed_type (array, rhs_type_node);
@@ -1019,25 +1196,45 @@ expand_java_arraystore (tree rhs_type_node)
*/
static void
-expand_java_arrayload (tree lhs_type_node )
+expand_java_arrayload (tree lhs_type_node)
{
tree load_node;
tree index_node = pop_value (int_type_node);
- tree array_node = pop_value (ptr_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)
+ {
+ 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);
+ }
+ else
+ array_type = ptr_type_node;
+ array_node = pop_value (array_type);
+ if (flag_new_verifier)
+ array_node = build1 (NOP_EXPR, promote_type (array_type), array_node);
index_node = save_expr (index_node);
array_node = save_expr (array_node);
-
+
if (TREE_TYPE (array_node) == ptr_type_node)
/* The only way we could get a node of type ptr_type_node at this
point is `aconst_null; arraylength' or something equivalent, so
- unconditionally throw NullPointerException. */
+ unconditionally throw NullPointerException. */
load_node = build3 (CALL_EXPR, lhs_type_node,
build_address_of (soft_nullpointer_node),
NULL_TREE, NULL_TREE);
else
{
- lhs_type_node = build_java_check_indexed_type (array_node, lhs_type_node);
+ lhs_type_node = build_java_check_indexed_type (array_node,
+ lhs_type_node);
load_node = build_java_arrayaccess (array_node,
lhs_type_node,
index_node);
@@ -1156,6 +1353,19 @@ class_has_finalize_method (tree type)
return HAS_FINALIZER_P (type) || class_has_finalize_method (super);
}
+tree
+java_create_object (tree type)
+{
+ tree alloc_node = (class_has_finalize_method (type)
+ ? alloc_object_node
+ : alloc_no_finalizer_node);
+
+ return build (CALL_EXPR, promote_type (type),
+ build_address_of (alloc_node),
+ build_tree_list (NULL_TREE, build_class_ref (type)),
+ NULL_TREE);
+}
+
static void
expand_java_NEW (tree type)
{
@@ -1221,7 +1431,8 @@ build_instanceof (tree value, tree type)
we only need to check for `null'. */
expr = build2 (NE_EXPR, itype, value, null_pointer_node);
}
- else if (! TYPE_ARRAY_P (type)
+ else if (flag_verify_invocations
+ && ! TYPE_ARRAY_P (type)
&& ! TYPE_ARRAY_P (valtype)
&& DECL_P (klass) && DECL_P (valclass)
&& ! CLASS_INTERFACE (valclass)
@@ -1292,7 +1503,7 @@ expand_iinc (unsigned int local_var_index, int ival, int pc)
update_aliases (local_var, local_var_index, pc);
}
-
+
tree
build_java_soft_divmod (enum tree_code op, tree type, tree op1, tree op2)
{
@@ -1529,12 +1740,13 @@ build_field_ref (tree self_value, tree self_class, tree name)
tree base_type = promote_type (base_class);
if (base_type != TREE_TYPE (self_value))
self_value = fold (build1 (NOP_EXPR, base_type, self_value));
- if (flag_indirect_dispatch
- && output_class != self_class)
- /* FIXME: output_class != self_class is not exactly the right
- test. What we really want to know is whether self_class is
- in the same translation unit as output_class. If it is,
- we can make a direct reference. */
+ if (! flag_syntax_only
+ && (flag_indirect_dispatch
+ /* DECL_FIELD_OFFSET == 0 if we have no reference for
+ the field, perhaps because we couldn't find the class
+ in which the field is defined.
+ FIXME: We should investigate this. */
+ || DECL_FIELD_OFFSET (field_decl) == 0))
{
tree otable_index
= build_int_cst (NULL_TREE, get_symbol_table_index
@@ -1696,29 +1908,6 @@ expand_java_add_case (tree switch_expr, int match, int target_pc)
append_to_statement_list (x, &SWITCH_BODY (switch_expr));
}
-#if 0
-static void
-expand_java_call (int target_pc, int return_address)
-{
- tree target_label = lookup_label (target_pc);
- tree value = build_int_cst (NULL_TREE, return_address);
- push_value (value);
- flush_quick_stack ();
- expand_goto (target_label);
-}
-
-static void
-expand_java_ret (tree return_address ATTRIBUTE_UNUSED)
-{
- warning ("ret instruction not implemented");
-#if 0
- tree target_label = lookup_label (target_pc);
- flush_quick_stack ();
- expand_goto (target_label);
-#endif
-}
-#endif
-
static tree
pop_arguments (tree arg_types)
{
@@ -1729,9 +1918,17 @@ pop_arguments (tree arg_types)
tree tail = pop_arguments (TREE_CHAIN (arg_types));
tree type = TREE_VALUE (arg_types);
tree arg = pop_value (type);
- if (targetm.calls.promote_prototypes (type)
- && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
- && INTEGRAL_TYPE_P (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)
+ arg = build1 (NOP_EXPR, type, arg);
+ else if (targetm.calls.promote_prototypes (type)
+ && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
+ && INTEGRAL_TYPE_P (type))
arg = convert (integer_type_node, arg);
return tree_cons (NULL_TREE, arg, tail);
}
@@ -1824,8 +2021,12 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
tree func;
if (is_compiled_class (self_type))
{
- if (!flag_indirect_dispatch
- || (!TREE_PUBLIC (method) && DECL_CONTEXT (method)))
+ /* With indirect dispatch we have to use indirect calls for all
+ publically visible methods or gcc will use PLT indirections
+ to reach them. We also have to use indirect dispatch for all
+ external methods. */
+ if (! flag_indirect_dispatch
+ || (! DECL_EXTERNAL (method) && ! TREE_PUBLIC (method)))
{
make_decl_rtl (method);
func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)),
@@ -1836,9 +2037,11 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
tree table_index
= build_int_cst (NULL_TREE, get_symbol_table_index
(method, &TYPE_ATABLE_METHODS (output_class)));
- func = build4 (ARRAY_REF, method_ptr_type_node,
- TYPE_ATABLE_DECL (output_class), table_index,
- NULL_TREE, NULL_TREE);
+ func
+ = build4 (ARRAY_REF,
+ TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))),
+ TYPE_ATABLE_DECL (output_class), table_index,
+ NULL_TREE, NULL_TREE);
}
func = convert (method_ptr_type_node, func);
}
@@ -1899,9 +2102,9 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list)
argument is an array then get the dispatch table of the class
Object rather than the one from the objectref. */
objectref = (is_invoke_interface
- && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list))) ?
- object_type_node : TREE_VALUE (arg_list));
-
+ && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
+ ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
+
if (dtable_ident == NULL_TREE)
dtable_ident = get_identifier ("vtable");
dtable = build_java_indirect_ref (object_type_node, objectref,
@@ -1914,8 +2117,8 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list)
/* Determine the index in SYMBOL_TABLE for a reference to the decl
T. If this decl has not been seen before, it will be added to the
- otable_methods. If it has, the existing table slot will be
- reused. */
+ [oa]table_methods. If it has, the existing table slot will be
+ reused. */
int
get_symbol_table_index (tree t, tree *symbol_table)
@@ -1935,7 +2138,7 @@ get_symbol_table_index (tree t, tree *symbol_table)
{
tree value = TREE_VALUE (method_list);
if (value == t)
- return i;
+ return i;
i++;
if (TREE_CHAIN (method_list) == NULL_TREE)
break;
@@ -1958,6 +2161,9 @@ build_invokevirtual (tree dtable, tree method)
if (flag_indirect_dispatch)
{
+ if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
+ abort ();
+
otable_index
= build_int_cst (NULL_TREE, get_symbol_table_index
(method, &TYPE_OTABLE_METHODS (output_class)));
@@ -1997,11 +2203,8 @@ build_invokeinterface (tree dtable, tree method)
tree lookup_arg;
tree interface;
tree idx;
- tree otable_index;
- /* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will
- ensure that the selected method exists, is public and not
- abstract nor static. */
+ /* We expand invokeinterface here. */
if (class_ident == NULL_TREE)
class_ident = get_identifier ("class");
@@ -2018,28 +2221,42 @@ build_invokeinterface (tree dtable, tree method)
if (flag_indirect_dispatch)
{
- otable_index
- = build_int_cst (NULL_TREE, get_symbol_table_index
- (method, &TYPE_OTABLE_METHODS (output_class)));
- idx = build4 (ARRAY_REF, integer_type_node,
- TYPE_OTABLE_DECL (output_class), otable_index,
- NULL_TREE, NULL_TREE);
+ int itable_index
+ = 2 * (get_symbol_table_index
+ (method, &TYPE_ITABLE_METHODS (output_class)));
+ interface
+ = build4 (ARRAY_REF,
+ TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
+ TYPE_ITABLE_DECL (output_class),
+ build_int_cst (NULL_TREE, itable_index-1),
+ NULL_TREE, NULL_TREE);
+ idx
+ = build4 (ARRAY_REF,
+ TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
+ TYPE_ITABLE_DECL (output_class),
+ build_int_cst (NULL_TREE, itable_index),
+ NULL_TREE, NULL_TREE);
+ interface = convert (class_ptr_type, interface);
+ idx = convert (integer_type_node, idx);
}
else
- idx = build_int_cst (NULL_TREE,
- get_interface_method_index (method, interface));
-
- lookup_arg = tree_cons (NULL_TREE, dtable,
- tree_cons (NULL_TREE, build_class_ref (interface),
- build_tree_list (NULL_TREE, idx)));
+ {
+ idx = build_int_cst (NULL_TREE,
+ get_interface_method_index (method, interface));
+ interface = build_class_ref (interface);
+ }
+ lookup_arg = tree_cons (NULL_TREE, dtable,
+ tree_cons (NULL_TREE, interface,
+ build_tree_list (NULL_TREE, idx)));
+
return build3 (CALL_EXPR, ptr_type_node,
build_address_of (soft_lookupinterfacemethod_node),
lookup_arg, NULL_TREE);
}
/* Expand one of the invoke_* opcodes.
- OCPODE is the specific opcode.
+ OPCODE is the specific opcode.
METHOD_REF_INDEX is an index into the constant pool.
NARGS is the number of arguments, or -1 if not specified. */
@@ -2048,7 +2265,8 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
{
tree method_signature
= COMPONENT_REF_SIGNATURE(&current_jcf->cpool, method_ref_index);
- tree method_name = COMPONENT_REF_NAME (&current_jcf->cpool, method_ref_index);
+ tree method_name = COMPONENT_REF_NAME (&current_jcf->cpool,
+ method_ref_index);
tree self_type
= get_class_constant (current_jcf,
COMPONENT_REF_CLASS_INDEX(&current_jcf->cpool,
@@ -2071,38 +2289,82 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED)
method = lookup_java_constructor (self_type, method_signature);
else
method = lookup_java_method (self_type, method_name, method_signature);
+
+ /* We've found a method in an interface, but this isn't an interface
+ call. */
+ if (opcode != OPCODE_invokeinterface
+ && method
+ && (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))))
+ method = NULL_TREE;
+
+ /* We've found a non-interface method but we are making an
+ interface call. This can happen if the interface overrides a
+ method in Object. */
+ if (! flag_verify_invocations
+ && opcode == OPCODE_invokeinterface
+ && method
+ && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
+ method = NULL_TREE;
+
if (method == NULL_TREE)
{
- error ("class '%s' has no method named '%s' matching signature '%s'",
- self_name,
- IDENTIFIER_POINTER (method_name),
- IDENTIFIER_POINTER (method_signature));
- }
- /* Invoke static can't invoke static/abstract method */
- else if (opcode == OPCODE_invokestatic)
- {
- if (!METHOD_STATIC (method))
+ if (flag_verify_invocations || ! flag_indirect_dispatch)
{
- error ("invokestatic on non static method");
- method = NULL_TREE;
+ error ("class '%s' has no method named '%s' matching signature '%s'",
+ self_name,
+ IDENTIFIER_POINTER (method_name),
+ IDENTIFIER_POINTER (method_signature));
}
- else if (METHOD_ABSTRACT (method))
+ else
{
- error ("invokestatic on abstract method");
- method = NULL_TREE;
+ int flags = ACC_PUBLIC;
+ if (opcode == OPCODE_invokestatic)
+ flags |= ACC_STATIC;
+ if (opcode == OPCODE_invokeinterface)
+ {
+ flags |= ACC_INTERFACE | ACC_ABSTRACT;
+ CLASS_INTERFACE (TYPE_NAME (self_type)) = 1;
+ }
+ method = add_method (self_type, flags, method_name,
+ method_signature);
+ DECL_ARTIFICIAL (method) = 1;
+ METHOD_DUMMY (method) = 1;
+ layout_class_method (self_type, NULL,
+ method, NULL);
}
}
- else
+
+ /* Invoke static can't invoke static/abstract method */
+ if (method != NULL_TREE)
{
- if (METHOD_STATIC (method))
+ if (opcode == OPCODE_invokestatic)
{
- error ("invoke[non-static] on static method");
- method = NULL_TREE;
+ if (!METHOD_STATIC (method))
+ {
+ error ("invokestatic on non static method");
+ method = NULL_TREE;
+ }
+ else if (METHOD_ABSTRACT (method))
+ {
+ error ("invokestatic on abstract method");
+ method = NULL_TREE;
+ }
+ }
+ else
+ {
+ if (METHOD_STATIC (method))
+ {
+ error ("invoke[non-static] on static method");
+ method = NULL_TREE;
+ }
}
}
if (method == NULL_TREE)
{
+ /* If we got here, we emitted an error message above. So we
+ just pop the arguments, push a properly-typed zero, and
+ continue. */
method_type = get_type_from_signature (method_signature);
pop_arguments (TYPE_ARG_TYPES (method_type));
if (opcode != OPCODE_invokestatic)
@@ -2385,6 +2647,7 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
tree new_value = is_putting ? pop_value (field_type) : NULL_TREE;
tree field_ref;
int is_error = 0;
+ tree original_self_type = self_type;
tree field_decl;
if (! CLASS_LOADED_P (self_type))
@@ -2396,9 +2659,23 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index)
}
else if (field_decl == NULL_TREE)
{
- error ("missing field '%s' in '%s'",
- IDENTIFIER_POINTER (field_name), self_name);
- is_error = 1;
+ if (! flag_verify_invocations)
+ {
+ int flags = ACC_PUBLIC;
+ if (is_static)
+ flags |= ACC_STATIC;
+ self_type = original_self_type;
+ field_decl = add_field (original_self_type, field_name,
+ field_type, flags);
+ DECL_ARTIFICIAL (field_decl) = 1;
+ DECL_IGNORED_P (field_decl) = 1;
+ }
+ else
+ {
+ error ("missing field '%s' in '%s'",
+ IDENTIFIER_POINTER (field_name), self_name);
+ is_error = 1;
+ }
}
else if (build_java_signature (TREE_TYPE (field_decl)) != field_signature)
{
@@ -2637,8 +2914,16 @@ expand_byte_code (JCF *jcf, tree method)
}
}
- if (! verify_jvm_instructions (jcf, byte_ops, length))
- return;
+ if (flag_new_verifier)
+ {
+ if (! verify_jvm_instructions_new (jcf, byte_ops, length))
+ return;
+ }
+ else
+ {
+ if (! verify_jvm_instructions (jcf, byte_ops, length))
+ return;
+ }
/* Translate bytecodes. */
linenumber_pointer = linenumber_table;
@@ -2749,8 +3034,14 @@ 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)
{
- tree type = pop_type (ptr_type_node);
- push_value (build_exception_object_ref (type));
+ /* 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)
+ {
+ tree type = pop_type (promote_type (throwable_type_node));
+ push_value (build_exception_object_ref (type));
+ }
}
switch (byte_ops[PC++])