/* Process expressions for the GNU compiler for the Java(TM) language.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- 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.
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_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. */
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.
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);
{
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);
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);
}
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)))
{
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
}
/* 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;
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 we're processing an `aaload' we might as well just pick
`Object'. */
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
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. */
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));
}
}
? alloc_object_node
: alloc_no_finalizer_node);
- return build3 (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);
}
constant_value = build_int_cst (NULL_TREE, ival);
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);
}
}
gcc_assert (call);
- call = build3 (CALL_EXPR, type,
- build_address_of (call),
- tree_cons (NULL_TREE, arg1,
- build_tree_list (NULL_TREE, arg2)),
- NULL_TREE);
-
+ 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);
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;
}
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)
{
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,
= build3 (COND_EXPR, TREE_TYPE (field_offset),
build2 (EQ_EXPR, boolean_type_node,
field_offset, integer_zero_node),
- build3 (CALL_EXPR, void_type_node,
- build_address_of (soft_nosuchfield_node),
- build_tree_list (NULL_TREE, otable_index),
- NULL_TREE),
+ 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)),
+ = 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);
}
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
*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))
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
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;
{
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;
/* 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));
+ build_call_nary (ptr_type_node,
+ build_address_of (soft_getjnienvnewframe_node),
+ 1, klass));
CAN_COMPLETE_NORMALLY (body) = 1;
/* All the arguments to this method become arguments to the
/* 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 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 = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (method)),
- build_address_of (soft_unwrapjni_node),
- build_tree_list (NULL_TREE, call),
- NULL_TREE);
+ 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 (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);
}
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
&& ! flag_indirect_dispatch)
- field_ref = build_class_init (self_type, field_ref);
+ {
+ 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 (DECL_CONTEXT (field_decl) != current_class)
error ("assignment to final field %q+D not in field's class",
field_decl);
- else if (FIELD_STATIC (field_decl))
- {
- if (!DECL_CLINIT_P (current_function_decl))
- warning (0, "assignment to final static field %q+D not in "
- "class initializer",
- field_decl);
- }
- else
- {
- tree cfndecl_name = DECL_NAME (current_function_decl);
- if (! DECL_CONSTRUCTOR_P (current_function_decl)
- && !ID_FINIT_P (cfndecl_name))
- warning (0, "assignment to final field %q+D not in constructor",
- field_decl);
- }
- }
- java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (field_ref),
- field_ref, new_value));
+ /* 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
return;
promote_arguments ();
+ cache_this_class_ref (method);
+ cache_cpool_data_ref ();
/* Translate bytecodes. */
linenumber_pointer = linenumber_table;
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. */
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);
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) \
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. */
- gcc_assert (TREE_CODE (arg) == TREE_LIST);
+ 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 arg = CALL_EXPR_ARG (call, i);
/* Promote types smaller than integer. This is required by
some ABIs. */
- tree type = TREE_TYPE (TREE_VALUE (arg));
+ 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)))
- TREE_VALUE (arg) = fold_convert (integer_type_node, TREE_VALUE (arg));
+ arg = fold_convert (integer_type_node, arg);
- saved = save_expr (force_evaluation_order (TREE_VALUE (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)
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). */
-
-tree
-build_expr_wfl (tree node,
-#ifdef USE_MAPPED_LOCATION
- source_location location
-#else
- const char *file, int line, int col
-#endif
-)
-{
- 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 (!TYPE_P (node))
- TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
- TREE_TYPE (wfl) = TREE_TYPE (node);
- }
-
- return wfl;
-}
-
-#ifdef USE_MAPPED_LOCATION
-tree
-expr_add_location (tree node, source_location location, bool statement)
-{
- 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))))
- {
- SET_EXPR_LOCATION (node, location);
- return node;
- }
- }
-#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 (!TYPE_P (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. */
tree
}
}
+/* Create a local variable that points to the constant pool. */
+
+static void
+cache_cpool_data_ref (void)
+{
+ 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"