📄 expr.c
字号:
/* Process expressions for the GNU compiler for the Java(TM) language. Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. Java and all Java-based marks are trademarks or registered trademarksof Sun Microsystems, Inc. in the United States and other countries.The Free Software Foundation is independent of Sun Microsystems, Inc. *//* Hacked by Per Bothner <bothner@cygnus.com> February 1996. */#include "config.h"#include "system.h"#include "tree.h"#include "real.h"#include "rtl.h"#include "flags.h"#include "expr.h"#include "java-tree.h"#include "javaop.h"#include "java-opcodes.h"#include "jcf.h"#include "java-except.h"#include "parse.h"#include "toplev.h"#include "except.h"static void flush_quick_stack PROTO ((void));static void push_value PROTO ((tree));static tree pop_value PROTO ((tree));static void java_stack_swap PROTO ((void));static void java_stack_dup PROTO ((int, int));static tree build_java_athrow PROTO ((tree));static void build_java_jsr PROTO ((tree, tree));static void build_java_ret PROTO ((tree));static void expand_java_multianewarray PROTO ((tree, int));static void expand_java_arraystore PROTO ((tree));static void expand_java_arrayload PROTO ((tree));static void expand_java_array_length PROTO ((void));static tree build_java_monitor PROTO ((tree, tree));static void expand_java_pushc PROTO ((int, tree));static void expand_java_return PROTO ((tree));static void expand_java_NEW PROTO ((tree));static void expand_java_INSTANCEOF PROTO ((tree));static void expand_java_CHECKCAST PROTO ((tree));static void expand_iinc PROTO ((unsigned int, int, int));static void expand_java_binop PROTO ((tree, enum tree_code));static void note_label PROTO ((int, int));static void expand_compare PROTO ((enum tree_code, tree, tree, int));static void expand_test PROTO ((enum tree_code, tree, int));static void expand_cond PROTO ((enum tree_code, tree, int));static void expand_java_goto PROTO ((int));#if 0static void expand_java_call PROTO ((int, int));static void expand_java_ret PROTO ((tree)); #endifstatic tree pop_arguments PROTO ((tree)); static void expand_invoke PROTO ((int, int, int)); static void expand_java_field_op PROTO ((int, int, int)); static void java_push_constant_from_pool PROTO ((struct JCF *, int)); static tree operand_type[59];extern struct obstack permanent_obstack;voidinit_expr_processing(){ operand_type[21] = operand_type[54] = int_type_node; operand_type[22] = operand_type[55] = long_type_node; operand_type[23] = operand_type[56] = float_type_node; operand_type[24] = operand_type[57] = double_type_node; operand_type[25] = operand_type[58] = ptr_type_node;}/* We store the stack state in two places: Within a basic block, we use the quick_stack, which is a pushdown list (TREE_LISTs) of expression nodes. This is the top part of the stack; below that we use find_stack_slot. At the end of a basic block, the quick_stack must be flushed to the stack slot array (as handled by find_stack_slot). Using quick_stack generates better code (especially when compiled without optimization), because we do not have to explicitly store and load trees to temporary variables. If a variable is on the quick stack, it means the value of variable when the quick stack was last flushed. Conceptually, flush_quick_stack saves all the the quick_stack elements in parellel. However, that is complicated, so it actually saves them (i.e. copies each stack value to is home virtual register) from low indexes. This allows a quick_stack element at index i (counting from the bottom of stack the) to references slot virtuals for register that are >= i, but not those that are deeper. This convention makes most operations easier. For example iadd works even when the stack contains (reg[0], reg[1]): It results in the stack containing (reg[0]+reg[1]), which is OK. However, some stack operations are more complicated. For example dup given a stack containing (reg[0]) would yield (reg[0], reg[0]), which would violate the convention, since stack value 1 would refer to a register with lower index (reg[0]), which flush_quick_stack does not safely handle. So dup cannot just add an extra element to the quick_stack, but iadd can.*/tree quick_stack = NULL_TREE;/* A free-list of unused permamnet TREE_LIST nodes. */tree tree_list_free_list = NULL_TREE;/* The stack pointer of the Java virtual machine. This does include the size of the quick_stack. */int stack_pointer;unsigned char *linenumber_table;int linenumber_count;treetruthvalue_conversion (expr) tree expr;{ /* It is simpler and generates better code to have only TRUTH_*_EXPR or comparison expressions as truth values at this level. This function should normally be identity for Java. */ switch (TREE_CODE (expr)) { case EQ_EXPR: case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case ERROR_MARK: return expr; case INTEGER_CST: return integer_zerop (expr) ? boolean_false_node : boolean_true_node; case REAL_CST: return real_zerop (expr) ? boolean_false_node : boolean_true_node; /* are these legal? XXX JH */ case NEGATE_EXPR: case ABS_EXPR: case FLOAT_EXPR: case FFS_EXPR: /* These don't change whether an object is non-zero or zero. */ return truthvalue_conversion (TREE_OPERAND (expr, 0)); case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), truthvalue_conversion (TREE_OPERAND (expr, 1)), truthvalue_conversion (TREE_OPERAND (expr, 2)))); case NOP_EXPR: /* If this is widening the argument, we can ignore it. */ if (TYPE_PRECISION (TREE_TYPE (expr)) >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) return truthvalue_conversion (TREE_OPERAND (expr, 0)); /* fall through to default */ default: return fold (build (NE_EXPR, boolean_type_node, expr, boolean_false_node)); }}#ifdef JAVA_USE_HANDLES/* Given a pointer to a handle, get a pointer to an object. */treeunhand_expr (expr) tree expr;{ tree field, handle_type; expr = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); handle_type = TREE_TYPE (expr); field = TYPE_FIELDS (handle_type); expr = build (COMPONENT_REF, TREE_TYPE (field), expr, field); return expr;}#endif/* Save any stack slots that happen to be in the quick_stack into their home virtual register slots. The copy order is from low stack index to high, to support the invariant that the expression for a slot may contain decls for stack slots with higher (or the same) index, but not lower. */static voidflush_quick_stack (){ int stack_index = stack_pointer; register tree prev, cur, next; /* First reverse the quick_stack, and count the number of slots it has. */ for (cur = quick_stack, prev = NULL_TREE; cur != NULL_TREE; cur = next) { next = TREE_CHAIN (cur); TREE_CHAIN (cur) = prev; prev = cur; stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (TREE_VALUE (cur))); } quick_stack = prev; while (quick_stack != NULL_TREE) { tree decl; tree node = quick_stack, type; quick_stack = TREE_CHAIN (node); TREE_CHAIN (node) = tree_list_free_list; tree_list_free_list = node; node = TREE_VALUE (node); type = TREE_TYPE (node); decl = find_stack_slot (stack_index, type); if (decl != node) expand_assignment (decl, node, 0, 0); stack_index += 1 + TYPE_IS_WIDE (type); }}voidpush_type (type) tree type;{ int n_words; type = promote_type (type); n_words = 1 + TYPE_IS_WIDE (type); if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl)) fatal ("stack overflow"); stack_type_map[stack_pointer++] = type; n_words--; while (--n_words >= 0) stack_type_map[stack_pointer++] = TYPE_SECOND;}static voidpush_value (value) tree value;{ tree type = TREE_TYPE (value); if (TYPE_PRECISION (type) < 32 && INTEGRAL_TYPE_P (type)) { type = promote_type (type); value = convert (type, value); } push_type (type); if (tree_list_free_list == NULL_TREE) quick_stack = perm_tree_cons (NULL_TREE, value, quick_stack); else { tree node = tree_list_free_list; tree_list_free_list = TREE_CHAIN (tree_list_free_list); TREE_VALUE (node) = value; TREE_CHAIN (node) = quick_stack; quick_stack = node; }}/* Pop a type from the type stack. TYPE is the expected type. Return the actual type, which must be convertible to TYPE, otherwise NULL_TREE is returned. */treepop_type_0 (type) tree type;{ int n_words; tree t; if (TREE_CODE (type) == RECORD_TYPE) type = promote_type (type); n_words = 1 + TYPE_IS_WIDE (type); if (stack_pointer < n_words) fatal ("stack underflow"); while (--n_words > 0) { if (stack_type_map[--stack_pointer] != void_type_node) fatal ("Invalid multi-word value on type stack"); } t = stack_type_map[--stack_pointer]; if (type == NULL_TREE || t == type) return t; if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t) && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32) return t; if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE) { if (type == ptr_type_node || type == object_ptr_type_node) return t; else if (t == ptr_type_node) /* Special case for null reference. */ return type; else if (can_widen_reference_to (t, type)) return t; /* This is a kludge, but matches what Sun's verifier does. It can be tricked, but is safe as long as type errors (i.e. interface method calls) are caught at run-time. */ else if (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (type))) && t == object_ptr_type_node) return t; } return NULL_TREE;}/* Pop a type from the type stack. TYPE is the expected type. Return the actual type, which must be convertible to TYPE, otherwise call error. */treepop_type (type) tree type;{ tree t = pop_type_0 (type); if (t != NULL_TREE) return t; error ("unexpected type on stack"); return type;}/* Return 1f if SOURCE_TYPE can be safely widened to TARGET_TYPE. Handles array types and interfaces. */intcan_widen_reference_to (source_type, target_type) tree source_type, target_type;{ if (source_type == ptr_type_node || target_type == object_ptr_type_node) return 1; /* Get rid of pointers */ if (TREE_CODE (source_type) == POINTER_TYPE) source_type = TREE_TYPE (source_type); if (TREE_CODE (target_type) == POINTER_TYPE) target_type = TREE_TYPE (target_type); if (source_type == target_type) return 1; else { source_type = HANDLE_TO_CLASS_TYPE (source_type); target_type = HANDLE_TO_CLASS_TYPE (target_type); if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type)) { HOST_WIDE_INT source_length, target_length; if (TYPE_ARRAY_P (source_type) != TYPE_ARRAY_P (target_type)) return 0; target_length = java_array_type_length (target_type); if (target_length >= 0) { source_length = java_array_type_length (source_type); if (source_length != target_length) return 0; } source_type = TYPE_ARRAY_ELEMENT (source_type); target_type = TYPE_ARRAY_ELEMENT (target_type); if (source_type == target_type) return 1; if (TREE_CODE (source_type) != POINTER_TYPE || TREE_CODE (target_type) != POINTER_TYPE) return 0; return can_widen_reference_to (source_type, target_type); } else { int source_depth = class_depth (source_type); int target_depth = class_depth (target_type); if (CLASS_INTERFACE (TYPE_NAME (target_type))) { /* target_type is OK if source_type or source_type ancestors implement target_type. We handle multiple sub-interfaces */ tree basetype_vec = TYPE_BINFO_BASETYPES (source_type); int n = TREE_VEC_LENGTH (basetype_vec), i; for (i=0 ; i < n; i++) if (can_widen_reference_to (TREE_TYPE (TREE_VEC_ELT (basetype_vec, i)), target_type)) return 1; if (n == 0) return 0; } for ( ; source_depth > target_depth; source_depth--) { source_type = TYPE_BINFO_BASETYPE (source_type, 0); } return source_type == target_type; } }}static treepop_value (type) tree type;{ type = pop_type (type); if (quick_stack) { tree node = quick_stack; quick_stack = TREE_CHAIN (quick_stack); TREE_CHAIN (node) = tree_list_free_list; tree_list_free_list = node; node = TREE_VALUE (node); return node; } else return find_stack_slot (stack_pointer, promote_type (type));}/* Pop and discrad the top COUNT stack slots. */static voidjava_stack_pop (count) int count;{ while (count > 0) { tree type, val; if (stack_pointer == 0) fatal ("stack underflow"); type = stack_type_map[stack_pointer - 1]; if (type == TYPE_SECOND)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -