/* Process expressions for the GNU compiler for the Java(TM) language.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2005, 2006, 2007, 2008, 2010 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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, 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.
#include "parse.h"
#include "toplev.h"
#include "except.h"
+#include "tm_p.h"
#include "ggc.h"
-#include "tree-gimple.h"
+#include "tree-iterator.h"
+#include "gimple.h"
#include "target.h"
static void flush_quick_stack (void);
static void expand_java_goto (int);
static tree expand_java_switch (tree, int);
static void expand_java_add_case (tree, int, int);
-static tree pop_arguments (tree);
+static VEC(tree,gc) *pop_arguments (tree);
static void expand_invoke (int, int, int);
static void expand_java_field_op (int, int, int);
static void java_push_constant_from_pool (struct JCF *, int);
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);
static hashval_t
type_assertion_hash (const void *p)
{
- const type_assertion *k_p = p;
+ const type_assertion *k_p = (const type_assertion *) p;
hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
k_p->assertion_code, 0);
- hash = iterative_hash (&k_p->op1, sizeof k_p->op1, hash);
- return iterative_hash (&k_p->op2, sizeof k_p->op2, hash);
+
+ switch (k_p->assertion_code)
+ {
+ case JV_ASSERT_TYPES_COMPATIBLE:
+ hash = iterative_hash (&TYPE_UID (k_p->op2), sizeof TYPE_UID (k_p->op2),
+ hash);
+ /* Fall through. */
+
+ case JV_ASSERT_IS_INSTANTIABLE:
+ hash = iterative_hash (&TYPE_UID (k_p->op1), sizeof TYPE_UID (k_p->op1),
+ hash);
+ /* Fall through. */
+
+ case JV_ASSERT_END_OF_TABLE:
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return hash;
}
/* Add an entry to the type assertion table for the given class.
- CLASS is the class for which this assertion will be evaluated by the
+ KLASS is the class for which this assertion will be evaluated by the
runtime during loading/initialization.
ASSERTION_CODE is the 'opcode' or type of this assertion: see java-tree.h.
OP1 and OP2 are the operands. The tree type of these arguments may be
specific to each assertion_code. */
void
-add_type_assertion (tree class, int assertion_code, tree op1, tree op2)
+add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
{
htab_t assertions_htab;
type_assertion as;
void **as_pp;
- assertions_htab = TYPE_ASSERTIONS (class);
+ assertions_htab = TYPE_ASSERTIONS (klass);
if (assertions_htab == NULL)
{
assertions_htab = htab_create_ggc (7, type_assertion_hash,
{
while (count > 0)
{
- tree type, val;
+ tree type;
gcc_assert (stack_pointer != 0);
type = stack_type_map[stack_pointer - 2];
}
- val = pop_value (type);
+ pop_value (type);
count--;
}
}
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 ();
flush_quick_stack ();
decl1 = find_stack_slot (stack_pointer - 1, type1);
decl2 = find_stack_slot (stack_pointer - 2, type2);
- temp = build_decl (VAR_DECL, NULL_TREE, type1);
+ temp = build_decl (input_location, VAR_DECL, NULL_TREE, type1);
java_add_local_var (temp);
java_add_stmt (build2 (MODIFY_EXPR, type1, temp, decl1));
java_add_stmt (build2 (MODIFY_EXPR, type2,
static tree
build_java_throw_out_of_bounds_exception (tree index)
{
- tree node = build_call_nary (int_type_node,
+ tree node;
+
+ /* We need to build a COMPOUND_EXPR because _Jv_ThrowBadArrayIndex()
+ has void return type. We cannot just set the type of the CALL_EXPR below
+ to int_type_node because we would lose it during gimplification. */
+ gcc_assert (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (soft_badarrayindex_node))));
+ node = build_call_nary (void_type_node,
build_address_of (soft_badarrayindex_node),
1, index);
+ TREE_SIDE_EFFECTS (node) = 1;
+
+ node = build2 (COMPOUND_EXPR, int_type_node, node, integer_zero_node);
TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */
+
return (node);
}
tree
build_java_arrayaccess (tree array, tree type, tree index)
{
- tree node, throw = NULL_TREE;
+ tree node, throw_expr = NULL_TREE;
tree data_field;
tree ref;
tree array_type = TREE_TYPE (TREE_TYPE (array));
len);
if (! integer_zerop (test))
{
- throw = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
- build_java_throw_out_of_bounds_exception (index));
+ throw_expr
+ = build2 (TRUTH_ANDIF_EXPR, int_type_node, test,
+ build_java_throw_out_of_bounds_exception (index));
/* allows expansion within COMPOUND */
- TREE_SIDE_EFFECTS( throw ) = 1;
+ TREE_SIDE_EFFECTS( throw_expr ) = 1;
}
}
/* If checking bounds, wrap the index expr with a COMPOUND_EXPR in order
to have the bounds check evaluated first. */
- if (throw != NULL_TREE)
- index = build2 (COMPOUND_EXPR, int_type_node, throw, index);
+ if (throw_expr != NULL_TREE)
+ index = build2 (COMPOUND_EXPR, int_type_node, throw_expr, index);
data_field = lookup_field (&array_type, get_identifier ("data"));
/* 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 = fold_convert (TREE_TYPE (node),
- build2 (MULT_EXPR, sizetype,
- fold_convert (sizetype, index),
- size_exp));
+ 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 (PLUS_EXPR, TREE_TYPE (node), node, index);
+ node = fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (node), node, index);
/* Finally, return
expand_java_multianewarray (tree class_type, int ndim)
{
int i;
- tree args = build_tree_list( NULL_TREE, null_pointer_node );
+ VEC(tree,gc) *args = NULL;
+
+ VEC_safe_grow (tree, gc, args, 3 + ndim);
- for( i = 0; i < ndim; i++ )
- args = tree_cons (NULL_TREE, pop_value (int_type_node), args);
+ VEC_replace (tree, args, 0, build_class_ref (class_type));
+ VEC_replace (tree, args, 1, build_int_cst (NULL_TREE, ndim));
- args = tree_cons (NULL_TREE,
- build_class_ref (class_type),
- tree_cons (NULL_TREE,
- build_int_cst (NULL_TREE, ndim),
- args));
+ for(i = ndim - 1; i >= 0; i-- )
+ VEC_replace (tree, args, (unsigned)(2 + i), pop_value (int_type_node));
- push_value (build_call_list (promote_type (class_type),
- build_address_of (soft_multianewarray_node),
- args));
+ VEC_replace (tree, args, 2 + ndim, null_pointer_node);
+
+ push_value (build_call_vec (promote_type (class_type),
+ build_address_of (soft_multianewarray_node),
+ args));
}
/* ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that
MODIFY_EXPR to set the array element. */
access = build_java_arrayaccess (array, rhs_type_node, index);
- temp = build_decl (VAR_DECL, NULL_TREE,
+ temp = build_decl (input_location, VAR_DECL, NULL_TREE,
build_pointer_type (TREE_TYPE (access)));
java_add_local_var (temp);
java_add_stmt (build2 (MODIFY_EXPR, TREE_TYPE (temp),
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));
}
}
generated. To avoid this we create a new local and copy our
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);
+ copy = build_decl (input_location, VAR_DECL, NULL_TREE, type);
if ((INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
&& TREE_TYPE (copy) != TREE_TYPE (var))
var = convert (type, var);
{
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);
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);
}
{
/* 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);
}
}
create_label_decl (tree name)
{
tree decl;
- decl = build_decl (LABEL_DECL, name,
+ decl = build_decl (input_location, LABEL_DECL, name,
TREE_TYPE (return_address_type_node));
DECL_CONTEXT (decl) = current_function_decl;
DECL_IGNORED_P (decl) = 1;
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)
{
java_add_stmt (switch_expr);
x = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE, NULL_TREE,
- create_artificial_label ());
+ create_artificial_label (input_location));
append_to_statement_list (x, &SWITCH_BODY (switch_expr));
x = build1 (GOTO_EXPR, void_type_node, lookup_label (default_pc));
value = build_int_cst (TREE_TYPE (switch_expr), match);
x = build3 (CASE_LABEL_EXPR, void_type_node, value, NULL_TREE,
- create_artificial_label ());
+ create_artificial_label (input_location));
append_to_statement_list (x, &SWITCH_BODY (switch_expr));
x = build1 (GOTO_EXPR, void_type_node, lookup_label (target_pc));
append_to_statement_list (x, &SWITCH_BODY (switch_expr));
}
-static tree
-pop_arguments (tree arg_types)
+static VEC(tree,gc) *
+pop_arguments (tree method_type)
{
- if (arg_types == end_params_node)
- return NULL_TREE;
- if (TREE_CODE (arg_types) == TREE_LIST)
+ function_args_iterator fnai;
+ tree type;
+ VEC(tree,gc) *args = NULL;
+ int arity;
+
+ FOREACH_FUNCTION_ARGS (method_type, type, fnai)
{
- tree tail = pop_arguments (TREE_CHAIN (arg_types));
- tree type = TREE_VALUE (arg_types);
- tree arg = pop_value (type);
+ /* XXX: leaky abstraction. */
+ if (type == void_type_node)
+ break;
+
+ VEC_safe_push (tree, gc, args, type);
+ }
+
+ arity = VEC_length (tree, args);
+
+ while (arity--)
+ {
+ tree arg = pop_value (VEC_index (tree, args, arity));
/* We simply cast each argument to its proper type. This is
needed since we lose type information coming out of the
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)
&& INTEGRAL_TYPE_P (type))
arg = convert (integer_type_node, arg);
- return tree_cons (NULL_TREE, arg, tail);
+
+ VEC_replace (tree, args, arity, arg);
}
- gcc_unreachable ();
+
+ return args;
}
/* Attach to PTR (a block) the declaration found in ENTRY. */
{
/* Build a declaration and mark it as a flag used to track
static class initializations. */
- decl = build_decl (VAR_DECL, NULL_TREE,
+ decl = build_decl (input_location, 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;
const char *classname;
const char *method;
const char *signature;
+ const char *new_classname;
const char *new_signature;
int flags;
- tree (*rewrite_arglist) (tree arglist);
+ void (*rewrite_arglist) (VEC(tree,gc) **);
} rewrite_rule;
/* Add __builtin_return_address(0) to the end of an arglist. */
-static tree
-rewrite_arglist_getcaller (tree arglist)
+static void
+rewrite_arglist_getcaller (VEC(tree,gc) **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));
+ DECL_UNINLINABLE (current_function_decl) = 1;
+
+ VEC_safe_push (tree, gc, *arglist, retaddr);
}
/* Add this.class to the end of an arglist. */
-static tree
-rewrite_arglist_getclass (tree arglist)
+static void
+rewrite_arglist_getclass (VEC(tree,gc) **arglist)
{
- return chainon (arglist,
- tree_cons (NULL_TREE, build_class_ref (output_class),
- NULL_TREE));
+ VEC_safe_push (tree, gc, *arglist, build_class_ref (output_class));
}
static rewrite_rule rules[] =
{{"java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;",
- "(Ljava/lang/Class;)Ljava/lang/ClassLoader;",
+ "java.lang.Class", "(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;",
+ "java.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;",
+ "gnu.classpath.VMStackWalker", "(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;",
+ "gnu.classpath.VMStackWalker", "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
- {NULL, NULL, NULL, NULL, 0, NULL}};
+ {"gnu.java.lang.VMCPStringBuilder", "toString", "([CII)Ljava/lang/String;",
+ "java.lang.String", "([CII)Ljava/lang/String;",
+ ACC_FINAL|ACC_PRIVATE|ACC_STATIC, NULL},
+
+ {NULL, 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. */
method, update SPECIAL.*/
void
-maybe_rewrite_invocation (tree *method_p, tree *arg_list_p,
+maybe_rewrite_invocation (tree *method_p, VEC(tree,gc) **arg_list_p,
tree *method_signature_p, tree *special)
{
tree context = DECL_NAME (TYPE_NAME (DECL_CONTEXT (*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),
+ tree maybe_method;
+ tree destination_class
+ = lookup_class (get_identifier (p->new_classname));
+ gcc_assert (destination_class);
+ maybe_method
+ = lookup_java_method (destination_class,
method,
get_identifier (p->new_signature));
if (! maybe_method && ! flag_verify_invocations)
{
maybe_method
- = add_method (DECL_CONTEXT (*method_p), p->flags,
+ = add_method (destination_class, 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);
+ if (p->rewrite_arglist)
+ p->rewrite_arglist (arg_list_p);
*method_signature_p = get_identifier (p->new_signature);
*special = integer_one_node;
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 special)
+ VEC(tree,gc) *arg_list ATTRIBUTE_UNUSED, tree special)
{
tree func;
if (is_compiled_class (self_type))
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),
}
tree
-invoke_build_dtable (int is_invoke_interface, tree arg_list)
+invoke_build_dtable (int is_invoke_interface, VEC(tree,gc) *arg_list)
{
tree dtable, objectref;
+ tree saved = save_expr (VEC_index (tree, arg_list, 0));
- TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list));
+ VEC_replace (tree, arg_list, 0, saved);
/* If we're dealing with interfaces and if the objectref
argument is an array then get the dispatch table of the class
Object rather than the one from the objectref. */
objectref = (is_invoke_interface
- && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list)))
- ? build_class_ref (object_type_node) : TREE_VALUE (arg_list));
+ && is_array_type_p (TREE_TYPE (saved))
+ ? build_class_ref (object_type_node) : saved);
if (dtable_ident == NULL_TREE)
dtable_ident = get_identifier ("vtable");
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;
}
method_ref_index));
const char *const self_name
= IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type)));
- tree call, func, method, arg_list, method_type;
+ tree call, func, method, method_type;
+ VEC(tree,gc) *arg_list;
tree check = NULL_TREE;
tree special = NULL_TREE;
just pop the arguments, push a properly-typed zero, and
continue. */
method_type = get_type_from_signature (method_signature);
- pop_arguments (TYPE_ARG_TYPES (method_type));
+ pop_arguments (method_type);
if (opcode != OPCODE_invokestatic)
pop_type (self_type);
method_type = promote_type (TREE_TYPE (method_type));
}
method_type = TREE_TYPE (method);
- arg_list = pop_arguments (TYPE_ARG_TYPES (method_type));
+ arg_list = pop_arguments (method_type);
flush_quick_stack ();
maybe_rewrite_invocation (&method, &arg_list, &method_signature,
We do omit the check if we're calling <init>. */
/* We use a SAVE_EXPR here to make sure we only evaluate
the new `self' expression once. */
- tree save_arg = save_expr (TREE_VALUE (arg_list));
- TREE_VALUE (arg_list) = save_arg;
+ tree save_arg = save_expr (VEC_index (tree, arg_list, 0));
+ VEC_replace (tree, arg_list, 0, 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, special);
else
func = build1 (NOP_EXPR, build_pointer_type (method_type), func);
- call = build_call_list (TREE_TYPE (method_type), func, arg_list);
+ call = build_call_vec (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, method_sig, arg_types;
+ tree jnifunc, call, 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;
+ tree method_args;
tree meth_var;
tree bind;
-
+ VEC(tree,gc) *args = NULL;
int args_size = 0;
tree klass = DECL_CONTEXT (method);
- int from_class = ! CLASS_FROM_SOURCE_P (klass);
klass = build_class_ref (klass);
gcc_assert (METHOD_NATIVE (method) && flag_jni);
DECL_ARTIFICIAL (method) = 1;
DECL_EXTERNAL (method) = 0;
- env_var = build_decl (VAR_DECL, get_identifier ("env"), ptr_type_node);
+ env_var = build_decl (input_location,
+ VAR_DECL, get_identifier ("env"), ptr_type_node);
DECL_CONTEXT (env_var) = method;
if (TREE_TYPE (TREE_TYPE (method)) != void_type_node)
{
- res_var = build_decl (VAR_DECL, get_identifier ("res"),
+ res_var = build_decl (input_location, VAR_DECL, get_identifier ("res"),
TREE_TYPE (TREE_TYPE (method)));
DECL_CONTEXT (res_var) = method;
TREE_CHAIN (env_var) = res_var;
}
- meth_var = build_decl (VAR_DECL, get_identifier ("meth"), ptr_type_node);
- TREE_STATIC (meth_var) = 1;
- TREE_PUBLIC (meth_var) = 0;
- DECL_EXTERNAL (meth_var) = 0;
- DECL_CONTEXT (meth_var) = method;
- DECL_ARTIFICIAL (meth_var) = 1;
- DECL_INITIAL (meth_var) = null_pointer_node;
- TREE_USED (meth_var) = 1;
- 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));
+ 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,
build_call_nary (ptr_type_node,
build_address_of (soft_getjnienvnewframe_node),
1, klass));
- CAN_COMPLETE_NORMALLY (body) = 1;
+
+ /* The JNIEnv structure is the first argument to the JNI function. */
+ args_size += int_size_in_bytes (TREE_TYPE (env_var));
+ VEC_safe_push (tree, gc, args, env_var);
+
+ /* For a static method the second argument is the class. For a
+ non-static method the second argument is `this'; that is already
+ available in the argument list. */
+ if (METHOD_STATIC (method))
+ {
+ args_size += int_size_in_bytes (TREE_TYPE (klass));
+ VEC_safe_push (tree, gc, args, klass);
+ }
/* All the arguments to this method become arguments to the
underlying JNI function. If we had to wrap object arguments in a
special way, we would do that here. */
- args = NULL_TREE;
for (tem = method_args; tem != NULL_TREE; tem = TREE_CHAIN (tem))
{
int arg_bits = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)));
#endif
args_size += (arg_bits / BITS_PER_UNIT);
- args = tree_cons (NULL_TREE, tem, args);
+ VEC_safe_push (tree, gc, args, tem);
}
- args = nreverse (args);
arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
- /* For a static method the second argument is the class. For a
- non-static method the second argument is `this'; that is already
- available in the argument list. */
+ /* Argument types for static methods and the JNIEnv structure.
+ FIXME: Write and use build_function_type_vec to avoid this. */
if (METHOD_STATIC (method))
- {
- args_size += int_size_in_bytes (TREE_TYPE (klass));
- args = tree_cons (NULL_TREE, klass, args);
- arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
- }
-
- /* The JNIEnv structure is the first argument to the JNI function. */
- args_size += int_size_in_bytes (TREE_TYPE (env_var));
- args = tree_cons (NULL_TREE, env_var, args);
+ arg_types = tree_cons (NULL_TREE, object_ptr_type_node, arg_types);
arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
/* We call _Jv_LookupJNIMethod to find the actual underlying
jni_func_type = build_pointer_type (tem);
- jnifunc = build3 (COND_EXPR, ptr_type_node,
- meth_var, meth_var,
- build2 (MODIFY_EXPR, ptr_type_node, meth_var,
- build_call_nary (ptr_type_node,
- build_address_of
- (soft_lookupjnimethod_node),
- 4,
- jniarg0, jniarg1,
- jniarg2, jniarg3)));
+ /* Use the actual function type, rather than a generic pointer type,
+ such that this decl keeps the actual pointer type from being
+ garbage-collected. If it is, we end up using canonical types
+ with different uids for equivalent function types, and this in
+ turn causes utf8 identifiers and output order to vary. */
+ meth_var = build_decl (input_location,
+ VAR_DECL, get_identifier ("meth"), jni_func_type);
+ TREE_STATIC (meth_var) = 1;
+ TREE_PUBLIC (meth_var) = 0;
+ DECL_EXTERNAL (meth_var) = 0;
+ DECL_CONTEXT (meth_var) = method;
+ DECL_ARTIFICIAL (meth_var) = 1;
+ DECL_INITIAL (meth_var) = null_pointer_node;
+ TREE_USED (meth_var) = 1;
+ chainon (env_var, meth_var);
+ build_result_decl (method);
+
+ jnifunc = build3 (COND_EXPR, jni_func_type,
+ build2 (NE_EXPR, boolean_type_node,
+ meth_var, build_int_cst (TREE_TYPE (meth_var), 0)),
+ meth_var,
+ build2 (MODIFY_EXPR, jni_func_type, meth_var,
+ build1
+ (NOP_EXPR, jni_func_type,
+ 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 = build_call_list (TREE_TYPE (TREE_TYPE (method)),
- build1 (NOP_EXPR, jni_func_type, jnifunc),
- args);
+ call = build_call_vec (TREE_TYPE (TREE_TYPE (method)), 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. */
}
TREE_SIDE_EFFECTS (call) = 1;
- CAN_COMPLETE_NORMALLY (call) = 1;
body = build2 (COMPOUND_EXPR, void_type_node, body, call);
TREE_SIDE_EFFECTS (body) = 1;
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;
/* Finally, do the return. */
- res_type = void_type_node;
if (res_var != NULL_TREE)
{
tree drt;
}
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
}
else
{
- tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
+ tree temp = build_decl (input_location,
+ VAR_DECL, NULL_TREE, TREE_TYPE (field_ref));
java_add_local_var (temp);
if (TREE_THIS_VOLATILE (field_decl))
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++)
JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
byte_ops = jcf->read_ptr;
- instruction_bits = xrealloc (instruction_bits, length + 1);
+ instruction_bits = XRESIZEVAR (char, 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 dead_code_index = -1;
unsigned char* byte_ops;
long length = DECL_CODE_LENGTH (method);
+ location_t max_location = input_location;
stack_pointer = 0;
JCF_SEEK (jcf, DECL_CODE_OFFSET (method));
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))
if (pc == PC)
{
int line = GET_u2 (linenumber_pointer - 2);
-#ifdef USE_MAPPED_LOCATION
- input_location = linemap_line_start (&line_table, line, 1);
-#else
- input_location.line = line;
-#endif
+ input_location = linemap_line_start (line_table, line, 1);
+ if (input_location > max_location)
+ max_location = input_location;
if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS))
break;
}
warning (0, "unreachable bytecode from %d to the end of the method",
dead_code_index);
}
+
+ DECL_FUNCTION_LAST_LINE (method) = max_location;
}
static void
{ \
int saw_index = 0; \
int index = OPERAND_VALUE; \
+ (void) saw_index; /* Avoid set but not used warning. */ \
build_java_ret \
(find_local_variable (index, return_address_type_node, oldpc)); \
}
}
#define ARRAY_NEW_MULTI() \
{ \
- tree class = get_class_constant (current_jcf, IMMEDIATE_u2 ); \
+ tree klass = get_class_constant (current_jcf, IMMEDIATE_u2 ); \
int ndims = IMMEDIATE_u1; \
- expand_java_multianewarray( class, ndims ); \
+ expand_java_multianewarray( klass, ndims ); \
}
#define UNOP(OPERAND_TYPE, OPERAND_VALUE) \
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;
}
tree
build_java_empty_stmt (void)
{
- tree t = build_empty_stmt ();
- CAN_COMPLETE_NORMALLY (t) = 1;
+ tree t = build_empty_stmt (input_location);
return t;
}
{
tree cpool;
tree d = build_constant_data_ref (flag_indirect_classes);
- tree cpool_ptr = build_decl (VAR_DECL, NULL_TREE,
+ tree cpool_ptr = build_decl (input_location, 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),