📄 expr.c
字号:
enum tree_code condition; tree type; int target_pc;{ tree value1, value2; flush_quick_stack (); /* note: pop values in opposite order */ value2 = pop_value (type); value1 = pop_value (type); /* Maybe should check value1 and value2 for type compatibility ??? */ expand_compare (condition, value1, value2, target_pc);}static voidexpand_java_goto (target_pc) int target_pc;{ tree target_label = lookup_label (target_pc); flush_quick_stack (); expand_goto (target_label);}#if 0static voidexpand_java_call (target_pc, return_address) int target_pc, return_address;{ tree target_label = lookup_label (target_pc); tree value = build_int_2 (return_address, return_address < 0 ? -1 : 0); push_value (value); flush_quick_stack (); expand_goto (target_label);}static voidexpand_java_ret (return_address) tree return_address ATTRIBUTE_UNUSED;{ warning ("ret instruction not implemented");#if 0 tree target_label = lookup_label (target_pc); flush_quick_stack (); expand_goto (target_label);#endif}#endif/* Recursive helper function to pop argument types during verifiation. */voidpop_argument_types (arg_types) tree arg_types;{ if (arg_types == end_params_node) return; if (TREE_CODE (arg_types) == TREE_LIST) { pop_argument_types (TREE_CHAIN (arg_types)); pop_type (TREE_VALUE (arg_types)); return; } abort ();}static treepop_arguments (arg_types) tree arg_types;{ if (arg_types == end_params_node) return NULL_TREE; if (TREE_CODE (arg_types) == TREE_LIST) { tree tail = pop_arguments (TREE_CHAIN (arg_types)); tree type = TREE_VALUE (arg_types); tree arg = pop_value (type);#ifdef PROMOTE_PROTOTYPES if (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node) && INTEGRAL_TYPE_P (type)) arg = convert (integer_type_node, arg);#endif return tree_cons (NULL_TREE, arg, tail); } abort ();}/* Build an expression to initialize the class CLAS. if EXPR is non-NULL, returns an expression to first call the initializer (if it is needed) and then calls EXPR. */treebuild_class_init (clas, expr) tree clas, expr;{ tree init; if (inherits_from_p (current_class, clas)) return expr; init = build (CALL_EXPR, void_type_node, build_address_of (soft_initclass_node), build_tree_list (NULL_TREE, build_class_ref (clas)), NULL_TREE); TREE_SIDE_EFFECTS (init) = 1; if (expr != NULL_TREE) { expr = build (COMPOUND_EXPR, TREE_TYPE (expr), init, expr); TREE_SIDE_EFFECTS (expr) = 1; return expr; } return init;}static tree methods_ident = NULL_TREE;static tree ncode_ident = NULL_TREE;tree dtable_ident = NULL_TREE;treebuild_known_method_ref (method, method_type, self_type, method_signature, arg_list) tree method, method_type ATTRIBUTE_UNUSED, self_type, method_signature ATTRIBUTE_UNUSED, arg_list ATTRIBUTE_UNUSED;{ tree func; if (is_compiled_class (self_type)) { make_decl_rtl (method, NULL, 1); func = build1 (ADDR_EXPR, method_ptr_type_node, method); } else { /* We don't know whether the method has been (statically) compiled. Compile this code to get a reference to the method's code: SELF_TYPE->methods[METHOD_INDEX].ncode This is guaranteed to work (assuming SELF_TYPE has been initialized), since if the method is not compiled yet, its ncode points to a trampoline that forces compilation. */ int method_index = 0; tree meth; tree ref = build_class_ref (self_type); ref = build1 (INDIRECT_REF, class_type_node, ref); if (ncode_ident == NULL_TREE) ncode_ident = get_identifier ("ncode"); if (methods_ident == NULL_TREE) methods_ident = get_identifier ("methods"); ref = build (COMPONENT_REF, method_ptr_type_node, ref, lookup_field (&class_type_node, methods_ident)); for (meth = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (self_type)); ; meth = TREE_CHAIN (meth)) { if (method == meth) break; if (meth == NULL_TREE) fatal ("method '%s' not found in class", IDENTIFIER_POINTER (DECL_NAME (method))); method_index++; } method_index *= int_size_in_bytes (method_type_node); ref = fold (build (PLUS_EXPR, method_ptr_type_node, ref, build_int_2 (method_index, 0))); ref = build1 (INDIRECT_REF, method_type_node, ref); func = build (COMPONENT_REF, nativecode_ptr_type_node, ref, lookup_field (&method_type_node, ncode_ident)); } return func;}treeinvoke_build_dtable (is_invoke_interface, arg_list) int is_invoke_interface; tree arg_list;{ tree dtable, objectref; TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list)); /* 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))) ? object_type_node : TREE_VALUE (arg_list)); if (dtable_ident == NULL_TREE) dtable_ident = get_identifier ("vtable"); dtable = build1 (INDIRECT_REF, object_type_node, objectref ); dtable = build (COMPONENT_REF, dtable_ptr_type, dtable, lookup_field (&object_type_node, dtable_ident)); return dtable;}tree build_invokevirtual (dtable, method) tree dtable, method;{ tree func; tree nativecode_ptr_ptr_type_node = build_pointer_type (nativecode_ptr_type_node); int method_index = TREE_INT_CST_LOW (DECL_VINDEX (method)); /* Add one to skip "class" field of dtable, and one to skip unused vtable entry (for C++ compatibility). */ method_index += 2; method_index *= int_size_in_bytes (nativecode_ptr_ptr_type_node); func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, dtable, build_int_2 (method_index, 0))); func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func); return func;}treebuild_invokeinterface (dtable, method_name, method_signature) tree dtable, method_name, method_signature;{ static tree class_ident = NULL_TREE; tree lookup_arg; /* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will ensure that the selected method exists, is public and not abstract nor static. */ if (class_ident == NULL_TREE) class_ident = get_identifier ("class"); dtable = build1 (INDIRECT_REF, dtable_type, dtable); dtable = build (COMPONENT_REF, class_ptr_type, dtable, lookup_field (&dtable_type, class_ident)); lookup_arg = build_tree_list (NULL_TREE, (build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER(method_signature), IDENTIFIER_LENGTH(method_signature))))); lookup_arg = tree_cons (NULL_TREE, dtable, tree_cons (NULL_TREE, build_utf8_ref (method_name), lookup_arg)); return build (CALL_EXPR, ptr_type_node, build_address_of (soft_lookupinterfacemethod_node), lookup_arg, NULL_TREE);} /* Expand one of the invoke_* opcodes. OCPODE is the specific opcode. METHOD_REF_INDEX is an index into the constant pool. NARGS is the number of arguments, or -1 if not specified. */static voidexpand_invoke (opcode, method_ref_index, nargs) int opcode; int method_ref_index; int nargs ATTRIBUTE_UNUSED;{ tree method_signature = COMPONENT_REF_SIGNATURE(¤t_jcf->cpool, method_ref_index); tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, method_ref_index); tree self_type = get_class_constant (current_jcf, COMPONENT_REF_CLASS_INDEX(¤t_jcf->cpool, method_ref_index)); char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type))); tree call, func, method, arg_list, method_type; if (! CLASS_LOADED_P (self_type)) { load_class (self_type, 1); if (TREE_CODE (TYPE_SIZE (self_type)) == ERROR_MARK) fatal ("failed to find class '%s'", self_name); } layout_class_methods (self_type); if (method_name == init_identifier_node) method = lookup_java_constructor (CLASS_TO_HANDLE_TYPE (self_type), method_signature); else method = lookup_java_method (CLASS_TO_HANDLE_TYPE (self_type), method_name, method_signature); if (method == NULL_TREE) { error ("Class '%s' has no method named '%s' matching signature '%s'", self_name, IDENTIFIER_POINTER (method_name), IDENTIFIER_POINTER (method_signature)); } /* Invoke static can't invoke static/abstract method */ else if (opcode == OPCODE_invokestatic) { if (!METHOD_STATIC (method)) { error ("invokestatic on non static method"); method = NULL_TREE; } else if (METHOD_ABSTRACT (method)) { error ("invokestatic on abstract method"); method = NULL_TREE; } } else { if (METHOD_STATIC (method)) { error ("invoke[non-static] on static method"); method = NULL_TREE; } } if (method == NULL_TREE) { method_type = get_type_from_signature (method_signature); pop_arguments (TYPE_ARG_TYPES (method_type)); if (opcode != OPCODE_invokestatic) pop_type (self_type); method_type = promote_type (TREE_TYPE (method_type)); push_value (convert (method_type, integer_zero_node)); return; } method_type = TREE_TYPE (method); arg_list = pop_arguments (TYPE_ARG_TYPES (method_type)); flush_quick_stack (); func = NULL_TREE; if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial || (opcode == OPCODE_invokevirtual && (METHOD_PRIVATE (method) || METHOD_FINAL (method) || CLASS_FINAL (TYPE_NAME (self_type))))) func = build_known_method_ref (method, method_type, self_type, method_signature, arg_list); else { tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface, arg_list); if (opcode == OPCODE_invokevirtual) func = build_invokevirtual (dtable, method); else func = build_invokeinterface (dtable, method_name, method_signature); } func = build1 (NOP_EXPR, build_pointer_type (method_type), func); call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE); TREE_SIDE_EFFECTS (call) = 1; if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE) expand_expr_stmt (call); else { push_value (call); flush_quick_stack (); }}/* 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. FIELD_REF_INDEX is an index into the constant pool. */static voidexpand_java_field_op (is_static, is_putting, field_ref_index) int is_static; int is_putting; int field_ref_index;{ tree self_type = get_class_constant (current_jcf, COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, field_ref_index)); char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type))); tree field_name = COMPONENT_REF_NAME (¤t_jcf->cpool, field_ref_index); tree field_signature = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, field_ref_index); tree field_type = get_type_from_signature (field_signature); tree new_value = is_putting ? pop_value (field_type) : NULL_TREE; tree field_ref; int is_error = 0; tree field_decl = lookup_field (&self_type, field_name); if (field_decl == error_mark_node) { is_error = 1; } else if (field_decl == NULL_TREE) { error ("Missing field '%s' in '%s'", IDENTIFIER_POINTER (field_name), self_name); is_error = 1; } else if (build_java_signature (TREE_TYPE (field_decl)) != field_signature) { error ("Mismatching signature for field '%s' in '%s'", IDENTIFIER_POINTER (field_name), self_name); is_error = 1; } field_ref = is_static ? NULL_TREE : pop_value (self_type); if (is_error) { if (! is_putting) push_value (convert (field_type, integer_zero_node)); flush_quick_stack (); return; } /* Inline references to java.lang.PRIMTYPE.TYPE. In addition to being a useful (minor) optimization, this is also needed to avoid circularities in the implementation of these fields in libjava. */ if (field_name == TYPE_identifier_node && ! is_putting && ! flag_emit_class_files && field_type == class_ptr_type && strncmp (self_name, "java.lang.", 10) == 0) { tree typ = build_primtype_type_ref (self_name); if (typ) { push_value (typ); return; } } field_ref = build_field_ref (field_ref, self_type, field_name); if (is_static) field_ref = build_class_init (self_type, field_ref); if (is_putting) { flush_quick_stack (); if (FIELD_FINAL (field_decl)) { if (DECL_CONTEXT (field_decl) != current_class) error_with_decl (field_decl, "assignment to final field `%s' not in field's class"); else if (FIELD_STATIC (field_decl)) { if (!IS_CLINIT (current_function_decl)) error_with_decl (field_decl, "assignment to final static field `%s' not in class initializer"); } else { if (! DECL_CONSTRUCTOR_P (current_function_decl)) error_with_decl (field_decl, "assignment to final field `%s' " "not in constructor"); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -