/* 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 Free Software Foundation, Inc.
This file is part of GCC.
#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 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,
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"));
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),
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);
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;
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));
{
/* 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);
tree retaddr
= build_call_expr (built_in_decls[BUILT_IN_RETURN_ADDRESS],
1, integer_zero_node);
-
- DECL_INLINE (current_function_decl) = 0;
+ DECL_UNINLINABLE (current_function_decl) = 1;
+
return chainon (arglist,
tree_cons (NULL_TREE, retaddr,
NULL_TREE));
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. */
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)
+ *arg_list_p = p->rewrite_arglist (*arg_list_p);
*method_signature_p = get_identifier (p->new_signature);
*special = integer_one_node;
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;
/* All the arguments to this method become arguments to the
underlying JNI function. If we had to wrap object arguments in a
jni_func_type = build_pointer_type (tem);
- jnifunc = build3 (COND_EXPR, ptr_type_node,
+ /* 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, ptr_type_node, meth_var,
- build_call_nary (ptr_type_node,
- build_address_of
- (soft_lookupjnimethod_node),
- 4,
- jniarg0, jniarg1,
- jniarg2, jniarg3)));
+ 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);
+ 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;
}
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))
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);
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));
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
}
#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),