/* Process expressions for the GNU compiler for the Java(TM) language.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007 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)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful,
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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>.
Java and all Java-based marks are trademarks or registered trademarks
of Sun Microsystems, Inc. in the United States and other countries.
static void expand_java_goto (int);
static tree expand_java_switch (tree, int);
static void expand_java_add_case (tree, int, int);
-#if 0
-static void expand_java_call (int, int);
-static void expand_java_ret (tree);
-#endif
static tree pop_arguments (tree);
static void expand_invoke (int, int, int);
static void expand_java_field_op (int, int, int);
static tree build_java_throw_out_of_bounds_exception (tree);
static tree build_java_check_indexed_type (tree, tree);
static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
+static void promote_arguments (void);
+static void cache_cpool_data_ref (void);
static GTY(()) tree operand_type[59];
/* A free-list of unused permanent TREE_LIST nodes. */
static GTY((deletable)) tree tree_list_free_list;
+/* The physical memory page size used in this computer. See
+ build_field_ref(). */
+static GTY(()) tree page_size;
+
/* The stack pointer of the Java virtual machine.
This does include the size of the quick_stack. */
const unsigned char *linenumber_table;
int linenumber_count;
+/* Largest pc so far in this method that has been passed to lookup_label. */
+int highest_label_pc_this_method = -1;
+
+/* Base value for this method to add to pc to get generated label. */
+int start_label_pc_this_method = 0;
+
void
init_expr_processing (void)
{
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
- return fold
- (build3 (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
- java_truthvalue_conversion (TREE_OPERAND (expr, 1)),
- java_truthvalue_conversion (TREE_OPERAND (expr, 2))));
+ return fold_build3 (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
+ java_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ java_truthvalue_conversion (TREE_OPERAND (expr, 2)));
case NOP_EXPR:
/* If this is widening the argument, we can ignore it. */
/* fall through to default */
default:
- return fold (build2 (NE_EXPR, boolean_type_node,
- expr, boolean_false_node));
+ return fold_build2 (NE_EXPR, boolean_type_node,
+ expr, boolean_false_node);
}
}
void
push_type (tree type)
{
- if (! push_type_0 (type))
- abort ();
+ int r = push_type_0 (type);
+ gcc_assert (r);
}
static void
TREE_CHAIN (node) = quick_stack;
quick_stack = node;
}
+ /* If the value has a side effect, then we need to evaluate it
+ whether or not the result is used. If the value ends up on the
+ quick stack and is then popped, this won't happen -- so we flush
+ the quick stack. It is safest to simply always flush, though,
+ since TREE_SIDE_EFFECTS doesn't capture COMPONENT_REF, and for
+ the latter we may need to strip conversions. */
+ flush_quick_stack ();
}
/* Pop a type from the type stack.
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;
- }
+ /* If the expected type we've been passed is object or ptr
+ (i.e. void*), the caller needs to know the real type. */
+ if (type == ptr_type_node || type == object_ptr_type_node)
+ 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
&& t == object_ptr_type_node)
{
if (type != ptr_type_node)
- warning ("need to insert runtime check for %s",
+ warning (0, "need to insert runtime check for %s",
xstrdup (lang_printable_name (type, 0)));
return type;
}
fail:
{
char *temp = xstrdup (lang_printable_name (type, 0));
+ /* If the stack contains a multi-word type, keep popping the stack until
+ the real type is found. */
+ while (t == void_type_node)
+ t = stack_type_map[--stack_pointer];
*messagep = concat ("expected type '", temp,
"' but stack contains '", lang_printable_name (t, 0),
"'", NULL);
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;
+ const type_assertion k1 = *(const type_assertion *)k1_p;
+ const type_assertion k2 = *(const type_assertion *)k2_p;
return (k1.assertion_code == k2.assertion_code
&& k1.op1 == k2.op1
&& k1.op2 == k2.op2);
as.op1 = op1;
as.op2 = op2;
- as_pp = htab_find_slot (assertions_htab, &as, true);
+ as_pp = htab_find_slot (assertions_htab, &as, INSERT);
/* Don't add the same assertion twice. */
if (*as_pp)
source_type, target_type);
if (!quiet_flag)
- warning ("assert: %s is assign compatible with %s",
+ warning (0, "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. */
if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type))
{
if (! quiet_flag)
- warning ("assert: %s is assign compatible with %s",
+ warning (0, "assert: %s is assign compatible with %s",
xstrdup (lang_printable_name (target_type, 0)),
xstrdup (lang_printable_name (source_type, 0)));
return 1;
{
tree type, val;
- if (stack_pointer == 0)
- abort ();
+ gcc_assert (stack_pointer != 0);
type = stack_type_map[stack_pointer - 1];
if (type == TYPE_SECOND)
{
count--;
- if (stack_pointer == 1 || count <= 0)
- abort ();
+ gcc_assert (stack_pointer != 1 && count > 0);
type = stack_type_map[stack_pointer - 2];
}
tree decl1, decl2;
if (stack_pointer < 2
- || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_UNKNOWN
- || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_UNKNOWN
- || type1 == TYPE_SECOND || type2 == TYPE_SECOND
+ || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_SECOND
+ || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_SECOND
|| TYPE_IS_WIDE (type1) || TYPE_IS_WIDE (type2))
/* Bad stack swap. */
abort ();
+ /* Bad stack swap. */
flush_quick_stack ();
decl1 = find_stack_slot (stack_pointer - 1, type1);
type = stack_type_map [src_index];
if (type == TYPE_SECOND)
{
- if (src_index <= low_index)
- /* Dup operation splits 64-bit number. */
- abort ();
+ /* Dup operation splits 64-bit number. */
+ gcc_assert (src_index > low_index);
stack_type_map[dst_index] = type;
src_index--; dst_index--;
type = stack_type_map[src_index];
- if (! TYPE_IS_WIDE (type))
- abort ();
+ gcc_assert (TYPE_IS_WIDE (type));
}
- else if (TYPE_IS_WIDE (type))
- abort ();
+ else
+ gcc_assert (! TYPE_IS_WIDE (type));
if (src_index != dst_index)
{
{
tree call;
- call = build3 (CALL_EXPR,
- void_type_node,
- build_address_of (throw_node),
- build_tree_list (NULL_TREE, node),
- NULL_TREE);
+ call = build_call_nary (void_type_node,
+ build_address_of (throw_node),
+ 1, node);
TREE_SIDE_EFFECTS (call) = 1;
java_add_stmt (call);
java_stack_pop (stack_pointer);
{
tree where = lookup_label (target_pc);
tree ret = lookup_label (return_pc);
- tree ret_label = fold (build1 (ADDR_EXPR, return_address_type_node, ret));
+ tree ret_label = fold_build1 (ADDR_EXPR, return_address_type_node, ret);
push_value (ret_label);
flush_quick_stack ();
java_add_stmt (build1 (GOTO_EXPR, void_type_node, where));
else if (type == long_type_node)
return 11;
else
- abort ();
+ gcc_unreachable ();
}
/* Build a call to _Jv_ThrowBadArrayIndex(), the
static tree
build_java_throw_out_of_bounds_exception (tree index)
{
- tree node = build3 (CALL_EXPR, int_type_node,
- build_address_of (soft_badarrayindex_node),
- build_tree_list (NULL_TREE, index), NULL_TREE);
+ tree node = build_call_nary (int_type_node,
+ build_address_of (soft_badarrayindex_node),
+ 1, index);
TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */
return (node);
}
tree array_type = TREE_TYPE (type);
HOST_WIDE_INT length;
- /* JVM spec: If the arrayref is null, the arraylength instruction
- 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 (!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))
{
/* With the new verifier, we will see an ordinary pointer type
expr = build3 (COND_EXPR, TREE_TYPE (expr),
build2 (EQ_EXPR, boolean_type_node,
expr, null_pointer_node),
- build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_nullpointer_node),
- NULL_TREE, NULL_TREE),
+ build_call_nary (void_type_node,
+ build_address_of (soft_nullpointer_node),
+ 0),
expr);
}
tree data_field;
tree ref;
tree array_type = TREE_TYPE (TREE_TYPE (array));
+ tree size_exp = fold_convert (sizetype, size_in_bytes (type));
if (!is_array_type_p (TREE_TYPE (array)))
{
tree test;
tree len = convert (unsigned_int_type_node,
build_java_array_length_access (array));
- test = fold (build2 (GE_EXPR, boolean_type_node,
- convert (unsigned_int_type_node, index),
- len));
+ test = fold_build2 (GE_EXPR, boolean_type_node,
+ convert (unsigned_int_type_node, index),
+ len);
if (! integer_zerop (test))
{
throw = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
to have the bounds check evaluated first. */
if (throw != NULL_TREE)
index = build2 (COMPOUND_EXPR, int_type_node, throw, index);
-
+
data_field = lookup_field (&array_type, get_identifier ("data"));
ref = build3 (COMPONENT_REF, TREE_TYPE (data_field),
build_java_indirect_ref (array_type, array,
flag_check_references),
data_field, NULL_TREE);
-
- node = build4 (ARRAY_REF, type, ref, index, NULL_TREE, NULL_TREE);
- return node;
+
+ /* Take the address of the data field and convert it to a pointer to
+ the element type. */
+ node = build1 (NOP_EXPR, build_pointer_type (type), build_address_of (ref));
+
+ /* Multiply the index by the size of an element to obtain a byte
+ offset. Convert the result to a pointer to the element type. */
+ index = build2 (MULT_EXPR, sizetype,
+ fold_convert (sizetype, index),
+ size_exp);
+
+ /* Sum the byte offset and the address of the data field. */
+ node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
+
+ /* Finally, return
+
+ *((&array->data) + index*size_exp)
+
+ */
+ return build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (node)), node);
}
/* Generate code to throw an ArrayStoreException if OBJECT is not assignable
}
else
{
- if (! is_array_type_p (array_type_p))
- abort ();
+ gcc_assert (is_array_type_p (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)
- abort ();
+ gcc_assert (TREE_CODE (element_type) == TYPE_DECL
+ && TREE_CODE (object_type) == TYPE_DECL);
if (!flag_store_check)
return build1 (NOP_EXPR, array_type_p, array);
}
/* Build an invocation of _Jv_CheckArrayStore */
- check = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_checkarraystore_node),
- tree_cons (NULL_TREE, array,
- build_tree_list (NULL_TREE, object)),
- NULL_TREE);
+ check = build_call_nary (void_type_node,
+ build_address_of (soft_checkarraystore_node),
+ 2, array, object);
TREE_SIDE_EFFECTS (check) = 1;
return check;
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
host_integerp (length, 0) == INTEGER_CST
? tree_low_cst (length, 0) : -1);
- /* If compiling to native, pass a reference to the primitive type class
- and save the runtime some work. However, the bytecode generator
- expects to find the type_code int here. */
- if (flag_emit_class_files)
- type_arg = build_int_cst (NULL_TREE, atype_value);
- else
- type_arg = build_class_ref (prim_type);
+ /* Pass a reference to the primitive type class and save the runtime
+ some work. */
+ type_arg = build_class_ref (prim_type);
- return build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_newarray_node),
- tree_cons (NULL_TREE,
- type_arg,
- build_tree_list (NULL_TREE, length)),
- NULL_TREE);
+ return build_call_nary (promote_type (type),
+ build_address_of (soft_newarray_node),
+ 2, type_arg, length);
}
/* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size
host_integerp (length, 0)
? tree_low_cst (length, 0) : -1);
- return build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_anewarray_node),
- tree_cons (NULL_TREE, length,
- tree_cons (NULL_TREE, build_class_ref (class_type),
- build_tree_list (NULL_TREE,
- null_pointer_node))),
- NULL_TREE);
+ return build_call_nary (promote_type (type),
+ build_address_of (soft_anewarray_node),
+ 3,
+ length,
+ build_class_ref (class_type),
+ null_pointer_node);
}
/* Return a node the evaluates 'new TYPE[LENGTH]'. */
for( i = 0; i < ndim; i++ )
args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
- push_value (build3 (CALL_EXPR,
- promote_type (class_type),
- build_address_of (soft_multianewarray_node),
- tree_cons (NULL_TREE, build_class_ref (class_type),
- tree_cons (NULL_TREE,
- build_int_cst (NULL_TREE, ndim),
- args)),
- NULL_TREE));
+ args = tree_cons (NULL_TREE,
+ build_class_ref (class_type),
+ tree_cons (NULL_TREE,
+ build_int_cst (NULL_TREE, ndim),
+ args));
+
+ push_value (build_call_list (promote_type (class_type),
+ build_address_of (soft_multianewarray_node),
+ args));
}
/* ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
&& TYPE_PRECISION (rhs_type_node) <= 32) ?
int_type_node : rhs_type_node);
tree index = pop_value (int_type_node);
- tree array_type, array;
+ tree array_type, array, temp, access;
- 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);
index = save_expr (index);
array = save_expr (array);
+ /* We want to perform the bounds check (done by
+ build_java_arrayaccess) before the type check (done by
+ build_java_arraystore_check). So, we call build_java_arrayaccess
+ -- which returns an ARRAY_REF lvalue -- and we then generate code
+ to stash the address of that lvalue in a temp. Then we call
+ build_java_arraystore_check, and finally we generate a
+ MODIFY_EXPR to set the array element. */
+
+ access = build_java_arrayaccess (array, rhs_type_node, index);
+ temp = build_decl (VAR_DECL, NULL_TREE,
+ build_pointer_type (TREE_TYPE (access)));
+ java_add_local_var (temp);
+ java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (temp),
+ temp,
+ build_fold_addr_expr (access)));
+
if (TREE_CODE (rhs_type_node) == POINTER_TYPE)
{
tree check = build_java_arraystore_check (array, rhs_node);
java_add_stmt (check);
}
- array = build_java_arrayaccess (array, rhs_type_node, index);
- java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (array), array, rhs_node));
+ java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (access),
+ build1 (INDIRECT_REF, TREE_TYPE (access), temp),
+ rhs_node));
}
/* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes
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);
- 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. */
- 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);
- load_node = build_java_arrayaccess (array_node,
- lhs_type_node,
- index_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);
if (INTEGRAL_TYPE_P (lhs_type_node) && TYPE_PRECISION (lhs_type_node) <= 32)
- load_node = fold (build1 (NOP_EXPR, int_type_node, load_node));
+ load_node = fold_build1 (NOP_EXPR, int_type_node, load_node);
push_value (load_node);
}
static tree
build_java_monitor (tree call, tree object)
{
- return build3 (CALL_EXPR,
- void_type_node,
- build_address_of (call),
- build_tree_list (NULL_TREE, object),
- NULL_TREE);
+ return build_call_nary (void_type_node,
+ build_address_of (call),
+ 1, object);
}
/* Emit code for one of the PUSHC instructions. */
value = build_real (type, x);
}
else
- abort ();
+ gcc_unreachable ();
push_value (value);
}
retval = build1(NOP_EXPR, TREE_TYPE(res), retval);
TREE_SIDE_EFFECTS (retval) = 1;
- java_add_stmt (build1 (RETURN_EXPR, TREE_TYPE (retval), retval));
+ java_add_stmt (build1 (RETURN_EXPR, void_type_node, retval));
}
}
value into it. Then we push this new local on the stack.
Hopefully this all gets optimized out. */
copy = build_decl (VAR_DECL, NULL_TREE, type);
+ if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
+ && TREE_TYPE (copy) != TREE_TYPE (var))
+ var = convert (type, var);
java_add_local_var (copy);
java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (var), copy, var));
? 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);
+ return build_call_nary (promote_type (type),
+ build_address_of (alloc_node),
+ 1, build_class_ref (type));
}
static void
if (! CLASS_LOADED_P (type))
load_class (type, 1);
safe_layout_class (type);
- push_value (build3 (CALL_EXPR, promote_type (type),
- build_address_of (alloc_node),
- build_tree_list (NULL_TREE, build_class_ref (type)),
- NULL_TREE));
+ push_value (build_call_nary (promote_type (type),
+ build_address_of (alloc_node),
+ 1, build_class_ref (type)));
}
/* This returns an expression which will extract the class of an
}
else
{
- expr = build3 (CALL_EXPR, itype,
- build_address_of (soft_instanceof_node),
- tree_cons (NULL_TREE, value,
- build_tree_list (NULL_TREE,
- build_class_ref (type))),
- NULL_TREE);
+ expr = build_call_nary (itype,
+ build_address_of (soft_instanceof_node),
+ 2, value, build_class_ref (type));
}
TREE_SIDE_EFFECTS (expr) = TREE_SIDE_EFFECTS (value);
return expr;
expand_java_CHECKCAST (tree type)
{
tree value = pop_value (ptr_type_node);
- value = build3 (CALL_EXPR, promote_type (type),
- build_address_of (soft_checkcast_node),
- tree_cons (NULL_TREE, build_class_ref (type),
- build_tree_list (NULL_TREE, value)),
- NULL_TREE);
+ value = build_call_nary (promote_type (type),
+ build_address_of (soft_checkcast_node),
+ 2, build_class_ref (type), value);
push_value (value);
}
flush_quick_stack ();
local_var = find_local_variable (local_var_index, int_type_node, pc);
constant_value = build_int_cst (NULL_TREE, ival);
- res = fold (build2 (PLUS_EXPR, int_type_node, local_var, constant_value));
+ res = fold_build2 (PLUS_EXPR, int_type_node, local_var, constant_value);
java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (local_var), local_var, res));
- update_aliases (local_var, local_var_index, pc);
}
}
}
- if (! call)
- abort ();
-
- call = build3 (CALL_EXPR, type,
- build_address_of (call),
- tree_cons (NULL_TREE, arg1,
- build_tree_list (NULL_TREE, arg2)),
- NULL_TREE);
-
+ gcc_assert (call);
+ call = build_call_nary (type, build_address_of (call), 2, arg1, arg2);
return call;
}
{
case URSHIFT_EXPR:
{
- tree u_type = java_unsigned_type (type);
+ tree u_type = unsigned_type_for (type);
arg1 = convert (u_type, arg1);
arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2);
return convert (type, arg1);
case RSHIFT_EXPR:
mask = build_int_cst (NULL_TREE,
TYPE_PRECISION (TREE_TYPE (arg1)) - 1);
- arg2 = fold (build2 (BIT_AND_EXPR, int_type_node, arg2, mask));
+ arg2 = fold_build2 (BIT_AND_EXPR, int_type_node, arg2, mask);
break;
case COMPARE_L_EXPR: /* arg1 > arg2 ? 1 : arg1 == arg2 ? 0 : -1 */
case COMPARE_G_EXPR: /* arg1 < arg2 ? -1 : arg1 == arg2 ? 0 : 1 */
arg1 = save_expr (arg1); arg2 = save_expr (arg2);
{
- tree ifexp1 = fold (build2 (op == COMPARE_L_EXPR ? GT_EXPR : LT_EXPR,
- boolean_type_node, arg1, arg2));
- tree ifexp2 = fold (build2 (EQ_EXPR, boolean_type_node, arg1, arg2));
- tree second_compare = fold (build3 (COND_EXPR, int_type_node,
- ifexp2, integer_zero_node,
- op == COMPARE_L_EXPR
- ? integer_minus_one_node
- : integer_one_node));
- return fold (build3 (COND_EXPR, int_type_node, ifexp1,
- op == COMPARE_L_EXPR ? integer_one_node
- : integer_minus_one_node,
- second_compare));
+ tree ifexp1 = fold_build2 (op == COMPARE_L_EXPR ? GT_EXPR : LT_EXPR,
+ boolean_type_node, arg1, arg2);
+ tree ifexp2 = fold_build2 (EQ_EXPR, boolean_type_node, arg1, arg2);
+ tree second_compare = fold_build3 (COND_EXPR, int_type_node,
+ ifexp2, integer_zero_node,
+ op == COMPARE_L_EXPR
+ ? integer_minus_one_node
+ : integer_one_node);
+ return fold_build3 (COND_EXPR, int_type_node, ifexp1,
+ op == COMPARE_L_EXPR ? integer_one_node
+ : integer_minus_one_node,
+ second_compare);
}
case COMPARE_EXPR:
arg1 = save_expr (arg1); arg2 = save_expr (arg2);
{
- tree ifexp1 = fold (build2 (LT_EXPR, boolean_type_node, arg1, arg2));
- tree ifexp2 = fold (build2 (GT_EXPR, boolean_type_node, arg1, arg2));
- tree second_compare = fold (build3 (COND_EXPR, int_type_node,
- ifexp2, integer_one_node,
- integer_zero_node));
- return fold (build3 (COND_EXPR, int_type_node,
- ifexp1, integer_minus_one_node, second_compare));
+ tree ifexp1 = fold_build2 (LT_EXPR, boolean_type_node, arg1, arg2);
+ tree ifexp2 = fold_build2 (GT_EXPR, boolean_type_node, arg1, arg2);
+ tree second_compare = fold_build3 (COND_EXPR, int_type_node,
+ ifexp2, integer_one_node,
+ integer_zero_node);
+ return fold_build3 (COND_EXPR, int_type_node,
+ ifexp1, integer_minus_one_node, second_compare);
}
case TRUNC_DIV_EXPR:
case TRUNC_MOD_EXPR:
arg1 = convert (double_type_node, arg1);
arg2 = convert (double_type_node, arg2);
}
- call = build3 (CALL_EXPR, double_type_node,
- build_address_of (soft_fmod_node),
- tree_cons (NULL_TREE, arg1,
- build_tree_list (NULL_TREE, arg2)),
- NULL_TREE);
+ call = build_call_nary (double_type_node,
+ build_address_of (soft_fmod_node),
+ 2, arg1, arg2);
if (type != double_type_node)
call = convert (type, call);
return call;
break;
default: ;
}
- return fold (build2 (op, type, arg1, arg2));
+ return fold_build2 (op, type, arg1, arg2);
}
static void
}
else
{
- int check = (flag_check_references
- && ! (DECL_P (self_value)
- && DECL_NAME (self_value) == this_identifier_node));
-
tree base_type = promote_type (base_class);
+
+ /* CHECK is true if self_value is not the this pointer. */
+ int check = (! (DECL_P (self_value)
+ && DECL_NAME (self_value) == this_identifier_node));
+
+ /* Determine whether a field offset from NULL will lie within
+ Page 0: this is necessary on those GNU/Linux/BSD systems that
+ trap SEGV to generate NullPointerExceptions.
+
+ We assume that Page 0 will be mapped with NOPERM, and that
+ memory may be allocated from any other page, so only field
+ offsets < pagesize are guaranteed to trap. We also assume
+ the smallest page size we'll encounter is 4k bytes. */
+ if (! flag_syntax_only && check && ! flag_check_references
+ && ! flag_indirect_dispatch)
+ {
+ tree field_offset = byte_position (field_decl);
+ if (! page_size)
+ page_size = size_int (4096);
+ check = ! INT_CST_LT_UNSIGNED (field_offset, page_size);
+ }
+
if (base_type != TREE_TYPE (self_value))
- self_value = fold (build1 (NOP_EXPR, base_type, self_value));
- 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))
+ self_value = fold_build1 (NOP_EXPR, base_type, self_value);
+ if (! flag_syntax_only && flag_indirect_dispatch)
{
tree otable_index
= build_int_cst (NULL_TREE, get_symbol_table_index
- (field_decl, &TYPE_OTABLE_METHODS (output_class)));
+ (field_decl, NULL_TREE,
+ &TYPE_OTABLE_METHODS (output_class)));
tree field_offset
= build4 (ARRAY_REF, integer_type_node,
TYPE_OTABLE_DECL (output_class), otable_index,
NULL_TREE, NULL_TREE);
tree address;
+ if (DECL_CONTEXT (field_decl) != output_class)
+ field_offset
+ = build3 (COND_EXPR, TREE_TYPE (field_offset),
+ build2 (EQ_EXPR, boolean_type_node,
+ field_offset, integer_zero_node),
+ build_call_nary (void_type_node,
+ build_address_of (soft_nosuchfield_node),
+ 1, otable_index),
+ field_offset);
+
field_offset = fold (convert (sizetype, field_offset));
+ self_value = java_check_reference (self_value, check);
address
- = fold (build2 (PLUS_EXPR,
- build_pointer_type (TREE_TYPE (field_decl)),
- self_value, field_offset));
- return fold (build1 (INDIRECT_REF, TREE_TYPE (field_decl), address));
+ = fold_build2 (POINTER_PLUS_EXPR,
+ TREE_TYPE (self_value),
+ self_value, field_offset);
+ address = fold_convert (build_pointer_type (TREE_TYPE (field_decl)),
+ address);
+ return fold_build1 (INDIRECT_REF, TREE_TYPE (field_decl), address);
}
self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
self_value, check);
- return fold (build3 (COMPONENT_REF, TREE_TYPE (field_decl),
- self_value, field_decl, NULL_TREE));
+ return fold_build3 (COMPONENT_REF, TREE_TYPE (field_decl),
+ self_value, field_decl, NULL_TREE);
}
}
{
tree name;
char buf[32];
- ASM_GENERATE_INTERNAL_LABEL(buf, "LJpc=", pc);
+ if (pc > highest_label_pc_this_method)
+ highest_label_pc_this_method = pc;
+ ASM_GENERATE_INTERNAL_LABEL(buf, "LJpc=", start_label_pc_this_method + pc);
name = get_identifier (buf);
if (IDENTIFIER_LOCAL_VALUE (name))
return IDENTIFIER_LOCAL_VALUE (name);
{
/* The type of the address of a label is return_address_type_node. */
tree decl = create_label_decl (name);
- LABEL_PC (decl) = pc;
return pushdecl (decl);
}
}
return decl;
}
-/* This maps a bytecode offset (PC) to various flags. */
+/* This maps a bytecode offset (PC) to various flags. */
char *instruction_bits;
+/* This is a vector of type states for the current method. It is
+ indexed by PC. Each element is a tree vector holding the type
+ state at that PC. We only note type states at basic block
+ boundaries. */
+VEC(tree, gc) *type_states;
+
static void
note_label (int current_pc ATTRIBUTE_UNUSED, int target_pc)
{
int target_pc)
{
tree target = lookup_label (target_pc);
- tree cond = fold (build2 (condition, boolean_type_node, value1, value2));
+ tree cond = fold_build2 (condition, boolean_type_node, value1, value2);
java_add_stmt
(build3 (COND_EXPR, void_type_node, java_truthvalue_conversion (cond),
build1 (GOTO_EXPR, void_type_node, target),
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)
arg = convert (integer_type_node, arg);
return tree_cons (NULL_TREE, arg, tail);
}
- abort ();
+ gcc_unreachable ();
}
/* Attach to PTR (a block) the declaration found in ENTRY. */
if (always_initialize_class_p)
{
- init = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE, build_class_ref (clas)),
- NULL_TREE);
+ init = build_call_nary (void_type_node,
+ build_address_of (soft_initclass_node),
+ 1, build_class_ref (clas));
TREE_SIDE_EFFECTS (init) = 1;
}
else
decl = build_decl (VAR_DECL, NULL_TREE,
boolean_type_node);
MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl);
- LOCAL_CLASS_INITIALIZATION_FLAG (decl) = 1;
DECL_CONTEXT (decl) = current_function_decl;
- DECL_FUNCTION_INIT_TEST_CLASS (decl) = clas;
- /* Tell the check-init code to ignore this decl when not
- optimizing class initialization. */
- if (!STATIC_CLASS_INIT_OPT_P ())
- DECL_BIT_INDEX (decl) = -1;
DECL_INITIAL (decl) = boolean_false_node;
/* Don't emit any symbolic debugging info for this decl. */
DECL_IGNORED_P (decl) = 1;
*init_test_decl = decl;
}
- init = build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_initclass_node),
- build_tree_list (NULL_TREE, build_class_ref (clas)),
- NULL_TREE);
+ init = build_call_nary (void_type_node,
+ build_address_of (soft_initclass_node),
+ 1, build_class_ref (clas));
TREE_SIDE_EFFECTS (init) = 1;
init = build3 (COND_EXPR, void_type_node,
build2 (EQ_EXPR, boolean_type_node,
return init;
}
+\f
+
+/* Rewrite expensive calls that require stack unwinding at runtime to
+ cheaper alternatives. The logic here performs these
+ transformations:
+
+ java.lang.Class.forName("foo") -> java.lang.Class.forName("foo", class$)
+ java.lang.Class.getClassLoader() -> java.lang.Class.getClassLoader(class$)
+
+*/
+
+typedef struct
+{
+ const char *classname;
+ const char *method;
+ const char *signature;
+ const char *new_signature;
+ int flags;
+ tree (*rewrite_arglist) (tree arglist);
+} rewrite_rule;
+
+/* Add __builtin_return_address(0) to the end of an arglist. */
+
+
+static tree
+rewrite_arglist_getcaller (tree arglist)
+{
+ tree retaddr
+ = build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
+ 1, integer_zero_node);
+
+ DECL_INLINE (current_function_decl) = 0;
+
+ return chainon (arglist,
+ tree_cons (NULL_TREE, retaddr,
+ NULL_TREE));
+}
+
+/* Add this.class to the end of an arglist. */
+
+static tree
+rewrite_arglist_getclass (tree arglist)
+{
+ return chainon (arglist,
+ tree_cons (NULL_TREE, build_class_ref (output_class),
+ NULL_TREE));
+}
+
+static rewrite_rule rules[] =
+ {{"java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;",
+ "(Ljava/lang/Class;)Ljava/lang/ClassLoader;",
+ ACC_FINAL|ACC_PRIVATE, rewrite_arglist_getclass},
+ {"java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;",
+ "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;",
+ ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getclass},
+ {"gnu.classpath.VMStackWalker", "getCallingClass", "()Ljava/lang/Class;",
+ "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
+ ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+ {"gnu.classpath.VMStackWalker", "getCallingClassLoader",
+ "()Ljava/lang/ClassLoader;",
+ "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
+ ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+
+ {NULL, NULL, NULL, NULL, 0, NULL}};
+
+/* True if this method is special, i.e. it's a private method that
+ should be exported from a DSO. */
+
+bool
+special_method_p (tree candidate_method)
+{
+ tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (candidate_method)));
+ tree method = DECL_NAME (candidate_method);
+ rewrite_rule *p;
+
+ for (p = rules; p->classname; p++)
+ {
+ if (get_identifier (p->classname) == context
+ && get_identifier (p->method) == method)
+ return true;
+ }
+ return false;
+}
+
+/* Scan the rules list for replacements for *METHOD_P and replace the
+ args accordingly. If the rewrite results in an access to a private
+ method, update SPECIAL.*/
+
+void
+maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
+ tree *method_signature_p, tree *special)
+{
+ tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (*method_p)));
+ rewrite_rule *p;
+ *special = NULL_TREE;
+
+ for (p = rules; p->classname; p++)
+ {
+ if (get_identifier (p->classname) == context)
+ {
+ tree method = DECL_NAME (*method_p);
+ if (get_identifier (p->method) == method
+ && get_identifier (p->signature) == *method_signature_p)
+ {
+ tree maybe_method
+ = lookup_java_method (DECL_CONTEXT (*method_p),
+ method,
+ get_identifier (p->new_signature));
+ if (! maybe_method && ! flag_verify_invocations)
+ {
+ maybe_method
+ = add_method (DECL_CONTEXT (*method_p), p->flags,
+ method, get_identifier (p->new_signature));
+ DECL_EXTERNAL (maybe_method) = 1;
+ }
+ *method_p = maybe_method;
+ gcc_assert (*method_p);
+ *arg_list_p = p->rewrite_arglist (*arg_list_p);
+ *method_signature_p = get_identifier (p->new_signature);
+ *special = integer_one_node;
+
+ break;
+ }
+ }
+ }
+}
+
+\f
+
tree
build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
tree self_type, tree method_signature ATTRIBUTE_UNUSED,
- tree arg_list ATTRIBUTE_UNUSED)
+ tree arg_list ATTRIBUTE_UNUSED, tree special)
{
tree func;
if (is_compiled_class (self_type))
if (! flag_indirect_dispatch
|| (! DECL_EXTERNAL (method) && ! TREE_PUBLIC (method)))
{
- make_decl_rtl (method);
func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)),
method);
}
else
{
tree table_index
- = build_int_cst (NULL_TREE, get_symbol_table_index
- (method, &TYPE_ATABLE_METHODS (output_class)));
+ = build_int_cst (NULL_TREE,
+ (get_symbol_table_index
+ (method, special,
+ &TYPE_ATABLE_METHODS (output_class))));
func
= build4 (ARRAY_REF,
TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))),
method_index++;
}
method_index *= int_size_in_bytes (method_type_node);
- ref = fold (build2 (PLUS_EXPR, method_ptr_type_node,
- ref, build_int_cst (NULL_TREE, method_index)));
+ ref = fold_build2 (POINTER_PLUS_EXPR, method_ptr_type_node,
+ ref, size_int (method_index));
ref = build1 (INDIRECT_REF, method_type_node, ref);
func = build3 (COMPONENT_REF, nativecode_ptr_type_node,
ref, lookup_field (&method_type_node, ncode_ident),
reused. */
int
-get_symbol_table_index (tree t, tree *symbol_table)
+get_symbol_table_index (tree t, tree special, tree *symbol_table)
{
int i = 1;
tree method_list;
if (*symbol_table == NULL_TREE)
{
- *symbol_table = build_tree_list (t, t);
+ *symbol_table = build_tree_list (special, t);
return 1;
}
while (1)
{
tree value = TREE_VALUE (method_list);
- if (value == t)
+ tree purpose = TREE_PURPOSE (method_list);
+ if (value == t && purpose == special)
return i;
i++;
if (TREE_CHAIN (method_list) == NULL_TREE)
method_list = TREE_CHAIN (method_list);
}
- TREE_CHAIN (method_list) = build_tree_list (t, t);
+ TREE_CHAIN (method_list) = build_tree_list (special, t);
return i;
}
tree
-build_invokevirtual (tree dtable, tree method)
+build_invokevirtual (tree dtable, tree method, tree special)
{
tree func;
tree nativecode_ptr_ptr_type_node
if (flag_indirect_dispatch)
{
- if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))
- abort ();
+ gcc_assert (! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))));
otable_index
= build_int_cst (NULL_TREE, get_symbol_table_index
- (method, &TYPE_OTABLE_METHODS (output_class)));
+ (method, special,
+ &TYPE_OTABLE_METHODS (output_class)));
method_index = build4 (ARRAY_REF, integer_type_node,
TYPE_OTABLE_DECL (output_class),
otable_index, NULL_TREE, NULL_TREE);
size_int (TARGET_VTABLE_USES_DESCRIPTORS));
}
- func = fold (build2 (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable,
- convert (nativecode_ptr_ptr_type_node, method_index)));
+ func = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (dtable), dtable,
+ convert (sizetype, method_index));
if (TARGET_VTABLE_USES_DESCRIPTORS)
func = build1 (NOP_EXPR, nativecode_ptr_type_node, func);
else
- func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+ {
+ func = fold_convert (nativecode_ptr_ptr_type_node, func);
+ func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func);
+ }
return func;
}
tree
build_invokeinterface (tree dtable, tree method)
{
- tree lookup_arg;
tree interface;
tree idx;
lookup_field (&dtable_type, class_ident), NULL_TREE);
interface = DECL_CONTEXT (method);
- if (! CLASS_INTERFACE (TYPE_NAME (interface)))
- abort ();
+ gcc_assert (CLASS_INTERFACE (TYPE_NAME (interface)));
layout_class_methods (interface);
if (flag_indirect_dispatch)
{
int itable_index
= 2 * (get_symbol_table_index
- (method, &TYPE_ITABLE_METHODS (output_class)));
+ (method, NULL_TREE, &TYPE_ITABLE_METHODS (output_class)));
interface
= build4 (ARRAY_REF,
TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))),
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);
+ return build_call_nary (ptr_type_node,
+ build_address_of (soft_lookupinterfacemethod_node),
+ 3, dtable, interface, idx);
}
/* Expand one of the invoke_* opcodes.
tree call, func, method, arg_list, method_type;
tree check = NULL_TREE;
+ tree special = NULL_TREE;
+
if (! CLASS_LOADED_P (self_type))
{
load_class (self_type, 1);
else
method = lookup_java_method (self_type, method_name, method_signature);
+ /* We've found a method in a class other than the one in which it
+ was wanted. This can happen if, for instance, we're trying to
+ compile invokespecial super.equals().
+ FIXME: This is a kludge. Rather than nullifying the result, we
+ should change lookup_java_method() so that it doesn't search the
+ superclass chain when we're BC-compiling. */
+ if (! flag_verify_invocations
+ && method
+ && ! TYPE_ARRAY_P (self_type)
+ && self_type != DECL_CONTEXT (method))
+ method = NULL_TREE;
+
/* We've found a method in an interface, but this isn't an interface
call. */
if (opcode != OPCODE_invokeinterface
arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
flush_quick_stack ();
+ maybe_rewrite_invocation (&method, &arg_list, &method_signature,
+ &special);
+
func = NULL_TREE;
if (opcode == OPCODE_invokestatic)
func = build_known_method_ref (method, method_type, self_type,
- method_signature, arg_list);
+ method_signature, arg_list, special);
else if (opcode == OPCODE_invokespecial
|| (opcode == OPCODE_invokevirtual
&& (METHOD_PRIVATE (method)
TREE_VALUE (arg_list) = save_arg;
check = java_check_reference (save_arg, ! DECL_INIT_P (method));
func = build_known_method_ref (method, method_type, self_type,
- method_signature, arg_list);
+ method_signature, arg_list, special);
}
else
{
tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface,
arg_list);
if (opcode == OPCODE_invokevirtual)
- func = build_invokevirtual (dtable, method);
+ func = build_invokevirtual (dtable, method, special);
else
func = build_invokeinterface (dtable, method);
}
else
func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
- call = build3 (CALL_EXPR, TREE_TYPE (method_type),
- func, arg_list, NULL_TREE);
+ call = build_call_list (TREE_TYPE (method_type), func, arg_list);
TREE_SIDE_EFFECTS (call) = 1;
call = check_for_builtin (method, call);
tree
build_jni_stub (tree method)
{
- tree jnifunc, call, args, body, lookup_arg, method_sig, arg_types;
+ tree jnifunc, call, args, body, method_sig, arg_types;
+ tree jniarg0, jniarg1, jniarg2, jniarg3;
tree jni_func_type, tem;
tree env_var, res_var = NULL_TREE, block;
tree method_args, res_type;
int args_size = 0;
tree klass = DECL_CONTEXT (method);
- int from_class = ! CLASS_FROM_SOURCE_P (klass);
klass = build_class_ref (klass);
- if (! METHOD_NATIVE (method) || ! flag_jni)
- abort ();
+ gcc_assert (METHOD_NATIVE (method) && flag_jni);
DECL_ARTIFICIAL (method) = 1;
DECL_EXTERNAL (method) = 0;
chainon (env_var, meth_var);
build_result_decl (method);
- /* One strange way that the front ends are different is that they
- store arguments differently. */
- if (from_class)
- method_args = DECL_ARGUMENTS (method);
- else
- method_args = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (method));
- block = build_block (env_var, NULL_TREE, NULL_TREE,
- method_args, NULL_TREE);
+ method_args = DECL_ARGUMENTS (method);
+ block = build_block (env_var, NULL_TREE, method_args, NULL_TREE);
TREE_SIDE_EFFECTS (block) = 1;
- /* When compiling from source we don't set the type of the block,
- because that will prevent patch_return from ever being run. */
- if (from_class)
- TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
+ TREE_TYPE (block) = TREE_TYPE (TREE_TYPE (method));
/* Compute the local `env' by calling _Jv_GetJNIEnvNewFrame. */
body = build2 (MODIFY_EXPR, ptr_type_node, env_var,
- build3 (CALL_EXPR, ptr_type_node,
- build_address_of (soft_getjnienvnewframe_node),
- build_tree_list (NULL_TREE, klass),
- NULL_TREE));
- CAN_COMPLETE_NORMALLY (body) = 1;
+ build_call_nary (ptr_type_node,
+ build_address_of (soft_getjnienvnewframe_node),
+ 1, klass));
/* All the arguments to this method become arguments to the
underlying JNI function. If we had to wrap object arguments in a
args = NULL_TREE;
for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
{
- int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (tem)));
+ int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
#ifdef PARM_BOUNDARY
arg_bits = (((arg_bits + PARM_BOUNDARY - 1) / PARM_BOUNDARY)
* PARM_BOUNDARY);
/* We call _Jv_LookupJNIMethod to find the actual underlying
function pointer. _Jv_LookupJNIMethod will throw the appropriate
exception if this function is not found at runtime. */
- tem = build_tree_list (NULL_TREE, build_int_cst (NULL_TREE, args_size));
method_sig = build_java_signature (TREE_TYPE (method));
- lookup_arg = tree_cons (NULL_TREE,
- build_utf8_ref (unmangle_classname
- (IDENTIFIER_POINTER (method_sig),
- IDENTIFIER_LENGTH (method_sig))),
- tem);
- tem = DECL_NAME (method);
- lookup_arg
- = tree_cons (NULL_TREE, klass,
- tree_cons (NULL_TREE, build_utf8_ref (tem), lookup_arg));
-
+ jniarg0 = klass;
+ jniarg1 = build_utf8_ref (DECL_NAME (method));
+ jniarg2 = build_utf8_ref (unmangle_classname
+ (IDENTIFIER_POINTER (method_sig),
+ IDENTIFIER_LENGTH (method_sig)));
+ jniarg3 = build_int_cst (NULL_TREE, args_size);
+
tem = build_function_type (TREE_TYPE (TREE_TYPE (method)), arg_types);
#ifdef MODIFY_JNI_METHOD_CALL
jni_func_type = build_pointer_type (tem);
jnifunc = build3 (COND_EXPR, ptr_type_node,
- meth_var, meth_var,
+ build2 (NE_EXPR, boolean_type_node,
+ meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
+ meth_var,
build2 (MODIFY_EXPR, ptr_type_node, meth_var,
- build3 (CALL_EXPR, ptr_type_node,
- build_address_of
- (soft_lookupjnimethod_node),
- lookup_arg, NULL_TREE)));
+ build_call_nary (ptr_type_node,
+ build_address_of
+ (soft_lookupjnimethod_node),
+ 4,
+ jniarg0, jniarg1,
+ jniarg2, jniarg3)));
/* Now we make the actual JNI call via the resulting function
pointer. */
- call = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
- build1 (NOP_EXPR, jni_func_type, jnifunc),
- args, NULL_TREE);
+ call = build_call_list (TREE_TYPE (TREE_TYPE (method)),
+ build1 (NOP_EXPR, jni_func_type, jnifunc),
+ args);
/* If the JNI call returned a result, capture it here. If we had to
unwrap JNI object results, we would do that here. */
if (res_var != NULL_TREE)
- call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
- res_var, call);
+ {
+ /* If the call returns an object, it may return a JNI weak
+ reference, in which case we must unwrap it. */
+ if (! JPRIMITIVE_TYPE_P (TREE_TYPE (TREE_TYPE (method))))
+ call = build_call_nary (TREE_TYPE (TREE_TYPE (method)),
+ build_address_of (soft_unwrapjni_node),
+ 1, call);
+ call = build2 (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (method)),
+ res_var, call);
+ }
TREE_SIDE_EFFECTS (call) = 1;
- CAN_COMPLETE_NORMALLY (call) = 1;
body = build2 (COMPOUND_EXPR, void_type_node, body, call);
TREE_SIDE_EFFECTS (body) = 1;
/* Now free the environment we allocated. */
- call = build3 (CALL_EXPR, ptr_type_node,
- build_address_of (soft_jnipopsystemframe_node),
- build_tree_list (NULL_TREE, env_var),
- NULL_TREE);
+ call = build_call_nary (ptr_type_node,
+ build_address_of (soft_jnipopsystemframe_node),
+ 1, env_var);
TREE_SIDE_EFFECTS (call) = 1;
- CAN_COMPLETE_NORMALLY (call) = 1;
body = build2 (COMPOUND_EXPR, void_type_node, body, call);
TREE_SIDE_EFFECTS (body) = 1;
if (res_var != NULL_TREE)
{
tree drt;
- if (! DECL_RESULT (method))
- abort ();
+ gcc_assert (DECL_RESULT (method));
/* Make sure we copy the result variable to the actual
result. We use the type of the DECL_RESULT because it
might be different from the return type of the function:
}
body = build2 (COMPOUND_EXPR, void_type_node, body,
- build1 (RETURN_EXPR, res_type, res_var));
+ build1 (RETURN_EXPR, void_type_node, res_var));
TREE_SIDE_EFFECTS (body) = 1;
+ /* Prepend class initialization for static methods reachable from
+ other classes. */
+ if (METHOD_STATIC (method)
+ && (! METHOD_PRIVATE (method)
+ || INNER_CLASS_P (DECL_CONTEXT (method))))
+ {
+ tree init = build_call_expr (soft_initclass_node, 1,
+ klass);
+ body = build2 (COMPOUND_EXPR, void_type_node, init, body);
+ TREE_SIDE_EFFECTS (body) = 1;
+ }
+
bind = build3 (BIND_EXPR, void_type_node, BLOCK_VARS (block),
body, block);
return bind;
}
+
+/* Given lvalue EXP, return a volatile expression that references the
+ same object. */
+
+tree
+java_modify_addr_for_volatile (tree exp)
+{
+ tree exp_type = TREE_TYPE (exp);
+ tree v_type
+ = build_qualified_type (exp_type,
+ TYPE_QUALS (exp_type) | TYPE_QUAL_VOLATILE);
+ tree addr = build_fold_addr_expr (exp);
+ v_type = build_pointer_type (v_type);
+ addr = fold_convert (v_type, addr);
+ exp = build_fold_indirect_ref (addr);
+ return exp;
+}
+
+
/* Expand an operation to extract from or store into a field.
IS_STATIC is 1 iff the field is static.
IS_PUTTING is 1 for putting into a field; 0 for getting from the field.
int is_error = 0;
tree original_self_type = self_type;
tree field_decl;
+ tree modify_expr;
if (! CLASS_LOADED_P (self_type))
load_class (self_type, 1);
field_type, flags);
DECL_ARTIFICIAL (field_decl) = 1;
DECL_IGNORED_P (field_decl) = 1;
+#if 0
+ /* FIXME: We should be pessimistic about volatility. We
+ don't know one way or another, but this is safe.
+ However, doing this has bad effects on code quality. We
+ need to look at better ways to do this. */
+ TREE_THIS_VOLATILE (field_decl) = 1;
+#endif
}
else
{
}
field_ref = build_field_ref (field_ref, self_type, field_name);
- if (is_static)
- field_ref = build_class_init (self_type, field_ref);
+ if (is_static
+ && ! flag_indirect_dispatch)
+ {
+ tree context = DECL_CONTEXT (field_ref);
+ if (context != self_type && CLASS_INTERFACE (TYPE_NAME (context)))
+ field_ref = build_class_init (context, field_ref);
+ else
+ field_ref = build_class_init (self_type, field_ref);
+ }
if (is_putting)
{
flush_quick_stack ();
if (FIELD_FINAL (field_decl))
{
if (DECL_CONTEXT (field_decl) != current_class)
- error ("%Jassignment to final field '%D' not in field's class",
- field_decl, field_decl);
- else if (FIELD_STATIC (field_decl))
- {
- if (!DECL_CLINIT_P (current_function_decl))
- warning ("%Jassignment to final static field %qD not in "
- "class initializer",
- field_decl, field_decl);
- }
- else
- {
- tree cfndecl_name = DECL_NAME (current_function_decl);
- if (! DECL_CONSTRUCTOR_P (current_function_decl)
- && !ID_FINIT_P (cfndecl_name))
- warning ("%Jassignment to final field '%D' not in constructor",
- field_decl, field_decl);
- }
- }
- java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (field_ref),
- field_ref, new_value));
+ error ("assignment to final field %q+D not in field's class",
+ field_decl);
+ /* We used to check for assignments to final fields not
+ occurring in the class initializer or in a constructor
+ here. However, this constraint doesn't seem to be
+ enforced by the JVM. */
+ }
+
+ if (TREE_THIS_VOLATILE (field_decl))
+ field_ref = java_modify_addr_for_volatile (field_ref);
+
+ modify_expr = build2 (MODIFY_EXPR, TREE_TYPE (field_ref),
+ field_ref, new_value);
+
+ if (TREE_THIS_VOLATILE (field_decl))
+ java_add_stmt
+ (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
+
+ java_add_stmt (modify_expr);
}
else
- push_value (field_ref);
+ {
+ tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
+ java_add_local_var (temp);
+
+ if (TREE_THIS_VOLATILE (field_decl))
+ field_ref = java_modify_addr_for_volatile (field_ref);
+
+ modify_expr
+ = build2 (MODIFY_EXPR, TREE_TYPE (field_ref), temp, field_ref);
+ java_add_stmt (modify_expr);
+
+ if (TREE_THIS_VOLATILE (field_decl))
+ java_add_stmt
+ (build_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], 0));
+
+ push_value (temp);
+ }
+ TREE_THIS_VOLATILE (field_ref) = TREE_THIS_VOLATILE (field_decl);
}
-void
-load_type_state (tree label)
+static void
+load_type_state (int pc)
{
int i;
- tree vec = LABEL_TYPE_STATE (label);
+ tree vec = VEC_index (tree, type_states, pc);
int cur_length = TREE_VEC_LENGTH (vec);
stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl);
for (i = 0; i < cur_length; i++)
byte_ops = jcf->read_ptr;
instruction_bits = xrealloc (instruction_bits, length + 1);
memset (instruction_bits, 0, length + 1);
+ type_states = VEC_alloc (tree, gc, length + 1);
+ VEC_safe_grow_cleared (tree, gc, type_states, length + 1);
/* This pass figures out which PC can be the targets of jumps. */
for (PC = 0; PC < length;)
int pc = GET_u2 (linenumber_pointer);
linenumber_pointer += 4;
if (pc >= length)
- warning ("invalid PC in line number table");
+ warning (0, "invalid PC in line number table");
else
{
if ((instruction_bits[pc] & BCODE_HAS_LINENUMBER) != 0)
}
}
- 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 ();
+ cache_this_class_ref (method);
+ cache_cpool_data_ref ();
/* Translate bytecodes. */
linenumber_pointer = linenumber_table;
flush_quick_stack ();
if ((instruction_bits [PC] & BCODE_TARGET) != 0)
java_add_stmt (build1 (LABEL_EXPR, void_type_node, label));
- if (LABEL_VERIFIED (label) || PC == 0)
- load_type_state (label);
+ if ((instruction_bits[PC] & BCODE_VERIFIED) != 0)
+ load_type_state (PC);
}
if (! (instruction_bits [PC] & BCODE_VERIFIED))
{
/* We've just reached the end of a region of dead code. */
if (extra_warnings)
- warning ("unreachable bytecode from %d to before %d",
+ warning (0, "unreachable bytecode from %d to before %d",
dead_code_index, PC);
dead_code_index = -1;
}
PC = process_jvm_instruction (PC, byte_ops, length);
maybe_poplevels (PC);
} /* for */
-
+
+ uncache_this_class_ref (method);
+
if (dead_code_index != -1)
{
/* We've just reached the end of a region of dead code. */
if (extra_warnings)
- warning ("unreachable bytecode from %d to the end of the method",
+ warning (0, "unreachable bytecode from %d to the end of the method",
dead_code_index);
}
}
c = build_ref_from_constant_pool (index);
c = convert (promote_type (string_type_node), c);
}
+ else if (JPOOL_TAG (jcf, index) == CONSTANT_Class
+ || JPOOL_TAG (jcf, index) == CONSTANT_ResolvedClass)
+ {
+ tree record = get_class_constant (jcf, index);
+ c = build_class_ref (record);
+ }
else
c = get_constant (jcf, index);
push_value (c);
const char *opname; /* Temporary ??? */
int oldpc = PC; /* PC at instruction start. */
- /* If the instruction is at the beginning of a exception handler,
- replace the top of the stack with the thrown object reference */
+ /* If the instruction is at the beginning of an exception handler,
+ 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));
}
#define UNOP(OPERAND_TYPE, OPERAND_VALUE) \
- push_value (fold (build1 (NEGATE_EXPR, OPERAND_TYPE##_type_node, \
- pop_value (OPERAND_TYPE##_type_node))));
+ push_value (fold_build1 (NEGATE_EXPR, OPERAND_TYPE##_type_node, \
+ pop_value (OPERAND_TYPE##_type_node)));
#define CONVERT2(FROM_TYPE, TO_TYPE) \
{ \
decl = find_local_variable (index, type, oldpc); \
set_local_type (index, type); \
java_add_stmt (build2 (MODIFY_EXPR, type, decl, value)); \
- update_aliases (decl, index, PC); \
}
#define STORE(OPERAND_TYPE, OPERAND_VALUE) \
This function is used by `give_name_to_locals' so that a local's
DECL features a DECL_LOCAL_START_PC such that the first related
- store operation will use DECL as a destination, not a unrelated
+ store operation will use DECL as a destination, not an unrelated
temporary created for the occasion.
This function uses a global (instruction_bits) `note_instructions' should
For method invocation, we modify the arguments so that a
left-to-right order evaluation is performed. Saved expressions
will, in CALL_EXPR order, be reused when the call will be expanded.
-*/
+
+ We also promote outgoing args if needed. */
tree
force_evaluation_order (tree node)
if (flag_syntax_only)
return node;
if (TREE_CODE (node) == CALL_EXPR
- || TREE_CODE (node) == NEW_CLASS_EXPR
|| (TREE_CODE (node) == COMPOUND_EXPR
&& TREE_CODE (TREE_OPERAND (node, 0)) == CALL_EXPR
&& TREE_CODE (TREE_OPERAND (node, 1)) == SAVE_EXPR))
{
- tree arg, cmp;
+ tree call, cmp;
+ int i, nargs;
- arg = node;
-
- /* Position arg properly, account for wrapped around ctors. */
+ /* Account for wrapped around ctors. */
if (TREE_CODE (node) == COMPOUND_EXPR)
- arg = TREE_OPERAND (node, 0);
-
- arg = TREE_OPERAND (arg, 1);
-
- /* An empty argument list is ok, just ignore it. */
- if (!arg)
- return node;
+ call = TREE_OPERAND (node, 0);
+ else
+ call = node;
- /* Not having a list of arguments here is an error. */
- if (TREE_CODE (arg) != TREE_LIST)
- abort ();
+ nargs = call_expr_nargs (call);
/* This reverses the evaluation order. This is a desired effect. */
- for (cmp = NULL_TREE; arg; arg = TREE_CHAIN (arg))
+ for (i = 0, cmp = NULL_TREE; i < nargs; i++)
{
- tree saved = save_expr (force_evaluation_order (TREE_VALUE (arg)));
+ tree arg = CALL_EXPR_ARG (call, i);
+ /* Promote types smaller than integer. This is required by
+ some ABIs. */
+ tree type = TREE_TYPE (arg);
+ tree saved;
+ if (targetm.calls.promote_prototypes (type)
+ && INTEGRAL_TYPE_P (type)
+ && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
+ TYPE_SIZE (integer_type_node)))
+ arg = fold_convert (integer_type_node, arg);
+
+ saved = save_expr (force_evaluation_order (arg));
cmp = (cmp == NULL_TREE ? saved :
build2 (COMPOUND_EXPR, void_type_node, cmp, saved));
- TREE_VALUE (arg) = saved;
+
+ CALL_EXPR_ARG (call, i) = saved;
}
if (cmp && TREE_CODE (cmp) == COMPOUND_EXPR)
cmp = build2 (COMPOUND_EXPR, TREE_TYPE (node), cmp, node);
if (TREE_TYPE (cmp) != void_type_node)
cmp = save_expr (cmp);
- CAN_COMPLETE_NORMALLY (cmp) = CAN_COMPLETE_NORMALLY (node);
TREE_SIDE_EFFECTS (cmp) = 1;
node = cmp;
}
return node;
}
-/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
- location where an expression or an identifier were encountered. It
- is necessary for languages where the frontend parser will handle
- recursively more than one file (Java is one of them). */
+/* Build a node to represent empty statements and blocks. */
tree
-build_expr_wfl (tree node,
-#ifdef USE_MAPPED_LOCATION
- source_location location
-#else
- const char *file, int line, int col
-#endif
-)
+build_java_empty_stmt (void)
{
- tree wfl;
-
-#ifdef USE_MAPPED_LOCATION
- wfl = make_node (EXPR_WITH_FILE_LOCATION);
- SET_EXPR_LOCATION (wfl, location);
-#else
- static const char *last_file = 0;
- static tree last_filenode = NULL_TREE;
-
- wfl = make_node (EXPR_WITH_FILE_LOCATION);
-
- EXPR_WFL_SET_LINECOL (wfl, line, col);
- if (file != last_file)
- {
- last_file = file;
- last_filenode = file ? get_identifier (file) : NULL_TREE;
- }
- EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
-#endif
- EXPR_WFL_NODE (wfl) = node;
- if (node)
- {
- if (IS_NON_TYPE_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node))))
- TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
- TREE_TYPE (wfl) = TREE_TYPE (node);
- }
-
- return wfl;
+ tree t = build_empty_stmt ();
+ return t;
}
-#ifdef USE_MAPPED_LOCATION
-tree
-expr_add_location (tree node, source_location location, bool statement)
+/* Promote all args of integral type before generating any code. */
+
+static void
+promote_arguments (void)
{
- tree wfl;
-#if 0
- /* FIXME. This optimization causes failures in code that expects an
- EXPR_WITH_FILE_LOCATION. E.g. in resolve_qualified_expression_name. */
- if (node && ! (statement && flag_emit_class_files))
- {
- source_location node_loc = EXPR_LOCATION (node);
- if (node_loc == location || location == UNKNOWN_LOCATION)
- return node;
- if (node_loc == UNKNOWN_LOCATION
- && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node))))
+ int i;
+ tree arg;
+ for (arg = DECL_ARGUMENTS (current_function_decl), i = 0;
+ arg != NULL_TREE; arg = TREE_CHAIN (arg), i++)
+ {
+ tree arg_type = TREE_TYPE (arg);
+ if (INTEGRAL_TYPE_P (arg_type)
+ && TYPE_PRECISION (arg_type) < 32)
{
- SET_EXPR_LOCATION (node, location);
- return node;
+ tree copy = find_local_variable (i, integer_type_node, -1);
+ java_add_stmt (build2 (MODIFY_EXPR, integer_type_node,
+ copy,
+ fold_convert (integer_type_node, arg)));
}
+ if (TYPE_IS_WIDE (arg_type))
+ i++;
}
-#endif
- wfl = make_node (EXPR_WITH_FILE_LOCATION);
- SET_EXPR_LOCATION (wfl, location);
- EXPR_WFL_NODE (wfl) = node;
- if (statement && debug_info_level != DINFO_LEVEL_NONE)
- EXPR_WFL_EMIT_LINE_NOTE (wfl) = 1;
- if (node)
- {
- if (IS_NON_TYPE_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node))))
- TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
- TREE_TYPE (wfl) = TREE_TYPE (node);
- }
-
- return wfl;
}
-#endif
-/* Build a node to represent empty statements and blocks. */
+/* Create a local variable that points to the constant pool. */
-tree
-build_java_empty_stmt (void)
+static void
+cache_cpool_data_ref (void)
{
- tree t = build_empty_stmt ();
- CAN_COMPLETE_NORMALLY (t) = 1;
- return t;
+ if (optimize)
+ {
+ tree cpool;
+ tree d = build_constant_data_ref (flag_indirect_classes);
+ tree cpool_ptr = build_decl (VAR_DECL, NULL_TREE,
+ build_pointer_type (TREE_TYPE (d)));
+ java_add_local_var (cpool_ptr);
+ TREE_INVARIANT (cpool_ptr) = 1;
+ TREE_CONSTANT (cpool_ptr) = 1;
+
+ java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (cpool_ptr),
+ cpool_ptr, build_address_of (d)));
+ cpool = build1 (INDIRECT_REF, TREE_TYPE (d), cpool_ptr);
+ TREE_THIS_NOTRAP (cpool) = 1;
+ TYPE_CPOOL_DATA_REF (output_class) = cpool;
+ }
}
#include "gt-java-expr.h"