diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-11-25 03:47:08 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-11-25 03:47:08 +0000 |
commit | a4ccc41f9a5f050d518b8c30739a647f67756f9e (patch) | |
tree | 477abdf83653e20b0e74447d6ca47eb67b0511b8 | |
parent | 2f3c6e08b9d664df3e416a186fd2938de188e706 (diff) | |
download | gcc-a4ccc41f9a5f050d518b8c30739a647f67756f9e.tar.gz |
* Merged gcj-abi-2-dev-branch to trunk.
(Actual changes too large to list in the commit message;
see ChangeLog.)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@91270 138bc75d-0d04-0410-961f-82ee72b054a4
70 files changed, 11294 insertions, 3348 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 272e8c52ab3..fc28a08c365 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,586 @@ +2004-11-24 Tom Tromey <tromey@redhat.com> + + * Merged gcj-abi-2-dev-branch to trunk. + +2004-11-24 Andrew Haley <aph@redhat.com> + + * jcf-parse.c (parse_class_file): Set file_start_location. + +2004-11-10 Tom Tromey <tromey@redhat.com> + + * class.c (make_field_value): Don't call build_static_field_ref. + (build_static_field_ref): Don't emit direct references when using + indirect dispatch. + + * gcj.texi (Invoking gij): Document -verbose. Put -verbose and + -verbose:class into man page synopsis. + +2004-11-09 Tom Tromey <tromey@redhat.com> + + * expr.c (build_java_arraystore_check): Still generate check if + element type is itself an array. + +2004-11-08 Tom Tromey <tromey@redhat.com> + + * java-tree.h (soft_check_assignment_node): Removed. + (enum java_tree_index): Removed JTI_SOFT_CHECK_ASSIGNMENT_NODE. + * decl.c (java_init_decl_processing): Don't initialize + soft_check_assignment_node. + +2004-11-05 Tom Tromey <tromey@redhat.com> + + * class.c (layout_class_methods): Don't add Miranda methods when + using indirect dispatch. + +2004-11-05 Bryce McKinlay <mckinlay@redhat.com> + + * class.c (make_class_data): Call emit_assertion_table to set the + 'assertion_table' field. + (build_signature_for_libgcj): Move here from expr.c. + (add_assertion_table_entry): New function. Callback for assertion + hashtable traversal. + (emit_assertion_table): New. Take class argument, and generate + assertion table DECL based on the TYPE_ASSERTIONS hashtable. + * decl.c (init_decl_processing): Define assertion_entry_type record. + Push 'assertion_table' class field instead of 'verify'. + * expr.c (type_assertion_eq): Compare 'assertion_code' field. + (type_assertion_hash): Include 'assertion_code' in hash. + (add_type_assertion): Rewritten. Take class and assertion_code + arguments. Add assertions to the TYPE_ASSERTIONS hashtable. + (can_widen_reference_to): Use new add_type_assertion() arguments. + * java-tree.h (java_tree_index): Add JTI_ASSERTION_ENTRY_TYPE, + JTI_ASSERTION_TABLE_TYPE. Remove JTI_VERIFY_IDENTIFIER_NODE. + (verify_identifier_node): Removed. + (assertion_entry_type, assertion_table_type): New. + (ASSERTION_TYPES_COMPATIBLE, ASSERTION_IS_INSTANTIABLE): New. Type + assertion code definitions. + (struct type_assertion): Add assertion_code. Rename 'source_type' and + 'target_type' to 'op1' and 'op2'. + (add_type_assertion): Declare. + (lang_printable_name_wls): Remove unused definition. + * verify-glue.c: (vfy_is_assignable_from): New. Call add_type_assertion + to emit runtime assertion. + (vfy_note_stack_type): Clean up non-C90 declarations. + (vfy_note_local_type): Likewise. + * verify.h (vfy_is_assignable_from): Declare. + * verify-impl.c (is_assignable_from_slow): Remove unused function. + (ref_compatible): Rename arguments. Call vfy_is_assignable_from() + instead of is_assignable_from_slow(). + (types_compatible): Reinstate ref_compatible() call. + +2004-11-04 Tom Tromey <tromey@redhat.com> + + * class.c (build_static_field_ref): Reverted previous patch. + + * class.c (build_static_field_ref): Don't emit direct references + when using indirect dispatch. + +2004-11-03 Tom Tromey <tromey@redhat.com> + + * expr.c (expand_java_arrayload): Set lhs_type_node. + (expand_java_arraystore): Set rhs_type_node. + +2004-11-02 Tom Tromey <tromey@redhat.com> + + * jcf-parse.c (compute_class_name): Use filename length from zip + directory, not strlen. + + * expr.c (expand_invoke): Mark new interface methods as abstract. + +2004-11-01 Tom Tromey <tromey@redhat.com> + + * verify-impl.c (push_jump): Removed check for uninitialized + objects. + (push_exception_jump): Likewise. + (handle_ret_insn): Likewise. + (handle_jsr_insn): Likewise. + (state_check_no_uninitialized_objects): Removed. + + * decl.c (check_local_unnamed_variable): Recognize + promoted-to-int parameters when using the new verifier. + * expr.c (expand_java_arraystore): Explicitly request array type + when using new verifier. + (expand_java_arrayload): Likewise. + (invoke_build_dtable): Don't pass object_type_node as + expression argument to build_java_indirect_ref. + (build_java_check_indexed_type): Do nothing. + (build_java_arraystore_check): Handle case where array doesn't + have array type. + (build_java_array_length_access): Likewise. + (expand_invoke): Handle case where interface overrides a method + from Object. + (pop_type_0): Always succeed for reference types. + (process_jvm_instruction): Don't pop a value in a dead + exception handler. + (pop_arguments): Convert arguments to correct types. + +2004-10-29 Andrew Haley <aph@redhat.com> + + * jcf-parse.c (give_name_to_class): Remove line that was + incorrectly merged. + +2004-10-29 Andrew Haley <aph@redhat.com> + + * jcf-parse.c (set_source_filename): Add code to build new sfname. + +2004-10-20 Andrew Haley <aph@redhat.com> + + * decl.c (end_java_method): Don't expand if flag_syntax_only. + +2004-10-26 Tom Tromey <tromey@redhat.com> + + * verify.h (vfy_notify_verified): Removed. + * verify-glue.c (vfy_notify_verified): Removed. + +2004-10-26 Tom Tromey <tromey@redhat.com> + + * verify-impl.c (debug_print_state): Declare `i' before code. + (merge_types): Modify `t' when it is null_type. + +2004-10-26 Tom Tromey <tromey@redhat.com> + + * verify-impl.c (type_print): Renamed from print. Now static and + takes an argument. + (debug_print_state): Use type_print. + +2004-10-25 Tom Tromey <tromey@redhat.com> + + * expr.c (build_invokeinterface): Compute correct offset for + index into interface methods. + +2004-10-20 Tom Tromey <tromey@redhat.com> + + * java-tree.h (verify_jvm_instructions_new): Declare. + + * jvspec.c (jvgenmain_spec): Remove -fnew-verifier from cc1 + command line. + + * verify-impl.c (verify_instructions): Correctly handle wide + types on the stack. + * verify-glue.c (vfy_get_class_name): Use DECL_NAME. + (vfy_get_component_type): Strip pointer types. + (vfy_find_class): Use get_type_from_signature. Strip pointer + types. + Include java-except.h. + +2004-10-20 Bryce McKinlay <mckinlay@redhat.com> + + * verify-impl.c (type_array_elementpop_raw, vfy_pop_type_t, + vfy_push_type_t, set_variable, add_new_state, merge_into, + handle_jsr_insn, branch_prepass, check_class_constant, + check_wide_constant, get_one_type, compute_static_types, + verify_instructions_0): Clean up C99 declarations after statements. + +2004-10-20 Tom Tromey <tromey@redhat.com> + + * verify-impl.c (merge_refs): Compare reference against iterator, + not ref2. + + * verify-glue.c (vfy_tag): Mask off resolved flag. + +2004-10-19 Tom Tromey <tromey@redhat.com> + + * verify-impl.c (verify_instructions): Call vfy_note_local_type. + (init_state_with_stack): Initialize `this_type' in state. + (verify_method): Use debug_print. + * verify-glue.c (vfy_is_primitive): Removed debugging print. + (vfy_note_stack_depth): Reverted last patch. + (vfy_note_stack_type): Note pointer to Object, not Object. + (vfy_note_local_type): Likewise. + + * verify.h (vfy_note_instruction_seen): Declare. + * verify-glue.c (verify_jvm_instructions_new): Set + BCODE_EXCEPTION_TARGET on target instruction. + (vfy_note_instruction_seen): New function. + * verify-impl.c (FLAG_INSN_SEEN): New define. + (verify_instructions_0): Set flag on instruction. Save state for + PC=0 later. + (verify_instructions): Call vfy_note_instruction_seen. + + * verify-glue.c (vfy_note_stack_depth): Fix off-by-one error. + (verify_jvm_instructions_new): Call method_init_exceptions, + add_handler, and handle_nested_ranges. + * verify-impl.c (verify_method): Return 1 on success. + (verify_instructions_0): Save the state at PC=0. + + * verify-impl.c (init_type_from_class): Set is_resolved and + ref_next on new ref_intersection. + (init_type_from_string): Likewise. + +2004-10-15 Bryce McKinlay <mckinlay@redhat.com> + + * expr.c (expand_bytecode): Use verify_jvm_instructions_new + if flag_new_verifier is set. + * java-tree.h (flag_new_verifier): Declare. + * lang.opt (fnew-verifier): New option. + * verify-impl.c: Work around namespace pollution by undef'ing + 'current_class'. + (struct verifier_context): Make 'bytecode' const. + (verify_fail_pc): Pass -1 PC argument to vfy_fail. + (types_compatible): For the BC-ABI, always consider reference types + compatible. + (check_class_constant): Use vfr->current_class. + (check_constant): Likewise. + (check_wide_constant): Likewise. + (check_field_constant): Check for 'L' at start of type name. + (get_one_type): Return pointer instead of type. Set type result in + caller via passed type pointer. + (compute_argument_types): Update to use new get_one_type arguments. + (compute_return_type): Likewise. + (make_verifier_context): New. Allocate and initialize 'vfr'. + (free_verifier_context): New. Free 'vfr' and its contents. + (verify_method): Remove ATTRIBUTE_UNUSED. Call make_verifier_context + and free_verifier_context. + +2004-10-15 Tom Tromey <tromey@redhat.com> + + * verify-glue.c (vfy_note_local_type): Mark argument as unused. + * verify.h (vfy_fail): Fixed formatting. + + * verify-impl.c (vfr): Fixed comment formatting. + (collapse_type): New function. + (verify_instructions): Notify compiler about type map. + * verify.h (vfy_note_stack_depth): Updated. + (vfy_note_stack_type): Likewise. + (vfy_note_local_type): Likewise. + (vfy_unsuitable_type, vfy_return_address_type, vfy_null_type): + Declare. + * verify-glue.c (vfy_note_stack_depth): Correctly size type + state. Added `method' argument. + (vfy_note_stack_type): Renamed from vfy_note_type. Added `method' + argument. + (vfy_note_local_type): New function. + (vfy_unsuitable_type): Likewise. + (vfy_return_address_type): Likewise. + (vfy_null_type): Likewise. + + * verify.h (VFY_IN_GCC): Removed. + (VFY_WANT_TYPEMAP): Removed. + * verify-impl.c (verify_instructions_0): Removed useless "\". + (struct state) <next>: Uncomment. + +2004-10-13 Bryce McKinlay <mckinlay@redhat.com> + + * verify-impl.c: Formatting fixes. Reformat C++-style comments to + C-style. + +2004-10-06 Bryce McKinlay <mckinlay@redhat.com> + + * Make-lang.in (verify.o): Re-enabled this target. + * verify-glue.c (vfy_get_interface_count): Add ATTRIBUTE_UNUSED. + (vfy_get_interface): Likewise. + (verify_jvm_instructions_new): Renamed from verify_jvm_instructions. + * verify.h (verify_jvm_instructions_new): Declare. + * verify-impl.c (free_state): Temporarily comment out unused + function. + +2004-10-06 Tom Tromey <tromey@redhat.com> + + * java-tree.h (JV_STATE_READ): New enum value. + +2004-10-06 Bryce McKinlay <mckinlay@redhat.com> + + * verify.h: New file. + +2004-10-05 Bryce McKinlay <mckinlay@redhat.com> + + * verify-impl.c, verify-glue.c, verify.h: New files. + * Make-lang.in: Add rules for verify-impl.o and verify-glue.o. + +2004-09-24 Andrew Haley <aph@redhat.com> + + * decl.c (check_local_unnamed_variable): Always use the PARM_DECL + for a slot if it's of pointer type. + +2004-09-14 Tom Tromey <tromey@redhat.com> + + * class.c (make_class_data): Correctly initialize "state" field. + Initialize "engine" field. + * decl.c (java_init_decl_processing): Add "engine" field. + +2004-09-10 Andrew Haley <aph@redhat.com> + + PR java/12760 + * expr.c (build_invokeinterface): Use fast method for interface + dispatch. + * java-tree.h (enum java_tree_index): Add JTI_ITABLE_TYPE, + JTI_ITABLE_PTR_TYPE. + (struct lang_type): Add itable_methods, itable_decl, itable_syms_decl. + (emit_symbol_table): Add new arg, element_size. + * decl.c (java_init_decl_processing): Initialize Class.itable. + * class.c (GEN_TABLE): New macro. + (gen_indirect_dispatch_tables): Use it. Add itable. + (make_class_data): Add new arg for emit_symbol_table(). + Emit itable. + (add_miranda_methods): Make sure search_class has been parsed. + (emit_symbol_table): Add new arg, element_size. + +2004-09-06 Andrew Haley <aph@redhat.com> + + * verify.c (merge_types): Return Object for all merges of + interfaces. + * expr.c (add_type_assertion): Don't generate assertions when + source type is array of Object. + +2004-09-03 Andrew Haley <aph@redhat.com> + + * class.c (finish_class): Nullify TYPE_VERIFY_METHOD. + + * lang.c (java_post_options): Force flag_verify_invocations if + we're not using indirect dispatch. + + * expr.c (pop_type_0): Move test for interfaces before call to + can_widen_reference_to(). + (build_signature_for_libgcj): Remove generation of canonical array + type. + (add_type_assertion): Canonicalize both arrays. + Don't assert that type X can be assigned to Object. + Don't assert that type X an be assigned to type X. + Don't assert that Object can be assigned to type X. + (can_widen_reference_to): Warn whenever we generate an assertion. + (process_jvm_instruction): Use throwable_type_node for the type of + an exception class. + +2004-09-01 Andrew Haley <aph@redhat.com> + + * decl.c (java_init_decl_processing): Change + verify_identifier_node to "__verify". + * expr.c (add_type_assertion): Use verify_identifier_node for name. + * java-tree.h (verify_identifier_node): Change to "__verify". + + * expr.c (build_signature_for_libgcj): New function. + (add_type_assertion): Use it to construct signatures for + source_type and target_type. + +2004-08-27 Andrew Haley <aph@redhat.com> + + * java-tree.h (enum java_tree_index): Add JTI_VERIFY_IDENTIFIER_NODE. + (verify_identifier_node): New. + (TYPE_VERIFY_METHOD): New. + (struct type_assertion): New type. + * expr.c (type_assertion_eq): New function. + (type_assertion_hash): New function. + (add_type_assertion): New function. + (can_widen_reference_to): Call add_type_assertion(). + * decl.c (java_init_decl_processing): Add verify_identifier_node. + * class.c (make_class_data): Initialize TYPE_VERIFY_METHOD (type). + (finish_class): Output TYPE_VERIFY_METHOD (type). + + * decl.c (end_java_method): Nullify unused fields. + +2004-08-17 Andrew Haley <aph@redhat.com> + + * verify.c (defer_merging): Quieten. + * jcf-parse.c (load_class): Only try to open a class file if it's + java.lang.Object or if it's part of the current compilation. + Check that the class we just tried to load is the class we just + loaded. Quieten. + (java_parse_file): Set flag_verify_invocations off if we're + compiling from .class. + (parse_zip_file_entries): Abort if we try to read a dummy class. + * expr.c (can_widen_reference_to): Quieten. + (build_invokevirtual): Abort if we try to invokevirtual an + interface. + (expand_invoke): Don't build a non-interface call to an interface. + (build_instanceof): Don't do premature optimization if + flag_verify_invocations is not set. + * class.c (set_super_info): Disable code that inherits TYPE_DUMMY + from superclass. + (build_static_field_ref): Add correct type conversion for + field_address. + (add_miranda_methods): Disable generation of Miranda methods for + dummy classes. + (layout_class_method): Don't complain about non-static method + overrides static method with dummy classes. + +2004-08-13 Tom Tromey <tromey@redhat.com> + + * class.c (build_static_field_ref): Re-enable atable lookups for + static fields. + + * parse.y (strip_out_static_field_access_decl): Indentation fix. + +2004-08-11 Tom Tromey <tromey@redhat.com> + + * gcj.texi (libgcj Runtime Properties): Document new properties. + +2004-08-06 Andrew Haley <aph@redhat.com> + + * jcf-parse.c (load_class): Check that we really have loaded the + class we're looking for. + +2004-07-19 Andrew Haley <aph@redhat.com> + + * verify.c (verify_jvm_instructions): Comment change only. + + * typeck.c (build_java_array_type): Add size field to array name. + + * java-tree.h (LOCAL_SLOT_P): New. + (update_aliases): Add PC argument. + (pushdecl_function_level): New function. + + * java-gimplify.c (java_gimplify_expr): Handle VAR_DECL, + MODIFY_EXPR, and SAVE_EXPR. + (java_gimplify_modify_expr): New function. + + * expr.c (push_type_0): Call find_stack_slot() to create temporary. + (expand_iinc): Pass PC to update_aliases(). + (STORE_INTERNAL): Likewise. + (process_jvm_instruction): Likewise. + + * decl.c (base_decl_map): New variable. + (uniq): New variable. + (update_aliases): Rewrite with more thorough checking. + (debug_variable_p): New function. + (push_jvm_slot): Don't initialize local variable. Don't pushdecl. + (check_local_named_variable): Delete whole function. + (initialize_local_variable): New function. + (check_local_unnamed_variable): Add checks and comments. + (find_local_variable): Rewrite. + (java_replace_reference): New function. + (function_binding_level): New variable. + (pushdecl_function_level): New function. + (maybe_pushlevels): Set DECL_LOCAL_END_PC. + (maybe_pushlevels): Call pushdecl() on each of the new decls. + (start_java_method): Reset uniq. Create base_decl_map. Set + function_binding_level. + (end_java_method): Null unused fields to save memory. + +2004-06-29 Andrew Haley <aph@redhat.com> + + * except.c (expand_start_java_handler): Push a new binding level. + Don't build a TRY_CATCH_EXPR now, we'll do it later. Call + register_exception_range() to register where we'll do it. + (expand_end_java_handler): Remove old bogus code. Replace with + new logic that simply builds TRY_CATCH_EXPRs and inserts them at + the top of the expression we're curently building. + (maybe_end_try): Delete. + * decl.c (binding_level.exception_range): New field. + (clear_binding_level): Add field exception_range. Reformat. + (poplevel): Call expand_end_java_handler(). + (poplevel): Call java_add_stmt only if functionbody is false. + (maybe_poplevels): Don't call maybe_end_try() from here. + (end_java_method): Clear no longer used trees in function decl. + (register_exception_range): New function. + * java-tree.h (register_exception_range, struct eh_range): Declare. + +2004-06-22 Andrew Haley <aph@redhat.com> + + * class.c (gen_indirect_dispatch_tables): Set the DECL_OWNER of + the otable. + * check-init.c (get_variable_decl): Teach check-init about + FIELD_DECLs addressed via the otable. + * jcf-parse.c (load_class): Check CLASS_LOADED_P, not + CLASS_PARSED_P. + +2004-05-28 Andrew Haley <aph@redhat.com> + + * jcf-parse.c (load_class): Don't try to read a class that we've + already read. + + * expr.c (build_invokeinterface): Use the old-fashioned way of + doing indirect dispatch: look up interfaces by name. + * java-tree.h (enum java_tree_index): Add + JTI_SOFT_LOOKUPINTERFACEMETHODBYNAME_NODE + * decl.c (java_init_decl_processing): Add + soft_lookupinterfacemethodbyname_node. + + * gjavah.c (print_method_info): Final methods have vtable entries, + so gjavah needs to output them. + * class.c (layout_class_method): Generate vtable entries for final + methods. + * parse.y (invocation_mode): Use INVOKE_VIRTUAL for indirect + dispatch, even if a method is final. + +2004-05-25 Andrew Haley <aph@redhat.com> + + * class.c (build_symbol_entry): Convert the names of constructors + to init_identifier_node when generating an entry for the indirect + dispatch table. + + * expr.c (build_known_method_ref): Generate indirect calls for + all methods marked DECL_EXTERNAL or TREE_PUBLIC. + +2004-05-24 Andrew Haley <aph@redhat.com> + + * expr.c (build_known_method_ref): Make sure ARRAY_REF access to + atable element is of the right type. + + * class.c (build_static_field_ref): Cast pointer to correct type + for field. + +2004-04-20 Bryce McKinlay <mckinlay@redhat.com> + + * Merged with HEAD as of 20040514. Diff against + gcj-abi-2-merge-20040514. + +2004-04-16 Andrew Haley <aph@redhat.com> + + * verify.c (check_pending_block): Disable subroutine checks. + (defer_merging): New function. + (merge_types): If types are dummy, use defer_merging to combine them. + (verify_jvm_instructions): If invocation is invokeinterface and + target is dummy, assume target really is an interface. + + * parse.y (patch_invoke): Break out call to java_create_object. + + * lang.c (flag_verify_invocations): New. + + * jcf-parse.c (load_class): If we've already failed to load a + class, don't try again. + (load_class): If we can't find a .class file, don't fail, but emit + a warning. + (parse_class_file): Don't act on dummy methods. + + * java-tree.h (flag_verify_invocations): New. + (TYPE_DUMMY): New. + (lang_type.dummy_class): New field. + (java_create_object): New function. + (METHOD_DUMMY): New. + + * expr.c (build_field_ref): Widen field offset. + (pop_type_0): If the type in stack_type_map is a TREE_LIST, check + that each of its elements is compatible with the one we're + popping. + (pop_type_0): Issue a warning to say that we need to generate a + runtime check. + (java_create_object): New function. + (build_field_ref): Only generate hard refs if we're not using + indirect dispatch. + (expand_java_field_op): If we're using !verify_invocations and we + see a missing field, generate a decl for it. + + (expand_invoke): If a class doesn't have the method we seek and + we're using !flag_verify_invocations, generate a decl for the + method now. + + (build_known_method_ref): Always use indirect dispatch via the + atable for static methods. + + (expand_java_NEW): Break out object creation into new function, + java_create_object. + + (can_widen_reference_to): Issue a warning to say that we need to + generate a runtime check. + + * class.c (set_super_info): Inherit TYPE_DUMMY from sureclass. + (make_method_value): Also use index for interfaces. + (make_class_data): Skip dummy field for inherited data. + Don't build method array for dummy methods. + Set size_in_byte to -1 when using inirect dispatch + Don't build a hard class ref if we don't have a hard ref to our + superclass, or if we're using inirect dispatch. + Null out dispatch tables. + + (layout_class_method): Don't complain about non-static method + overrides static method is method is artificial. + + (build_static_field_ref): Disable atable references to static + fields for the time being. + + (layout_class_methods): Check for CLASS_INTERFACE as + well as CLASS_ABSTRACT. + 2004-11-24 Steven Bosscher <stevenb@suse.de> * class.c (make_class_data): Don't check flag_inline_functions. diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in index bea8c73d556..16094b9c28b 100644 --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -102,6 +102,7 @@ gt-java-builtins.h gtype-java.h gt-java-resource.h : s-gtype ; @true # Executables built by this Makefile: JAVA_OBJS = java/parse.o java/class.o java/decl.o java/expr.o \ java/constants.o java/lang.o java/typeck.o java/except.o java/verify.o \ + java/verify-glue.o java/verify-impl.o \ java/zextract.o java/jcf-io.o java/win32-host.o java/jcf-parse.o java/mangle.o \ java/mangle_name.o java/builtins.o java/resource.o \ java/jcf-write.o java/buffer.o java/check-init.o java/jcf-depend.o \ @@ -338,6 +339,10 @@ java/win32-host.o: java/win32-host.c $(CONFIG_H) $(SYSTEM_H) coretypes.h java/jc java/verify.o: java/verify.c $(CONFIG_H) $(JAVA_TREE_H) java/jcf.h \ java/javaop.h java/java-opcodes.h java/java-except.h toplev.h $(SYSTEM_H) \ coretypes.h $(TM_H) +java/verify-glue.o: java/verify-glue.c $(CONFIG_H) $(SYSTEM_H) $(JAVA_TREE_H) \ + coretypes.h $(TM_H) java/verify.h +java/verify-impl.o: java/verify-impl.c $(CONFIG_H) java/verify.h $(SYSTEM_H) \ + coretypes.h java/jcf.h $(JAVA_TREE_H) java/xref.o: java/xref.c java/xref.h $(CONFIG_H) $(JAVA_TREE_H) toplev.h \ $(SYSTEM_H) coretypes.h $(TM_H) java/zextract.o: java/zextract.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ diff --git a/gcc/java/check-init.c b/gcc/java/check-init.c index dacc4b914b5..05692b0a4c2 100644 --- a/gcc/java/check-init.c +++ b/gcc/java/check-init.c @@ -36,7 +36,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ /* The basic idea is that we assign each local variable declaration and each blank final field an index, and then we pass around bitstrings, where the (2*i)'th bit is set if decl whose DECL_BIT_INDEX - is i is definitely assigned, and the (2*i+1)'th bit is set if + is i is definitely assigned, and the the (2*i=1)'th bit is set if decl whose DECL_BIT_INDEX is i is definitely unassigned */ /* One segment of a bitstring. */ @@ -45,7 +45,7 @@ typedef unsigned int word; /* Pointer to a bitstring. */ typedef word *words; -/* Number of local variables currently active. */ +/* Number of locals variables currently active. */ static int num_current_locals = 0; /* The value of num_current_locals when we entered the closest @@ -191,6 +191,50 @@ get_variable_decl (tree exp) return op1; } } + else if (TREE_CODE (exp) == INDIRECT_REF) + { + /* For indirect dispatch, look for an expression of the form + (indirect_ref (+ (array_ref otable <N>) this)). + FIXME: it would probably be better to generate a JAVA_FIELD_REF + expression that gets converted to OTABLE access at + gimplification time. */ + exp = TREE_OPERAND (exp, 0); + if (TREE_CODE (exp) == PLUS_EXPR) + { + tree op0 = TREE_OPERAND (exp, 0); + STRIP_NOPS (op0); + if (TREE_CODE (op0) == ARRAY_REF) + { + tree table = TREE_OPERAND (op0, 0); + if (TREE_CODE (table) == VAR_DECL + && DECL_LANG_SPECIFIC (table) + && DECL_OWNER (table) + && TYPE_OTABLE_DECL (DECL_OWNER (table)) == table) + { + HOST_WIDE_INT index + = TREE_INT_CST_LOW (TREE_OPERAND (op0, 1)); + tree otable_methods + = TYPE_OTABLE_METHODS (DECL_OWNER (table)); + tree element; + for (element = otable_methods; + element; + element = TREE_CHAIN (element)) + { + if (index == 1) + { + tree purpose = TREE_PURPOSE (element); + if (TREE_CODE (purpose) == FIELD_DECL) + return purpose; + else + return NULL_TREE; + } + --index; + } + } + } + } + } + return NULL_TREE; } @@ -306,7 +350,7 @@ check_bool2_init (enum tree_code code, tree exp0, tree exp1, /* Check a boolean expression EXP for definite [un]assignment. BEFORE is the set of variables definitely [un]assigned before the conditional. (This bitstring may be modified arbitrarily in this function.) - On output, WHEN_FALSE is the set of variables definitely [un]assigned after + On output, WHEN_FALSE is the set of variables [un]definitely assigned after the conditional when the conditional is false. On output, WHEN_TRUE is the set of variables definitely [un]assigned after the conditional when the conditional is true. @@ -432,8 +476,8 @@ done_alternative (words after, struct alternatives *current) WORDS_NEEDED (2 * current->num_locals)); } -/* Used when we are done with a control flow branch and are all merged again. - AFTER is the merged state of [un]assigned variables, +/* Used when we done with a control flow branch and are all merged again. + * AFTER is the merged state of [un]assigned variables, CURRENT is a struct alt that was passed to BEGIN_ALTERNATIVES. */ #define END_ALTERNATIVES(after, current) \ @@ -445,7 +489,7 @@ done_alternative (words after, struct alternatives *current) start_current_locals = current.save_start_current_locals; \ } -/* Check for [un]initialized local variables in EXP. */ +/* Check for (un)initialized local variables in EXP. */ static void check_init (tree exp, words before) @@ -460,7 +504,7 @@ check_init (tree exp, words before) && DECL_NAME (exp) != this_identifier_node) { int index = DECL_BIT_INDEX (exp); - /* We don't want to report and mark as non-initialized class + /* We don't want to report and mark as non initialized class initialization flags. */ if (! LOCAL_CLASS_INITIALIZATION_FLAG_P (exp) && index >= 0 && ! ASSIGNED_P (before, index)) @@ -604,7 +648,7 @@ check_init (tree exp, words before) "hypothetical" analysis model. We do something much simpler: We just disallow assignments inside loops to final variables declared outside the loop. This means we may - disallow some contrived assignments that the JLS allows, but I + disallow some contrived assignments that the JLS, but I can't see how anything except a very contrived testcase (a do-while whose condition is false?) would care. */ diff --git a/gcc/java/class.c b/gcc/java/class.c index 543bdf2d984..391752ad271 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -43,6 +43,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "stdio.h" #include "target.h" #include "except.h" +#include "cgraph.h" #include "tree-iterator.h" /* DOS brain-damage */ @@ -61,6 +62,7 @@ static tree maybe_layout_super_class (tree, tree); static void add_miranda_methods (tree, tree); static int assume_compiled (const char *); static tree build_symbol_entry (tree); +static tree emit_assertion_table (tree); struct obstack temporary_obstack; @@ -342,6 +344,34 @@ unmangle_classname (const char *name, int name_length) return to_return; } +#define GEN_TABLE(TABLE, NAME, TABLE_TYPE, TYPE) \ +do \ +{ \ + const char *typename = IDENTIFIER_POINTER (mangled_classname ("", TYPE)); \ + char *buf = alloca (strlen (typename) + strlen (#NAME "_syms_") + 1); \ + tree decl; \ + \ + sprintf (buf, #NAME "_%s", typename); \ + TYPE_## TABLE ##_DECL (type) = decl = \ + build_decl (VAR_DECL, get_identifier (buf), TABLE_TYPE); \ + DECL_EXTERNAL (decl) = 1; \ + TREE_STATIC (decl) = 1; \ + TREE_READONLY (decl) = 1; \ + TREE_CONSTANT (decl) = 1; \ + DECL_IGNORED_P (decl) = 1; \ + /* Mark the table as belonging to this class. */ \ + pushdecl (decl); \ + MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); \ + DECL_OWNER (decl) = TYPE; \ + sprintf (buf, #NAME "_syms_%s", typename); \ + TYPE_## TABLE ##_SYMS_DECL (TYPE) = \ + build_decl (VAR_DECL, get_identifier (buf), symbols_array_type); \ + TREE_STATIC (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ + TREE_CONSTANT (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ + DECL_IGNORED_P (TYPE_## TABLE ##_SYMS_DECL (TYPE)) = 1; \ + pushdecl (TYPE_## TABLE ##_SYMS_DECL (TYPE)); \ +} \ +while (0) /* Given a class, create the DECLs for all its associated indirect dispatch tables. */ @@ -372,54 +402,14 @@ gen_indirect_dispatch_tables (tree type) if (flag_indirect_dispatch) { - { - char *buf = alloca (strlen (typename) + strlen ("_otable_syms_") + 1); - - sprintf (buf, "_otable_%s", typename); - TYPE_OTABLE_DECL (type) = - build_decl (VAR_DECL, get_identifier (buf), otable_type); - DECL_EXTERNAL (TYPE_OTABLE_DECL (type)) = 1; - TREE_STATIC (TYPE_OTABLE_DECL (type)) = 1; - TREE_READONLY (TYPE_OTABLE_DECL (type)) = 1; - TREE_CONSTANT (TYPE_OTABLE_DECL (type)) = 1; - DECL_IGNORED_P (TYPE_OTABLE_DECL (type)) = 1; - pushdecl (TYPE_OTABLE_DECL (type)); - sprintf (buf, "_otable_syms_%s", typename); - TYPE_OTABLE_SYMS_DECL (type) = - build_decl (VAR_DECL, get_identifier (buf), symbols_array_type); - TREE_STATIC (TYPE_OTABLE_SYMS_DECL (type)) = 1; - TREE_CONSTANT (TYPE_OTABLE_SYMS_DECL (type)) = 1; - DECL_IGNORED_P(TYPE_OTABLE_SYMS_DECL (type)) = 1; - pushdecl (TYPE_OTABLE_SYMS_DECL (type)); - } - - { - char *buf = alloca (strlen (typename) + strlen ("_atable_syms_") + 1); - tree decl; - - sprintf (buf, "_atable_%s", typename); - TYPE_ATABLE_DECL (type) = decl = - build_decl (VAR_DECL, get_identifier (buf), atable_type); - DECL_EXTERNAL (decl) = 1; - TREE_STATIC (decl) = 1; - TREE_READONLY (decl) = 1; - TREE_CONSTANT (decl) = 1; - DECL_IGNORED_P (decl) = 1; - /* Mark the atable as belonging to this class. */ - pushdecl (decl); - MAYBE_CREATE_VAR_LANG_DECL_SPECIFIC (decl); - DECL_OWNER (decl) = type; - sprintf (buf, "_atable_syms_%s", typename); - TYPE_ATABLE_SYMS_DECL (type) = - build_decl (VAR_DECL, get_identifier (buf), symbols_array_type); - TREE_STATIC (TYPE_ATABLE_SYMS_DECL (type)) = 1; - TREE_CONSTANT (TYPE_ATABLE_SYMS_DECL (type)) = 1; - DECL_IGNORED_P (TYPE_ATABLE_SYMS_DECL (type)) = 1; - pushdecl (TYPE_ATABLE_SYMS_DECL (type)); - } + GEN_TABLE (ATABLE, _atable, atable_type, type); + GEN_TABLE (OTABLE, _otable, otable_type, type); + GEN_TABLE (ITABLE, _itable, itable_type, type); } } +#undef GEN_TABLE + tree push_class (tree class_type, tree class_name) { @@ -959,7 +949,7 @@ build_class_ref (tree type) we always emit this hard superclass reference. */ if (flag_indirect_dispatch && type != output_class - && type != CLASSTYPE_SUPER (output_class) +// && type != CLASSTYPE_SUPER (output_class) && TREE_CODE (type) == RECORD_TYPE) return build_indirect_class_ref (type); @@ -1062,8 +1052,7 @@ build_static_field_ref (tree fdecl) However, currently sometimes gcj is too eager and will end up returning the field itself, leading to an incorrect external reference being generated. */ - if ((is_compiled - && (! flag_indirect_dispatch || current_class == fclass)) + if ((is_compiled && !flag_indirect_dispatch) || (FIELD_FINAL (fdecl) && DECL_INITIAL (fdecl) != NULL_TREE && (JSTRING_TYPE_P (TREE_TYPE (fdecl)) || JNUMERIC_TYPE_P (TREE_TYPE (fdecl))) @@ -1084,16 +1073,19 @@ build_static_field_ref (tree fdecl) = build_int_cst (NULL_TREE, get_symbol_table_index (fdecl, &TYPE_ATABLE_METHODS (output_class))); tree field_address - = build4 (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)), + = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))), TYPE_ATABLE_DECL (output_class), table_index, NULL_TREE, NULL_TREE); + field_address = convert (build_pointer_type (TREE_TYPE (fdecl)), + field_address); return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), field_address)); } else { /* Compile as: - * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */ + *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr */ tree ref = build_class_ref (fclass); tree fld; int field_index = 0; @@ -1117,7 +1109,7 @@ build_static_field_ref (tree fdecl) ref, build_int_cst (NULL_TREE, field_index))); ref = build1 (INDIRECT_REF, field_type_node, ref); ref = build3 (COMPONENT_REF, field_info_union_node, - ref, lookup_field (&field_type_node, info_ident), + ref, lookup_field (&field_type_node, info_ident), NULL_TREE); ref = build3 (COMPONENT_REF, ptr_type_node, ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)), @@ -1284,7 +1276,7 @@ make_field_value (tree fdecl) ? TREE_CHAIN (TYPE_FIELDS (field_info_union_node)) : TYPE_FIELDS (field_info_union_node)), (FIELD_STATIC (fdecl) - ? build_address_of (build_static_field_ref (fdecl)) + ? build_address_of (fdecl) : byte_position (fdecl))))); FINISH_RECORD_CONSTRUCTOR (finit); @@ -1565,7 +1557,9 @@ make_class_data (tree type) /* Build Field array. */ field = TYPE_FIELDS (type); - if (DECL_NAME (field) == NULL_TREE) + while (field && DECL_ARTIFICIAL (field)) + field = TREE_CHAIN (field); /* Skip dummy fields. */ + if (field && DECL_NAME (field) == NULL_TREE) field = TREE_CHAIN (field); /* Skip dummy field for inherited data. */ for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { @@ -1620,6 +1614,11 @@ make_class_data (tree type) && ! flag_keep_inline_functions && optimize) continue; + /* Even if we have a decl, we don't necessaily have the code. + This can happen if we inherit a method from a superclass for + which we don't have a .class file. */ + if (METHOD_DUMMY (method)) + continue; init = make_method_value (method); method_count++; methods = tree_cons (NULL_TREE, init, methods); @@ -1663,10 +1662,8 @@ make_class_data (tree type) super = CLASSTYPE_SUPER (type); if (super == NULL_TREE) super = null_pointer_node; - else if (/* FIXME: we should also test for (! - flag_indirect_dispatch) here, but libgcj can't cope with - a symbolic reference a superclass in the class data. */ - assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) + else if (! flag_indirect_dispatch + && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (type_decl))) && assume_compiled (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (super))))) super = build_class_ref (super); else @@ -1721,13 +1718,19 @@ make_class_data (tree type) = emit_symbol_table (DECL_NAME (TYPE_OTABLE_DECL (type)), TYPE_OTABLE_DECL (type), TYPE_OTABLE_METHODS (type), - TYPE_OTABLE_SYMS_DECL (type), integer_type_node); + TYPE_OTABLE_SYMS_DECL (type), integer_type_node, 1); TYPE_ATABLE_DECL (type) = emit_symbol_table (DECL_NAME (TYPE_ATABLE_DECL (type)), TYPE_ATABLE_DECL (type), TYPE_ATABLE_METHODS (type), - TYPE_ATABLE_SYMS_DECL (type), ptr_type_node); + TYPE_ATABLE_SYMS_DECL (type), ptr_type_node, 1); + + TYPE_ITABLE_DECL (type) + = emit_symbol_table + (DECL_NAME (TYPE_ITABLE_DECL (type)), + TYPE_ITABLE_DECL (type), TYPE_ITABLE_METHODS (type), + TYPE_ITABLE_SYMS_DECL (type), ptr_type_node, 2); } TYPE_CTABLE_DECL (type) = emit_catch_table (type); @@ -1765,8 +1768,13 @@ make_class_data (tree type) PUSH_FIELD_VALUE (cons, "fields", fields_decl == NULL_TREE ? null_pointer_node : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl)); - PUSH_FIELD_VALUE (cons, "size_in_bytes", size_in_bytes (type)); - PUSH_FIELD_VALUE (cons, "field_count", + /* If we're using the binary compatibility ABI we don't know the + size until load time. */ + PUSH_FIELD_VALUE (cons, "size_in_bytes", + (flag_indirect_dispatch + ? integer_minus_one_node + : size_in_bytes (type))); + PUSH_FIELD_VALUE (cons, "field_count", build_int_cst (NULL_TREE, field_count)); PUSH_FIELD_VALUE (cons, "static_field_count", build_int_cst (NULL_TREE, static_field_count)); @@ -1810,6 +1818,21 @@ make_class_data (tree type) TREE_CONSTANT (TYPE_ATABLE_DECL (type)) = 1; TREE_INVARIANT (TYPE_ATABLE_DECL (type)) = 1; } + if (TYPE_ITABLE_METHODS(type) == NULL_TREE) + { + PUSH_FIELD_VALUE (cons, "itable", null_pointer_node); + PUSH_FIELD_VALUE (cons, "itable_syms", null_pointer_node); + } + else + { + PUSH_FIELD_VALUE (cons, "itable", + build1 (ADDR_EXPR, itable_ptr_type, TYPE_ITABLE_DECL (type))); + PUSH_FIELD_VALUE (cons, "itable_syms", + build1 (ADDR_EXPR, symbols_array_ptr_type, + TYPE_ITABLE_SYMS_DECL (type))); + TREE_CONSTANT (TYPE_ITABLE_DECL (type)) = 1; + TREE_INVARIANT (TYPE_ITABLE_DECL (type)) = 1; + } PUSH_FIELD_VALUE (cons, "catch_classes", build1 (ADDR_EXPR, ptr_type_node, TYPE_CTABLE_DECL (type))); @@ -1817,7 +1840,13 @@ make_class_data (tree type) PUSH_FIELD_VALUE (cons, "loader", null_pointer_node); PUSH_FIELD_VALUE (cons, "interface_count", build_int_cst (NULL_TREE, interface_len)); - PUSH_FIELD_VALUE (cons, "state", integer_zero_node); + PUSH_FIELD_VALUE + (cons, "state", + convert (byte_type_node, + build_int_cst (NULL_TREE, + flag_indirect_dispatch + ? JV_STATE_PRELOADING + : JV_STATE_COMPILED))); PUSH_FIELD_VALUE (cons, "thread", null_pointer_node); PUSH_FIELD_VALUE (cons, "depth", integer_zero_node); @@ -1825,9 +1854,23 @@ make_class_data (tree type) PUSH_FIELD_VALUE (cons, "idt", null_pointer_node); PUSH_FIELD_VALUE (cons, "arrayclass", null_pointer_node); PUSH_FIELD_VALUE (cons, "protectionDomain", null_pointer_node); + + { + tree assertion_table_ref; + if (TYPE_ASSERTIONS (type) == NULL) + assertion_table_ref = null_pointer_node; + else + assertion_table_ref = build1 (ADDR_EXPR, + build_pointer_type (assertion_table_type), + emit_assertion_table (type)); + + PUSH_FIELD_VALUE (cons, "assertion_table", assertion_table_ref); + } + PUSH_FIELD_VALUE (cons, "hack_signers", null_pointer_node); PUSH_FIELD_VALUE (cons, "chain", null_pointer_node); PUSH_FIELD_VALUE (cons, "aux_info", null_pointer_node); + PUSH_FIELD_VALUE (cons, "engine", null_pointer_node); FINISH_RECORD_CONSTRUCTOR (cons); @@ -1838,11 +1881,26 @@ make_class_data (tree type) DECL_ALIGN (decl) = 64; rest_of_decl_compilation (decl, 1, 0); + + TYPE_OTABLE_DECL (type) = NULL_TREE; + TYPE_ATABLE_DECL (type) = NULL_TREE; + TYPE_CTABLE_DECL (type) = NULL_TREE; } void finish_class (void) { + if (TYPE_VERIFY_METHOD (output_class)) + { + tree verify_method = TYPE_VERIFY_METHOD (output_class); + DECL_SAVED_TREE (verify_method) + = add_stmt_to_compound (DECL_SAVED_TREE (verify_method), void_type_node, + build (RETURN_EXPR, void_type_node, NULL)); + java_genericize (verify_method); + cgraph_finalize_function (verify_method, false); + TYPE_ASSERTIONS (current_class) = NULL; + } + java_expand_catch_classes (current_class); current_function_decl = NULL_TREE; @@ -2095,20 +2153,22 @@ layout_class (tree this_class) if (!CLASS_FROM_SOURCE_P (this_class)) { int i; - - for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--) + if (TYPE_BINFO (this_class)) { - tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i); - tree super_interface = BINFO_TYPE (binfo); - tree maybe_super_interface - = maybe_layout_super_class (super_interface, NULL_TREE); - if (maybe_super_interface == NULL - || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK) + for (i = BINFO_N_BASE_BINFOS (TYPE_BINFO (this_class)) - 1; i > 0; i--) { - TYPE_SIZE (this_class) = error_mark_node; - CLASS_BEING_LAIDOUT (this_class) = 0; - class_list = TREE_CHAIN (class_list); - return; + tree binfo = BINFO_BASE_BINFO (TYPE_BINFO (this_class), i); + tree super_interface = BINFO_TYPE (binfo); + tree maybe_super_interface + = maybe_layout_super_class (super_interface, NULL_TREE); + if (maybe_super_interface == NULL + || TREE_CODE (TYPE_SIZE (maybe_super_interface)) == ERROR_MARK) + { + TYPE_SIZE (this_class) = error_mark_node; + CLASS_BEING_LAIDOUT (this_class) = 0; + class_list = TREE_CHAIN (class_list); + return; + } } } } @@ -2124,8 +2184,11 @@ layout_class (tree this_class) static void add_miranda_methods (tree base_class, tree search_class) { - tree binfo, base_binfo; int i; + tree binfo, base_binfo; + + if (!CLASS_PARSED_P (search_class)) + load_class (search_class, 1); for (binfo = TYPE_BINFO (search_class), i = 1; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) @@ -2133,6 +2196,11 @@ add_miranda_methods (tree base_class, tree search_class) tree method_decl; tree elt = BINFO_TYPE (base_binfo); + /* FIXME: This is totally bogus. We should not be handling + Miranda methods at all if we're using the BC ABI. */ + if (TYPE_DUMMY (elt)) + continue; + /* Ensure that interface methods are seen in declared order. */ if (!CLASS_LOADED_P (elt)) load_class (elt, 1); @@ -2193,7 +2261,8 @@ layout_class_methods (tree this_class) dtable_count = integer_zero_node; type_name = TYPE_NAME (this_class); - if (CLASS_ABSTRACT (type_name) || CLASS_INTERFACE (type_name)) + if (!flag_indirect_dispatch + && (CLASS_ABSTRACT (type_name) || CLASS_INTERFACE (type_name))) { /* An abstract class can have methods which are declared only in an implemented interface. These are called "Miranda @@ -2273,7 +2342,9 @@ layout_class_method (tree this_class, tree super_class, bool method_override = false; tree super_method = lookup_argument_method (super_class, method_name, method_sig); - if (super_method != NULL_TREE) + if (super_method != NULL_TREE + && ! METHOD_DUMMY (super_method) + && ! DECL_ARTIFICIAL (super_method)) { method_override = true; if (! METHOD_PUBLIC (super_method) && @@ -2296,11 +2367,19 @@ layout_class_method (tree this_class, tree super_class, error ("%Jnon-static method '%D' overrides static method", method_decl, method_decl); } - else if (! METHOD_FINAL (method_decl) - && ! METHOD_PRIVATE (method_decl) - && ! CLASS_FINAL (TYPE_NAME (this_class)) + else if (this_class == object_type_node + && (METHOD_FINAL (method_decl) + || METHOD_PRIVATE (method_decl))) + { + /* We don't generate vtable entries for final Object + methods. This is simply to save space, since every + object would otherwise have to define them. */ + } + else if (! METHOD_PRIVATE (method_decl) && dtable_count) { + /* We generate vtable entries for final methods because they + may one day be changed to non-final. */ set_method_index (method_decl, dtable_count); dtable_count = fold (build2 (PLUS_EXPR, integer_type_node, dtable_count, integer_one_node)); @@ -2387,14 +2466,20 @@ static tree build_symbol_entry (tree decl) { tree clname, name, signature, sym; - clname = build_utf8_ref (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl)))); - name = build_utf8_ref (DECL_NAME (decl)); + /* ??? Constructors are given the name foo.foo all the way through + the compiler, but in the method table they're all renamed + foo.<init>. So, we have to do the same here unless we want an + unresolved reference at runtime. */ + name = build_utf8_ref ((TREE_CODE (decl) == FUNCTION_DECL + && DECL_CONSTRUCTOR_P (decl)) + ? init_identifier_node + : DECL_NAME (decl)); signature = build_java_signature (TREE_TYPE (decl)); signature = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (signature), IDENTIFIER_LENGTH (signature))); - + START_RECORD_CONSTRUCTOR (sym, symbol_type); PUSH_FIELD_VALUE (sym, "clname", clname); PUSH_FIELD_VALUE (sym, "name", name); @@ -2410,7 +2495,8 @@ build_symbol_entry (tree decl) tree emit_symbol_table (tree name, tree the_table, tree decl_list, - tree the_syms_decl, tree the_array_element_type) + tree the_syms_decl, tree the_array_element_type, + int element_size) { tree method_list, method, table, list, null_symbol; tree table_size, the_array_type; @@ -2457,7 +2543,8 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, uninitialized static array of INDEX + 1 elements. The extra entry is used by the runtime to track whether the table has been initialized. */ - table_size = build_index_type (build_int_cst (NULL_TREE, index)); + table_size + = build_index_type (build_int_cst (NULL_TREE, index * element_size + 1)); the_array_type = build_array_type (the_array_element_type, table_size); the_table = build_decl (VAR_DECL, name, the_array_type); TREE_STATIC (the_table) = 1; @@ -2467,7 +2554,7 @@ emit_symbol_table (tree name, tree the_table, tree decl_list, return the_table; } -/* make an entry for the catch_classes list. */ +/* Make an entry for the catch_classes list. */ tree make_catch_class_record (tree catch_class, tree classname) { @@ -2512,7 +2599,95 @@ emit_catch_table (tree this_class) rest_of_decl_compilation (table, 1, 0); return table; } - + +/* Given a type, return the signature used by + _Jv_FindClassFromSignature() in libgcj. This isn't exactly the + same as build_java_signature() because we want the canonical array + type. */ + +static tree +build_signature_for_libgcj (tree type) +{ + tree sig, ref; + + sig = build_java_signature (type); + ref = build_utf8_ref (unmangle_classname (IDENTIFIER_POINTER (sig), + IDENTIFIER_LENGTH (sig))); + return ref; +} + +/* Add an entry to the type assertion table. Callback used during hashtable + traversal. */ + +static int +add_assertion_table_entry (void **htab_entry, void *ptr) +{ + tree entry; + tree code_val, op1_utf8, op2_utf8; + tree *list = (tree *) ptr; + type_assertion *as = (type_assertion *) *htab_entry; + + code_val = build_int_cst (NULL_TREE, as->assertion_code); + + if (as->op1 == NULL_TREE) + op1_utf8 = null_pointer_node; + else + op1_utf8 = build_signature_for_libgcj (as->op1); + + if (as->op2 == NULL_TREE) + op2_utf8 = null_pointer_node; + else + op2_utf8 = build_signature_for_libgcj (as->op2); + + START_RECORD_CONSTRUCTOR (entry, assertion_entry_type); + PUSH_FIELD_VALUE (entry, "assertion_code", code_val); + PUSH_FIELD_VALUE (entry, "op1", op1_utf8); + PUSH_FIELD_VALUE (entry, "op2", op2_utf8); + FINISH_RECORD_CONSTRUCTOR (entry); + + *list = tree_cons (NULL_TREE, entry, *list); + return true; +} + +/* Generate the type assertion table for CLASS, and return its DECL. */ + +static tree +emit_assertion_table (tree class) +{ + tree null_entry, ctor, table_decl; + tree list = NULL_TREE; + htab_t assertions_htab = TYPE_ASSERTIONS (class); + + /* Iterate through the hash table. */ + htab_traverse (assertions_htab, add_assertion_table_entry, &list); + + /* Finish with a null entry. */ + START_RECORD_CONSTRUCTOR (null_entry, assertion_entry_type); + PUSH_FIELD_VALUE (null_entry, "assertion_code", integer_zero_node); + PUSH_FIELD_VALUE (null_entry, "op1", null_pointer_node); + PUSH_FIELD_VALUE (null_entry, "op2", null_pointer_node); + FINISH_RECORD_CONSTRUCTOR (null_entry); + + list = tree_cons (NULL_TREE, null_entry, list); + + /* Put the list in the right order and make it a constructor. */ + list = nreverse (list); + ctor = build_constructor (assertion_table_type, list); + + table_decl = build_decl (VAR_DECL, mangled_classname ("_type_assert_", class), + assertion_table_type); + + TREE_STATIC (table_decl) = 1; + TREE_READONLY (table_decl) = 1; + TREE_CONSTANT (table_decl) = 1; + DECL_IGNORED_P (table_decl) = 1; + + DECL_INITIAL (table_decl) = ctor; + DECL_ARTIFICIAL (table_decl) = 1; + rest_of_decl_compilation (table_decl, 1, 0); + + return table_decl; +} void init_class_processing (void) diff --git a/gcc/java/decl.c b/gcc/java/decl.c index 47310220a2f..54f788e0d7d 100644 --- a/gcc/java/decl.c +++ b/gcc/java/decl.c @@ -242,17 +242,44 @@ check_local_unnamed_variable (tree best, tree decl, tree type) || (INTEGRAL_TYPE_P (decl_type) && INTEGRAL_TYPE_P (type) && TYPE_PRECISION (decl_type) <= 32 - && TYPE_PRECISION (type) <= 32 + && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (decl_type) >= TYPE_PRECISION (type)) - || (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE - && type == ptr_type_node)) - { - if (best == NULL_TREE + /* ptr_type_node is used for null pointers, which are + assignment compatible with everything. */ + || (TREE_CODE (decl_type) == POINTER_TYPE + && type == ptr_type_node) + /* Whenever anyone wants to use a slot that is initially + occupied by a PARM_DECL of pointer type they must get that + decl, even if they asked for a pointer to a different type. + However, if someone wants a scalar variable in a slot that + initially held a pointer arg -- or vice versa -- we create a + new VAR_DECL. + + ???: As long as verification is correct, this will be a + compatible type. But maybe we should create a dummy vribale + and replace all references to it with the DECL and a + NOP_EXPR. + */ + || (TREE_CODE (decl_type) == POINTER_TYPE + && TREE_CODE (decl) == PARM_DECL + && TREE_CODE (type) == POINTER_TYPE) + + /* The new verifier requires a similar treatment in the + situation where the parameter has an integral type which + promotes to `int'. */ + || (flag_new_verifier + && TREE_CODE (decl) == PARM_DECL + && INTEGRAL_TYPE_P (decl_type) + && TYPE_PRECISION (decl_type) <= 32 + && INTEGRAL_TYPE_P (type) + && TYPE_PRECISION (type) <= 32)) + { + if (best == NULL_TREE || (decl_type == type && TREE_TYPE (best) != type)) - return decl; - } + return decl; + } - return best; + return best; } @@ -286,9 +313,9 @@ find_local_variable (int index, tree type, int pc ATTRIBUTE_UNUSED) variable that is used for every reference in that local variable slot. */ if (! decl) - { - char buf[64]; - tree name; + { + char buf[64]; + tree name; sprintf (buf, "#slot#%d#%d", index, uniq++); name = get_identifier (buf); decl = build_decl (VAR_DECL, name, type); @@ -688,6 +715,11 @@ java_init_decl_processing (void) TYPE_NONALIASED_COMPONENT (atable_type) = 1; atable_ptr_type = build_pointer_type (atable_type); + itable_type = build_array_type (ptr_type_node, + one_elt_array_domain_type); + TYPE_NONALIASED_COMPONENT (itable_type) = 1; + itable_ptr_type = build_pointer_type (itable_type); + symbol_type = make_node (RECORD_TYPE); PUSH_FIELD (symbol_type, field, "clname", utf8const_ptr_type); PUSH_FIELD (symbol_type, field, "name", utf8const_ptr_type); @@ -698,6 +730,15 @@ java_init_decl_processing (void) one_elt_array_domain_type); symbols_array_ptr_type = build_pointer_type (symbols_array_type); + assertion_entry_type = make_node (RECORD_TYPE); + PUSH_FIELD (assertion_entry_type, field, "assertion_code", integer_type_node); + PUSH_FIELD (assertion_entry_type, field, "op1", utf8const_ptr_type); + PUSH_FIELD (assertion_entry_type, field, "op2", utf8const_ptr_type); + FINISH_RECORD (assertion_entry_type); + + assertion_table_type = build_array_type (assertion_entry_type, + one_elt_array_domain_type); + /* As you're adding items here, please update the code right after this section, so that the filename containing the source code of the pre-defined class gets registered correctly. */ @@ -813,6 +854,9 @@ java_init_decl_processing (void) PUSH_FIELD (class_type_node, field, "atable", atable_ptr_type); PUSH_FIELD (class_type_node, field, "atable_syms", symbols_array_ptr_type); + PUSH_FIELD (class_type_node, field, "itable", itable_ptr_type); + PUSH_FIELD (class_type_node, field, "itable_syms", + symbols_array_ptr_type); PUSH_FIELD (class_type_node, field, "catch_classes", ptr_type_node); PUSH_FIELD (class_type_node, field, "interfaces", build_pointer_type (class_ptr_type)); @@ -825,9 +869,11 @@ java_init_decl_processing (void) PUSH_FIELD (class_type_node, field, "idt", ptr_type_node); PUSH_FIELD (class_type_node, field, "arrayclass", ptr_type_node); PUSH_FIELD (class_type_node, field, "protectionDomain", ptr_type_node); + PUSH_FIELD (class_type_node, field, "assertion_table", ptr_type_node); PUSH_FIELD (class_type_node, field, "hack_signers", ptr_type_node); PUSH_FIELD (class_type_node, field, "chain", ptr_type_node); PUSH_FIELD (class_type_node, field, "aux_info", ptr_type_node); + PUSH_FIELD (class_type_node, field, "engine", ptr_type_node); for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) FIELD_PRIVATE (t) = 1; push_super_field (class_type_node, object_type_node); @@ -993,8 +1039,14 @@ java_init_decl_processing (void) = builtin_function ("_Jv_LookupInterfaceMethodIdx", build_function_type (ptr_type_node, t), 0, NOT_BUILT_IN, NULL, NULL_TREE); - DECL_IS_PURE (soft_lookupinterfacemethod_node) = 1; + t = tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, endlink))); + soft_lookupinterfacemethodbyname_node + = builtin_function ("_Jv_LookupInterfaceMethod", + build_function_type (ptr_type_node, t), + 0, NOT_BUILT_IN, NULL, NULL_TREE); t = tree_cons (NULL_TREE, object_ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, diff --git a/gcc/java/expr.c b/gcc/java/expr.c index deb75a9e7f9..305ab5bdfee 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -323,26 +323,63 @@ pop_type_0 (tree type, char **messagep) t = stack_type_map[--stack_pointer]; if (type == NULL_TREE || t == type) return t; + if (TREE_CODE (t) == TREE_LIST) + { + do + { + tree tt = TREE_PURPOSE (t); + if (! can_widen_reference_to (tt, type)) + { + t = tt; + goto fail; + } + t = TREE_CHAIN (t); + } + while (t); + return t; + } if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t) && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32) - return t; + 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)))) - return object_ptr_type_node; + if (flag_new_verifier) + { + /* Since the verifier has already run, we know that any + types we see will be compatible. In BC mode, this fact + may be checked at runtime, but if that is so then we can + assume its truth here as well. So, we always succeed + here, with the expected type. */ + return type; + } + else + { + 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; + /* 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)))) + return object_ptr_type_node; + else if (can_widen_reference_to (t, type)) + return t; + } + } + + if (! flag_verify_invocations && flag_indirect_dispatch + && t == object_ptr_type_node) + { + if (type != ptr_type_node) + warning ("need to insert runtime check for %s", + xstrdup (lang_printable_name (type, 0))); + return type; } /* lang_printable_name uses a static buffer, so we must save the result from calling it the first time. */ + fail: { char *temp = xstrdup (lang_printable_name (type, 0)); *messagep = concat ("expected type '", temp, @@ -370,6 +407,68 @@ pop_type (tree type) return type; } + +/* Return true if two type assertions are equal. */ + +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; + return (k1.assertion_code == k2.assertion_code + && k1.op1 == k2.op1 + && k1.op2 == k2.op2); +} + +/* Hash a type assertion. */ + +static hashval_t +type_assertion_hash (const void *p) +{ + const type_assertion *k_p = 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); +} + +/* 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 + 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) +{ + htab_t assertions_htab; + type_assertion as; + void **as_pp; + + assertions_htab = TYPE_ASSERTIONS (class); + if (assertions_htab == NULL) + { + assertions_htab = htab_create_ggc (7, type_assertion_hash, + type_assertion_eq, NULL); + TYPE_ASSERTIONS (current_class) = assertions_htab; + } + + as.assertion_code = assertion_code; + as.op1 = op1; + as.op2 = op2; + + as_pp = htab_find_slot (assertions_htab, &as, true); + + /* Don't add the same assertion twice. */ + if (*as_pp) + return; + + *as_pp = ggc_alloc (sizeof (type_assertion)); + **(type_assertion **)as_pp = as; +} + + /* Return 1 if SOURCE_TYPE can be safely widened to TARGET_TYPE. Handles array types and interfaces. */ @@ -387,6 +486,28 @@ can_widen_reference_to (tree source_type, tree target_type) if (source_type == target_type) return 1; + + /* FIXME: This is very pessimistic, in that it checks everything, + even if we already know that the types are compatible. If we're + to support full Java class loader semantics, we need this. + However, we could do something more optimal. */ + if (! flag_verify_invocations) + { + add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE, + source_type, target_type); + + if (!quiet_flag) + warning ("assert: %s is assign compatible with %s", + xstrdup (lang_printable_name (target_type, 0)), + xstrdup (lang_printable_name (source_type, 0))); + /* Punt everything to runtime. */ + return 1; + } + + if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type)) + { + return 1; + } else { if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type)) @@ -420,7 +541,16 @@ can_widen_reference_to (tree source_type, tree target_type) int source_depth = class_depth (source_type); int target_depth = class_depth (target_type); - /* class_depth can return a negative depth if an error occurred */ + if (TYPE_DUMMY (source_type) || TYPE_DUMMY (target_type)) + { + if (! quiet_flag) + warning ("assert: %s is assign compatible with %s", + xstrdup (lang_printable_name (target_type, 0)), + xstrdup (lang_printable_name (source_type, 0))); + return 1; + } + + /* class_depth can return a negative depth if an error occurred */ if (source_depth < 0 || target_depth < 0) return 0; @@ -687,13 +817,18 @@ build_java_array_length_access (tree node) throws a NullPointerException. The only way we could get a node of type ptr_type_node at this point is `aconst_null; arraylength' or something equivalent. */ - if (type == ptr_type_node) + if (!flag_new_verifier && type == ptr_type_node) return build3 (CALL_EXPR, int_type_node, build_address_of (soft_nullpointer_node), NULL_TREE, NULL_TREE); if (!is_array_type_p (type)) - abort (); + { + /* With the new verifier, we will see an ordinary pointer type + here. In this case, we just use an arbitrary array type. */ + array_type = build_java_array_type (object_ptr_type_node, -1); + type = promote_type (array_type); + } length = java_array_type_length (type); if (length >= 0) @@ -754,6 +889,13 @@ build_java_arrayaccess (tree array, tree type, tree index) tree ref; tree array_type = TREE_TYPE (TREE_TYPE (array)); + if (!is_array_type_p (TREE_TYPE (array))) + { + /* With the new verifier, we will see an ordinary pointer type + here. In this case, we just use the correct array type. */ + array_type = build_java_array_type (type, -1); + } + if (flag_bounds_check) { /* Generate: @@ -803,11 +945,21 @@ build_java_arraystore_check (tree array, tree object) tree array_type_p = TREE_TYPE (array); tree object_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (object))); - if (! is_array_type_p (array_type_p)) - abort (); + if (! flag_verify_invocations) + { + /* With the new verifier, we don't track precise types. FIXME: + performance regression here. */ + element_type = TYPE_NAME (object_type_node); + } + else + { + if (! is_array_type_p (array_type_p)) + abort (); - /* Get the TYPE_DECL for ARRAY's element type. */ - element_type = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p)))); + /* Get the TYPE_DECL for ARRAY's element type. */ + element_type + = TYPE_NAME (TREE_TYPE (TREE_TYPE (TREE_TYPE (array_type_p)))); + } if (TREE_CODE (element_type) != TYPE_DECL || TREE_CODE (object_type) != TYPE_DECL) @@ -816,13 +968,14 @@ build_java_arraystore_check (tree array, tree object) if (!flag_store_check) return build1 (NOP_EXPR, array_type_p, array); - /* No check is needed if the element type is final or is itself an array. - Also check that element_type matches object_type, since in the bytecode - compilation case element_type may be the actual element type of the array - rather than its declared type. */ + /* No check is needed if the element type is final. Also check that + element_type matches object_type, since in the bytecode + compilation case element_type may be the actual element type of + the array rather than its declared type. However, if we're doing + indirect dispatch, we can't do the `final' optimization. */ if (element_type == object_type - && (TYPE_ARRAY_P (TREE_TYPE (element_type)) - || CLASS_FINAL (element_type))) + && ! flag_indirect_dispatch + && CLASS_FINAL (element_type)) return build1 (NOP_EXPR, array_type_p, array); /* OBJECT might be wrapped by a SAVE_EXPR. */ @@ -864,24 +1017,30 @@ build_java_arraystore_check (tree array, tree object) ARRAY_NODE. This function is used to retrieve something less vague than a pointer type when indexing the first dimension of something like [[<t>. May return a corrected type, if necessary, otherwise INDEXED_TYPE is - return unchanged. - As a side effect, it also makes sure that ARRAY_NODE is an array. */ + return unchanged. */ static tree build_java_check_indexed_type (tree array_node, tree indexed_type) { tree elt_type; + /* We used to check to see if ARRAY_NODE really had array type. + However, with the new verifier, this is not necessary, as we know + that the object will be an array of the appropriate type. */ + + if (flag_new_verifier) + return indexed_type; + if (!is_array_type_p (TREE_TYPE (array_node))) abort (); elt_type = (TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (array_node)))); - if (indexed_type == ptr_type_node ) - return promote_type (elt_type); + if (indexed_type == ptr_type_node) + return promote_type (elt_type); /* BYTE/BOOLEAN store and load are used for both type */ - if (indexed_type == byte_type_node && elt_type == boolean_type_node ) + if (indexed_type == byte_type_node && elt_type == boolean_type_node) return boolean_type_node; if (indexed_type != elt_type ) @@ -992,7 +1151,25 @@ expand_java_arraystore (tree rhs_type_node) && TYPE_PRECISION (rhs_type_node) <= 32) ? int_type_node : rhs_type_node); tree index = pop_value (int_type_node); - tree array = pop_value (ptr_type_node); + tree array_type, array; + + if (flag_new_verifier) + { + /* If we're processing an `aaload' we might as well just pick + `Object'. */ + if (TREE_CODE (rhs_type_node) == POINTER_TYPE) + { + array_type = build_java_array_type (object_ptr_type_node, -1); + rhs_type_node = object_ptr_type_node; + } + else + array_type = build_java_array_type (rhs_type_node, -1); + } + else + array_type = ptr_type_node; + array = pop_value (array_type); + if (flag_new_verifier) + array = build1 (NOP_EXPR, promote_type (array_type), array); rhs_type_node = build_java_check_indexed_type (array, rhs_type_node); @@ -1019,25 +1196,45 @@ expand_java_arraystore (tree rhs_type_node) */ static void -expand_java_arrayload (tree lhs_type_node ) +expand_java_arrayload (tree lhs_type_node) { tree load_node; tree index_node = pop_value (int_type_node); - tree array_node = pop_value (ptr_type_node); + tree array_type; + tree array_node; + + if (flag_new_verifier) + { + /* If we're processing an `aaload' we might as well just pick + `Object'. */ + if (TREE_CODE (lhs_type_node) == POINTER_TYPE) + { + array_type = build_java_array_type (object_ptr_type_node, -1); + lhs_type_node = object_ptr_type_node; + } + else + array_type = build_java_array_type (lhs_type_node, -1); + } + else + array_type = ptr_type_node; + array_node = pop_value (array_type); + if (flag_new_verifier) + array_node = build1 (NOP_EXPR, promote_type (array_type), array_node); index_node = save_expr (index_node); array_node = save_expr (array_node); - + if (TREE_TYPE (array_node) == ptr_type_node) /* The only way we could get a node of type ptr_type_node at this point is `aconst_null; arraylength' or something equivalent, so - unconditionally throw NullPointerException. */ + unconditionally throw NullPointerException. */ load_node = build3 (CALL_EXPR, lhs_type_node, build_address_of (soft_nullpointer_node), NULL_TREE, NULL_TREE); else { - lhs_type_node = build_java_check_indexed_type (array_node, lhs_type_node); + lhs_type_node = build_java_check_indexed_type (array_node, + lhs_type_node); load_node = build_java_arrayaccess (array_node, lhs_type_node, index_node); @@ -1156,6 +1353,19 @@ class_has_finalize_method (tree type) return HAS_FINALIZER_P (type) || class_has_finalize_method (super); } +tree +java_create_object (tree type) +{ + tree alloc_node = (class_has_finalize_method (type) + ? alloc_object_node + : alloc_no_finalizer_node); + + return build (CALL_EXPR, promote_type (type), + build_address_of (alloc_node), + build_tree_list (NULL_TREE, build_class_ref (type)), + NULL_TREE); +} + static void expand_java_NEW (tree type) { @@ -1221,7 +1431,8 @@ build_instanceof (tree value, tree type) we only need to check for `null'. */ expr = build2 (NE_EXPR, itype, value, null_pointer_node); } - else if (! TYPE_ARRAY_P (type) + else if (flag_verify_invocations + && ! TYPE_ARRAY_P (type) && ! TYPE_ARRAY_P (valtype) && DECL_P (klass) && DECL_P (valclass) && ! CLASS_INTERFACE (valclass) @@ -1292,7 +1503,7 @@ expand_iinc (unsigned int local_var_index, int ival, int pc) update_aliases (local_var, local_var_index, pc); } - + tree build_java_soft_divmod (enum tree_code op, tree type, tree op1, tree op2) { @@ -1529,12 +1740,13 @@ build_field_ref (tree self_value, tree self_class, tree name) tree base_type = promote_type (base_class); if (base_type != TREE_TYPE (self_value)) self_value = fold (build1 (NOP_EXPR, base_type, self_value)); - if (flag_indirect_dispatch - && output_class != self_class) - /* FIXME: output_class != self_class is not exactly the right - test. What we really want to know is whether self_class is - in the same translation unit as output_class. If it is, - we can make a direct reference. */ + if (! flag_syntax_only + && (flag_indirect_dispatch + /* DECL_FIELD_OFFSET == 0 if we have no reference for + the field, perhaps because we couldn't find the class + in which the field is defined. + FIXME: We should investigate this. */ + || DECL_FIELD_OFFSET (field_decl) == 0)) { tree otable_index = build_int_cst (NULL_TREE, get_symbol_table_index @@ -1696,29 +1908,6 @@ expand_java_add_case (tree switch_expr, int match, int target_pc) append_to_statement_list (x, &SWITCH_BODY (switch_expr)); } -#if 0 -static void -expand_java_call (int target_pc, int return_address) -{ - tree target_label = lookup_label (target_pc); - tree value = build_int_cst (NULL_TREE, return_address); - push_value (value); - flush_quick_stack (); - expand_goto (target_label); -} - -static void -expand_java_ret (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 - static tree pop_arguments (tree arg_types) { @@ -1729,9 +1918,17 @@ pop_arguments (tree arg_types) tree tail = pop_arguments (TREE_CHAIN (arg_types)); tree type = TREE_VALUE (arg_types); tree arg = pop_value (type); - if (targetm.calls.promote_prototypes (type) - && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node) - && INTEGRAL_TYPE_P (type)) + + /* With the new verifier we simply cast each argument to its + proper type. This is needed since we lose type information + coming out of the verifier. We also have to do this with the + old verifier when we pop an integer type that must be + promoted for the function call. */ + if (flag_new_verifier && TREE_CODE (type) == POINTER_TYPE) + arg = build1 (NOP_EXPR, type, arg); + else if (targetm.calls.promote_prototypes (type) + && 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); } @@ -1824,8 +2021,12 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED, tree func; if (is_compiled_class (self_type)) { - if (!flag_indirect_dispatch - || (!TREE_PUBLIC (method) && DECL_CONTEXT (method))) + /* With indirect dispatch we have to use indirect calls for all + publically visible methods or gcc will use PLT indirections + to reach them. We also have to use indirect dispatch for all + external methods. */ + if (! flag_indirect_dispatch + || (! DECL_EXTERNAL (method) && ! TREE_PUBLIC (method))) { make_decl_rtl (method); func = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (method)), @@ -1836,9 +2037,11 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED, tree table_index = build_int_cst (NULL_TREE, get_symbol_table_index (method, &TYPE_ATABLE_METHODS (output_class))); - func = build4 (ARRAY_REF, method_ptr_type_node, - TYPE_ATABLE_DECL (output_class), table_index, - NULL_TREE, NULL_TREE); + func + = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (TYPE_ATABLE_DECL (output_class))), + TYPE_ATABLE_DECL (output_class), table_index, + NULL_TREE, NULL_TREE); } func = convert (method_ptr_type_node, func); } @@ -1899,9 +2102,9 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list) 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)); - + && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list))) + ? build_class_ref (object_type_node) : TREE_VALUE (arg_list)); + if (dtable_ident == NULL_TREE) dtable_ident = get_identifier ("vtable"); dtable = build_java_indirect_ref (object_type_node, objectref, @@ -1914,8 +2117,8 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list) /* Determine the index in SYMBOL_TABLE for a reference to the decl T. If this decl has not been seen before, it will be added to the - otable_methods. If it has, the existing table slot will be - reused. */ + [oa]table_methods. If it has, the existing table slot will be + reused. */ int get_symbol_table_index (tree t, tree *symbol_table) @@ -1935,7 +2138,7 @@ get_symbol_table_index (tree t, tree *symbol_table) { tree value = TREE_VALUE (method_list); if (value == t) - return i; + return i; i++; if (TREE_CHAIN (method_list) == NULL_TREE) break; @@ -1958,6 +2161,9 @@ build_invokevirtual (tree dtable, tree method) if (flag_indirect_dispatch) { + if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))) + abort (); + otable_index = build_int_cst (NULL_TREE, get_symbol_table_index (method, &TYPE_OTABLE_METHODS (output_class))); @@ -1997,11 +2203,8 @@ build_invokeinterface (tree dtable, tree method) tree lookup_arg; tree interface; tree idx; - tree otable_index; - /* We expand invokeinterface here. _Jv_LookupInterfaceMethod() will - ensure that the selected method exists, is public and not - abstract nor static. */ + /* We expand invokeinterface here. */ if (class_ident == NULL_TREE) class_ident = get_identifier ("class"); @@ -2018,28 +2221,42 @@ build_invokeinterface (tree dtable, tree method) if (flag_indirect_dispatch) { - otable_index - = build_int_cst (NULL_TREE, get_symbol_table_index - (method, &TYPE_OTABLE_METHODS (output_class))); - idx = build4 (ARRAY_REF, integer_type_node, - TYPE_OTABLE_DECL (output_class), otable_index, - NULL_TREE, NULL_TREE); + int itable_index + = 2 * (get_symbol_table_index + (method, &TYPE_ITABLE_METHODS (output_class))); + interface + = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))), + TYPE_ITABLE_DECL (output_class), + build_int_cst (NULL_TREE, itable_index-1), + NULL_TREE, NULL_TREE); + idx + = build4 (ARRAY_REF, + TREE_TYPE (TREE_TYPE (TYPE_ITABLE_DECL (output_class))), + TYPE_ITABLE_DECL (output_class), + build_int_cst (NULL_TREE, itable_index), + NULL_TREE, NULL_TREE); + interface = convert (class_ptr_type, interface); + idx = convert (integer_type_node, idx); } else - idx = build_int_cst (NULL_TREE, - get_interface_method_index (method, interface)); - - lookup_arg = tree_cons (NULL_TREE, dtable, - tree_cons (NULL_TREE, build_class_ref (interface), - build_tree_list (NULL_TREE, idx))); + { + idx = build_int_cst (NULL_TREE, + get_interface_method_index (method, interface)); + 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); } /* Expand one of the invoke_* opcodes. - OCPODE is the specific opcode. + OPCODE 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. */ @@ -2048,7 +2265,8 @@ expand_invoke (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 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, @@ -2071,38 +2289,82 @@ expand_invoke (int opcode, int method_ref_index, int nargs ATTRIBUTE_UNUSED) method = lookup_java_constructor (self_type, method_signature); else method = lookup_java_method (self_type, method_name, method_signature); + + /* We've found a method in an interface, but this isn't an interface + call. */ + if (opcode != OPCODE_invokeinterface + && method + && (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method))))) + method = NULL_TREE; + + /* We've found a non-interface method but we are making an + interface call. This can happen if the interface overrides a + method in Object. */ + if (! flag_verify_invocations + && opcode == OPCODE_invokeinterface + && method + && ! CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))) + method = NULL_TREE; + 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)) + if (flag_verify_invocations || ! flag_indirect_dispatch) { - error ("invokestatic on non static method"); - method = NULL_TREE; + error ("class '%s' has no method named '%s' matching signature '%s'", + self_name, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_POINTER (method_signature)); } - else if (METHOD_ABSTRACT (method)) + else { - error ("invokestatic on abstract method"); - method = NULL_TREE; + int flags = ACC_PUBLIC; + if (opcode == OPCODE_invokestatic) + flags |= ACC_STATIC; + if (opcode == OPCODE_invokeinterface) + { + flags |= ACC_INTERFACE | ACC_ABSTRACT; + CLASS_INTERFACE (TYPE_NAME (self_type)) = 1; + } + method = add_method (self_type, flags, method_name, + method_signature); + DECL_ARTIFICIAL (method) = 1; + METHOD_DUMMY (method) = 1; + layout_class_method (self_type, NULL, + method, NULL); } } - else + + /* Invoke static can't invoke static/abstract method */ + if (method != NULL_TREE) { - if (METHOD_STATIC (method)) + if (opcode == OPCODE_invokestatic) { - error ("invoke[non-static] on static method"); - method = NULL_TREE; + 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) { + /* If we got here, we emitted an error message above. So we + 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)); if (opcode != OPCODE_invokestatic) @@ -2385,6 +2647,7 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index) tree new_value = is_putting ? pop_value (field_type) : NULL_TREE; tree field_ref; int is_error = 0; + tree original_self_type = self_type; tree field_decl; if (! CLASS_LOADED_P (self_type)) @@ -2396,9 +2659,23 @@ expand_java_field_op (int is_static, int is_putting, int field_ref_index) } else if (field_decl == NULL_TREE) { - error ("missing field '%s' in '%s'", - IDENTIFIER_POINTER (field_name), self_name); - is_error = 1; + if (! flag_verify_invocations) + { + int flags = ACC_PUBLIC; + if (is_static) + flags |= ACC_STATIC; + self_type = original_self_type; + field_decl = add_field (original_self_type, field_name, + field_type, flags); + DECL_ARTIFICIAL (field_decl) = 1; + DECL_IGNORED_P (field_decl) = 1; + } + else + { + 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) { @@ -2637,8 +2914,16 @@ expand_byte_code (JCF *jcf, tree method) } } - if (! verify_jvm_instructions (jcf, byte_ops, length)) - return; + if (flag_new_verifier) + { + if (! verify_jvm_instructions_new (jcf, byte_ops, length)) + return; + } + else + { + if (! verify_jvm_instructions (jcf, byte_ops, length)) + return; + } /* Translate bytecodes. */ linenumber_pointer = linenumber_table; @@ -2749,8 +3034,14 @@ process_jvm_instruction (int PC, const unsigned char* byte_ops, replace the top of the stack with the thrown object reference */ if (instruction_bits [PC] & BCODE_EXCEPTION_TARGET) { - tree type = pop_type (ptr_type_node); - push_value (build_exception_object_ref (type)); + /* Note that the new verifier will not emit a type map at all + for dead exception handlers. In this case we just ignore + the situation. */ + if (! flag_new_verifier || (instruction_bits[PC] & BCODE_VERIFIED) != 0) + { + tree type = pop_type (promote_type (throwable_type_node)); + push_value (build_exception_object_ref (type)); + } } switch (byte_ops[PC++]) diff --git a/gcc/java/gcj.texi b/gcc/java/gcj.texi index 1ef0babb4c0..370585a7aff 100644 --- a/gcc/java/gcj.texi +++ b/gcc/java/gcj.texi @@ -873,7 +873,7 @@ gij [@option{-jar}] [@option{OPTION}] @dots{} @var{CLASS} [@var{ARGS}@dots{}] [@option{-cp} @var{path}] [@option{-classpath} @var{path}] [@option{-D}@var{name}[=@var{value}]@dots{}] [@option{-ms=}@var{number}] [@option{-mx=}@var{number}] - [@option{-X@var{argument}] + [@option{-X@var{argument}}] [@option{-verbose}] [@option{-verbose:class}] [@option{--showversion}] [@option{--version}] [@option{--help}][@option{-?}] @c man end @c man begin SEEALSO gij @@ -954,7 +954,8 @@ Print version number and continue. @item --version Print version number, then exit. -@item -verbose:class +@item -verbose +@itemx -verbose:class Each time a class is initialized, print a short message on standard error. @end table @@ -2385,6 +2386,24 @@ property is set to @samp{cache}, then any failed lookups are cached and not tried again. If this property is set to @samp{never}, then lookups are never done. For more information, @xref{Extensions}. +@item gnu.gcj.jit.compiler +@c FIXME we should probably have a whole node on this... +This is the full path to @command{gcj} executable which should be +used to compile classes just-in-time when +@code{ClassLoader.defineClass} is called. If not set, @command{gcj} +will not be invoked by the runtime; this can also be controlled via +@code{Compiler.disable}. + +@item gnu.gcj.jit.options +This is a space-separated string of options which should be passed to +@command{gcj} when in JIT mode. If not set, a sensible default is +chosen. + +@item gnu.gcj.jit.cachedir +This is the directory where cached shared library files are +stored. If not set, JIT compilation is disabled. This should never +be set to a directory that is writable by any other user. + @end table diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c index abf75c4dc69..0badaf19829 100644 --- a/gcc/java/gjavah.c +++ b/gcc/java/gjavah.c @@ -112,6 +112,9 @@ static JCF_u2 last_access; #define METHOD_IS_NATIVE(Method) \ ((Method) & ACC_NATIVE) +#define METHOD_IS_PRIVATE(Class, Method) \ + (((Method) & ACC_PRIVATE) != 0) + /* We keep a linked list of all method names we have seen. This lets us determine if a method name and a field name are in conflict. */ struct method_name @@ -937,7 +940,7 @@ print_method_info (FILE *stream, JCF* jcf, int name_index, int sig_index, fputs (" ", out); if ((flags & ACC_STATIC)) fputs ("static ", out); - else if (! METHOD_IS_FINAL (jcf->access_flags, flags)) + else if (! METHOD_IS_PRIVATE (jcf->access_flags, flags)) { /* Don't print `virtual' if we have a constructor. */ if (! is_init) diff --git a/gcc/java/java-except.h b/gcc/java/java-except.h index 3aa5e0105ef..45e4f0aa8e9 100644 --- a/gcc/java/java-except.h +++ b/gcc/java/java-except.h @@ -53,6 +53,8 @@ struct eh_range /* The TRY_CATCH_EXPR for this EH range. */ tree stmt; + + tree handler; }; /* A dummy range that represents the entire method. */ diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 558d0f50cc6..e8144ee908c 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -227,6 +227,9 @@ extern int flag_indirect_dispatch; /* When zero, don't generate runtime array store checks. */ extern int flag_store_check; +/* When nonzero, use the new bytecode verifier. */ +extern int flag_new_verifier; + /* Encoding used for source files. */ extern const char *current_encoding; @@ -237,6 +240,8 @@ extern GTY(()) struct JCF * current_jcf; before static field references. */ extern int always_initialize_class_p; +extern int flag_verify_invocations; + typedef struct CPool constant_pool; #define CONSTANT_ResolvedFlag 16 @@ -367,9 +372,13 @@ enum java_tree_index JTI_OTABLE_PTR_TYPE, JTI_ATABLE_TYPE, JTI_ATABLE_PTR_TYPE, + JTI_ITABLE_TYPE, + JTI_ITABLE_PTR_TYPE, JTI_SYMBOL_TYPE, JTI_SYMBOLS_ARRAY_TYPE, JTI_SYMBOLS_ARRAY_PTR_TYPE, + JTI_ASSERTION_ENTRY_TYPE, + JTI_ASSERTION_TABLE_TYPE, JTI_END_PARAMS_NODE, @@ -388,6 +397,7 @@ enum java_tree_index JTI_SOFT_MONITORENTER_NODE, JTI_SOFT_MONITOREXIT_NODE, JTI_SOFT_LOOKUPINTERFACEMETHOD_NODE, + JTI_SOFT_LOOKUPINTERFACEMETHODBYNAME_NODE, JTI_SOFT_LOOKUPJNIMETHOD_NODE, JTI_SOFT_GETJNIENVNEWFRAME_NODE, JTI_SOFT_JNIPOPSYSTEMFRAME_NODE, @@ -597,18 +607,24 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; java_global_trees[JTI_OTABLE_TYPE] #define atable_type \ java_global_trees[JTI_ATABLE_TYPE] +#define itable_type \ + java_global_trees[JTI_ITABLE_TYPE] #define otable_ptr_type \ java_global_trees[JTI_OTABLE_PTR_TYPE] #define atable_ptr_type \ java_global_trees[JTI_ATABLE_PTR_TYPE] +#define itable_ptr_type \ + java_global_trees[JTI_ITABLE_PTR_TYPE] #define symbol_type \ java_global_trees[JTI_SYMBOL_TYPE] #define symbols_array_type \ java_global_trees[JTI_SYMBOLS_ARRAY_TYPE] #define symbols_array_ptr_type \ - java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE] -#define class_refs_decl \ - Jjava_global_trees[TI_CLASS_REFS_DECL] + java_global_trees[JTI_SYMBOLS_ARRAY_PTR_TYPE] +#define assertion_entry_type \ + java_global_trees[JTI_ASSERTION_ENTRY_TYPE] +#define assertion_table_type \ + java_global_trees[JTI_ASSERTION_TABLE_TYPE] #define end_params_node \ java_global_trees[JTI_END_PARAMS_NODE] @@ -644,6 +660,8 @@ extern GTY(()) tree java_global_trees[JTI_MAX]; java_global_trees[JTI_SOFT_MONITOREXIT_NODE] #define soft_lookupinterfacemethod_node \ java_global_trees[JTI_SOFT_LOOKUPINTERFACEMETHOD_NODE] +#define soft_lookupinterfacemethodbyname_node \ + java_global_trees[JTI_SOFT_LOOKUPINTERFACEMETHODBYNAME_NODE] #define soft_lookupjnimethod_node \ java_global_trees[JTI_SOFT_LOOKUPJNIMETHOD_NODE] #define soft_getjnienvnewframe_node \ @@ -984,6 +1002,7 @@ struct lang_decl_func GTY(()) unsigned int invisible : 1; /* Set for methods we generate internally but which shouldn't be written to the .class file. */ + unsigned int dummy:1; }; struct treetreehash_entry GTY(()) @@ -992,6 +1011,22 @@ struct treetreehash_entry GTY(()) tree value; }; +/* These represent the possible assertion_code's that can be emitted in the + type assertion table. */ +enum +{ + JV_ASSERT_END_OF_TABLE = 0, /* Last entry in table. */ + JV_ASSERT_TYPES_COMPATIBLE = 1, /* Operand A is assignable to Operand B. */ + JV_ASSERT_IS_INSTANTIABLE = 2 /* Operand A is an instantiable class. */ +}; + +typedef struct type_assertion GTY(()) +{ + int assertion_code; /* 'opcode' for the type of this assertion. */ + tree op1; /* First operand. */ + tree op2; /* Second operand. */ +} type_assertion; + extern tree java_treetreehash_find (htab_t, tree); extern tree * java_treetreehash_new (htab_t, tree); extern htab_t java_treetreehash_create (size_t size, int ggc); @@ -1043,6 +1078,9 @@ struct lang_decl GTY(()) #define TYPE_II_STMT_LIST(T) (TYPE_LANG_SPECIFIC (T)->ii_block) /* The decl of the synthetic method `class$' used to handle `.class' for non primitive types when compiling to bytecode. */ + +#define TYPE_DUMMY(T) (TYPE_LANG_SPECIFIC(T)->dummy_class) + #define TYPE_DOT_CLASS(T) (TYPE_LANG_SPECIFIC (T)->dot_class) #define TYPE_PACKAGE_LIST(T) (TYPE_LANG_SPECIFIC (T)->package_list) #define TYPE_IMPORT_LIST(T) (TYPE_LANG_SPECIFIC (T)->import_list) @@ -1060,10 +1098,16 @@ struct lang_decl GTY(()) #define TYPE_OTABLE_SYMS_DECL(T) (TYPE_LANG_SPECIFIC (T)->otable_syms_decl) #define TYPE_OTABLE_DECL(T) (TYPE_LANG_SPECIFIC (T)->otable_decl) +#define TYPE_ITABLE_METHODS(T) (TYPE_LANG_SPECIFIC (T)->itable_methods) +#define TYPE_ITABLE_SYMS_DECL(T) (TYPE_LANG_SPECIFIC (T)->itable_syms_decl) +#define TYPE_ITABLE_DECL(T) (TYPE_LANG_SPECIFIC (T)->itable_decl) + #define TYPE_CTABLE_DECL(T) (TYPE_LANG_SPECIFIC (T)->ctable_decl) #define TYPE_CATCH_CLASSES(T) (TYPE_LANG_SPECIFIC (T)->catch_classes) +#define TYPE_VERIFY_METHOD(T) (TYPE_LANG_SPECIFIC (T)->verify_method) #define TYPE_TO_RUNTIME_MAP(T) (TYPE_LANG_SPECIFIC (T)->type_to_runtime_map) +#define TYPE_ASSERTIONS(T) (TYPE_LANG_SPECIFIC (T)->type_assertions) struct lang_type GTY(()) { @@ -1092,18 +1136,31 @@ struct lang_type GTY(()) tree atable_decl; /* The static address table. */ tree atable_syms_decl; + tree itable_methods; /* List of interfaces methods referred + to by this class. */ + tree itable_decl; /* The interfaces table. */ + tree itable_syms_decl; + tree ctable_decl; /* The table of classes for the runtime type matcher. */ tree catch_classes; + tree verify_method; /* The verify method for this class. + Used in split verification. */ + htab_t GTY ((param_is (struct treetreehash_entry))) type_to_runtime_map; /* The mapping of classes to exception region markers. */ + htab_t GTY ((param_is (struct type_assertion))) type_assertions; + /* Table of type assertions to be evaluated + by the runtime when this class is loaded. */ + unsigned pic:1; /* Private Inner Class. */ unsigned poic:1; /* Protected Inner Class. */ unsigned strictfp:1; /* `strictfp' class. */ unsigned assertions:1; /* Any method uses `assert'. */ + unsigned dummy_class:1; /* Not a real class, just a placeholder. */ }; #define JCF_u4 unsigned long @@ -1243,7 +1300,7 @@ extern void make_class_data (tree); extern void register_class (void); extern int alloc_name_constant (int, tree); extern void emit_register_classes (tree *); -extern tree emit_symbol_table (tree, tree, tree, tree, tree); +extern tree emit_symbol_table (tree, tree, tree, tree, tree, int); extern void lang_init_source (int); extern void write_classfile (tree); extern char *print_int_node (tree); @@ -1259,9 +1316,12 @@ extern int alloc_class_constant (tree); extern void init_expr_processing (void); extern void push_super_field (tree, tree); extern void init_class_processing (void); +extern void add_type_assertion (tree, int, tree, tree); extern int can_widen_reference_to (tree, tree); extern int class_depth (tree); extern int verify_jvm_instructions (struct JCF *, const unsigned char *, long); +extern int verify_jvm_instructions_new (struct JCF *, const unsigned char *, + long); extern void maybe_pushlevels (int); extern void maybe_poplevels (int); extern void force_poplevels (int); @@ -1274,6 +1334,7 @@ extern void push_type (tree); extern void load_type_state (tree); extern void add_interface (tree, tree); extern tree force_evaluation_order (tree); +extern tree java_create_object (tree); extern int verify_constant_pool (struct JCF *); extern void start_java_method (tree); extern void end_java_method (void); @@ -1321,7 +1382,6 @@ extern tree java_mangle_decl (struct obstack *, tree); extern tree java_mangle_class_field (struct obstack *, tree); extern tree java_mangle_class_field_from_string (struct obstack *, char *); extern tree java_mangle_vtable (struct obstack *, tree); -extern const char *lang_printable_name_wls (tree, int); extern void append_gpp_mangled_name (const char *, int); extern void add_predefined_file (tree); @@ -1363,6 +1423,8 @@ extern tree builtin_function (const char *, tree, int, enum built_in_class, /* Access flags etc for a method (a FUNCTION_DECL): */ +#define METHOD_DUMMY(DECL) (DECL_LANG_SPECIFIC (DECL)->u.f.dummy) + #define METHOD_PUBLIC(DECL) DECL_LANG_FLAG_1 (FUNCTION_DECL_CHECK (DECL)) #define METHOD_PRIVATE(DECL) TREE_PRIVATE (FUNCTION_DECL_CHECK (DECL)) #define METHOD_PROTECTED(DECL) TREE_PROTECTED (FUNCTION_DECL_CHECK (DECL)) @@ -1800,7 +1862,8 @@ enum JV_STATE_PRELOADING = 1, /* Can do _Jv_FindClass. */ JV_STATE_LOADING = 3, /* Has super installed. */ - JV_STATE_LOADED = 5, /* Is complete. */ + JV_STATE_READ = 4, /* Has been completely defined. */ + JV_STATE_LOADED = 5, /* Has Miranda methods defined. */ JV_STATE_COMPILED = 6, /* This was a compiled class. */ diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c index f04b9f958d9..a7cd57a6d77 100644 --- a/gcc/java/jcf-parse.c +++ b/gcc/java/jcf-parse.c @@ -610,8 +610,14 @@ void load_class (tree class_or_name, int verbose) { tree name, saved; - int class_loaded; - tree class_decl; + int class_loaded = 0; + tree class_decl = NULL_TREE; + bool is_compiled_class = false; + + /* We've already failed, don't try again. */ + if (TREE_CODE (class_or_name) == RECORD_TYPE + && TYPE_DUMMY (class_or_name)) + return; /* class_or_name can be the name of the class we want to load */ if (TREE_CODE (class_or_name) == IDENTIFIER_NODE) @@ -624,41 +630,99 @@ load_class (tree class_or_name, int verbose) else name = DECL_NAME (TYPE_NAME (class_or_name)); + class_decl = IDENTIFIER_CLASS_VALUE (name); + if (class_decl != NULL_TREE) + { + tree type = TREE_TYPE (class_decl); + is_compiled_class + = ((TYPE_JCF (type) && JCF_SEEN_IN_ZIP (TYPE_JCF (type))) + || CLASS_FROM_CURRENTLY_COMPILED_P (type)); + } + /* If the class is from source code, then it must already be loaded. */ class_decl = IDENTIFIER_CLASS_VALUE (name); if (class_decl && CLASS_FROM_SOURCE_P (TREE_TYPE (class_decl))) return; saved = name; - while (1) + + /* If flag_verify_invocations is unset, we don't try to load a class + unless we're looking for Object (which is fixed by the ABI) or + it's a class that we're going to compile. */ + if (flag_verify_invocations + || class_or_name == object_type_node + || is_compiled_class + || TREE_CODE (class_or_name) == IDENTIFIER_NODE) { - char *separator; + while (1) + { + char *separator; - if ((class_loaded = read_class (name))) - break; + /* We've already loaded it. */ + if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE) + { + tree tmp_decl = IDENTIFIER_CLASS_VALUE (name); + if (CLASS_PARSED_P (TREE_TYPE (tmp_decl))) + break; + } + + if (read_class (name)) + break; - /* We failed loading name. Now consider that we might be looking - for a inner class. */ - if ((separator = strrchr (IDENTIFIER_POINTER (name), '$')) - || (separator = strrchr (IDENTIFIER_POINTER (name), '.'))) - { - int c = *separator; - *separator = '\0'; - name = get_identifier (IDENTIFIER_POINTER (name)); - *separator = c; - - /* Otherwise we might get infinite recursion, if say we have - String.class but not String$CaseInsensitiveComparator.class. */ - if (current_jcf && current_jcf->java_source == 0) + /* We failed loading name. Now consider that we might be looking + for a inner class. */ + if ((separator = strrchr (IDENTIFIER_POINTER (name), '$')) + || (separator = strrchr (IDENTIFIER_POINTER (name), '.'))) + { + int c = *separator; + *separator = '\0'; + name = get_identifier (IDENTIFIER_POINTER (name)); + *separator = c; + + /* Otherwise we might get infinite recursion, if say we + have String.class but not + String$CaseInsensitiveComparator.class. */ + if (current_jcf && current_jcf->java_source == 0) + break; + } + /* Otherwise, we failed, we bail. */ + else break; } - /* Otherwise, we failed, we bail. */ - else - break; - } - if (!class_loaded && verbose) - error ("cannot find file for class %s", IDENTIFIER_POINTER (saved)); + { + /* have we found the class we're looking for? */ + tree type_decl = IDENTIFIER_CLASS_VALUE (saved); + tree type = type_decl ? TREE_TYPE (type_decl) : NULL; + class_loaded = type && CLASS_PARSED_P (type); + } + } + + if (!class_loaded) + { + if (flag_verify_invocations || ! flag_indirect_dispatch + || flag_emit_class_files) + { + if (verbose) + error ("cannot find file for class %s", IDENTIFIER_POINTER (saved)); + } + else if (verbose) + { + /* This is just a diagnostic during testing, not a real problem. */ + if (!quiet_flag) + warning("cannot find file for class %s", + IDENTIFIER_POINTER (saved)); + + /* Fake it. */ + if (TREE_CODE (class_or_name) == RECORD_TYPE) + { + set_super_info (0, class_or_name, object_type_node, 0); + TYPE_DUMMY (class_or_name) = 1; + /* We won't be able to output any debug info for this class. */ + DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1; + } + } + } } /* Parse the .class file JCF. */ @@ -760,6 +824,7 @@ parse_class_file (void) java_layout_seen_class_methods (); input_location = DECL_SOURCE_LOCATION (TYPE_NAME (current_class)); + file_start_location = input_location; (*debug_hooks->start_source_file) (input_line, input_filename); /* Currently we always have to emit calls to _Jv_InitClass when @@ -775,7 +840,7 @@ parse_class_file (void) { JCF *jcf = current_jcf; - if (METHOD_ABSTRACT (method)) + if (METHOD_ABSTRACT (method) || METHOD_DUMMY (method)) continue; if (METHOD_NATIVE (method)) @@ -911,6 +976,7 @@ static void parse_source_file_2 (void) { int save_error_count = java_error_count; + flag_verify_invocations = true; java_complete_class (); /* Parse unsatisfied class decl. */ java_parse_abort_on_error (); } @@ -1196,7 +1262,12 @@ java_parse_file (int set_yydebug ATTRIBUTE_UNUSED) input_location = DECL_SOURCE_LOCATION (node); if (CLASS_FILE_P (node)) { + /* FIXME: These two flags really should be independent. We + should be able to compile fully binary compatible, but + with flag_verify_invocations on. */ + flag_verify_invocations = ! flag_indirect_dispatch; output_class = current_class = TREE_TYPE (node); + current_jcf = TYPE_JCF (current_class); layout_class (current_class); load_inner_classes (current_class); @@ -1232,13 +1303,15 @@ compute_class_name (struct ZipDirectory *zdir) char *class_name_in_zip_dir = ZIPDIR_FILENAME (zdir); char *class_name; int i; - int filename_length; + int filename_length = zdir->filename_length; - while (strncmp (class_name_in_zip_dir, "./", 2) == 0) - class_name_in_zip_dir += 2; + while (filename_length > 2 && strncmp (class_name_in_zip_dir, "./", 2) == 0) + { + class_name_in_zip_dir += 2; + filename_length -= 2; + } - filename_length = (strlen (class_name_in_zip_dir) - - strlen (".class")); + filename_length -= strlen (".class"); class_name = ALLOC (filename_length + 1); memcpy (class_name, class_name_in_zip_dir, filename_length); class_name [filename_length] = '\0'; @@ -1300,6 +1373,13 @@ parse_zip_file_entries (void) current_jcf = TYPE_JCF (class); output_class = current_class = class; + if (TYPE_DUMMY (class)) + { + /* This is a dummy class, and now we're compiling it + for real. */ + abort (); + } + /* This is for a corner case where we have a superclass but no superclass fields. diff --git a/gcc/java/jvspec.c b/gcc/java/jvspec.c index 940cd8c9fff..a3e8c6fd317 100644 --- a/gcc/java/jvspec.c +++ b/gcc/java/jvspec.c @@ -68,7 +68,7 @@ static const char jvgenmain_spec[] = %<fcompile-resource* %<fassert %<fno-assert \ %<femit-class-file %<femit-class-files %<fencoding*\ %<fuse-boehm-gc %<fhash-synchronization %<fjni\ - %<findirect-dispatch \ + %<findirect-dispatch %<fnew-verifier\ %<fno-store-check %<foutput-class-dir\ %<fclasspath* %<fCLASSPATH* %<fbootclasspath*\ %<fextdirs*\ diff --git a/gcc/java/lang.c b/gcc/java/lang.c index be789fe5381..bcf4e45b4bb 100644 --- a/gcc/java/lang.c +++ b/gcc/java/lang.c @@ -128,6 +128,17 @@ int flag_wall = 0; /* The encoding of the source file. */ const char *current_encoding = NULL; +/* When nonzero, report use of deprecated classes, methods, or fields. */ +int flag_deprecated = 1; + +/* When zero, don't optimize static class initialization. This flag shouldn't + be tested alone, use STATIC_CLASS_INITIALIZATION_OPTIMIZATION_P instead. */ +/* FIXME: Make this work with gimplify. */ +/* int flag_optimize_sci = 0; */ + +/* Don't attempt to verify invocations. */ +int flag_verify_invocations = 0; + /* When nonzero, print extra version information. */ static int v_flag = 0; @@ -593,6 +604,11 @@ java_post_options (const char **pfilename) if (flag_inline_functions) flag_inline_trees = 2; + /* An absolute requirement: if we're not using indirect dispatch, we + must always verify everything. */ + if (! flag_indirect_dispatch) + flag_verify_invocations = true; + /* Open input file. */ if (filename == 0 || !strcmp (filename, "-")) @@ -972,6 +988,10 @@ java_get_callee_fndecl (tree call_expr) HOST_WIDE_INT index; + /* FIXME: This is disabled because we end up passing calls through + the PLT, and we do NOT want to do that. */ + return NULL; + if (TREE_CODE (call_expr) != CALL_EXPR) return NULL; method = TREE_OPERAND (call_expr, 0); diff --git a/gcc/java/lang.opt b/gcc/java/lang.opt index 0e4ffcfd994..644bd5be2e7 100644 --- a/gcc/java/lang.opt +++ b/gcc/java/lang.opt @@ -176,5 +176,9 @@ fuse-divide-subroutine Java Var(flag_use_divide_subroutine) Init(1) Call a library routine to do integer divisions +fnew-verifier +Java Var(flag_new_verifier) +Enable the new bytecode verifier + version Java diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 1c1a686d727..91776c6f7f5 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -9690,8 +9690,8 @@ strip_out_static_field_access_decl (tree node) tree call = TREE_OPERAND (op1, 0); if (TREE_CODE (call) == CALL_EXPR && TREE_CODE (TREE_OPERAND (call, 0)) == ADDR_EXPR - && TREE_OPERAND (TREE_OPERAND (call, 0), 0) - == soft_initclass_node) + && (TREE_OPERAND (TREE_OPERAND (call, 0), 0) + == soft_initclass_node)) return TREE_OPERAND (op1, 1); } else if (JDECL_P (op1)) @@ -11025,7 +11025,7 @@ patch_invoke (tree patch, tree method, tree args) if (TREE_CODE (original_call) == NEW_CLASS_EXPR) { tree class = DECL_CONTEXT (method); - tree c1, saved_new, size, new; + tree c1, saved_new, new; tree alloc_node; if (flag_emit_class_files || flag_emit_xref) @@ -11035,7 +11035,6 @@ patch_invoke (tree patch, tree method, tree args) } if (!TYPE_SIZE (class)) safe_layout_class (class); - size = size_in_bytes (class); alloc_node = (class_has_finalize_method (class) ? alloc_object_node : alloc_no_finalizer_node); @@ -11109,11 +11108,20 @@ invocation_mode (tree method, int super) if (DECL_CONSTRUCTOR_P (method)) return INVOKE_STATIC; - if (access & ACC_FINAL || access & ACC_PRIVATE) + if (access & ACC_PRIVATE) return INVOKE_NONVIRTUAL; - if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method)))) - return INVOKE_NONVIRTUAL; + /* Binary compatibility: just because it's final today, that doesn't + mean it'll be final tomorrow. */ + if (! flag_indirect_dispatch + || DECL_CONTEXT (method) == object_type_node) + { + if (access & ACC_FINAL) + return INVOKE_NONVIRTUAL; + + if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method)))) + return INVOKE_NONVIRTUAL; + } if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))) return INVOKE_INTERFACE; diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index 0c61174f251..4db69b4ea0c 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -743,7 +743,7 @@ lookup_java_method (tree searched_class, tree method_name, method_signature, build_java_signature); } -/* Return true iff CLASS (or its ancestors) has a method METHOD_NAME. */ +/* Return true iff CLASS (or its ancestors) has a method METHOD_NAME. */ int has_method (tree class, tree method_name) { diff --git a/gcc/java/verify-glue.c b/gcc/java/verify-glue.c new file mode 100644 index 00000000000..fb213405e43 --- /dev/null +++ b/gcc/java/verify-glue.c @@ -0,0 +1,514 @@ +/* Glue to interface gcj with bytecode verifier. + Copyright (C) 2003, 2004 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) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +/* Written by Tom Tromey <tromey@redhat.com>. */ + +#include "config.h" + +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "errors.h" +#include "parse.h" + +#include "verify.h" +#include "java-tree.h" +#include "java-except.h" + +void * +vfy_alloc (size_t bytes) +{ + return xmalloc (bytes); +} + +void +vfy_free (void *mem) +{ + free (mem); +} + +bool +vfy_strings_equal (vfy_string one, vfy_string two) +{ + return one == two; +} + +const char * +vfy_string_bytes (vfy_string str) +{ + return IDENTIFIER_POINTER (str); +} + +int +vfy_string_length (vfy_string str) +{ + return IDENTIFIER_LENGTH (str); +} + +vfy_string +vfy_init_name () +{ + return init_identifier_node; +} + +vfy_string +vfy_clinit_name () +{ + return clinit_identifier_node; +} + +static const char* +skip_one_type (const char* ptr) +{ + int ch = *ptr++; + + while (ch == '[') + { + ch = *ptr++; + } + + if (ch == 'L') + { + do { ch = *ptr++; } while (ch != ';'); + } + + return ptr; +} + +int +vfy_count_arguments (vfy_string signature) +{ + const char *ptr = IDENTIFIER_POINTER (signature); + int arg_count = 0; + + /* Skip '('. */ + ptr++; + + /* Count args. */ + while (*ptr != ')') + { + ptr = skip_one_type (ptr); + arg_count += 1; + } + + return arg_count; +} + +vfy_string +vfy_get_string (const char *s, int len) +{ + return get_identifier_with_length (s, len); +} + +vfy_string +vfy_get_signature (vfy_method *method) +{ + return method->signature; +} + +vfy_string +vfy_get_method_name (vfy_method *method) +{ + return method->name; +} + +bool +vfy_is_static (vfy_method *method) +{ + return METHOD_STATIC (method->method); +} + +const unsigned char * +vfy_get_bytecode (vfy_method *method) +{ + return method->bytes; +} + +vfy_exception * +vfy_get_exceptions (vfy_method *method) +{ + return method->exceptions; +} + +void +vfy_get_exception (vfy_exception *exceptions, int index, int *handler, + int *start, int *end, int *handler_type) +{ + *handler = exceptions[index].handler; + *start = exceptions[index].start; + *end = exceptions[index].end; + *handler_type = exceptions[index].type; +} + +int +vfy_tag (vfy_constants *pool, int index) +{ + int result = JPOOL_TAG (pool, index); + /* gcj will resolve constant pool entries other than string and + class references. The verifier doesn't care about the values, so + we just strip off the resolved flag. */ + if ((result & CONSTANT_ResolvedFlag) != 0 + && result != CONSTANT_ResolvedString + && result != CONSTANT_ResolvedClass) + result &= ~ CONSTANT_ResolvedFlag; + return result; +} + +void +vfy_load_indexes (vfy_constants *pool, int index, + vfy_uint_16 *index0, vfy_uint_16 *index1) +{ + *index0 = JPOOL_USHORT1 (pool, index); + *index1 = JPOOL_USHORT2 (pool, index); +} + +vfy_constants * +vfy_get_constants (vfy_jclass klass) +{ + return TYPE_JCF (klass); +} + +int +vfy_get_constants_size (vfy_jclass klass) +{ + return JPOOL_SIZE (TYPE_JCF (klass)); +} + +vfy_string +vfy_get_pool_string (vfy_constants *pool, int index) +{ + return get_name_constant (pool, index); +} + +vfy_jclass +vfy_get_pool_class (vfy_constants *pool, int index) +{ + vfy_jclass k; + k = get_class_constant (pool, index); + return k; +} + +vfy_string +vfy_make_string (const char *s, int len) +{ + tree result; + char *s2 = (char *) s; + char save = s2[len]; + s2[len] = '\0'; + result = get_identifier (s2); + s2[len] = save; + return result; +} + +vfy_string +vfy_get_class_name (vfy_jclass klass) +{ + return DECL_NAME (TYPE_NAME (klass)); +} + +bool +vfy_is_assignable_from (vfy_jclass target, vfy_jclass source) +{ + /* At compile time, for the BC-ABI we assume that reference types are always + compatible. However, a type assertion table entry is emitted so that the + runtime can detect binary-incompatible changes. */ + + /* FIXME: implement real test for old ABI. */ + + /* Any class is always assignable to itself, or java.lang.Object. */ + if (source == target || target == object_type_node) + return true; + + /* Otherwise, a type assertion is required. */ + add_type_assertion (current_class, JV_ASSERT_TYPES_COMPATIBLE, source, + target); + return true; +} + +char +vfy_get_primitive_char (vfy_jclass klass) +{ + tree sig; + if (! vfy_is_primitive (klass)) + abort (); + sig = build_java_signature (klass); + return (IDENTIFIER_POINTER (sig))[0]; +} + +int +vfy_get_interface_count (vfy_jclass klass ATTRIBUTE_UNUSED) +{ + /* FIXME: Need to merge from mainline to get this. */ + #if 0 + return BINFO_N_BASE_BINFOS (klass); + #endif + return -1; +} + +vfy_jclass +vfy_get_interface (vfy_jclass klass ATTRIBUTE_UNUSED, int index ATTRIBUTE_UNUSED) +{ + /* FIXME: Need to merge from mainline to get this. */ + #if 0 + vfy_jclass k; + k = BINFO_BASE_BINFO (klass, index); + return k; + #endif + return NULL; +} + +bool +vfy_is_array (vfy_jclass klass) +{ + return TYPE_ARRAY_P (klass); +} + +bool +vfy_is_interface (vfy_jclass klass) +{ + return CLASS_INTERFACE (TYPE_NAME (klass)); +} + +bool +vfy_is_primitive (vfy_jclass klass) +{ + return JPRIMITIVE_TYPE_P (klass); +} + +vfy_jclass +vfy_get_superclass (vfy_jclass klass) +{ + vfy_jclass k; + k = CLASSTYPE_SUPER (klass); + return k; +} + +vfy_jclass +vfy_get_array_class (vfy_jclass klass) +{ + vfy_jclass k; + k = build_java_array_type (klass, -1); + return k; +} + +vfy_jclass +vfy_get_component_type (vfy_jclass klass) +{ + vfy_jclass k; + if (! vfy_is_array (klass)) + abort (); + k = TYPE_ARRAY_ELEMENT (klass); + if (TREE_CODE (k) == POINTER_TYPE) + k = TREE_TYPE (k); + return k; +} + +bool +vfy_is_abstract (vfy_jclass klass) +{ + return CLASS_ABSTRACT (TYPE_NAME (klass)); +} + +vfy_jclass +vfy_find_class (vfy_jclass ignore ATTRIBUTE_UNUSED, vfy_string name) +{ + vfy_jclass k; + + k = get_type_from_signature (name); + if (TREE_CODE (k) == POINTER_TYPE) + k = TREE_TYPE (k); + + return k; +} + +vfy_jclass +vfy_object_type () +{ + vfy_jclass k; + k = object_type_node; + return k; +} + +vfy_jclass +vfy_string_type () +{ + vfy_jclass k; + k = string_type_node; + return k; +} + +vfy_jclass +vfy_throwable_type () +{ + vfy_jclass k; + k = throwable_type_node; + return k; +} + +vfy_jclass +vfy_unsuitable_type (void) +{ + return TYPE_SECOND; +} + +vfy_jclass +vfy_return_address_type (void) +{ + return TYPE_RETURN_ADDR; +} + +vfy_jclass +vfy_null_type (void) +{ + return TYPE_NULL; +} + +int +vfy_fail (const char *message, int pc, vfy_jclass ignore1 ATTRIBUTE_UNUSED, + vfy_method *ignore2 ATTRIBUTE_UNUSED) +{ + if (pc == -1) + error ("verification failed: %s", message); + else + error ("verification failed at PC=%d: %s", pc, message); + /* We have to return a value for the verifier to throw. */ + return 1; +} + +vfy_jclass +vfy_get_primitive_type (int type) +{ + vfy_jclass k; + k = decode_newarray_type (type); + return k; +} + +void +vfy_note_stack_depth (vfy_method *method, int pc, int depth) +{ + tree label = lookup_label (pc); + LABEL_TYPE_STATE (label) = make_tree_vec (method->max_locals + depth); +} + +void +vfy_note_stack_type (vfy_method *method, int pc, int slot, vfy_jclass type) +{ + tree label, vec; + + slot += method->max_locals; + + if (type == object_type_node) + type = object_ptr_type_node; + + label = lookup_label (pc); + vec = LABEL_TYPE_STATE (label); + TREE_VEC_ELT (vec, slot) = type; +} + +void +vfy_note_local_type (vfy_method *method ATTRIBUTE_UNUSED, int pc, int slot, + vfy_jclass type) +{ + tree label, vec; + + if (type == object_type_node) + type = object_ptr_type_node; + + label = lookup_label (pc); + vec = LABEL_TYPE_STATE (label); + TREE_VEC_ELT (vec, slot) = type; +} + +void +vfy_note_instruction_seen (int pc) +{ + instruction_bits[pc] |= BCODE_VERIFIED; +} + +/* Verify the bytecodes of the current method. + Return 1 on success, 0 on failure. */ +int +verify_jvm_instructions_new (JCF *jcf, const unsigned char *byte_ops, + long length) +{ + vfy_method method; + int i, result, eh_count; + vfy_exception *exceptions; + + method_init_exceptions (); + + JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length); + eh_count = JCF_readu2 (jcf); + + exceptions = (vfy_exception *) xmalloc (eh_count * sizeof (vfy_exception)); + for (i = 0; i < eh_count; ++i) + { + int start_pc, end_pc, handler_pc, catch_type; + unsigned char *p = jcf->read_ptr + 8 * i; + start_pc = GET_u2 (p); + end_pc = GET_u2 (p+2); + handler_pc = GET_u2 (p+4); + catch_type = GET_u2 (p+6); + + if (start_pc < 0 || start_pc >= length + || end_pc < 0 || end_pc > length || start_pc >= end_pc + || handler_pc < 0 || handler_pc >= length) + { + error ("bad pc in exception_table"); + free (exceptions); + return 0; + } + + exceptions[i].handler = handler_pc; + exceptions[i].start = start_pc; + exceptions[i].end = end_pc; + exceptions[i].type = catch_type; + + add_handler (start_pc, end_pc, + lookup_label (handler_pc), + catch_type == 0 ? NULL_TREE + : get_class_constant (jcf, catch_type)); + instruction_bits[handler_pc] |= BCODE_EXCEPTION_TARGET; + } + + handle_nested_ranges (); + + method.method = current_function_decl; + method.signature = build_java_signature (TREE_TYPE (current_function_decl)); + method.name = DECL_NAME (current_function_decl); + method.bytes = byte_ops; + method.exceptions = exceptions; + method.defining_class = DECL_CONTEXT (current_function_decl); + method.max_stack = DECL_MAX_STACK (current_function_decl); + method.max_locals = DECL_MAX_LOCALS (current_function_decl); + method.code_length = length; + method.exc_count = eh_count; + + result = verify_method (&method); + + free (exceptions); + + return result; +} diff --git a/gcc/java/verify-impl.c b/gcc/java/verify-impl.c new file mode 100644 index 00000000000..2c402a8c62b --- /dev/null +++ b/gcc/java/verify-impl.c @@ -0,0 +1,3418 @@ +/* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Written by Tom Tromey <tromey@redhat.com> */ + +/* Uncomment this to enable debugging output. */ +/* #define VERIFY_DEBUG */ + +#include "config.h" + +#include "verify.h" + +/* Hack to work around namespace pollution from java-tree.h. */ +#undef current_class + +#ifdef VERIFY_DEBUG +#include <stdio.h> +#endif /* VERIFY_DEBUG */ + +/* This is used to mark states which are not scheduled for + verification. */ +#define INVALID_STATE ((state *) -1) + +#ifdef VERIFY_DEBUG +static void +debug_print (const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +} +#else +static void +debug_print (const char *fmt ATTRIBUTE_UNUSED, ...) +{ +} +#endif /* VERIFY_DEBUG */ + +#if 0 +static void debug_print (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static void +debug_print (const char *fmt, ...) +{ +#ifdef VERIFY_DEBUG + va_list ap; + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); +#endif /* VERIFY_DEBUG */ +} +#endif + +/* This started as a fairly ordinary verifier, and for the most part + it remains so. It works in the obvious way, by modeling the effect + of each opcode as it is encountered. For most opcodes, this is a + straightforward operation. + + This verifier does not do type merging. It used to, but this + results in difficulty verifying some relatively simple code + involving interfaces, and it pushed some verification work into the + interpreter. + + Instead of merging reference types, when we reach a point where two + flows of control merge, we simply keep the union of reference types + from each branch. Then, when we need to verify a fact about a + reference on the stack (e.g., that it is compatible with the + argument type of a method), we check to ensure that all possible + types satisfy the requirement. + + Another area this verifier differs from the norm is in its handling + of subroutines. The JVM specification has some confusing things to + say about subroutines. For instance, it makes claims about not + allowing subroutines to merge and it rejects recursive subroutines. + For the most part these are red herrings; we used to try to follow + these things but they lead to problems. For example, the notion of + "being in a subroutine" is not well-defined: is an exception + handler in a subroutine? If you never execute the `ret' but + instead `goto 1' do you remain in the subroutine? + + For clarity on what is really required for type safety, read + "Simple Verification Technique for Complex Java Bytecode + Subroutines" by Alessandro Coglio. Among other things this paper + shows that recursive subroutines are not harmful to type safety. + We implement something similar to what he proposes. Note that this + means that this verifier will accept code that is rejected by some + other verifiers. + + For those not wanting to read the paper, the basic observation is + that we can maintain split states in subroutines. We maintain one + state for each calling `jsr'. In other words, we re-verify a + subroutine once for each caller, using the exact types held by the + callers (as opposed to the old approach of merging types and + keeping a bitmap registering what did or did not change). This + approach lets us continue to verify correctly even when a + subroutine is exited via `goto' or `athrow' and not `ret'. + + In some other areas the JVM specification is (mildly) incorrect, + so we diverge. For instance, you cannot + violate type safety by allocating an object with `new' and then + failing to initialize it, no matter how one branches or where one + stores the uninitialized reference. See "Improving the official + specification of Java bytecode verification" by Alessandro Coglio. + + Note that there's no real point in enforcing that padding bytes or + the mystery byte of invokeinterface must be 0, but we do that + regardless. + + The verifier is currently neither completely lazy nor eager when it + comes to loading classes. It tries to represent types by name when + possible, and then loads them when it needs to verify a fact about + the type. Checking types by name is valid because we only use + names which come from the current class' constant pool. Since all + such names are looked up using the same class loader, there is no + danger that we might be fooled into comparing different types with + the same name. + + In the future we plan to allow for a completely lazy mode of + operation, where the verifier will construct a list of type + assertions to be checked later. + + Some test cases for the verifier live in the "verify" module of the + Mauve test suite. However, some of these are presently + (2004-01-20) believed to be incorrect. (More precisely the notion + of "correct" is not well-defined, and this verifier differs from + others while remaining type-safe.) Some other tests live in the + libgcj test suite. + + This verifier is also written to be pluggable. This means that it + is intended for use in a variety of environments, not just libgcj. + As a result the verifier expects a number of type and method + declarations to be declared in "verify.h". The intent is that you + recompile the verifier for your particular environment. This + approach was chosen so that operations could be inlined in verify.h + as much as possible. + + See the verify.h that accompanies this copy of the verifier to see + what types, preprocessor defines, and functions must be declared. + The interface is ad hoc, but was defined so that it could be + implemented to connect to a pure C program. +*/ + +#define FLAG_INSN_START 1 +#define FLAG_BRANCH_TARGET 2 +#define FLAG_INSN_SEEN 4 + +struct state; +struct type; +struct ref_intersection; + +typedef struct state state; +typedef struct type type; +typedef struct ref_intersection ref_intersection; + +/*typedef struct state_list state_list;*/ + +typedef struct state_list +{ + state *val; + struct state_list *next; +} state_list; + +typedef struct vfy_string_list +{ + vfy_string val; + struct vfy_string_list *next; +} vfy_string_list; + +typedef struct verifier_context +{ + /* The current PC. */ + int PC; + /* The PC corresponding to the start of the current instruction. */ + int start_PC; + + /* The current state of the stack, locals, etc. */ + state *current_state; + + /* At each branch target we keep a linked list of all the states we + can process at that point. We'll only have multiple states at a + given PC if they both have different return-address types in the + same stack or local slot. This array is indexed by PC and holds + the list of all such states. */ + state_list **states; + + /* We keep a linked list of all the states which we must reverify. + This is the head of the list. */ + state *next_verify_state; + + /* We keep some flags for each instruction. The values are the + FLAG_* constants defined above. This is an array indexed by PC. */ + char *flags; + + /* The bytecode itself. */ + const unsigned char *bytecode; + /* The exceptions. */ + vfy_exception *exception; + + /* Defining class. */ + vfy_jclass current_class; + /* This method. */ + vfy_method *current_method; + + /* A linked list of utf8 objects we allocate. */ + vfy_string_list *utf8_list; + + /* A linked list of all ref_intersection objects we allocate. */ + ref_intersection *isect_list; +} verifier_context; + +/* The current verifier's state data. This is maintained by + {push/pop}_verifier_context to provide a shorthand form to access + the verification state. */ +static GTY(()) verifier_context *vfr; + +/* Local function declarations. */ +bool type_initialized (type *t); +int ref_count_dimensions (ref_intersection *ref); + +#if 0 + /* Create a new Utf-8 constant and return it. We do this to avoid + having our Utf-8 constants prematurely collected. */ + static vfy_string + make_utf8_const (const char *s, int len) + { + vfy_string val = vfy_make_string (s, len); + vfy_string_list *lu = vfy_alloc (sizeof (vfy_string_list)); + lu->val = val; + lu->next = vfr->utf8_list; + vfr->utf8_list = lu; + + return val; + } +#endif + +static void +verify_fail_pc (const char *s, int pc) +{ + vfy_fail (s, pc, vfr->current_class, vfr->current_method); +} + +static void +verify_fail (const char *s) +{ + verify_fail_pc (s, -1); +} + +/* This enum holds a list of tags for all the different types we + need to handle. Reference types are treated specially by the + type class. */ +typedef enum type_val +{ + void_type, + + /* The values for primitive types are chosen to correspond to values + specified to newarray. */ + boolean_type = 4, + char_type = 5, + float_type = 6, + double_type = 7, + byte_type = 8, + short_type = 9, + int_type = 10, + long_type = 11, + + /* Used when overwriting second word of a double or long in the + local variables. Also used after merging local variable states + to indicate an unusable value. */ + unsuitable_type, + return_address_type, + /* This is the second word of a two-word value, i.e., a double or + a long. */ + continuation_type, + + /* Everything after `reference_type' must be a reference type. */ + reference_type, + null_type, + uninitialized_reference_type +} type_val; + +/* This represents a merged class type. Some verifiers (including + earlier versions of this one) will compute the intersection of + two class types when merging states. However, this loses + critical information about interfaces implemented by the various + classes. So instead we keep track of all the actual classes that + have been merged. */ +struct ref_intersection +{ + /* Whether or not this type has been resolved. */ + bool is_resolved; + + /* Actual type data. */ + union + { + /* For a resolved reference type, this is a pointer to the class. */ + vfy_jclass klass; + /* For other reference types, this it the name of the class. */ + vfy_string name; + } data; + + /* Link to the next reference in the intersection. */ + ref_intersection *ref_next; + + /* This is used to keep track of all the allocated + ref_intersection objects, so we can free them. + FIXME: we should allocate these in chunks. */ + ref_intersection *alloc_next; +}; + +static ref_intersection * +make_ref (void) +{ + ref_intersection *new_ref = + (ref_intersection *) vfy_alloc (sizeof (ref_intersection)); + + new_ref->alloc_next = vfr->isect_list; + vfr->isect_list = new_ref; + return new_ref; +} + +static ref_intersection * +clone_ref (ref_intersection *dup) +{ + ref_intersection *new_ref = make_ref (); + + new_ref->is_resolved = dup->is_resolved; + new_ref->data = dup->data; + return new_ref; +} + +static void +resolve_ref (ref_intersection *ref) +{ + if (ref->is_resolved) + return; + ref->data.klass = vfy_find_class (vfr->current_class, ref->data.name); + ref->is_resolved = true; +} + +static bool +refs_equal (ref_intersection *ref1, ref_intersection *ref2) +{ + if (! ref1->is_resolved && ! ref2->is_resolved + && vfy_strings_equal (ref1->data.name, ref2->data.name)) + return true; + if (! ref1->is_resolved) + resolve_ref (ref1); + if (! ref2->is_resolved) + resolve_ref (ref2); + return ref1->data.klass == ref2->data.klass; +} + +/* Merge REF1 type into REF2, returning the result. This will + return REF2 if all the classes in THIS already appear in + REF2. */ +static ref_intersection * +merge_refs (ref_intersection *ref1, ref_intersection *ref2) +{ + ref_intersection *tail = ref2; + for (; ref1 != NULL; ref1 = ref1->ref_next) + { + bool add = true; + ref_intersection *iter; + for (iter = ref2; iter != NULL; iter = iter->ref_next) + { + if (refs_equal (ref1, iter)) + { + add = false; + break; + } + } + + if (add) + { + ref_intersection *new_tail = clone_ref (ref1); + new_tail->ref_next = tail; + tail = new_tail; + } + } + return tail; +} + +/* See if an object of type SOURCE can be assigned to an object of + type TARGET. This might resolve classes in one chain or the other. */ +static bool +ref_compatible (ref_intersection *target, ref_intersection *source) +{ + for (; target != NULL; target = target->ref_next) + { + ref_intersection *source_iter = source; + + for (; source_iter != NULL; source_iter = source_iter->ref_next) + { + /* Avoid resolving if possible. */ + if (! target->is_resolved + && ! source_iter->is_resolved + && vfy_strings_equal (target->data.name, + source_iter->data.name)) + continue; + + if (! target->is_resolved) + resolve_ref (target); + if (! source_iter->is_resolved) + resolve_ref (source_iter); + + if (! vfy_is_assignable_from (target->data.klass, + source_iter->data.klass)) + return false; + } + } + + return true; +} + +static bool +ref_isarray (ref_intersection *ref) +{ + /* assert (ref_next == NULL); */ + if (ref->is_resolved) + return vfy_is_array (ref->data.klass); + else + return vfy_string_bytes (ref->data.name)[0] == '['; +} + +static bool +ref_isinterface (ref_intersection *ref) +{ + /* assert (ref_next == NULL); */ + if (! ref->is_resolved) + resolve_ref (ref); + return vfy_is_interface (ref->data.klass); +} + +static bool +ref_isabstract (ref_intersection *ref) +{ + /* assert (ref_next == NULL); */ + if (! ref->is_resolved) + resolve_ref (ref); + return vfy_is_abstract (ref->data.klass); +} + +static vfy_jclass +ref_getclass (ref_intersection *ref) +{ + if (! ref->is_resolved) + resolve_ref (ref); + return ref->data.klass; +} + +int +ref_count_dimensions (ref_intersection *ref) +{ + int ndims = 0; + if (ref->is_resolved) + { + vfy_jclass k = ref->data.klass; + while (vfy_is_array (k)) + { + k = vfy_get_component_type (k); + ++ndims; + } + } + else + { + const char *p = vfy_string_bytes (ref->data.name); + while (*p++ == '[') + ++ndims; + } + return ndims; +} + +/* Return the type_val corresponding to a primitive signature + character. For instance `I' returns `int.class'. */ +static type_val +get_type_val_for_signature (char sig) +{ + type_val rt; + switch (sig) + { + case 'Z': + rt = boolean_type; + break; + case 'B': + rt = byte_type; + break; + case 'C': + rt = char_type; + break; + case 'S': + rt = short_type; + break; + case 'I': + rt = int_type; + break; + case 'J': + rt = long_type; + break; + case 'F': + rt = float_type; + break; + case 'D': + rt = double_type; + break; + case 'V': + rt = void_type; + break; + default: + verify_fail ("invalid signature"); + return null_type; + } + return rt; +} + +/* Return the type_val corresponding to a primitive class. */ +static type_val +get_type_val_for_primtype (vfy_jclass k) +{ + return get_type_val_for_signature (vfy_get_primitive_char (k)); +} + +/* The `type' class is used to represent a single type in the verifier. */ +struct type +{ + /* The type key. */ + type_val key; + + /* For reference types, the representation of the type. */ + ref_intersection *klass; + + /* This is used in two situations. + + First, when constructing a new object, it is the PC of the + `new' instruction which created the object. We use the special + value UNINIT to mean that this is uninitialized, and the + special value SELF for the case where the current method is + itself the <init> method. + + Second, when the key is return_address_type, this holds the PC + of the instruction following the `jsr'. */ + int pc; + + #define UNINIT -2 + #define SELF -1 +}; + +#if 0 +/* Basic constructor. */ +static void +init_type (type *t) +{ + t->key = unsuitable_type; + t->klass = NULL; + t->pc = UNINIT; +} +#endif + +/* Make a new instance given the type tag. We assume a generic + `reference_type' means Object. */ +static void +init_type_from_tag (type *t, type_val k) +{ + t->key = k; + /* For reference_type, if KLASS==NULL then that means we are + looking for a generic object of any kind, including an + uninitialized reference. */ + t->klass = NULL; + t->pc = UNINIT; +} + +/* Make a type for the given type_val tag K. */ +static type +make_type (type_val k) +{ + type t; + init_type_from_tag (&t, k); + return t; +} + +/* Make a new instance given a class. */ +static void +init_type_from_class (type *t, vfy_jclass k) +{ + t->key = reference_type; + t->klass = make_ref (); + t->klass->is_resolved = true; + t->klass->data.klass = k; + t->klass->ref_next = NULL; + t->pc = UNINIT; +} + +static type +make_type_from_class (vfy_jclass k) +{ + type t; + init_type_from_class (&t, k); + return t; +} + +static void +init_type_from_string (type *t, vfy_string n) +{ + t->key = reference_type; + t->klass = make_ref (); + t->klass->is_resolved = false; + t->klass->data.name = n; + t->klass->ref_next = NULL; + t->pc = UNINIT; +} + +static type +make_type_from_string (vfy_string n) +{ + type t; + init_type_from_string (&t, n); + return t; +} + +#if 0 + /* Make a new instance given the name of a class. */ + type (vfy_string n) + { + key = reference_type; + klass = new ref_intersection (n, verifier); + pc = UNINIT; + } + + /* Copy constructor. */ + static type copy_type (type *t) + { + type copy; + copy.key = t->key; + copy.klass = t->klass; + copy.pc = t->pc; + return copy; + } +#endif + +/* Promote a numeric type. */ +static void +vfy_promote_type (type *t) +{ + if (t->key == boolean_type || t->key == char_type + || t->key == byte_type || t->key == short_type) + t->key = int_type; +} +#define promote_type vfy_promote_type + +/* Mark this type as the uninitialized result of `new'. */ +static void +type_set_uninitialized (type *t, int npc) +{ + if (t->key == reference_type) + t->key = uninitialized_reference_type; + else + verify_fail ("internal error in type::uninitialized"); + t->pc = npc; +} + +/* Mark this type as now initialized. */ +static void +type_set_initialized (type *t, int npc) +{ + if (npc != UNINIT && t->pc == npc && t->key == uninitialized_reference_type) + { + t->key = reference_type; + t->pc = UNINIT; + } +} + +/* Mark this type as a particular return address. */ +static void type_set_return_address (type *t, int npc) +{ + t->pc = npc; +} + +/* Return true if this type and type OTHER are considered + mergeable for the purposes of state merging. This is related + to subroutine handling. For this purpose two types are + considered unmergeable if they are both return-addresses but + have different PCs. */ +static bool +type_state_mergeable_p (type *t1, type *t2) +{ + return (t1->key != return_address_type + || t2->key != return_address_type + || t1->pc == t2->pc); +} + +/* Return true if an object of type K can be assigned to a variable + of type T. Handle various special cases too. Might modify + T or K. Note however that this does not perform numeric + promotion. */ +static bool +types_compatible (type *t, type *k) +{ + /* Any type is compatible with the unsuitable type. */ + if (k->key == unsuitable_type) + return true; + + if (t->key < reference_type || k->key < reference_type) + return t->key == k->key; + + /* The `null' type is convertible to any initialized reference + type. */ + if (t->key == null_type) + return k->key != uninitialized_reference_type; + if (k->key == null_type) + return t->key != uninitialized_reference_type; + + /* A special case for a generic reference. */ + if (t->klass == NULL) + return true; + if (k->klass == NULL) + verify_fail ("programmer error in type::compatible"); + + /* An initialized type and an uninitialized type are not + compatible. */ + if (type_initialized (t) != type_initialized (k)) + return false; + + /* Two uninitialized objects are compatible if either: + * The PCs are identical, or + * One PC is UNINIT. */ + if (type_initialized (t)) + { + if (t->pc != k->pc && t->pc != UNINIT && k->pc != UNINIT) + return false; + } + + return ref_compatible (t->klass, k->klass); +} + +static bool +type_isvoid (type *t) +{ + return t->key == void_type; +} + +static bool +type_iswide (type *t) +{ + return t->key == long_type || t->key == double_type; +} + +/* Return number of stack or local variable slots taken by this type. */ +static int +type_depth (type *t) +{ + return type_iswide (t) ? 2 : 1; +} + +static bool +type_isarray (type *t) +{ + /* We treat null_type as not an array. This is ok based on the + current uses of this method. */ + if (t->key == reference_type) + return ref_isarray (t->klass); + return false; +} + +static bool +type_isnull (type *t) +{ + return t->key == null_type; +} + +static bool +type_isinterface (type *t) +{ + if (t->key != reference_type) + return false; + return ref_isinterface (t->klass); +} + +static bool +type_isabstract (type *t) +{ + if (t->key != reference_type) + return false; + return ref_isabstract (t->klass); +} + +/* Return the element type of an array. */ +static type +type_array_element (type *t) +{ + type et; + vfy_jclass k; + + if (t->key != reference_type) + verify_fail ("programmer error in type::element_type()"); + + k = vfy_get_component_type (ref_getclass (t->klass)); + if (vfy_is_primitive (k)) + init_type_from_tag (&et, get_type_val_for_primtype (k)); + else + init_type_from_class (&et, k); + return et; +} + +/* Return the array type corresponding to an initialized + reference. We could expand this to work for other kinds of + types, but currently we don't need to. */ +static type +type_to_array (type *t) +{ + type at; + vfy_jclass k; + + if (t->key != reference_type) + verify_fail ("internal error in type::to_array()"); + + k = ref_getclass (t->klass); + init_type_from_class (&at, vfy_get_array_class (k)); + return at; +} + +static bool +type_isreference (type *t) +{ + return t->key >= reference_type; +} + +static int +type_get_pc (type *t) +{ + return t->pc; +} + +bool +type_initialized (type *t) +{ + return t->key == reference_type || t->key == null_type; +} + +#if 0 +static bool +type_isresolved (type *t) +{ + return (t->key == reference_type + || t->key == null_type + || t->key == uninitialized_reference_type); +} +#endif + +static void +type_verify_dimensions (type *t, int ndims) +{ + /* The way this is written, we don't need to check isarray(). */ + if (t->key != reference_type) + verify_fail ("internal error in verify_dimensions:" + " not a reference type"); + + if (ref_count_dimensions (t->klass) < ndims) + verify_fail ("array type has fewer dimensions" + " than required"); +} + +/* Merge OLD_TYPE into this. On error throw exception. Return + true if the merge caused a type change. */ +static bool +merge_types (type *t, type *old_type, bool local_semantics) +{ + bool changed = false; + bool refo = type_isreference (old_type); + bool refn = type_isreference (t); + if (refo && refn) + { + if (old_type->key == null_type) + ; + else if (t->key == null_type) + { + *t = *old_type; + changed = true; + } + else if (type_initialized (t) != type_initialized (old_type)) + verify_fail ("merging initialized and uninitialized types"); + else + { + ref_intersection *merged; + if (! type_initialized (t)) + { + if (t->pc == UNINIT) + t->pc = old_type->pc; + else if (old_type->pc == UNINIT) + ; + else if (t->pc != old_type->pc) + verify_fail ("merging different uninitialized types"); + } + + merged = merge_refs (old_type->klass, t->klass); + if (merged != t->klass) + { + t->klass = merged; + changed = true; + } + } + } + else if (refo || refn || t->key != old_type->key) + { + if (local_semantics) + { + /* If we already have an `unsuitable' type, then we + don't need to change again. */ + if (t->key != unsuitable_type) + { + t->key = unsuitable_type; + changed = true; + } + } + else + verify_fail ("unmergeable type"); + } + return changed; +} + +#ifdef VERIFY_DEBUG +static void +type_print (type *t) +{ + char c = '?'; + switch (t->key) + { + case boolean_type: c = 'Z'; break; + case byte_type: c = 'B'; break; + case char_type: c = 'C'; break; + case short_type: c = 'S'; break; + case int_type: c = 'I'; break; + case long_type: c = 'J'; break; + case float_type: c = 'F'; break; + case double_type: c = 'D'; break; + case void_type: c = 'V'; break; + case unsuitable_type: c = '-'; break; + case return_address_type: c = 'r'; break; + case continuation_type: c = '+'; break; + case reference_type: c = 'L'; break; + case null_type: c = '@'; break; + case uninitialized_reference_type: c = 'U'; break; + } + debug_print ("%c", c); +} +#endif /* VERIFY_DEBUG */ + +/* This class holds all the state information we need for a given + location. */ +struct state +{ + /* The current top of the stack, in terms of slots. */ + int stacktop; + /* The current depth of the stack. This will be larger than + STACKTOP when wide types are on the stack. */ + int stackdepth; + /* The stack. */ + type *stack; + /* The local variables. */ + type *locals; + /* We keep track of the type of `this' specially. This is used to + ensure that an instance initializer invokes another initializer + on `this' before returning. We must keep track of this + specially because otherwise we might be confused by code which + assigns to locals[0] (overwriting `this') and then returns + without really initializing. */ + type this_type; + + /* The PC for this state. This is only valid on states which are + permanently attached to a given PC. For an object like + `current_state', which is used transiently, this has no + meaning. */ + int pc; + /* We keep a linked list of all states requiring reverification. + If this is the special value INVALID_STATE then this state is + not on the list. NULL marks the end of the linked list. */ + state *next; +}; + +/* NO_NEXT is the PC value meaning that a new state must be + acquired from the verification list. */ +#define NO_NEXT -1 + +#if 0 +static void +init_state (state *s) +{ + s->stack = NULL; + s->locals = NULL; + s->next = INVALID_STATE; +} +#endif + +static void +init_state_with_stack (state *s, int max_stack, int max_locals) +{ + int i; + s->stacktop = 0; + s->stackdepth = 0; + s->stack = (type *) vfy_alloc (max_stack * sizeof (type)); + for (i = 0; i < max_stack; ++i) + init_type_from_tag (&s->stack[i], unsuitable_type); + s->locals = (type *) vfy_alloc (max_locals * sizeof (type)); + for (i = 0; i < max_locals; ++i) + init_type_from_tag (&s->locals[i], unsuitable_type); + init_type_from_tag (&s->this_type, unsuitable_type); + s->pc = NO_NEXT; + s->next = INVALID_STATE; +} + +static void +copy_state (state *s, state *copy, int max_stack, int max_locals) +{ + int i; + s->stacktop = copy->stacktop; + s->stackdepth = copy->stackdepth; + for (i = 0; i < max_stack; ++i) + s->stack[i] = copy->stack[i]; + for (i = 0; i < max_locals; ++i) + s->locals[i] = copy->locals[i]; + + s->this_type = copy->this_type; + /* Don't modify `next' or `pc'. */ +} + +static void +copy_state_with_stack (state *s, state *orig, int max_stack, int max_locals) +{ + init_state_with_stack (s, max_stack, max_locals); + copy_state (s, orig, max_stack, max_locals); +} + +/* Allocate a new state, copying ORIG. */ +static state * +make_state_copy (state *orig, int max_stack, int max_locals) +{ + state *s = vfy_alloc (sizeof (state)); + copy_state_with_stack (s, orig, max_stack, max_locals); + return s; +} + +static state * +make_state (int max_stack, int max_locals) +{ + state *s = vfy_alloc (sizeof (state)); + init_state_with_stack (s, max_stack, max_locals); + return s; +} + +#if 0 +static void +free_state (state *s) +{ + if (s->stack != NULL) + vfy_free (s->stack); + if (s->locals != NULL) + vfy_free (s->locals); +} +#endif + +#if 0 + void *operator new[] (size_t bytes) + { + return vfy_alloc (bytes); + } + + void operator delete[] (void *mem) + { + vfy_free (mem); + } + + void *operator new (size_t bytes) + { + return vfy_alloc (bytes); + } + + void operator delete (void *mem) + { + vfy_free (mem); + } +#endif + +/* Modify this state to reflect entry to an exception handler. */ +static void +state_set_exception (state *s, type *t, int max_stack) +{ + int i; + s->stackdepth = 1; + s->stacktop = 1; + s->stack[0] = *t; + for (i = s->stacktop; i < max_stack; ++i) + init_type_from_tag (&s->stack[i], unsuitable_type); +} + +static int +state_get_pc (state *s) +{ + return s->pc; +} + +#if 0 +static void +set_pc (state *s, int npc) +{ + s->pc = npc; +} +#endif + +/* Merge STATE_OLD into this state. Destructively modifies this + state. Returns true if the new state was in fact changed. + Will throw an exception if the states are not mergeable. */ +static bool +merge_states (state *s, state *state_old, int max_locals) +{ + int i; + bool changed = false; + + /* Special handling for `this'. If one or the other is + uninitialized, then the merge is uninitialized. */ + if (type_initialized (&s->this_type)) + s->this_type = state_old->this_type; + + /* Merge stacks. */ + if (state_old->stacktop != s->stacktop) /* FIXME stackdepth instead? */ + verify_fail ("stack sizes differ"); + for (i = 0; i < state_old->stacktop; ++i) + { + if (merge_types (&s->stack[i], &state_old->stack[i], false)) + changed = true; + } + + /* Merge local variables. */ + for (i = 0; i < max_locals; ++i) + { + if (merge_types (&s->locals[i], &state_old->locals[i], true)) + changed = true; + } + + return changed; +} + +/* Ensure that `this' has been initialized. */ +static void +state_check_this_initialized (state *s) +{ + if (type_isreference (&s->this_type) && ! type_initialized (&s->this_type)) + verify_fail ("`this' is uninitialized"); +} + +/* Set type of `this'. */ +static void +state_set_this_type (state *s, type *k) +{ + s->this_type = *k; +} + +/* Mark each `new'd object we know of that was allocated at PC as + initialized. */ +static void +state_set_initialized (state *s, int pc, int max_locals) +{ + int i; + for (i = 0; i < s->stacktop; ++i) + type_set_initialized (&s->stack[i], pc); + for (i = 0; i < max_locals; ++i) + type_set_initialized (&s->locals[i], pc); + type_set_initialized (&s->this_type, pc); +} + +/* This tests to see whether two states can be considered "merge + compatible". If both states have a return-address in the same + slot, and the return addresses are different, then they are not + compatible and we must not try to merge them. */ +static bool +state_mergeable_p (state *s, state *other, int max_locals) + +{ + int i; + + /* This is tricky: if the stack sizes differ, then not only are + these not mergeable, but in fact we should give an error, as + we've found two execution paths that reach a branch target + with different stack depths. FIXME stackdepth instead? */ + if (s->stacktop != other->stacktop) + verify_fail ("stack sizes differ"); + + for (i = 0; i < s->stacktop; ++i) + if (! type_state_mergeable_p (&s->stack[i], &other->stack[i])) + return false; + for (i = 0; i < max_locals; ++i) + if (! type_state_mergeable_p (&s->locals[i], &other->locals[i])) + return false; + return true; +} + +static void +state_reverify (state *s) +{ + if (s->next == INVALID_STATE) + { + s->next = vfr->next_verify_state; + vfr->next_verify_state = s; + } +} + +#ifdef VERIFY_DEBUG +static void +debug_print_state (state *s, const char *leader, int pc, int max_stack, + int max_locals) +{ + int i; + debug_print ("%s [%4d]: [stack] ", leader, pc); + for (i = 0; i < s->stacktop; ++i) + type_print (&s->stack[i]); + for (; i < max_stack; ++i) + debug_print ("."); + debug_print (" [local] "); + for (i = 0; i < max_locals; ++i) + type_print (&s->locals[i]); + debug_print (" | %p\n", s); +} +#else +static void +debug_print_state (state *s ATTRIBUTE_UNUSED, + const char *leader ATTRIBUTE_UNUSED, + int pc ATTRIBUTE_UNUSED, int max_stack ATTRIBUTE_UNUSED, + int max_locals ATTRIBUTE_UNUSED) +{ +} +#endif /* VERIFY_DEBUG */ + +static type +pop_raw (void) +{ + type r; + state *s = vfr->current_state; + if (s->stacktop <= 0) + verify_fail ("stack empty"); + r = s->stack[--s->stacktop]; + s->stackdepth -= type_depth (&r); + if (s->stackdepth < 0) + verify_fail_pc ("stack empty", vfr->start_PC); + return r; +} + +static type +pop32 (void) +{ + type r = pop_raw (); + if (type_iswide (&r)) + verify_fail ("narrow pop of wide type"); + return r; +} + +static type +vfy_pop_type_t (type match) +{ + type t; + vfy_promote_type (&match); + t = pop_raw (); + if (! types_compatible (&match, &t)) + verify_fail ("incompatible type on stack"); + return t; +} + +static type +vfy_pop_type (type_val match) +{ + type t = make_type (match); + return vfy_pop_type_t (t); +} + +#define pop_type vfy_pop_type +#define pop_type_t vfy_pop_type_t + +/* Pop a reference which is guaranteed to be initialized. MATCH + doesn't have to be a reference type; in this case this acts like + pop_type. */ +static type +pop_init_ref_t (type match) +{ + type t = pop_raw (); + if (type_isreference (&t) && ! type_initialized (&t)) + verify_fail ("initialized reference required"); + else if (! types_compatible (&match, &t)) + verify_fail ("incompatible type on stack"); + return t; +} + +static type +pop_init_ref (type_val match) +{ + type t = make_type (match); + return pop_init_ref_t (t); +} + +/* Pop a reference type or a return address. */ +static type +pop_ref_or_return (void) +{ + type t = pop_raw (); + if (! type_isreference (&t) && t.key != return_address_type) + verify_fail ("expected reference or return address on stack"); + return t; +} + +static void +vfy_push_type_t (type t) +{ + int depth; + state *s = vfr->current_state; + /* If T is a numeric type like short, promote it to int. */ + promote_type (&t); + + depth = type_depth (&t); + + if (s->stackdepth + depth > vfr->current_method->max_stack) + verify_fail ("stack overflow"); + s->stack[s->stacktop++] = t; + s->stackdepth += depth; +} + +static void +vfy_push_type (type_val tval) +{ + type t = make_type (tval); + return vfy_push_type_t (t); +} + +#define push_type vfy_push_type +#define push_type_t vfy_push_type_t + +static void +set_variable (int index, type t) +{ + int depth; + state *s = vfr->current_state; + /* If T is a numeric type like short, promote it to int. */ + promote_type (&t); + + depth = type_depth (&t); + if (index > vfr->current_method->max_locals - depth) + verify_fail ("invalid local variable"); + s->locals[index] = t; + + if (depth == 2) + init_type_from_tag (&s->locals[index + 1], continuation_type); + if (index > 0 && type_iswide (&s->locals[index - 1])) + init_type_from_tag (&s->locals[index - 1], unsuitable_type); +} + +static type +get_variable_t (int index, type *t) +{ + state *s = vfr->current_state; + int depth = type_depth (t); + if (index > vfr->current_method->max_locals - depth) + verify_fail ("invalid local variable"); + if (! types_compatible (t, &s->locals[index])) + verify_fail ("incompatible type in local variable"); + if (depth == 2) + { + type cont = make_type (continuation_type); + if (! types_compatible (&s->locals[index + 1], &cont)) + verify_fail ("invalid local variable"); + } + return s->locals[index]; +} + +static type +get_variable (int index, type_val v) +{ + type t = make_type (v); + return get_variable_t (index, &t); +} + +/* Make sure ARRAY is an array type and that its elements are + compatible with type ELEMENT. Returns the actual element type. */ +static type +require_array_type_t (type array, type element) +{ + type t; + /* An odd case. Here we just pretend that everything went ok. If + the requested element type is some kind of reference, return + the null type instead. */ + if (type_isnull (&array)) + return type_isreference (&element) ? make_type (null_type) : element; + + if (! type_isarray (&array)) + verify_fail ("array required"); + + t = type_array_element (&array); + if (! types_compatible (&element, &t)) + { + /* Special case for byte arrays, which must also be boolean + arrays. */ + bool ok = true; + if (element.key == byte_type) + { + type e2 = make_type (boolean_type); + ok = types_compatible (&e2, &t); + } + if (! ok) + verify_fail ("incompatible array element type"); + } + + /* Return T and not ELEMENT, because T might be specialized. */ + return t; +} + +static type +require_array_type (type array, type_val element) +{ + type t = make_type (element); + return require_array_type_t (array, t); +} + +static jint +get_byte (void) +{ + if (vfr->PC >= vfr->current_method->code_length) + verify_fail ("premature end of bytecode"); + return (jint) vfr->bytecode[vfr->PC++] & 0xff; +} + +static jint +get_ushort (void) +{ + jint b1 = get_byte (); + jint b2 = get_byte (); + return (jint) ((b1 << 8) | b2) & 0xffff; +} + +static jint +get_short (void) +{ + jint b1 = get_byte (); + jint b2 = get_byte (); + jshort s = (b1 << 8) | b2; + return (jint) s; +} + +static jint +get_int (void) +{ + jint b1 = get_byte (); + jint b2 = get_byte (); + jint b3 = get_byte (); + jint b4 = get_byte (); + return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; +} + +static int +compute_jump (int offset) +{ + int npc = vfr->start_PC + offset; + if (npc < 0 || npc >= vfr->current_method->code_length) + verify_fail_pc ("branch out of range", vfr->start_PC); + return npc; +} + +/* Add a new state to the state list at NPC. */ +static state * +add_new_state (int npc, state *old_state) +{ + state_list *nlink; + vfy_method *current_method = vfr->current_method; + state *new_state = make_state_copy (old_state, current_method->max_stack, + current_method->max_locals); + debug_print ("== New state in add_new_state\n"); + debug_print_state (new_state, "New", npc, current_method->max_stack, + current_method->max_locals); + + nlink = vfy_alloc (sizeof (state_list)); + nlink->val = new_state; + nlink->next = vfr->states[npc]; + vfr->states[npc] = nlink; + new_state->pc = npc; + return new_state; +} + +/* Merge the indicated state into the state at the branch target and + schedule a new PC if there is a change. NPC is the PC of the + branch target, and FROM_STATE is the state at the source of the + branch. This method returns true if the destination state + changed and requires reverification, false otherwise. */ +static void +merge_into (int npc, state *from_state) +{ + /* Iterate over all target states and merge our state into each, + if applicable. FIXME one improvement we could make here is + "state destruction". Merging a new state into an existing one + might cause a return_address_type to be merged to + unsuitable_type. In this case the resulting state may now be + mergeable with other states currently held in parallel at this + location. So in this situation we could pairwise compare and + reduce the number of parallel states. */ + state_list *iter; + bool applicable = false; + for (iter = vfr->states[npc]; iter != NULL; iter = iter->next) + { + state *new_state = iter->val; + vfy_method *current_method = vfr->current_method; + + if (state_mergeable_p (new_state, from_state, + current_method->max_locals)) + { + bool changed; + applicable = true; + + debug_print ("== Merge states in merge_into\n"); + debug_print_state (from_state, "Frm", vfr->start_PC, current_method->max_stack, + current_method->max_locals); + debug_print_state (new_state, " To", npc, current_method->max_stack, + current_method->max_locals); + changed = merge_states (new_state, from_state, + current_method->max_locals); + debug_print_state (new_state, "New", npc, current_method->max_stack, + current_method->max_locals); + + if (changed) + state_reverify (new_state); + } + } + + if (! applicable) + { + /* Either we don't yet have a state at NPC, or we have a + return-address type that is in conflict with all existing + state. So, we need to create a new entry. */ + state *new_state = add_new_state (npc, from_state); + /* A new state added in this way must always be reverified. */ + state_reverify (new_state); + } +} + +static void +push_jump (int offset) +{ + int npc = compute_jump (offset); + /* According to the JVM Spec, we need to check for uninitialized + objects here. However, this does not actually affect type + safety, and the Eclipse java compiler generates code that + violates this constraint. */ + merge_into (npc, vfr->current_state); +} + +static void +push_exception_jump (type t, int pc) +{ + state s; + /* According to the JVM Spec, we need to check for uninitialized + objects here. However, this does not actually affect type + safety, and the Eclipse java compiler generates code that + violates this constraint. */ + copy_state_with_stack (&s, vfr->current_state, + vfr->current_method->max_stack, + vfr->current_method->max_locals); + if (vfr->current_method->max_stack < 1) + verify_fail ("stack overflow at exception handler"); + state_set_exception (&s, &t, vfr->current_method->max_stack); + merge_into (pc, &s); + /* FIXME: leak.. need free_state or GC */ +} + +static state * +pop_jump (void) +{ + state *new_state = vfr->next_verify_state; + if (new_state == INVALID_STATE) + verify_fail ("programmer error in pop_jump"); + if (new_state != NULL) + { + vfr->next_verify_state = new_state->next; + new_state->next = INVALID_STATE; + } + return new_state; +} + +static void +invalidate_pc (void) +{ + vfr->PC = NO_NEXT; +} + +static void +note_branch_target (int pc) +{ + /* Don't check `pc <= PC', because we've advanced PC after + fetching the target and we haven't yet checked the next + instruction. */ + if (pc < vfr->PC && ! (vfr->flags[pc] & FLAG_INSN_START)) + verify_fail_pc ("branch not to instruction start", vfr->start_PC); + vfr->flags[pc] |= FLAG_BRANCH_TARGET; +} + +static void +skip_padding (void) +{ + while ((vfr->PC % 4) > 0) + if (get_byte () != 0) + verify_fail ("found nonzero padding byte"); +} + +/* Do the work for a `ret' instruction. INDEX is the index into the + local variables. */ +static void +handle_ret_insn (int index) +{ + type ret = make_type (return_address_type); + type ret_addr = get_variable_t (index, &ret); + /* It would be nice if we could do this. However, the JVM Spec + doesn't say that this is what happens. It is implied that + reusing a return address is invalid, but there's no actual + prohibition against it. */ + /* set_variable (index, unsuitable_type); */ + + int npc = type_get_pc (&ret_addr); + /* We might be returning to a `jsr' that is at the end of the + bytecode. This is ok if we never return from the called + subroutine, but if we see this here it is an error. */ + if (npc >= vfr->current_method->code_length) + verify_fail ("fell off end"); + + /* According to the JVM Spec, we need to check for uninitialized + objects here. However, this does not actually affect type + safety, and the Eclipse java compiler generates code that + violates this constraint. */ + merge_into (npc, vfr->current_state); + invalidate_pc (); +} + +static void handle_jsr_insn (int offset) +{ + type ret_addr; + int npc = compute_jump (offset); + + /* According to the JVM Spec, we need to check for uninitialized + objects here. However, this does not actually affect type + safety, and the Eclipse java compiler generates code that + violates this constraint. */ + + /* Modify our state as appropriate for entry into a subroutine. */ + ret_addr = make_type (return_address_type); + type_set_return_address (&ret_addr, vfr->PC); + vfy_push_type_t (ret_addr); + merge_into (npc, vfr->current_state); + invalidate_pc (); +} + +static vfy_jclass +construct_primitive_array_type (type_val prim) +{ + vfy_jclass k = NULL; + switch (prim) + { + case boolean_type: + case char_type: + case float_type: + case double_type: + case byte_type: + case short_type: + case int_type: + case long_type: + k = vfy_get_primitive_type ((int) prim); + break; + + /* These aren't used here but we call them out to avoid + warnings. */ + case void_type: + case unsuitable_type: + case return_address_type: + case continuation_type: + case reference_type: + case null_type: + case uninitialized_reference_type: + default: + verify_fail ("unknown type in construct_primitive_array_type"); + } + k = vfy_get_array_class (k); + return k; +} + +/* This pass computes the location of branch targets and also + instruction starts. */ +static void +branch_prepass (void) +{ + int i, pc; + vfr->flags = (char *) vfy_alloc (vfr->current_method->code_length); + + for (i = 0; i < vfr->current_method->code_length; ++i) + vfr->flags[i] = 0; + + vfr->PC = 0; + while (vfr->PC < vfr->current_method->code_length) + { + java_opcode opcode; + /* Set `start_PC' early so that error checking can have the + correct value. */ + vfr->start_PC = vfr->PC; + vfr->flags[vfr->PC] |= FLAG_INSN_START; + + opcode = (java_opcode) vfr->bytecode[vfr->PC++]; + switch (opcode) + { + case op_nop: + case op_aconst_null: + case op_iconst_m1: + case op_iconst_0: + case op_iconst_1: + case op_iconst_2: + case op_iconst_3: + case op_iconst_4: + case op_iconst_5: + case op_lconst_0: + case op_lconst_1: + case op_fconst_0: + case op_fconst_1: + case op_fconst_2: + case op_dconst_0: + case op_dconst_1: + case op_iload_0: + case op_iload_1: + case op_iload_2: + case op_iload_3: + case op_lload_0: + case op_lload_1: + case op_lload_2: + case op_lload_3: + case op_fload_0: + case op_fload_1: + case op_fload_2: + case op_fload_3: + case op_dload_0: + case op_dload_1: + case op_dload_2: + case op_dload_3: + case op_aload_0: + case op_aload_1: + case op_aload_2: + case op_aload_3: + case op_iaload: + case op_laload: + case op_faload: + case op_daload: + case op_aaload: + case op_baload: + case op_caload: + case op_saload: + case op_istore_0: + case op_istore_1: + case op_istore_2: + case op_istore_3: + case op_lstore_0: + case op_lstore_1: + case op_lstore_2: + case op_lstore_3: + case op_fstore_0: + case op_fstore_1: + case op_fstore_2: + case op_fstore_3: + case op_dstore_0: + case op_dstore_1: + case op_dstore_2: + case op_dstore_3: + case op_astore_0: + case op_astore_1: + case op_astore_2: + case op_astore_3: + case op_iastore: + case op_lastore: + case op_fastore: + case op_dastore: + case op_aastore: + case op_bastore: + case op_castore: + case op_sastore: + case op_pop: + case op_pop2: + case op_dup: + case op_dup_x1: + case op_dup_x2: + case op_dup2: + case op_dup2_x1: + case op_dup2_x2: + case op_swap: + case op_iadd: + case op_isub: + case op_imul: + case op_idiv: + case op_irem: + case op_ishl: + case op_ishr: + case op_iushr: + case op_iand: + case op_ior: + case op_ixor: + case op_ladd: + case op_lsub: + case op_lmul: + case op_ldiv: + case op_lrem: + case op_lshl: + case op_lshr: + case op_lushr: + case op_land: + case op_lor: + case op_lxor: + case op_fadd: + case op_fsub: + case op_fmul: + case op_fdiv: + case op_frem: + case op_dadd: + case op_dsub: + case op_dmul: + case op_ddiv: + case op_drem: + case op_ineg: + case op_i2b: + case op_i2c: + case op_i2s: + case op_lneg: + case op_fneg: + case op_dneg: + case op_i2l: + case op_i2f: + case op_i2d: + case op_l2i: + case op_l2f: + case op_l2d: + case op_f2i: + case op_f2l: + case op_f2d: + case op_d2i: + case op_d2l: + case op_d2f: + case op_lcmp: + case op_fcmpl: + case op_fcmpg: + case op_dcmpl: + case op_dcmpg: + case op_monitorenter: + case op_monitorexit: + case op_ireturn: + case op_lreturn: + case op_freturn: + case op_dreturn: + case op_areturn: + case op_return: + case op_athrow: + case op_arraylength: + break; + + case op_bipush: + case op_ldc: + case op_iload: + case op_lload: + case op_fload: + case op_dload: + case op_aload: + case op_istore: + case op_lstore: + case op_fstore: + case op_dstore: + case op_astore: + case op_ret: + case op_newarray: + get_byte (); + break; + + case op_iinc: + case op_sipush: + case op_ldc_w: + case op_ldc2_w: + case op_getstatic: + case op_getfield: + case op_putfield: + case op_putstatic: + case op_new: + case op_anewarray: + case op_instanceof: + case op_checkcast: + case op_invokespecial: + case op_invokestatic: + case op_invokevirtual: + get_short (); + break; + + case op_multianewarray: + get_short (); + get_byte (); + break; + + case op_jsr: + case op_ifeq: + case op_ifne: + case op_iflt: + case op_ifge: + case op_ifgt: + case op_ifle: + case op_if_icmpeq: + case op_if_icmpne: + case op_if_icmplt: + case op_if_icmpge: + case op_if_icmpgt: + case op_if_icmple: + case op_if_acmpeq: + case op_if_acmpne: + case op_ifnull: + case op_ifnonnull: + case op_goto: + note_branch_target (compute_jump (get_short ())); + break; + + case op_tableswitch: + { + jint low, hi; + skip_padding (); + note_branch_target (compute_jump (get_int ())); + low = get_int (); + hi = get_int (); + if (low > hi) + verify_fail_pc ("invalid tableswitch", vfr->start_PC); + for (i = low; i <= hi; ++i) + note_branch_target (compute_jump (get_int ())); + } + break; + + case op_lookupswitch: + { + int npairs; + skip_padding (); + note_branch_target (compute_jump (get_int ())); + npairs = get_int (); + if (npairs < 0) + verify_fail_pc ("too few pairs in lookupswitch", vfr->start_PC); + while (npairs-- > 0) + { + get_int (); + note_branch_target (compute_jump (get_int ())); + } + } + break; + + case op_invokeinterface: + get_short (); + get_byte (); + get_byte (); + break; + + case op_wide: + { + opcode = (java_opcode) get_byte (); + get_short (); + if (opcode == op_iinc) + get_short (); + } + break; + + case op_jsr_w: + case op_goto_w: + note_branch_target (compute_jump (get_int ())); + break; + +#if 0 + /* These are unused here, but we call them out explicitly + so that -Wswitch-enum doesn't complain. */ + case op_putfield_1: + case op_putfield_2: + case op_putfield_4: + case op_putfield_8: + case op_putfield_a: + case op_putstatic_1: + case op_putstatic_2: + case op_putstatic_4: + case op_putstatic_8: + case op_putstatic_a: + case op_getfield_1: + case op_getfield_2s: + case op_getfield_2u: + case op_getfield_4: + case op_getfield_8: + case op_getfield_a: + case op_getstatic_1: + case op_getstatic_2s: + case op_getstatic_2u: + case op_getstatic_4: + case op_getstatic_8: + case op_getstatic_a: +#endif /* VFY_FAST_OPCODES */ + default: + verify_fail_pc ("unrecognized instruction in branch_prepass", + vfr->start_PC); + } + + /* See if any previous branch tried to branch to the middle of + this instruction. */ + for (pc = vfr->start_PC + 1; pc < vfr->PC; ++pc) + { + if ((vfr->flags[pc] & FLAG_BRANCH_TARGET)) + verify_fail_pc ("branch to middle of instruction", pc); + } + } + + /* Verify exception handlers. */ + for (i = 0; i < vfr->current_method->exc_count; ++i) + { + int handler, start, end, htype; + vfy_get_exception (vfr->exception, i, &handler, &start, &end, &htype); + if (! (vfr->flags[handler] & FLAG_INSN_START)) + verify_fail_pc ("exception handler not at instruction start", + handler); + if (! (vfr->flags[start] & FLAG_INSN_START)) + verify_fail_pc ("exception start not at instruction start", start); + if (end != vfr->current_method->code_length + && ! (vfr->flags[end] & FLAG_INSN_START)) + verify_fail_pc ("exception end not at instruction start", end); + + vfr->flags[handler] |= FLAG_BRANCH_TARGET; + } +} + +static void +check_pool_index (int index) +{ + if (index < 0 || index >= vfy_get_constants_size (vfr->current_class)) + verify_fail_pc ("constant pool index out of range", vfr->start_PC); +} + +static type +check_class_constant (int index) +{ + type t; + vfy_constants *pool; + + check_pool_index (index); + pool = vfy_get_constants (vfr->current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedClass) + init_type_from_class (&t, vfy_get_pool_class (pool, index)); + else if (vfy_tag (pool, index) == JV_CONSTANT_Class) + init_type_from_string (&t, vfy_get_pool_string (pool, index)); + else + verify_fail_pc ("expected class constant", vfr->start_PC); + return t; +} + +static type +check_constant (int index) +{ + type t; + vfy_constants *pool; + + check_pool_index (index); + pool = vfy_get_constants (vfr->current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_ResolvedString + || vfy_tag (pool, index) == JV_CONSTANT_String) + init_type_from_class (&t, vfy_string_type ()); + else if (vfy_tag (pool, index) == JV_CONSTANT_Integer) + init_type_from_tag (&t, int_type); + else if (vfy_tag (pool, index) == JV_CONSTANT_Float) + init_type_from_tag (&t, float_type); + else + verify_fail_pc ("String, int, or float constant expected", vfr->start_PC); + return t; +} + +static type +check_wide_constant (int index) +{ + type t; + vfy_constants *pool; + + check_pool_index (index); + pool = vfy_get_constants (vfr->current_class); + if (vfy_tag (pool, index) == JV_CONSTANT_Long) + init_type_from_tag (&t, long_type); + else if (vfy_tag (pool, index) == JV_CONSTANT_Double) + init_type_from_tag (&t, double_type); + else + verify_fail_pc ("long or double constant expected", vfr->start_PC); + return t; +} + +/* Helper for both field and method. These are laid out the same in + the constant pool. */ +static type +handle_field_or_method (int index, int expected, + vfy_string *name, vfy_string *fmtype) +{ + vfy_uint_16 class_index, name_and_type_index; + vfy_uint_16 name_index, desc_index; + vfy_constants *pool; + + check_pool_index (index); + pool = vfy_get_constants (vfr->current_class); + if (vfy_tag (pool, index) != expected) + verify_fail_pc ("didn't see expected constant", vfr->start_PC); + /* Once we know we have a Fieldref or Methodref we assume that it + is correctly laid out in the constant pool. I think the code + in defineclass.cc guarantees this. */ + vfy_load_indexes (pool, index, &class_index, &name_and_type_index); + vfy_load_indexes (pool, name_and_type_index, &name_index, &desc_index); + + *name = vfy_get_pool_string (pool, name_index); + *fmtype = vfy_get_pool_string (pool, desc_index); + + return check_class_constant (class_index); +} + +/* Return field's type, compute class' type if requested. */ +static type +check_field_constant (int index, type *class_type) +{ + vfy_string name, field_type; + const char *typec; + int len; + type t; + + type ct = handle_field_or_method (index, + JV_CONSTANT_Fieldref, + &name, &field_type); + if (class_type) + *class_type = ct; + typec = vfy_string_bytes (field_type); + len = vfy_string_length (field_type); + if (typec[0] == '[' || typec[0] == 'L') + init_type_from_string (&t, field_type); + else + init_type_from_tag (&t, get_type_val_for_signature (typec[0])); + return t; +} + +static type +check_method_constant (int index, bool is_interface, + vfy_string *method_name, + vfy_string *method_signature) +{ + return handle_field_or_method (index, + (is_interface + ? JV_CONSTANT_InterfaceMethodref + : JV_CONSTANT_Methodref), + method_name, method_signature); +} + +static char * +get_one_type (char *p, type *t) +{ + const char *start = p; + vfy_jclass k; + type_val rt; + char v; + + int arraycount = 0; + while (*p == '[') + { + ++arraycount; + ++p; + } + + v = *p++; + + if (v == 'L') + { + vfy_string name; + while (*p != ';') + ++p; + ++p; + name = vfy_get_string (start, p - start); + *t = make_type_from_string (name); + return p; + } + + /* Casting to jchar here is ok since we are looking at an ASCII + character. */ + rt = get_type_val_for_signature (v); + + if (arraycount == 0) + { + /* Callers of this function eventually push their arguments on + the stack. So, promote them here. */ + type new_t = make_type (rt); + vfy_promote_type (&new_t); + *t = new_t; + return p; + } + + k = construct_primitive_array_type (rt); + while (--arraycount > 0) + k = vfy_get_array_class (k); + *t = make_type_from_class (k); + return p; +} + +static void +compute_argument_types (vfy_string signature, type *types) +{ + int i; + char *p = (char *) vfy_string_bytes (signature); + + /* Skip `('. */ + ++p; + + i = 0; + while (*p != ')') + p = get_one_type (p, &types[i++]); +} + +static type +compute_return_type (vfy_string signature) +{ + char *p = (char *) vfy_string_bytes (signature); + type t; + while (*p != ')') + ++p; + ++p; + get_one_type (p, &t); + return t; +} + +static void +check_return_type (type onstack) +{ + type rt = compute_return_type (vfy_get_signature (vfr->current_method)); + if (! types_compatible (&rt, &onstack)) + verify_fail ("incompatible return type"); +} + +/* Initialize the stack for the new method. Returns true if this + method is an instance initializer. */ +static bool +initialize_stack (void) +{ + int arg_count, i; + int var = 0; + bool is_init = vfy_strings_equal (vfy_get_method_name (vfr->current_method), + vfy_init_name()); + bool is_clinit = vfy_strings_equal (vfy_get_method_name (vfr->current_method), + vfy_clinit_name()); + + if (! vfy_is_static (vfr->current_method)) + { + type kurr = make_type_from_class (vfr->current_class); + if (is_init) + { + type_set_uninitialized (&kurr, SELF); + is_init = true; + } + else if (is_clinit) + verify_fail ("<clinit> method must be static"); + set_variable (0, kurr); + state_set_this_type (vfr->current_state, &kurr); + ++var; + } + else + { + if (is_init) + verify_fail ("<init> method must be non-static"); + } + + /* We have to handle wide arguments specially here. */ + arg_count = vfy_count_arguments (vfy_get_signature (vfr->current_method)); + { + type arg_types[arg_count]; + compute_argument_types (vfy_get_signature (vfr->current_method), arg_types); + for (i = 0; i < arg_count; ++i) + { + set_variable (var, arg_types[i]); + ++var; + if (type_iswide (&arg_types[i])) + ++var; + } + } + + return is_init; +} + +static void +verify_instructions_0 (void) +{ + int i; + bool this_is_init; + + vfr->current_state = make_state (vfr->current_method->max_stack, + vfr->current_method->max_locals); + + vfr->PC = 0; + vfr->start_PC = 0; + + /* True if we are verifying an instance initializer. */ + this_is_init = initialize_stack (); + + vfr->states = (state_list **) vfy_alloc (sizeof (state_list *) + * vfr->current_method->code_length); + + for (i = 0; i < vfr->current_method->code_length; ++i) + vfr->states[i] = NULL; + + vfr->next_verify_state = NULL; + + while (true) + { + java_opcode opcode; + + /* If the PC was invalidated, get a new one from the work list. */ + if (vfr->PC == NO_NEXT) + { + state *new_state = pop_jump (); + /* If it is null, we're done. */ + if (new_state == NULL) + break; + + vfr->PC = state_get_pc (new_state); + debug_print ("== State pop from pending list\n"); + /* Set up the current state. */ + copy_state (vfr->current_state, new_state, + vfr->current_method->max_stack, vfr->current_method->max_locals); + } + else + { + /* We only have to do this checking in the situation where + control flow falls through from the previous + instruction. Otherwise merging is done at the time we + push the branch. */ + if (vfr->states[vfr->PC] != NULL) + { + /* We've already visited this instruction. So merge + the states together. It is simplest, but not most + efficient, to just always invalidate the PC here. */ + merge_into (vfr->PC, vfr->current_state); + invalidate_pc (); + continue; + } + } + + /* Control can't fall off the end of the bytecode. We need to + check this in both cases, not just the fall-through case, + because we don't check to see whether a `jsr' appears at + the end of the bytecode until we process a `ret'. */ + if (vfr->PC >= vfr->current_method->code_length) + verify_fail ("fell off end"); + vfr->flags[vfr->PC] |= FLAG_INSN_SEEN; + + /* We only have to keep saved state at branch targets. If + we're at a branch target and the state here hasn't been set + yet, we set it now. You might notice that `ret' targets + won't necessarily have FLAG_BRANCH_TARGET set. This + doesn't matter, since those states will be filled in by + merge_into. */ + /* Note that other parts of the compiler assume that there is a + label with a type map at PC=0. */ + if (vfr->states[vfr->PC] == NULL + && (vfr->PC == 0 || (vfr->flags[vfr->PC] & FLAG_BRANCH_TARGET) != 0)) + add_new_state (vfr->PC, vfr->current_state); + + /* Set this before handling exceptions so that debug output is + sane. */ + vfr->start_PC = vfr->PC; + + /* Update states for all active exception handlers. Ordinarily + there are not many exception handlers. So we simply run + through them all. */ + for (i = 0; i < vfr->current_method->exc_count; ++i) + { + int hpc, start, end, htype; + vfy_get_exception (vfr->exception, i, &hpc, &start, &end, &htype); + if (vfr->PC >= start && vfr->PC < end) + { + type handler = make_type_from_class (vfy_throwable_type ()); + if (htype != 0) + handler = check_class_constant (htype); + push_exception_jump (handler, hpc); + } + } + + + debug_print_state (vfr->current_state, " ", vfr->PC, + vfr->current_method->max_stack, + vfr->current_method->max_locals); + opcode = (java_opcode) vfr->bytecode[vfr->PC++]; + switch (opcode) + { + case op_nop: + break; + + case op_aconst_null: + push_type (null_type); + break; + + case op_iconst_m1: + case op_iconst_0: + case op_iconst_1: + case op_iconst_2: + case op_iconst_3: + case op_iconst_4: + case op_iconst_5: + push_type (int_type); + break; + + case op_lconst_0: + case op_lconst_1: + push_type (long_type); + break; + + case op_fconst_0: + case op_fconst_1: + case op_fconst_2: + push_type (float_type); + break; + + case op_dconst_0: + case op_dconst_1: + push_type (double_type); + break; + + case op_bipush: + get_byte (); + push_type (int_type); + break; + + case op_sipush: + get_short (); + push_type (int_type); + break; + + case op_ldc: + push_type_t (check_constant (get_byte ())); + break; + case op_ldc_w: + push_type_t (check_constant (get_ushort ())); + break; + case op_ldc2_w: + push_type_t (check_wide_constant (get_ushort ())); + break; + + case op_iload: + push_type_t (get_variable (get_byte (), int_type)); + break; + case op_lload: + push_type_t (get_variable (get_byte (), long_type)); + break; + case op_fload: + push_type_t (get_variable (get_byte (), float_type)); + break; + case op_dload: + push_type_t (get_variable (get_byte (), double_type)); + break; + case op_aload: + push_type_t (get_variable (get_byte (), reference_type)); + break; + + case op_iload_0: + case op_iload_1: + case op_iload_2: + case op_iload_3: + push_type_t (get_variable (opcode - op_iload_0, int_type)); + break; + case op_lload_0: + case op_lload_1: + case op_lload_2: + case op_lload_3: + push_type_t (get_variable (opcode - op_lload_0, long_type)); + break; + case op_fload_0: + case op_fload_1: + case op_fload_2: + case op_fload_3: + push_type_t (get_variable (opcode - op_fload_0, float_type)); + break; + case op_dload_0: + case op_dload_1: + case op_dload_2: + case op_dload_3: + push_type_t (get_variable (opcode - op_dload_0, double_type)); + break; + case op_aload_0: + case op_aload_1: + case op_aload_2: + case op_aload_3: + push_type_t (get_variable (opcode - op_aload_0, reference_type)); + break; + case op_iaload: + pop_type (int_type); + push_type_t (require_array_type (pop_init_ref (reference_type), + int_type)); + break; + case op_laload: + pop_type (int_type); + push_type_t (require_array_type (pop_init_ref (reference_type), + long_type)); + break; + case op_faload: + pop_type (int_type); + push_type_t (require_array_type (pop_init_ref (reference_type), + float_type)); + break; + case op_daload: + pop_type (int_type); + push_type_t (require_array_type (pop_init_ref (reference_type), + double_type)); + break; + case op_aaload: + pop_type (int_type); + push_type_t (require_array_type (pop_init_ref (reference_type), + reference_type)); + break; + case op_baload: + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), byte_type); + push_type (int_type); + break; + case op_caload: + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), char_type); + push_type (int_type); + break; + case op_saload: + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), short_type); + push_type (int_type); + break; + case op_istore: + set_variable (get_byte (), pop_type (int_type)); + break; + case op_lstore: + set_variable (get_byte (), pop_type (long_type)); + break; + case op_fstore: + set_variable (get_byte (), pop_type (float_type)); + break; + case op_dstore: + set_variable (get_byte (), pop_type (double_type)); + break; + case op_astore: + set_variable (get_byte (), pop_ref_or_return ()); + break; + case op_istore_0: + case op_istore_1: + case op_istore_2: + case op_istore_3: + set_variable (opcode - op_istore_0, pop_type (int_type)); + break; + case op_lstore_0: + case op_lstore_1: + case op_lstore_2: + case op_lstore_3: + set_variable (opcode - op_lstore_0, pop_type (long_type)); + break; + case op_fstore_0: + case op_fstore_1: + case op_fstore_2: + case op_fstore_3: + set_variable (opcode - op_fstore_0, pop_type (float_type)); + break; + case op_dstore_0: + case op_dstore_1: + case op_dstore_2: + case op_dstore_3: + set_variable (opcode - op_dstore_0, pop_type (double_type)); + break; + case op_astore_0: + case op_astore_1: + case op_astore_2: + case op_astore_3: + set_variable (opcode - op_astore_0, pop_ref_or_return ()); + break; + case op_iastore: + pop_type (int_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), int_type); + break; + case op_lastore: + pop_type (long_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), long_type); + break; + case op_fastore: + pop_type (float_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), float_type); + break; + case op_dastore: + pop_type (double_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), double_type); + break; + case op_aastore: + pop_type (reference_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), reference_type); + break; + case op_bastore: + pop_type (int_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), byte_type); + break; + case op_castore: + pop_type (int_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), char_type); + break; + case op_sastore: + pop_type (int_type); + pop_type (int_type); + require_array_type (pop_init_ref (reference_type), short_type); + break; + case op_pop: + pop32 (); + break; + case op_pop2: + { + type t = pop_raw (); + if (! type_iswide (&t)) + pop32 (); + } + break; + case op_dup: + { + type t = pop32 (); + push_type_t (t); + push_type_t (t); + } + break; + case op_dup_x1: + { + type t1 = pop32 (); + type t2 = pop32 (); + push_type_t (t1); + push_type_t (t2); + push_type_t (t1); + } + break; + case op_dup_x2: + { + type t1 = pop32 (); + type t2 = pop_raw (); + if (! type_iswide (&t2)) + { + type t3 = pop32 (); + push_type_t (t1); + push_type_t (t3); + } + else + push_type_t (t1); + push_type_t (t2); + push_type_t (t1); + } + break; + case op_dup2: + { + type t = pop_raw (); + if (! type_iswide (&t)) + { + type t2 = pop32 (); + push_type_t (t2); + push_type_t (t); + push_type_t (t2); + } + else + push_type_t (t); + push_type_t (t); + } + break; + case op_dup2_x1: + { + type t1 = pop_raw (); + type t2 = pop32 (); + if (! type_iswide (&t1)) + { + type t3 = pop32 (); + push_type_t (t2); + push_type_t (t1); + push_type_t (t3); + } + else + push_type_t (t1); + push_type_t (t2); + push_type_t (t1); + } + break; + case op_dup2_x2: + { + type t1 = pop_raw (); + if (type_iswide (&t1)) + { + type t2 = pop_raw (); + if (type_iswide (&t2)) + { + push_type_t (t1); + push_type_t (t2); + } + else + { + type t3 = pop32 (); + push_type_t (t1); + push_type_t (t3); + push_type_t (t2); + } + push_type_t (t1); + } + else + { + type t2 = pop32 (); + type t3 = pop_raw (); + if (type_iswide (&t3)) + { + push_type_t (t2); + push_type_t (t1); + } + else + { + type t4 = pop32 (); + push_type_t (t2); + push_type_t (t1); + push_type_t (t4); + } + push_type_t (t3); + push_type_t (t2); + push_type_t (t1); + } + } + break; + case op_swap: + { + type t1 = pop32 (); + type t2 = pop32 (); + push_type_t (t1); + push_type_t (t2); + } + break; + case op_iadd: + case op_isub: + case op_imul: + case op_idiv: + case op_irem: + case op_ishl: + case op_ishr: + case op_iushr: + case op_iand: + case op_ior: + case op_ixor: + pop_type (int_type); + push_type_t (pop_type (int_type)); + break; + case op_ladd: + case op_lsub: + case op_lmul: + case op_ldiv: + case op_lrem: + case op_land: + case op_lor: + case op_lxor: + pop_type (long_type); + push_type_t (pop_type (long_type)); + break; + case op_lshl: + case op_lshr: + case op_lushr: + pop_type (int_type); + push_type_t (pop_type (long_type)); + break; + case op_fadd: + case op_fsub: + case op_fmul: + case op_fdiv: + case op_frem: + pop_type (float_type); + push_type_t (pop_type (float_type)); + break; + case op_dadd: + case op_dsub: + case op_dmul: + case op_ddiv: + case op_drem: + pop_type (double_type); + push_type_t (pop_type (double_type)); + break; + case op_ineg: + case op_i2b: + case op_i2c: + case op_i2s: + push_type_t (pop_type (int_type)); + break; + case op_lneg: + push_type_t (pop_type (long_type)); + break; + case op_fneg: + push_type_t (pop_type (float_type)); + break; + case op_dneg: + push_type_t (pop_type (double_type)); + break; + case op_iinc: + get_variable (get_byte (), int_type); + get_byte (); + break; + case op_i2l: + pop_type (int_type); + push_type (long_type); + break; + case op_i2f: + pop_type (int_type); + push_type (float_type); + break; + case op_i2d: + pop_type (int_type); + push_type (double_type); + break; + case op_l2i: + pop_type (long_type); + push_type (int_type); + break; + case op_l2f: + pop_type (long_type); + push_type (float_type); + break; + case op_l2d: + pop_type (long_type); + push_type (double_type); + break; + case op_f2i: + pop_type (float_type); + push_type (int_type); + break; + case op_f2l: + pop_type (float_type); + push_type (long_type); + break; + case op_f2d: + pop_type (float_type); + push_type (double_type); + break; + case op_d2i: + pop_type (double_type); + push_type (int_type); + break; + case op_d2l: + pop_type (double_type); + push_type (long_type); + break; + case op_d2f: + pop_type (double_type); + push_type (float_type); + break; + case op_lcmp: + pop_type (long_type); + pop_type (long_type); + push_type (int_type); + break; + case op_fcmpl: + case op_fcmpg: + pop_type (float_type); + pop_type (float_type); + push_type (int_type); + break; + case op_dcmpl: + case op_dcmpg: + pop_type (double_type); + pop_type (double_type); + push_type (int_type); + break; + case op_ifeq: + case op_ifne: + case op_iflt: + case op_ifge: + case op_ifgt: + case op_ifle: + pop_type (int_type); + push_jump (get_short ()); + break; + case op_if_icmpeq: + case op_if_icmpne: + case op_if_icmplt: + case op_if_icmpge: + case op_if_icmpgt: + case op_if_icmple: + pop_type (int_type); + pop_type (int_type); + push_jump (get_short ()); + break; + case op_if_acmpeq: + case op_if_acmpne: + pop_type (reference_type); + pop_type (reference_type); + push_jump (get_short ()); + break; + case op_goto: + push_jump (get_short ()); + invalidate_pc (); + break; + case op_jsr: + handle_jsr_insn (get_short ()); + break; + case op_ret: + handle_ret_insn (get_byte ()); + break; + case op_tableswitch: + { + int i; + jint low, high; + pop_type (int_type); + skip_padding (); + push_jump (get_int ()); + low = get_int (); + high = get_int (); + /* Already checked LOW -vs- HIGH. */ + for (i = low; i <= high; ++i) + push_jump (get_int ()); + invalidate_pc (); + } + break; + + case op_lookupswitch: + { + int i; + jint npairs, lastkey; + + pop_type (int_type); + skip_padding (); + push_jump (get_int ()); + npairs = get_int (); + /* Already checked NPAIRS >= 0. */ + lastkey = 0; + for (i = 0; i < npairs; ++i) + { + jint key = get_int (); + if (i > 0 && key <= lastkey) + verify_fail_pc ("lookupswitch pairs unsorted", vfr->start_PC); + lastkey = key; + push_jump (get_int ()); + } + invalidate_pc (); + } + break; + case op_ireturn: + check_return_type (pop_type (int_type)); + invalidate_pc (); + break; + case op_lreturn: + check_return_type (pop_type (long_type)); + invalidate_pc (); + break; + case op_freturn: + check_return_type (pop_type (float_type)); + invalidate_pc (); + break; + case op_dreturn: + check_return_type (pop_type (double_type)); + invalidate_pc (); + break; + case op_areturn: + check_return_type (pop_init_ref (reference_type)); + invalidate_pc (); + break; + case op_return: + /* We only need to check this when the return type is + void, because all instance initializers return void. */ + if (this_is_init) + state_check_this_initialized (vfr->current_state); + check_return_type (make_type (void_type)); + invalidate_pc (); + break; + case op_getstatic: + push_type_t (check_field_constant (get_ushort (), NULL)); + break; + case op_putstatic: + pop_type_t (check_field_constant (get_ushort (), NULL)); + break; + case op_getfield: + { + type klass; + type field = check_field_constant (get_ushort (), &klass); + pop_type_t (klass); + push_type_t (field); + } + break; + case op_putfield: + { + type klass; + type field = check_field_constant (get_ushort (), &klass); + pop_type_t (field); + + /* We have an obscure special case here: we can use + `putfield' on a field declared in this class, even if + `this' has not yet been initialized. */ + if (! type_initialized (&vfr->current_state->this_type) + && vfr->current_state->this_type.pc == SELF) + type_set_uninitialized (&klass, SELF); + pop_type_t (klass); + } + break; + + case op_invokevirtual: + case op_invokespecial: + case op_invokestatic: + case op_invokeinterface: + { + vfy_string method_name, method_signature; + const char *namec; + int i, arg_count; + type rt; + bool is_init = false; + + type class_type + = check_method_constant (get_ushort (), + opcode == op_invokeinterface, + &method_name, + &method_signature); + /* NARGS is only used when we're processing + invokeinterface. It is simplest for us to compute it + here and then verify it later. */ + int nargs = 0; + if (opcode == op_invokeinterface) + { + nargs = get_byte (); + if (get_byte () != 0) + verify_fail ("invokeinterface dummy byte is wrong"); + } + + namec = vfy_string_bytes (method_name); + + if (vfy_strings_equal (method_name, vfy_init_name())) + { + is_init = true; + if (opcode != op_invokespecial) + verify_fail ("can't invoke <init>"); + } + else if (namec[0] == '<') + verify_fail ("can't invoke method starting with `<'"); + + arg_count = vfy_count_arguments (method_signature); + { + /* Pop arguments and check types. */ + type arg_types[arg_count]; + + compute_argument_types (method_signature, arg_types); + for (i = arg_count - 1; i >= 0; --i) + { + /* This is only used for verifying the byte for + invokeinterface. */ + nargs -= type_depth (&arg_types[i]); + pop_init_ref_t (arg_types[i]); + } + } + + if (opcode == op_invokeinterface + && nargs != 1) + verify_fail ("wrong argument count for invokeinterface"); + + if (opcode != op_invokestatic) + { + type raw; + type t = class_type; + if (is_init) + { + /* In this case the PC doesn't matter. */ + type_set_uninitialized (&t, UNINIT); + /* FIXME: check to make sure that the <init> + call is to the right class. + It must either be super or an exact class + match. */ + } + raw = pop_raw (); + if (! types_compatible (&t, &raw)) + verify_fail ("incompatible type on stack"); + + if (is_init) + state_set_initialized (vfr->current_state, + type_get_pc (&raw), vfr->current_method->max_locals); + } + + rt = compute_return_type (method_signature); + if (! type_isvoid (&rt)) + push_type_t (rt); + } + break; + + case op_new: + { + type t = check_class_constant (get_ushort ()); + if (type_isarray (&t) || type_isinterface (&t) + || type_isabstract (&t)) + verify_fail ("type is array, interface, or abstract"); + type_set_uninitialized (&t, vfr->start_PC); + push_type_t (t); + } + break; + + case op_newarray: + { + int atype = get_byte (); + type t; + /* We intentionally have chosen constants to make this + valid. */ + if (atype < boolean_type || atype > long_type) + verify_fail_pc ("type not primitive", vfr->start_PC); + pop_type (int_type); + init_type_from_class (&t, construct_primitive_array_type (atype)); + push_type_t (t); + } + break; + case op_anewarray: + { + type t; + pop_type (int_type); + t = check_class_constant (get_ushort ()); + push_type_t (type_to_array (&t)); + } + break; + case op_arraylength: + { + type t = pop_init_ref (reference_type); + if (! type_isarray (&t) && ! type_isnull (&t)) + verify_fail ("array type expected"); + push_type (int_type); + } + break; + case op_athrow: + pop_type_t (make_type_from_class (vfy_throwable_type ())); + invalidate_pc (); + break; + case op_checkcast: + pop_init_ref (reference_type); + push_type_t (check_class_constant (get_ushort ())); + break; + case op_instanceof: + pop_init_ref (reference_type); + check_class_constant (get_ushort ()); + push_type (int_type); + break; + case op_monitorenter: + pop_init_ref (reference_type); + break; + case op_monitorexit: + pop_init_ref (reference_type); + break; + case op_wide: + { + switch (get_byte ()) + { + case op_iload: + push_type_t (get_variable (get_ushort (), int_type)); + break; + case op_lload: + push_type_t (get_variable (get_ushort (), long_type)); + break; + case op_fload: + push_type_t (get_variable (get_ushort (), float_type)); + break; + case op_dload: + push_type_t (get_variable (get_ushort (), double_type)); + break; + case op_aload: + push_type_t (get_variable (get_ushort (), reference_type)); + break; + case op_istore: + set_variable (get_ushort (), pop_type (int_type)); + break; + case op_lstore: + set_variable (get_ushort (), pop_type (long_type)); + break; + case op_fstore: + set_variable (get_ushort (), pop_type (float_type)); + break; + case op_dstore: + set_variable (get_ushort (), pop_type (double_type)); + break; + case op_astore: + set_variable (get_ushort (), pop_init_ref (reference_type)); + break; + case op_ret: + handle_ret_insn (get_short ()); + break; + case op_iinc: + get_variable (get_ushort (), int_type); + get_short (); + break; + default: + verify_fail_pc ("unrecognized wide instruction", vfr->start_PC); + } + } + break; + case op_multianewarray: + { + int i; + type atype = check_class_constant (get_ushort ()); + int dim = get_byte (); + if (dim < 1) + verify_fail_pc ("too few dimensions to multianewarray", vfr->start_PC); + type_verify_dimensions (&atype, dim); + for (i = 0; i < dim; ++i) + pop_type (int_type); + push_type_t (atype); + } + break; + case op_ifnull: + case op_ifnonnull: + pop_type (reference_type); + push_jump (get_short ()); + break; + case op_goto_w: + push_jump (get_int ()); + invalidate_pc (); + break; + case op_jsr_w: + handle_jsr_insn (get_int ()); + break; + +#if 0 + /* These are unused here, but we call them out explicitly + so that -Wswitch-enum doesn't complain. */ + case op_putfield_1: + case op_putfield_2: + case op_putfield_4: + case op_putfield_8: + case op_putfield_a: + case op_putstatic_1: + case op_putstatic_2: + case op_putstatic_4: + case op_putstatic_8: + case op_putstatic_a: + case op_getfield_1: + case op_getfield_2s: + case op_getfield_2u: + case op_getfield_4: + case op_getfield_8: + case op_getfield_a: + case op_getstatic_1: + case op_getstatic_2s: + case op_getstatic_2u: + case op_getstatic_4: + case op_getstatic_8: + case op_getstatic_a: +#endif + default: + /* Unrecognized opcode. */ + verify_fail_pc ("unrecognized instruction in verify_instructions_0", + vfr->start_PC); + } + } +} + +/* This turns a `type' into something suitable for use by the type map + in the other parts of the compiler. In particular, reference types + are mapped to Object, primitive types are unchanged, and other + types are mapped using special functions declared in verify.h. */ +static vfy_jclass +collapse_type (type *t) +{ + switch (t->key) + { + case void_type: + case boolean_type: + case char_type: + case float_type: + case double_type: + case byte_type: + case short_type: + case int_type: + case long_type: + return vfy_get_primitive_type (t->key); + + case unsuitable_type: + case continuation_type: + return vfy_unsuitable_type (); + + case return_address_type: + return vfy_return_address_type (); + + case null_type: + return vfy_null_type (); + + case reference_type: + case uninitialized_reference_type: + return vfy_object_type (); + } + + abort (); +} + +static void +verify_instructions (void) +{ + int i; + + branch_prepass (); + verify_instructions_0 (); + + /* Now tell the rest of the compiler about the types we've found. */ + for (i = 0; i < vfr->current_method->code_length; ++i) + { + int j, slot; + struct state *curr; + + if ((vfr->flags[i] & FLAG_INSN_SEEN) != 0) + vfy_note_instruction_seen (i); + + if (! vfr->states[i]) + continue; + + curr = vfr->states[i]->val; + vfy_note_stack_depth (vfr->current_method, i, curr->stackdepth); + + /* Tell the compiler about each local variable. */ + for (j = 0; j < vfr->current_method->max_locals; ++j) + vfy_note_local_type (vfr->current_method, i, j, + collapse_type (&curr->locals[j])); + /* Tell the compiler about each stack slot. */ + for (slot = j = 0; j < curr->stacktop; ++j, ++slot) + { + vfy_note_stack_type (vfr->current_method, i, slot, + collapse_type (&curr->stack[j])); + if (type_iswide (&curr->stack[j])) + { + ++slot; + vfy_note_stack_type (vfr->current_method, i, slot, + vfy_unsuitable_type ()); + } + } + if (slot != curr->stackdepth) + abort (); + } +} + +#if 0 +_Jv_BytecodeVerifier (_Jv_InterpMethod *m) +{ + /* We just print the text as utf-8. This is just for debugging + anyway. */ + debug_print ("--------------------------------\n"); + debug_print ("-- Verifying method `%s'\n", m->self->name->chars()); + +} +#endif + +static void +make_verifier_context (vfy_method *m) +{ + vfr = (verifier_context *) vfy_alloc (sizeof (struct verifier_context)); + + vfr->current_method = m; + vfr->bytecode = vfy_get_bytecode (m); + vfr->exception = vfy_get_exceptions (m); + vfr->current_class = m->defining_class; + + vfr->states = NULL; + vfr->flags = NULL; + vfr->utf8_list = NULL; + vfr->isect_list = NULL; +} + +static void +free_verifier_context (void) +{ + vfy_string_list *utf8_list; + ref_intersection *isect_list; + + if (vfr->flags) + vfy_free (vfr->flags); + + utf8_list = vfr->utf8_list; + while (utf8_list != NULL) + { + vfy_string_list *n = utf8_list->next; + vfy_free (utf8_list); + utf8_list = n; + } + + isect_list = vfr->isect_list; + while (isect_list != NULL) + { + ref_intersection *next = isect_list->alloc_next; + vfy_free (isect_list); + isect_list = next; + } + + if (vfr->states != NULL) + { + int i; + for (i = 0; i < vfr->current_method->code_length; ++i) + { + state_list *iter = vfr->states[i]; + while (iter != NULL) + { + state_list *next = iter->next; + vfy_free (iter->val); + vfy_free (iter); + iter = next; + } + } + vfy_free (vfr->states); + } + + vfy_free (vfr); +} + +int +verify_method (vfy_method *meth) +{ + debug_print ("verify_method (%s) %i\n", vfy_string_bytes (meth->name), + meth->code_length); + + if (vfr != NULL) + verify_fail ("verifier re-entered"); + + make_verifier_context (meth); + verify_instructions (); + free_verifier_context (); + vfr = NULL; + + return 1; +} diff --git a/gcc/java/verify.c b/gcc/java/verify.c index aaf7e4df1f4..8eb0c308488 100644 --- a/gcc/java/verify.c +++ b/gcc/java/verify.c @@ -89,23 +89,23 @@ check_pending_block (tree target_label) if (current_subr == NULL_TREE) { - if (LABEL_IN_SUBR (target_label)) - return "might transfer control into subroutine"; +/* if (LABEL_IN_SUBR (target_label)) */ +/* return "might transfer control into subroutine"; */ } else { if (LABEL_IN_SUBR (target_label)) { - if (LABEL_SUBR_START (target_label) != current_subr) - return "transfer out of subroutine"; +/* if (LABEL_SUBR_START (target_label) != current_subr) */ +/* return "transfer out of subroutine"; */ } else if (! LABEL_VERIFIED (target_label)) { LABEL_IN_SUBR (target_label) = 1; LABEL_SUBR_START (target_label) = current_subr; } - else - return "transfer out of subroutine"; +/* else */ +/* return "transfer out of subroutine"; */ } return NULL; } @@ -126,6 +126,54 @@ subroutine_nesting (tree label) return nesting; } +static tree +defer_merging (tree type1, tree type2) +{ + // FIXME: This is just a placeholder until we replace the verifier + // altogether. We really need to ouput a type assertion for all of + // the types, every time they are used. + return object_ptr_type_node; + + if (TREE_CODE (type1) == POINTER_TYPE) + type1 = TREE_TYPE (type1); + if (TREE_CODE (type2) == POINTER_TYPE) + type2 = TREE_TYPE (type2); + + if (TREE_CODE (type1) == RECORD_TYPE && TREE_CODE (type2) == RECORD_TYPE) + { + tree list = build_tree_list (type1, NULL_TREE); + list = tree_cons (type2, NULL_TREE, list); + return list; + } + + if (TREE_CODE (type1) == TREE_LIST && TREE_CODE (type2) == TREE_LIST) + { + return chainon (copy_list (type1), copy_list (type2)); + } + + if (TREE_CODE (type1) == TREE_LIST && TREE_CODE (type2) == RECORD_TYPE) + { + tree tmp = type1; + do + { + if (TREE_PURPOSE (tmp) == type2) + return type1; + tmp = TREE_CHAIN (tmp); + } + while (tmp); + + return tree_cons (type2, NULL_TREE, copy_list (type1)); + } + + if (TREE_CODE (type2) == TREE_LIST && TREE_CODE (type1) == RECORD_TYPE) + { + return defer_merging (type2, type1); + } + + abort (); +} + + /* Return the "merged" types of TYPE1 and TYPE2. If either is primitive, the other must match (after promotion to int). For reference types, return the common super-class. @@ -138,7 +186,11 @@ merge_types (tree type1, tree type2) return type1; if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR) - return TYPE_UNKNOWN; + return TYPE_UNKNOWN; + + if (TREE_CODE (type1) == TREE_LIST || TREE_CODE (type2) == TREE_LIST) + return defer_merging (type1, type2); + if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE) { int depth1, depth2; @@ -153,6 +205,9 @@ merge_types (tree type1, tree type2) tt1 = TREE_TYPE (type1); tt2 = TREE_TYPE (type2); + if (TYPE_DUMMY (tt1) || TYPE_DUMMY (tt2)) + return defer_merging (tt1, tt2); + /* If tt{1,2} haven't been properly loaded, now is a good time to do it. */ if (!TYPE_SIZE (tt1)) @@ -193,31 +248,10 @@ merge_types (tree type1, tree type2) return object_ptr_type_node; } - if (CLASS_INTERFACE (TYPE_NAME (tt1))) - { - /* FIXME: should see if two interfaces have a common - superinterface. */ - if (CLASS_INTERFACE (TYPE_NAME (tt2))) - { - /* 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. */ - return object_ptr_type_node; - } - else - { - if (can_widen_reference_to (tt2, tt1)) - return type1; - else - return object_ptr_type_node; - } - } - else if (CLASS_INTERFACE (TYPE_NAME (tt2))) + if (CLASS_INTERFACE (TYPE_NAME (tt1)) + || (CLASS_INTERFACE (TYPE_NAME (tt2)))) { - if (can_widen_reference_to (tt1, tt2)) - return type2; - else - return object_ptr_type_node; + return object_ptr_type_node; } type1 = tt1; @@ -675,6 +709,8 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) VERIFICATION_ERROR_WITH_INDEX ("invalid local variable index %d in load"); tmp = type_map[index]; + if (TREE_CODE (tmp) != TREE_LIST) + { if (tmp == TYPE_UNKNOWN) VERIFICATION_ERROR_WITH_INDEX ("loading local variable %d which has unknown type"); @@ -688,6 +724,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) : type != tmp)) VERIFICATION_ERROR_WITH_INDEX ("loading local variable %d which has invalid type"); + } PUSH_TYPE (tmp); goto note_used; case OPCODE_istore: type = int_type_node; goto general_store; @@ -736,7 +773,7 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) prev_eh_ranges = NULL_EH_RANGE; /* Allocate decl for this variable now, so we get a temporary -! that survives the whole method. */ + that survives the whole method. */ find_local_variable (index, type, oldpc); if (TYPE_IS_WIDE (type)) @@ -1092,6 +1129,10 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) if (! CLASS_LOADED_P (self_type)) load_class (self_type, 1); + if (TYPE_DUMMY (self_type) && op_code == OPCODE_invokeinterface) + /* Assume we are an interface. */ + CLASS_INTERFACE (TYPE_NAME (self_type)) = 1; + self_is_interface = CLASS_INTERFACE (TYPE_NAME (self_type)); method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, index); method_type = parse_signature_string ((const unsigned char *) IDENTIFIER_POINTER (sig), @@ -1129,7 +1170,6 @@ verify_jvm_instructions (JCF* jcf, const unsigned char *byte_ops, long length) if (!nargs || notZero) VERIFICATION_ERROR ("invalid argument number in invokeinterface"); - /* If we verify/resolve the constant pool, as we should, this test (and the one just following) are redundant. */ if (! self_is_interface) diff --git a/gcc/java/verify.h b/gcc/java/verify.h new file mode 100644 index 00000000000..6657ffc471a --- /dev/null +++ b/gcc/java/verify.h @@ -0,0 +1,160 @@ +/* Declarations to interface gcj with bytecode verifier. + Copyright (C) 2003, 2004 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) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +Java and all Java-based marks are trademarks or registered trademarks +of Sun Microsystems, Inc. in the United States and other countries. +The Free Software Foundation is independent of Sun Microsystems, Inc. */ + +/* Written by Tom Tromey <tromey@redhat.com>. */ + +#ifndef GCC_VERIFY_H +#define GCC_VERIFY_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "system.h" +#include "coretypes.h" +#include "jcf.h" +#include "tree.h" +#include "java-tree.h" + +typedef JCF vfy_constants; + +/* For our purposes a string is the same as an identifier. */ +typedef tree vfy_string; + +/* The TYPE_DECL for a class or primitive type. */ +typedef tree vfy_jclass; + +/* An unsigned jshort. */ +typedef uint16 vfy_uint_16; + +typedef struct +{ + int handler, start, end, type; +} vfy_exception; + +typedef struct +{ + tree method; + vfy_string signature; + vfy_string name; + const unsigned char *bytes; + vfy_exception *exceptions; + + /* These fields are referred to directly by the verifier. */ + vfy_jclass defining_class; + int max_stack; + int max_locals; + int code_length; + int exc_count; +} vfy_method; + +/* Entry point to the verifier. */ +int verify_jvm_instructions_new (JCF *jcf, const unsigned char *byte_ops, + long length); + +void *vfy_alloc (size_t bytes); +void vfy_free (void *mem); +bool vfy_strings_equal (vfy_string one, vfy_string two); +const char *vfy_string_bytes (vfy_string str); +int vfy_string_length (vfy_string str); +vfy_string vfy_get_string (const char *chars, int length); +vfy_string vfy_init_name (void); +vfy_string vfy_clinit_name (void); +int vfy_count_arguments (vfy_string signature); +vfy_string vfy_get_signature (vfy_method *method); +vfy_string vfy_get_method_name (vfy_method *method); +bool vfy_is_static (vfy_method *method); +const unsigned char *vfy_get_bytecode (vfy_method *method); +vfy_exception *vfy_get_exceptions (vfy_method *method); +void vfy_get_exception (vfy_exception *, int index, int *handler, + int *start, int *end, int *handler_type); +int vfy_tag (vfy_constants *pool, int index); +void vfy_load_indexes (vfy_constants *pool, int index, + vfy_uint_16 *index0, vfy_uint_16 *index1); +vfy_constants *vfy_get_constants (vfy_jclass klass); +int vfy_get_constants_size (vfy_jclass klass); +vfy_string vfy_get_pool_string (vfy_constants *pool, int index); +vfy_jclass vfy_get_pool_class (vfy_constants *pool, int index); +vfy_string vfy_make_string (const char *s, int len); +vfy_string vfy_get_class_name (vfy_jclass klass); +bool vfy_is_assignable_from (vfy_jclass target, vfy_jclass source); +char vfy_get_primitive_char (vfy_jclass klass); +int vfy_get_interface_count (vfy_jclass klass); +vfy_jclass vfy_get_interface (vfy_jclass klass, int index); +bool vfy_is_array (vfy_jclass klass); +bool vfy_is_interface (vfy_jclass klass); +bool vfy_is_primitive (vfy_jclass klass); +vfy_jclass vfy_get_superclass (vfy_jclass klass); +vfy_jclass vfy_get_array_class (vfy_jclass klass); +vfy_jclass vfy_get_component_type (vfy_jclass klass); +bool vfy_is_abstract (vfy_jclass klass); +vfy_jclass vfy_find_class (vfy_jclass klass, vfy_string name); +vfy_jclass vfy_object_type (void); +vfy_jclass vfy_string_type (void); +vfy_jclass vfy_throwable_type (void); +vfy_jclass vfy_unsuitable_type (void); +vfy_jclass vfy_return_address_type (void); +vfy_jclass vfy_null_type (void); +int vfy_fail (const char *message, int pc, vfy_jclass ignore1, + vfy_method *method); +vfy_jclass vfy_get_primitive_type (int type); +void vfy_note_stack_depth (vfy_method *method, int pc, int depth); +void vfy_note_stack_type (vfy_method *method, int pc, int slot, + vfy_jclass type); +void vfy_note_local_type (vfy_method *method, int pc, int slot, + vfy_jclass type); +void vfy_note_instruction_seen (int pc); + +#define GLOM(name, stuff) name ## stuff +#define VFY_PRIMITIVE_CLASS(name) \ + vfy_get_primitive_type ((int) (GLOM (name, _type))) + +typedef enum +{ +#define JAVAOP(name, num, ignore1, ignore2, ignore3) \ + GLOM (op_, name) = num, +#include "javaop.def" +} java_opcode; + + +#define JV_CONSTANT_Class CONSTANT_Class +#define JV_CONSTANT_ResolvedClass CONSTANT_ResolvedClass +#define JV_CONSTANT_String CONSTANT_String +#define JV_CONSTANT_ResolvedString CONSTANT_ResolvedString +#define JV_CONSTANT_Integer CONSTANT_Integer +#define JV_CONSTANT_Float CONSTANT_Float +#define JV_CONSTANT_Long CONSTANT_Long +#define JV_CONSTANT_Double CONSTANT_Double +#define JV_CONSTANT_Fieldref CONSTANT_Fieldref +#define JV_CONSTANT_InterfaceMethodref CONSTANT_InterfaceMethodref +#define JV_CONSTANT_Methodref CONSTANT_Methodref + +int verify_method (vfy_method *meth); + +#ifdef __cplusplus +} +#endif + +#endif /* ! GCC_VERIFY_H */ diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 94442652db4..add3919e8fa 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,758 @@ +2004-11-24 Tom Tromey <tromey@redhat.com> + + * Merged gcj-abi-2-dev-branch to trunk. + +2004-11-16 Tom Tromey <tromey@redhat.com> + + * include/java-interp.h (_Jv_DefineClass): Updated. + * java/lang/natVMClassLoader.cc (defineClass): Pass protection + domain to class reader. + * defineclass.cc (parse): Use print_class_loaded. + Include ProtectionDomain.h. + (_Jv_DefineClass): Added ProtectionDomain argument. + (_Jv_ClassReader): Likewise. + * include/jvm.h (_Jv_Linker::print_class_loaded): Declare. + * link.cc: Include CodeSource.h. + (print_class_loaded): New function. + (wait_for_state): Use it. + +2004-11-16 Andrew Haley <aph@redhat.com> + + * gnu/gcj/util/Debug.java (print): Add RawDataManaged. + +2004-11-16 Andrew Haley <aph@redhat.com> + + * configure.ac (LIBGCJ_LD_SYMBOLIC): AC_SUBST this definition. + * configure.host: Define libgcj_ld_symbolic for Linux hosts. + * Makefile.am (lib_*_la_LDFLAGS): Add LIBGCJ_LD_SYMBOLIC. + * configure: Regenerate. + * Makefile.in: Regenerate. + +2004-11-15 Andrew Haley <aph@redhat.com> + + * boehm.cc (_Jv_GCRegisterDisappearingLink): Check that *objp is a + gc-allocated object. + +2004-11-15 Andrew Haley <aph@redhat.com> + + * java/net/URLClassLoader.java + (URLLoader.getClassPath): New method. + (JarURLLoader.JarURLLoader): Read mainfest to parse "Class-Path" + attribute and add URLs for each entry. + (JarURLLoader.classPath): New field. + (JarURLLoader.getClassPath): New method. + (addURLImpl): Scan through the list of extraUrls in the new + loader, adding them to our urlinfos. + (definePackage, findURLResource, findResources): Use + urlinfos.size(), not urls.size(). + +2004-11-11 Tom Tromey <tromey@redhat.com> + + * gnu/gcj/runtime/natSharedLibLoader.cc (ensureSupersLinked): New + method. + * gnu/gcj/runtime/SharedLibHelper.java (findClass): Ensure supers + linked. + (ensureSupersLinked): Declare. + * java/lang/natVMClassLoader.cc (loadClass): Ensure supers + linked. + +2004-11-10 Tom Tromey <tromey@redhat.com> + + * gij.cc (main): Treat -verbose the same as -verbose:class. + (help): Document -verbose and -verbose:class. + + * link.cc (verbose_class_flag): Declare. + (wait_for_state): Print message when handling precompiled class. + * java/lang/natClass.cc (verbose_class_flag): Moved to link.cc. + +2004-11-09 Tom Tromey <tromey@redhat.com> + + * testsuite/libjava.lang/assign2.out: New file. + * testsuite/libjava.lang/assign2.java: New file. + + * java/lang/natRuntime.cc (insertSystemProperties): Set + java.version to 1.4.2 and java.specification.version to 1.4. Set + java.runtime.version. + +2004-11-08 Tom Tromey <tromey@redhat.com> + + * java/lang/natClass.cc (_Jv_IsAssignableFromSlow): Ensure + supers installed. + * link.cc (verify_type_assertions): Don't link supers. + + * include/jvm.h (_Jv_Linker::search_method_in_class): Declare. + * include/java-interp.h (class _Jv_InterpClass) + <_Jv_PrepareMissingMethods>: No longer `friend'. + * java/lang/Class.h (_Jv_SearchMethodInClass): No longer + `friend'. + (_Jv_PrepareMissingMethods, _Jv_PrepareCompiledClass, + _Jv_GetInterfaces, _Jv_GenerateITable, _Jv_FindIIndex, + _Jv_AppendPartialITable, _Jv_LinkSymbolTable, + _Jv_LayoutInterfaceMethods, _Jv_SetVTableEntries, _Jv_MakeVTable, + _Jv_linkExceptionClassTable, _Jv_WaitForState): Likewise. + * link.cc (search_method_in_class): Renamed from + _Jv_SearchMethodInClass. + (resolve_pool_entry): Updated. + + * include/jvm.h (_Jv_CheckAssignment): Removed. + * java/lang/natClass.cc (_Jv_CheckAssignment): Removed. + +2004-11-05 Tom Tromey <tromey@redhat.com> + + * link.cc (verify_type_assertions): Ensure classes have supers + linked. Strip off array types first. + +2004-11-05 Bryce McKinlay <mckinlay@redhat.com> + + * link.cc: Include VerifyError.h. + (_Jv_Linker::verify_type_assertions): New. Read and evaluate entries + in the type assertion table. + * include/execution.h (_Jv_CompiledEngine::do_verify): Use + verify_type_assertions. + * include/jvm.h (_Jv_Linker::verify_type_assertions): declare. + * java/lang/Class.h (JV_ASSERT_END_OF_TABLE, + JV_ASSERT_TYPES_COMPATIBLE, JV_ASSERT_IS_INSTANTIABLE): Declare + assertion code values. + (struct _Jv_TypeAssertion): Declare. + (assertion_table): New class field. + (verify): Remove class field. + +2004-11-05 Andrew Haley <aph@redhat.com> + + * Makefile.am: Move jv_dbtool.java to + gnu/gcj/tools/gcj_dbtool/Main.java. + * Makefile.in: Rebuild. + * java/lang/VMCompiler.java: Rename property + "gnu.gcj.precompiled.db" to "gnu.gcj.precompiled.db.path". + * gnu/gcj/tools/gcj_dbtool/Main.java: moved here from + jv_dbtool.java. + +2004-11-05 Andrew Haley <aph@redhat.com> + + * jv_dbtool.java (main): Allow the user to specify the size of the + database. Display the capacity and the size. + (usage): Show the new option. + +2004-11-04 Tom Tromey <tromey@redhat.com> + + * include/jvm.h (_Jv_Linker::set_vtable_entries): Updated. + * link.cc (make_vtable): Use correct index when searching for + missing method's name. Don't use `flags'. + (set_vtable_entries): Removed `flags' argument. Don't recurse + into superclasses. + (link_symbol_table): Ensure target class method table is + complete. Ensure target fields are laid out before entering + loop. + + * java/lang/natClass.cc (_Jv_getInterfaceMethod): Indentation + fix. + + * interpret.cc (do_verify): Don't verify abstract methods. + +2004-11-01 Tom Tromey <tromey@redhat.com> + + * link.cc (wait_for_state): Call verify_class. + + * verify.cc (state::check_no_uninitialized_objects): Removed. + (push_jump): Updated. + (push_exception_jump): Likewise. + (handle_ret_insn): Likewise. + (handle_jsr_insn): Likewise. + +2004-10-28 Andrew Haley <aph@redhat.com> + + * gnu/gcj/runtime/PersistentByteMap.java: New file. + * jv_dbtool.java: New file. + * Makefile.am (bin_PROGRAMS): Add jv-dbtool + (jv_dbtool_SOURCES, jv_dbtool_LDFLAGS, jv_dbtool_LINK) + (jv_dbtool_LDADD, jv_dbtool_DEPENDENCIES): New. + * Makefile.in: Regenerate, + * java/lang/VMCompiler.java: Import NoSuchAlgorithmException, + Enumeration, StringTokenizer, Vector, PersistentByteMap. + (precompiledMapFiles): New variable. + (VMCompiler static intializer): Read "gnu.gcj.precompiled.db" to + initialize precompiledMapFiles. + (compileClass): Look at the database of precompiled class files + before firing up gcj. + + * gnu/gcj/runtime/VMClassLoader.java (findClass): Fix comment. + +2004-10-27 Andrew Haley <aph@redhat.com> + + * java/lang/VMCompiler.java (compileClass): try looking for + precompiledMapFiles. + * gnu/gcj/runtime/PersistentByteMap.java: New file. + +2004-10-27 Tom Tromey <tromey@redhat.com> + + * link.cc (ensure_class_linked): Only resolve classes for + compiled classes. + (add_miranda_methods): Ensure interface supers are installed. + (resolve_pool_entry): Better error message. + +2004-10-25 Tom Tromey <tromey@redhat.com> + + * boehm.cc (_Jv_MarkObj): Test aux_info before dereferencing it. + + * java/util/ResourceBundle.java (tryBundle): Use + Class.isAssignableFrom rather than catching ClassCastException. + + * java/util/zip/InflaterInputStream.java (fill): Don't throw an + exception if we hit EOF of `in'. + (read): Handle case where inflating returns -1. + + * gnu/java/text/WordBreakIterator.java (WordBreakIterator): Don't + initialize `iter'. + * gnu/java/text/SentenceBreakIterator.java + (SentenceBreakIterator): Don't initialize `iter'. + * gnu/java/text/LineBreakIterator.java (LineBreakIterator): Don't + initialize `iter'. + * gnu/java/text/CharacterBreakIterator.java + (CharacterBreakIterator): Don't initialize `iter'. + * gnu/java/text/BaseBreakIterator.java (BaseBreakIterator): New + constructor. + * java/text/BreakIterator.java: Updated documentation. + +2004-10-20 Tom Tromey <tromey@redhat.com> + + * java/util/ResourceBundle.java (tryBundle): Also ignore + ClassCastException. + +2004-10-18 Tom Tromey <tromey@redhat.com> + + * interpret.cc (do_post_miranda_hook): New method. + * include/execution.h (_Jv_ExecutionEngine::post_miranda_hook): + New field. + (_Jv_CompiledEngine::do_post_miranda_hook): New method. + (_Jv_CompiledEngine): Initialize new field. + (_Jv_InterpreterEngine::do_post_miranda_hook): Declare. + (_Jv_InterpreterEngine): Initialize new field. + * link.cc (resolve_pool_entry): Put Miranda methods in target + class. + (ensure_method_table_complete): Call post_miranda_hook. + * java/lang/natVMClassLoader.cc (defineClass): Don't set class' + aux_info. + * defineclass.cc (read_one_method_attribute): Use _Jv_AllocBytes. + (parse): Set class' aux_info here. + + * boehm.cc (_Jv_MarkObj): Mark `throws'. + + * boehm.cc: Re-merged with trunk. + +2004-10-18 Andrew Haley <aph@redhat.com> + + PR java/18036: + * gnu/gcj/runtime/natStackTrace.cc (fillInStackTrace): Reorganize + and correct logic used to find interpreter. + +2004-10-13 Andrew Haley <aph@redhat.com> + + * interpret.cc (_Jv_InterpMethod::run): Initialize + _Jv_StartOfInterpreter. + (_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): Functions removed. + (_Jv_StartOfInterpreter, _Jv_EndOfInterpreter): New variables. + * gnu/gcj/runtime/natStackTrace.cc (fillInStackTrace): Use + _Unwind_FindEnclosingFunction to discover whether PC is within the + interpreter. + +2004-10-13 Tom Tromey <tromey@redhat.com> + + * link.cc (find_iindex): Copy correct number of slots to new + ioffsets. + +2004-10-12 Tom Tromey <tromey@redhat.com> + + * testsuite/libjava.loader/loader.exp (gcj_object_file_name): New + proc. + (gcj_loader_test_one): Use it. + (gcj_loader_run): Likewise. + + * prims.cc: Don't include FirstThread.h. + +2004-10-06 Tom Tromey <tromey@redhat.com> + + * link.cc (ensure_method_table_complete): Ensure superclass + Miranda methods installed. + + * include/java-interp.h (class _Jv_JNIMethod): Added + JV_MARKOBJ_DECL as a friend. + * interpret.cc (ncode): Allocate jni_arg_types field with GC. + * boehm.cc (_Jv_MarkObj): Skip abstract methods when marking + interpreter method structures. Mark jni_arg_types of JNI + methods. + + * defineclass.cc (parse): Use JV_STATE_READ. + * java/lang/Class.h (JV_STATE_READ): New enum value. + +2004-10-05 Tom Tromey <tromey@redhat.com> + + * link.cc (resolve_pool_entry): Add signature info to missing + method's information. + + * gnu/gcj/util/Debug.java (Debug(int,boolean)): New constructor. + * gnu/gcj/util/natDebug.cc (_Jv_StaticDeepDebug): New function. + +2004-10-04 Tom Tromey <tromey@redhat.com> + + * boehm.cc (_Jv_MarkObj): Correctly indicate base pointer when + marking IDT. + +2004-09-29 Tom Tromey <tromey@redhat.com> + + * Makefile.am (libgcj_la_SOURCES): Mention link.cc, not + resolve.cc. + * include/jvm.h (class _Jv_Linker): Renamed from _Jv_Resolver. + * jni.cc: Use _Jv_Linker. + * interpret.cc: Use _Jv_Linker. + * java/lang/reflect/natField.cc (getType): Use _Jv_Linker. + * java/lang/natClassLoader.cc: Use _Jv_Linker. + * java/lang/natVMClassLoader.cc (resolveClass): Use _Jv_Linker. + * java/lang/Class.h: Use _Jv_Linker. + * java/lang/natClass.cc (initializeClass): Use _Jv_Linker. + * resolve.cc: Renamed ... + * link.cc: ... here. Use _Jv_Linker. + * defineclass.cc (checkExtends): Use _Jv_Linker. + +2004-09-17 Tom Tromey <tromey@redhat.com> + + * defineclass.cc (handleCodeAttribute): Don't reference + `deferred'. + (handleMethodsEnd): Likewise. + * include/java-interp.h (_Jv_MethodBase::deferred): Removed + field. + (_Jv_Defer_Resolution): Don't declare or define. + * interpret.cc (do_create_ncode): Don't resolve deferred method + pointers. + * java/lang/Class.h (_Jv_Defer_Resolution): Don't declare. + * resolve.cc (link_symbol_table): No need to defer resolution. + +2004-09-14 Tom Tromey <tromey@redhat.com> + + * boehm.cc (MAYBE_MARK): Remove unused `Exit' argument. + (_Jv_MarkObj): Updated. + (_Jv_MarkArray): Likewise. + + * include/jvm.h (StringClass): Removed. + * jni.cc (_Jv_JNI_ThrowNew): Don't use StringClass. + * interpret.cc (_Jv_InitField): Don't use StringClass. + * java/lang/natString.cc (_Jv_StringFindSlot): Don't use + StringClass. + (rehash): Likewise + (intern): Likewise. + (_Jv_FinalizeString): Likewise. + (_Jv_NewStringUtf8Const): Likewise. + (equals): Likewise. + * prims.cc (JvConvertArgv): Don't use StringClass. + + * gcj/field.h (struct _Jv_Field): Don't mention COMPACT_FIELDS. + * resolve.cc (ensure_fields_laid_out): Don't mention + COMPACT_FIELDS. + * defineclass.cc (handleField): Don't mention COMPACT_FIELDS. + * boehm.cc (_Jv_MarkObj): Don't mention COMPACT_FIELDS. + + * java/lang/reflect/natField.cc (getType): Use resolve_field. + * java/lang/natVMClassLoader.cc (resolveClass): New native + implementation. + (linkClass0): Removed. + (markClassErrorState0): Likewise. + * java/lang/natClassLoader.cc: Include execution.h. Moved class + preparation code to resolve.cc. + (_Jv_RegisterClassHookDefault): Set class's execution engine if + not already set. + (_Jv_FindClass): Use wait_for_state. + (_Jv_NewArrayClass): Likewise. Simplified permissions setting. + * java/lang/natClass.cc (_Jv_IsInstanceOf): Include execution.h. + Moved interface table and class preparation code to resolve.cc. + (finalize): Rewrote. + (initializeClass): Simplified locking and class preparation. + * java/lang/VMClassLoader.java (linkClass0): Removed. + (markClassErrorState0): Likewise. + (resolveClass): Now native. + (transformException): New method. + * java/lang/Class.h (getSuperclass): Don't try to resolve super + reference. + (getInterface): Likewise. + (size): Likewise. + (set_state): New method. + (Class): Updated friend declarations. + (verify): Field now private. + (engine): New field. + * include/jvm.h (class _Jv_Resolver): New class declaration. + (_Jv_ResolveField): Removed declaration. + (_Jv_CheckAccessNoInit): Likewise. + (_Jv_isBinaryCompatible): Removed. + * include/java-interp.h (class _Jv_MethodBase): Updated friend + declarations. + (class _Jv_InterpMethod): Likewise. + (class _Jv_InterpClass): Likewise. + (class _Jv_JNIMethod): Likewise. + * include/execution.h: New file. + * gnu/gcj/runtime/natSharedLibLoader.cc: Include execution.h. + (_Jv_sharedlib_register_hook): Set `engine' on loaded class. + Register class after setting fields. + * resolve.cc: Include execution.h, VerifyError.h. Moved + interpreter-specific code to interpret.cc. + (uaddr): New location. + (struct aligner): Likewise. + (ALIGNOF): Likewise. + (INITIAL_IOFFSETS_LEN): Interface dispatch code moved here. + (INITIAL_IFACES_LEN): Likewise. + (null_idt): Likewise. + (_Jv_GetMethodString): Likewise. + (_Jv_ThrowNoSuchMethodError): Likewise. + (_Jv_abstractMethodError): Likewise. + (_Jv_Resolver::get_alignment_from_class): Renamed. + (_Jv_Resolver::resolve_field): Likewise. + (_Jv_Resolver::resolve_pool_entry): Likewise. + (_Jv_Resolver::resolve_class_ref): Likewise. + (_Jv_Resolver::prepare_constant_time_tables): Likewise. + (_Jv_Resolver::indexof): Likewise. + (_Jv_Resolver::get_interfaces): Likewise. + (_Jv_Resolver::generate_itable): Likewise. + (_Jv_Resolver::append_partial_itable): Likewise. + (_Jv_Resolver::find_iindex): Likewise. + (_Jv_Resolver::link_symbol_table): Likewise. + (_Jv_Resolver::link_exception_table): Likewise. + (_Jv_Resolver::layout_interface_methods): Likewise. + (_Jv_Resolver::layout_vtable_methods): Likewise. + (_Jv_Resolver::set_vtable_entries): Likewise. + (_Jv_Resolver::make_vtable): Likewise. + (_Jv_Resolver::ensure_fields_laid_out): Likewise. + (_Jv_Resolver::ensure_class_linked): Likewise. + (_Jv_Resolver::ensure_supers_installed): Likewise. + (_Jv_Resolver::add_miranda_methods): Likewise. + (_Jv_Resolver::ensure_method_table_complete): Likewise. + (_Jv_Resolver::verify_class): Likewise. + (_Jv_Resolver::wait_for_state): Likewise. + * prims.cc (_Jv_soleCompiledEngine): New global. + (_Jv_CheckAccess): Use _Jv_IsAssignableFromSlow. + (_Jv_CheckAccessNoInit): Removed. + * jni.cc (_Jv_JNI_GetAnyFieldID): Use resolve_field. + * interpret.cc: Include platform.h, ClassFormatError.h, + Modifier.h, execution.h. + (_Jv_soleInterpreterEngine): New global. + (compile): Use resolve_pool_entry. + (run): Likewise. + (_Jv_InitField): New location. + (skip_one_type): Likewise. + (get_ffi_type_from_signature): Likewise. + (_Jv_count_arguments): Likewise. + (init_cif): Likewise. + (ncode_closure): Likewise. + (ffi_closure_fun): Likewise. + (ncode): Likewise. + (throw_class_format_error): Likewise. + (throw_class_format_error): Likewise. + (_Jv_InterpreterEngine::do_verify): New method. + (_Jv_InterpreterEngine::do_create_ncode): Likewise. + (_Jv_InterpreterEngine::do_allocate_static_fields): Likewise. + (_Jv_InterpreterEngine::do_resolve_method): Likewise. + * defineclass.cc: Include execution.h. + (_Jv_ClassReader): Initialize size_in_bytes, vtable_method_count, + engine. + (checkExtends): Ensure superclass has supers installed. + (_Jv_ClassNameSamePackage): Clarify usage constraints. + * boehm.cc (GC_enable, GC_disable): Declare at top of file. + (_Jv_MarkObj): Unconditionally mark vtable. Mark interface + dispatch tables. + +2004-09-13 Tom Tromey <tromey@redhat.com> + + * mauve-libgcj: List some classes we don't have. + +2004-09-10 Andrew Haley <aph@redhat.com> + + * java/lang/Class.h (_Jv_getInterfaceMethod(): new friend. + * java/lang/natClass.cc (initializeClass): Check itable. + (_Jv_getInterfaceMethod): New. + (_Jv_LinkSymbolTable): Rewrite code that handles inerface calls. + Check that an interface method isn't called with invokevirtual. + + * java/lang/natClass.cc (_Jv_LayoutVTableMethods): Make sure + super_meth is virtual. + +2004-09-01 Tom Tromey <tromey@redhat.com> + + * java/lang/Class.h (_Jv_CheckAccessNoInit): Declare as friend. + * java/lang/natClass.cc (_Jv_LayoutVTableMethods): Use + _Jv_CheckAccessNoInit. + * include/jvm.h (_Jv_CheckAccessNoInit): Declare. + * prims.cc (_Jv_CheckAccessNoInit): New method. + + * java/lang/reflect/natMethod.cc (invoke): Check access against + declaring class, not object's class. + * java/lang/natClass.cc (_Jv_LookupDeclaredMethod): Added another + argument. + (_Jv_LayoutVTableMethods): Perform checks of accessibility of + overridden method. + * java/lang/Class.h (_Jv_LookupDeclaredMethod): Added another + argument. + +2004-08-30 Andrew Haley <aph@redhat.com> + + * java/lang/natClass.cc (_Jv_CheckAssignment): Catch + ClassNotFoundException. + Throw NoClassDefFoundError. + + * java/lang/natClassLoader.cc (_Jv_FindClassInCache): Remove call + to klass->verify() from here ... + (_Jv_PrepareCompiledClass): ...and put it here. + +2004-08-27 Andrew Haley <aph@redhat.com> + + * java/lang/natClassLoader.cc (_Jv_FindClassInCache): Call + klass->verify(). + * java/lang/natClass.cc (_Jv_LinkSymbolTable): Add debugging. + (_Jv_LinkSymbolTable): Call Jv_LayoutClass on target class. + +2004-08-27 Tom Tromey <tromey@redhat.com> + + * java/lang/Class.h (_Jv_IsAssignableFromSlow): Declare as + friend. + * java/lang/natClass.cc (_Jv_CheckAssignment): New function. + (_Jv_IsAssignableFromSlow): New function. + Include VerifyError.h. + * include/jvm.h (_Jv_CheckAssignment): Declare. + +2004-08-18 Andrew Haley <aph@redhat.com> + + * java/lang/VMCompiler.java (loadSharedLibrary): Add className + argument. Pass it to findClass instead of fileName. + (compileClass): Pass class name to loadSharedLibrary. + +2004-06-22 Andrew Haley <aph@redhat.com> + + * testsuite/libjava.compile/compile.exp: Force indirect dispatch. + +2004-06-15 Andrew Haley <aph@redhat.com> + + * java/lang/natSystem.cc (getenv0): Don't assume environment + variable is Latin 1 coded. + +2004-06-07 Andrew Haley <aph@redhat.com> + + * java/lang/System.java: (getenv0): New method. + (getenv): Add security check. Do the right thing. + * java/lang/natSystem.cc (getenv0): New method. + +2004-04-19 Andrew Haley <aph@redhat.com> + + * gnu/gcj/runtime/NameFinder.java: Call waitFor() on the processes + we destroy. + + * gnu/java/net/natPlainSocketImplPosix.cc (read): The value byte + is returned as an int in the range 0 to 255. + +2004-08-13 Tom Tromey <tromey@redhat.com> + + * java/lang/natClass.cc (_Jv_LinkSymbolTable): Prepare the target + class if it is interpreted. + +2004-08-12 Tom Tromey <tromey@redhat.com> + + * java/lang/natClassLoader.cc (_Jv_WaitForState): Updated. + * java/lang/Class.h (_Jv_ResolveClassRef): Updated declaration. + (Class::getSuperclass): Updated. + (Class::getInterfaces): Likewise. + (Class::size): Updated. + (_Jv_LayoutClass): Updated declaration. + * java/lang/natClass.cc (_Jv_ResolveClassRef): Changed interface. + Synchronize on class. + (_Jv_LayoutClass): Changed interface. + (initializeClass): Updated. + (_Jv_LinkSymbolTable): Likewise. + + * java/lang/Class.h (Class::_Jv_isBinaryCompatible): Declare as + friend. + * java/lang/natClassLoader.cc (_Jv_WaitForState): Use + _Jv_isBinaryCompatible. + * java/lang/natClass.cc (initializeClass): Use + _Jv_isBinaryCompatible. + (_Jv_LinkSymbolTable): Likewise. + * include/jvm.h (_Jv_isBinaryCompatible): New function. + +2004-08-11 Tom Tromey <tromey@redhat.com> + + * gcj/javaprims.h: Regenerated. + * java/lang/natClassLoader.cc (getClassLoader0): Removed. + (_registerClass): Likewise. + * Makefile.in: Rebuilt. + * Makefile.am (core_java_source_files): Added VMCompiler. + * java/lang/Compiler.java: Rewrote in terms of VMCompiler. + * java/lang/VMCompiler.java: New file. + * gnu/gcj/runtime/SharedLibHelper.java (findClass): Removed + `verbose' code. + (copyFile): Don't use fully-qualified name. + (h): Removed. + * java/lang/natVMClassLoader.cc: Include VMCompiler.h. + (defineClass): Use VMCompiler. + * java/lang/ClassLoader.java (defineClass): Removed jit + compilation code and `verbose' code. + (getClassLoader0): Removed. + (_registerClass): Likewise. + (SharedLibHelpers): Removed. + +2004-08-10 Tom Tromey <tromey@redhat.com> + + * java/net/URLClassLoader.java (URLLoader(URLClassLoader, URL, + URL)): New constructor. + (SoURLLoader): Likewise. + (JarURLLoader): Create SoURLLoader with override URL. + +2004-08-10 Mark Wielaard <mark@klomp.org> + + * Makefile.in: Rebuilt. + * Makefile.am (interpret.lo): New rule. + +2004-08-05 Andrew Haley <aph@redhat.com> + + * java/net/URLClassLoader.java (JarURLLoader.JarURLLoader): Look + aside for "GCJLIBS" in directory where jarfiles are loaded. + (JarURLLoader.getClass): New method. + (JarURLLoader.toString): New method. + (FileResource.toString): New method. + * java/lang/natClassLoader.cc (_Jv_RegisterClassHookDefault): + Remove "Duplicate class registration: " bug. + (_registerClass): New method. + * java/lang/natClass.cc (_Jv_LinkSymbolTable): Check method index. + (_Jv_LinkSymbolTable): Call _Jv_LayoutClass(). + Add debugging. + (_Jv_LayoutClass): Use getSuperclass() rather than directly + accessing the field. + * java/lang/ClassLoader.java (SharedLibHelpers): New variable. + (defineClass): Call gcj to JIT-compile a class. + (_registerClass): New method. + * gnu/gcj/runtime/SharedLibHelper.java (findHelper): A shared + library name can refer to more than one loaded library, so use a + Set of SharedLibHelpers. + If a shared library is already loaded, take a copy. + (copyFile): New function. + + * testsuite/libjava.compile/compile.exp: Force + -findirect-dispatch. + + * java/security/BasicPermission.java: Remove bogus checks. + + * java/lang/System.java (getenv0): New method. + * java/lang/natSystem.cc (getenv0): New method. + +2004-05-24 Andrew Haley <aph@redhat.com> + + * java/lang/natClass.cc (_Jv_LayoutClass): Remove warning message. + +2004-04-20 Bryce McKinlay <mckinlay@redhat.com> + + * Merged with HEAD as of 20040514. Diff against + gcj-abi-2-merge-20040514. + +2004-04-16 Andrew Haley <aph@redhat.com> + + * java/lang/natClassLoader.cc (_Jv_WaitForState): Call + _Jv_LayoutClass. + (_Jv_PrepareCompiledClass): Cast address to uaddr for comparison. + (_Jv_PrepareCompiledClass): If we throw an exception during + preparation, restore state. + (ClassLoader::getClassLoader0): New method. + + * java/lang/natClass.cc (get_alignment_from_class): Moved here + from resolve.cc. + (ALIGNOF): Use offsetof, not __alignof__. + (_Jv_ResolveClassRef): Resolve a reference to a class in a + constant pool. + (getInterfaces): Emit debug output if interface hasn't been + resolved. + (initializeClass): Call _Jv_LayoutClass. + (_Jv_LinkSymbolTable): Add debugging output. + (_Jv_LinkSymbolTable): NoClassDefFoundError if target_class isn't + found. + (_Jv_LinkSymbolTable): Call _Jv_PrepareClass. + (_Jv_LinkSymbolTable): Pass the real class loader to + _Jv_FindClass. + (_Jv_linkExceptionClassTable): Don't throw if we fail to find an + exception class. + (_Jv_LinkSymbolTable): Assert if we find a static field reference + to an interpreted class. + (_Jv_LayoutVTableMethods): Use klass->getSuperclass to get the + superclass. + (_Jv_LayoutClass): Moved here; it was part of _Jv_PrepareClass in + resolve.cc. + + * java/lang/VMSecurityManager.java: Check for the system class + loader as well as loader != null. + + * java/lang/SecurityManager.java (checkPermission): Remove + security check. + (checkRead): Likewise. + (checkConnect): Likewise. + + * java/lang/ClassLoader.java (loadClass): Include all class + loaders in stack trace string. + Look for class in "gcjlib.so" in the same directory. + (getSystemClassLoader) Use getClassLoader0. + (getClassLoader0): New native method. + + * java/lang/Class.h (getSuperclass): New method. + (getInterface): New method. + (size): Lay out class if needed. + (firstMethodIndex): New method. + (Jv_ResolveClassRef): New declaration. + (_Jv_LinkSymbolTable): New declaration. + + * java/io/ObjectOutputStream.java: Add DEBUG statements + everywhere. + (dumpElementln): New method. + (depth): New field. + * java/io/ObjectInputStream.java (MyIOException): new, for + debugging. + Everywhere: use MyIOException rather than IOException. + Indent debugging output to make nesting visible. + (currentClassLoader): Make native + (callersClassLoader): New field. + (depth): New field. + * java/io/natObjectInputStream.cc (getCallersClassLoader): New + method. + + (readObject): ENDBLOCKDATA is generated if the class has a write + method, not if it has a read method. + + * include/jvm.h (_Jv_CallAnyMethodA): Add new arg, iface. + + * gnu/javax/rmi/CORBA/DelegateFactory.java: Use the + getContextClassLoader form the current thread after our own class + loader. + + * gnu/gcj/runtime/SharedLibHelper.java (findClass): Class loader + debugging. + (toString): New method. + + * verify.cc (class _Jv_BytecodeVerifier): Don't directly access + interfaces array. + + * resolve.cc (_Jv_PrepareMissingMethods): If interface looks like + a constant pool entry, resolve it now. + (_Jv_PrepareClass): Break out part of this function to Jv_LayoutClass + in natClass.cc. + Move get_alignment_from_class to natClass.cc. + + * prims.cc (_Jv_AllocObjectNoFinalizer): Use size field from class. + (_Jv_AllocObjectNoInitNoFinalizer): Likewise. + + * defineclass.cc (checkExtends): Don't access superclass field + directly. + + * Makefile.in: regenerate. + + * gnu/gcj/util/natDebug.cc: New + * gnu/gcj/util/Debug.java: New. + + * Makefile.am (java/io/ObjectInputStream.lo): Use + -fno-optimize-sibling-calls. + + * java/lang/reflect/natMethod.cc (_Jv_CallAnyMethodA): Use + _Jv_LookupInterfaceMethodIdx to calculate the address of a method + in an interface. + * include/jvm.h (_Jv_CallAnyMethodA): Add new arg: iface. + 2004-11-24 Kelley Cook <kcook@gcc.gnu.org> * configure: Regenerate for libtool change. diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 192845f2cc5..0b07288b148 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -124,7 +124,7 @@ propdir = $(libdir) ## For now, only on native systems. FIXME. if NATIVE -bin_PROGRAMS = jv-convert gij grmic grmiregistry +bin_PROGRAMS = jv-convert gij grmic grmiregistry gcj-dbtool endif bin_SCRIPTS = addr2name.awk @@ -207,7 +207,7 @@ libgij_la_LIBADD = libgcj.la libgij_la_DEPENDENCIES = libgcj.la libgcj.spec libgcj_la_SOURCES = prims.cc jni.cc exception.cc \ - resolve.cc defineclass.cc interpret.cc verify.cc \ + link.cc defineclass.cc interpret.cc verify.cc \ $(nat_source_files) $(math_c_source_files) $(java_source_files) \ $(built_java_source_files) \ $(BOEHMGC_SRC) $(NOGC_SRC) \ @@ -363,7 +363,7 @@ lib_gnu_java_awt_peer_gtk_la_LIBADD = $(GTK_LIBS) $(GLIB_LIBS) $(LIBART_LIBS) $( lib_gnu_java_awt_peer_gtk_la_DEPENDENCIES = $(gtk_jni_headers) libgcj-@gcc_version@.jar libgcj.la libgcj.spec ## The mysterious backslash in the grep pattern is consumed by make. lib_gnu_java_awt_peer_gtk_la_LDFLAGS = \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_java_awt_peer_gtk_la_LINK = $(LIBLINK) lib_org_ietf_jgss_la_SOURCES = \ @@ -384,7 +384,7 @@ lib_org_ietf_jgss_la_LIBADD = -L$(here)/.libs $(jgss_propertyo_files) \ ## The mysterious backslash in the grep pattern is consumed by make. lib_org_ietf_jgss_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_org_w3c_dom_la_SOURCES = org/w3c/dom/Attr.java \ org/w3c/dom/CDATASection.java \ @@ -415,7 +415,7 @@ org/w3c/dom/traversal/TreeWalker.java lib_org_w3c_dom_la_LIBADD = -L$(here)/.libs libgcj.la ## The mysterious backslash in the grep pattern is consumed by make. lib_org_w3c_dom_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_org_xml_sax_la_SOURCES = org/xml/sax/ext/DeclHandler.java \ org/xml/sax/ext/LexicalHandler.java \ @@ -451,7 +451,7 @@ org/xml/sax/XMLReader.java lib_org_xml_sax_la_LIBADD = -L$(here)/.libs libgcj.la ## The mysterious backslash in the grep pattern is consumed by make. lib_org_xml_sax_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_awt_xlib_la_SOURCES = \ $(xlib_java_source_files) \ @@ -467,7 +467,7 @@ lib_gnu_awt_xlib_la_CPPFLAGS = \ lib_gnu_awt_xlib_la_LDFLAGS = ../libstdc++-v3/src/libstdc++.la \ @X_PRE_LIBS@ @X_LIBS@ -lX11 @X_EXTRA_LIBS@ \ -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_awt_xlib_la_LINK = $(LIBLINK) all_java_source_files = \ @@ -945,6 +945,25 @@ jv_convert_LDADD = -L$(here)/.libs libgcj.la ## linking this program. jv_convert_DEPENDENCIES = libgcj.la libgcj.spec +gcj_dbtool_SOURCES = gnu/gcj/tools/gcj_dbtool/Main.java +## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'. We +## need this because we are explicitly using libtool to link using the +## `.la' file. +gcj_dbtool_LDFLAGS = --main=gnu.gcj.tools.gcj_dbtool.Main \ + -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS) +gcj_dbtool_LINK = $(GCJLINK) +## We don't explicitly link in the libraries we need; libgcj.la brings +## in all dependencies. We need the -L so that gcj can find libgcj +## with `-lgcj', but it must come first, otherwise the -L flags +## brought in from libgcj.la would cause the install directories to be +## searched before the build-tree ones, and we'd get errors because of +## different libraries with the same SONAME from picky linkers such as +## Solaris'. FIXME: should be _libs on some systems. +gcj_dbtool_LDADD = -L$(here)/.libs libgcj.la +## Depend on the spec file to make sure it is up to date before +## linking this program. +gcj_dbtool_DEPENDENCIES = libgcj.la libgcj.spec + gij_SOURCES = ## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'. We ## need this because we are explicitly using libtool to link using the @@ -2140,65 +2159,35 @@ javax/print/attribute/SupportedValuesAttribute.java \ javax/print/attribute/TextSyntax.java \ javax/print/attribute/UnmodifiableSetException.java \ javax/print/attribute/URISyntax.java \ -javax/print/attribute/standard/ColorSupported.java \ -javax/print/attribute/standard/Compression.java \ javax/print/attribute/standard/Copies.java \ -javax/print/attribute/standard/CopiesSupported.java \ javax/print/attribute/standard/DateTimeAtCompleted.java \ javax/print/attribute/standard/DateTimeAtCreation.java \ javax/print/attribute/standard/DateTimeAtProcessing.java \ javax/print/attribute/standard/DocumentName.java \ -javax/print/attribute/standard/Fidelity.java \ -javax/print/attribute/standard/Finishings.java \ javax/print/attribute/standard/JobHoldUntil.java \ javax/print/attribute/standard/JobImpressions.java \ javax/print/attribute/standard/JobImpressionsCompleted.java \ -javax/print/attribute/standard/JobImpressionsSupported.java \ javax/print/attribute/standard/JobKOctets.java \ javax/print/attribute/standard/JobKOctetsProcessed.java \ -javax/print/attribute/standard/JobKOctetsSupported.java \ javax/print/attribute/standard/JobMediaSheets.java \ javax/print/attribute/standard/JobMediaSheetsCompleted.java \ -javax/print/attribute/standard/JobMediaSheetsSupported.java \ javax/print/attribute/standard/JobMessageFromOperator.java \ javax/print/attribute/standard/JobName.java \ javax/print/attribute/standard/JobOriginatingUserName.java \ javax/print/attribute/standard/JobPriority.java \ javax/print/attribute/standard/JobPrioritySupported.java \ -javax/print/attribute/standard/JobSheets.java \ -javax/print/attribute/standard/JobState.java \ -javax/print/attribute/standard/JobStateReason.java \ -javax/print/attribute/standard/JobStateReasons.java \ -javax/print/attribute/standard/Media.java \ -javax/print/attribute/standard/MediaSizeName.java \ -javax/print/attribute/standard/MultipleDocumentHandling.java \ javax/print/attribute/standard/NumberOfDocuments.java \ javax/print/attribute/standard/NumberOfInterveningJobs.java \ javax/print/attribute/standard/NumberUp.java \ -javax/print/attribute/standard/NumberUpSupported.java \ -javax/print/attribute/standard/OrientationRequested.java \ javax/print/attribute/standard/OutputDeviceAssigned.java \ -javax/print/attribute/standard/PDLOverrideSupported.java \ -javax/print/attribute/standard/PageRanges.java \ javax/print/attribute/standard/PagesPerMinute.java \ javax/print/attribute/standard/PagesPerMinuteColor.java \ -javax/print/attribute/standard/PresentationDirection.java \ -javax/print/attribute/standard/PrintQuality.java \ javax/print/attribute/standard/PrinterInfo.java \ -javax/print/attribute/standard/PrinterIsAcceptingJobs.java \ javax/print/attribute/standard/PrinterLocation.java \ javax/print/attribute/standard/PrinterMakeAndModel.java \ javax/print/attribute/standard/PrinterMessageFromOperator.java \ -javax/print/attribute/standard/PrinterMoreInfo.java \ -javax/print/attribute/standard/PrinterMoreInfoManufacturer.java \ javax/print/attribute/standard/PrinterName.java \ -javax/print/attribute/standard/PrinterResolution.java \ -javax/print/attribute/standard/PrinterState.java \ -javax/print/attribute/standard/PrinterStateReason.java \ -javax/print/attribute/standard/PrinterStateReasons.java \ -javax/print/attribute/standard/PrinterURI.java \ javax/print/attribute/standard/QueuedJobCount.java \ -javax/print/attribute/standard/ReferenceUriSchemesSupported.java \ javax/print/attribute/standard/RequestingUserName.java \ javax/print/attribute/standard/Severity.java \ javax/print/attribute/standard/SheetCollate.java \ @@ -2379,6 +2368,7 @@ java/lang/UnsupportedOperationException.java \ java/lang/VerifyError.java \ java/lang/VirtualMachineError.java \ java/lang/VMClassLoader.java \ +java/lang/VMCompiler.java \ java/lang/VMSecurityManager.java \ java/lang/VMThrowable.java \ java/lang/Void.java \ @@ -2567,11 +2557,13 @@ gnu/gcj/runtime/FinalizerThread.java \ gnu/gcj/runtime/JNIWeakRef.java \ gnu/gcj/runtime/MethodRef.java \ gnu/gcj/runtime/NameFinder.java \ +gnu/gcj/runtime/PersistentByteMap.java \ gnu/gcj/runtime/SharedLibHelper.java \ gnu/gcj/runtime/SharedLibLoader.java \ gnu/gcj/runtime/StackTrace.java \ gnu/gcj/runtime/StringBuffer.java \ gnu/gcj/runtime/VMClassLoader.java \ +gnu/gcj/util/Debug.java \ gnu/java/io/ASN1ParsingException.java \ gnu/java/io/Base64InputStream.java \ gnu/java/io/ClassLoaderObjectInputStream.java \ @@ -3282,6 +3274,7 @@ gnu/gcj/runtime/natSharedLibLoader.cc \ gnu/gcj/runtime/natStackTrace.cc \ gnu/gcj/runtime/natStringBuffer.cc \ gnu/gcj/runtime/natVMClassLoader.cc \ +gnu/gcj/util/natDebug.cc \ gnu/java/lang/natMainThread.cc \ gnu/java/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index 31032fc6f02..60161a4bee9 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -17,7 +17,7 @@ -SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) $(lib_gnu_java_awt_peer_gtk_la_SOURCES) $(lib_org_ietf_jgss_la_SOURCES) $(lib_org_w3c_dom_la_SOURCES) $(lib_org_xml_sax_la_SOURCES) $(libgcj_la_SOURCES) $(libgij_la_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) +SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) $(lib_gnu_java_awt_peer_gtk_la_SOURCES) $(lib_org_ietf_jgss_la_SOURCES) $(lib_org_w3c_dom_la_SOURCES) $(lib_org_xml_sax_la_SOURCES) $(libgcj_la_SOURCES) $(libgij_la_SOURCES) $(gcj_dbtool_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -43,7 +43,8 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @NATIVE_TRUE@bin_PROGRAMS = jv-convert$(EXEEXT) gij$(EXEEXT) \ -@NATIVE_TRUE@ grmic$(EXEEXT) grmiregistry$(EXEEXT) +@NATIVE_TRUE@ grmic$(EXEEXT) grmiregistry$(EXEEXT) \ +@NATIVE_TRUE@ gcj-dbtool$(EXEEXT) @MAINTAINER_MODE_TRUE@@NATIVE_TRUE@noinst_PROGRAMS = \ @MAINTAINER_MODE_TRUE@@NATIVE_TRUE@ gen-from-JIS$(EXEEXT) DIST_COMMON = README $(am__configure_deps) $(srcdir)/../compile \ @@ -371,7 +372,7 @@ lib_org_xml_sax_la_OBJECTS = $(am_lib_org_xml_sax_la_OBJECTS) am__DEPENDENCIES_4 = gnu/regexp/MessagesBundle.properties.lo \ gnu/regexp/MessagesBundle_fr.properties.lo am__DEPENDENCIES_5 = $(am__DEPENDENCIES_4) -am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ +am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc link.cc \ defineclass.cc interpret.cc verify.cc gnu/gcj/natCore.cc \ gnu/gcj/convert/JIS0208_to_Unicode.cc \ gnu/gcj/convert/JIS0212_to_Unicode.cc \ @@ -386,7 +387,7 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ gnu/gcj/runtime/natSharedLibLoader.cc \ gnu/gcj/runtime/natStackTrace.cc \ gnu/gcj/runtime/natStringBuffer.cc \ - gnu/gcj/runtime/natVMClassLoader.cc \ + gnu/gcj/runtime/natVMClassLoader.cc gnu/gcj/util/natDebug.cc \ gnu/java/lang/natMainThread.cc \ gnu/java/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ @@ -481,9 +482,9 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ java/lang/UnsupportedClassVersionError.java \ java/lang/UnsupportedOperationException.java \ java/lang/VerifyError.java java/lang/VirtualMachineError.java \ - java/lang/VMClassLoader.java java/lang/VMSecurityManager.java \ - java/lang/VMThrowable.java java/lang/Void.java \ - java/io/BufferedInputStream.java \ + java/lang/VMClassLoader.java java/lang/VMCompiler.java \ + java/lang/VMSecurityManager.java java/lang/VMThrowable.java \ + java/lang/Void.java java/io/BufferedInputStream.java \ java/io/BufferedOutputStream.java java/io/BufferedReader.java \ java/io/BufferedWriter.java java/io/ByteArrayInputStream.java \ java/io/ByteArrayOutputStream.java \ @@ -597,11 +598,12 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ gnu/gcj/runtime/FinalizerThread.java \ gnu/gcj/runtime/JNIWeakRef.java gnu/gcj/runtime/MethodRef.java \ gnu/gcj/runtime/NameFinder.java \ + gnu/gcj/runtime/PersistentByteMap.java \ gnu/gcj/runtime/SharedLibHelper.java \ gnu/gcj/runtime/SharedLibLoader.java \ gnu/gcj/runtime/StackTrace.java \ gnu/gcj/runtime/StringBuffer.java \ - gnu/gcj/runtime/VMClassLoader.java \ + gnu/gcj/runtime/VMClassLoader.java gnu/gcj/util/Debug.java \ gnu/java/io/ASN1ParsingException.java \ gnu/java/io/Base64InputStream.java \ gnu/java/io/ClassLoaderObjectInputStream.java \ @@ -2174,65 +2176,35 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ javax/print/attribute/TextSyntax.java \ javax/print/attribute/UnmodifiableSetException.java \ javax/print/attribute/URISyntax.java \ - javax/print/attribute/standard/ColorSupported.java \ - javax/print/attribute/standard/Compression.java \ javax/print/attribute/standard/Copies.java \ - javax/print/attribute/standard/CopiesSupported.java \ javax/print/attribute/standard/DateTimeAtCompleted.java \ javax/print/attribute/standard/DateTimeAtCreation.java \ javax/print/attribute/standard/DateTimeAtProcessing.java \ javax/print/attribute/standard/DocumentName.java \ - javax/print/attribute/standard/Fidelity.java \ - javax/print/attribute/standard/Finishings.java \ javax/print/attribute/standard/JobHoldUntil.java \ javax/print/attribute/standard/JobImpressions.java \ javax/print/attribute/standard/JobImpressionsCompleted.java \ - javax/print/attribute/standard/JobImpressionsSupported.java \ javax/print/attribute/standard/JobKOctets.java \ javax/print/attribute/standard/JobKOctetsProcessed.java \ - javax/print/attribute/standard/JobKOctetsSupported.java \ javax/print/attribute/standard/JobMediaSheets.java \ javax/print/attribute/standard/JobMediaSheetsCompleted.java \ - javax/print/attribute/standard/JobMediaSheetsSupported.java \ javax/print/attribute/standard/JobMessageFromOperator.java \ javax/print/attribute/standard/JobName.java \ javax/print/attribute/standard/JobOriginatingUserName.java \ javax/print/attribute/standard/JobPriority.java \ javax/print/attribute/standard/JobPrioritySupported.java \ - javax/print/attribute/standard/JobSheets.java \ - javax/print/attribute/standard/JobState.java \ - javax/print/attribute/standard/JobStateReason.java \ - javax/print/attribute/standard/JobStateReasons.java \ - javax/print/attribute/standard/Media.java \ - javax/print/attribute/standard/MediaSizeName.java \ - javax/print/attribute/standard/MultipleDocumentHandling.java \ javax/print/attribute/standard/NumberOfDocuments.java \ javax/print/attribute/standard/NumberOfInterveningJobs.java \ javax/print/attribute/standard/NumberUp.java \ - javax/print/attribute/standard/NumberUpSupported.java \ - javax/print/attribute/standard/OrientationRequested.java \ javax/print/attribute/standard/OutputDeviceAssigned.java \ - javax/print/attribute/standard/PDLOverrideSupported.java \ - javax/print/attribute/standard/PageRanges.java \ javax/print/attribute/standard/PagesPerMinute.java \ javax/print/attribute/standard/PagesPerMinuteColor.java \ - javax/print/attribute/standard/PresentationDirection.java \ - javax/print/attribute/standard/PrintQuality.java \ javax/print/attribute/standard/PrinterInfo.java \ - javax/print/attribute/standard/PrinterIsAcceptingJobs.java \ javax/print/attribute/standard/PrinterLocation.java \ javax/print/attribute/standard/PrinterMakeAndModel.java \ javax/print/attribute/standard/PrinterMessageFromOperator.java \ - javax/print/attribute/standard/PrinterMoreInfo.java \ - javax/print/attribute/standard/PrinterMoreInfoManufacturer.java \ javax/print/attribute/standard/PrinterName.java \ - javax/print/attribute/standard/PrinterResolution.java \ - javax/print/attribute/standard/PrinterState.java \ - javax/print/attribute/standard/PrinterStateReason.java \ - javax/print/attribute/standard/PrinterStateReasons.java \ - javax/print/attribute/standard/PrinterURI.java \ javax/print/attribute/standard/QueuedJobCount.java \ - javax/print/attribute/standard/ReferenceUriSchemesSupported.java \ javax/print/attribute/standard/RequestingUserName.java \ javax/print/attribute/standard/Severity.java \ javax/print/attribute/standard/SheetCollate.java \ @@ -2337,7 +2309,7 @@ am__objects_6 = gnu/gcj/natCore.lo \ gnu/gcj/runtime/natSharedLibLoader.lo \ gnu/gcj/runtime/natStackTrace.lo \ gnu/gcj/runtime/natStringBuffer.lo \ - gnu/gcj/runtime/natVMClassLoader.lo \ + gnu/gcj/runtime/natVMClassLoader.lo gnu/gcj/util/natDebug.lo \ gnu/java/lang/natMainThread.lo \ gnu/java/net/natPlainDatagramSocketImpl.lo \ gnu/java/net/natPlainSocketImpl.lo \ @@ -2428,11 +2400,11 @@ am__objects_9 = java/lang/AbstractMethodError.lo \ java/lang/UnsupportedClassVersionError.lo \ java/lang/UnsupportedOperationException.lo \ java/lang/VerifyError.lo java/lang/VirtualMachineError.lo \ - java/lang/VMClassLoader.lo java/lang/VMSecurityManager.lo \ - java/lang/VMThrowable.lo java/lang/Void.lo \ - java/io/BufferedInputStream.lo java/io/BufferedOutputStream.lo \ - java/io/BufferedReader.lo java/io/BufferedWriter.lo \ - java/io/ByteArrayInputStream.lo \ + java/lang/VMClassLoader.lo java/lang/VMCompiler.lo \ + java/lang/VMSecurityManager.lo java/lang/VMThrowable.lo \ + java/lang/Void.lo java/io/BufferedInputStream.lo \ + java/io/BufferedOutputStream.lo java/io/BufferedReader.lo \ + java/io/BufferedWriter.lo java/io/ByteArrayInputStream.lo \ java/io/ByteArrayOutputStream.lo java/io/CharArrayReader.lo \ java/io/CharArrayWriter.lo java/io/CharConversionException.lo \ java/io/DataInput.lo java/io/DataInputStream.lo \ @@ -3435,65 +3407,35 @@ am__objects_13 = javax/accessibility/Accessible.lo \ javax/print/attribute/TextSyntax.lo \ javax/print/attribute/UnmodifiableSetException.lo \ javax/print/attribute/URISyntax.lo \ - javax/print/attribute/standard/ColorSupported.lo \ - javax/print/attribute/standard/Compression.lo \ javax/print/attribute/standard/Copies.lo \ - javax/print/attribute/standard/CopiesSupported.lo \ javax/print/attribute/standard/DateTimeAtCompleted.lo \ javax/print/attribute/standard/DateTimeAtCreation.lo \ javax/print/attribute/standard/DateTimeAtProcessing.lo \ javax/print/attribute/standard/DocumentName.lo \ - javax/print/attribute/standard/Fidelity.lo \ - javax/print/attribute/standard/Finishings.lo \ javax/print/attribute/standard/JobHoldUntil.lo \ javax/print/attribute/standard/JobImpressions.lo \ javax/print/attribute/standard/JobImpressionsCompleted.lo \ - javax/print/attribute/standard/JobImpressionsSupported.lo \ javax/print/attribute/standard/JobKOctets.lo \ javax/print/attribute/standard/JobKOctetsProcessed.lo \ - javax/print/attribute/standard/JobKOctetsSupported.lo \ javax/print/attribute/standard/JobMediaSheets.lo \ javax/print/attribute/standard/JobMediaSheetsCompleted.lo \ - javax/print/attribute/standard/JobMediaSheetsSupported.lo \ javax/print/attribute/standard/JobMessageFromOperator.lo \ javax/print/attribute/standard/JobName.lo \ javax/print/attribute/standard/JobOriginatingUserName.lo \ javax/print/attribute/standard/JobPriority.lo \ javax/print/attribute/standard/JobPrioritySupported.lo \ - javax/print/attribute/standard/JobSheets.lo \ - javax/print/attribute/standard/JobState.lo \ - javax/print/attribute/standard/JobStateReason.lo \ - javax/print/attribute/standard/JobStateReasons.lo \ - javax/print/attribute/standard/Media.lo \ - javax/print/attribute/standard/MediaSizeName.lo \ - javax/print/attribute/standard/MultipleDocumentHandling.lo \ javax/print/attribute/standard/NumberOfDocuments.lo \ javax/print/attribute/standard/NumberOfInterveningJobs.lo \ javax/print/attribute/standard/NumberUp.lo \ - javax/print/attribute/standard/NumberUpSupported.lo \ - javax/print/attribute/standard/OrientationRequested.lo \ javax/print/attribute/standard/OutputDeviceAssigned.lo \ - javax/print/attribute/standard/PDLOverrideSupported.lo \ - javax/print/attribute/standard/PageRanges.lo \ javax/print/attribute/standard/PagesPerMinute.lo \ javax/print/attribute/standard/PagesPerMinuteColor.lo \ - javax/print/attribute/standard/PresentationDirection.lo \ - javax/print/attribute/standard/PrintQuality.lo \ javax/print/attribute/standard/PrinterInfo.lo \ - javax/print/attribute/standard/PrinterIsAcceptingJobs.lo \ javax/print/attribute/standard/PrinterLocation.lo \ javax/print/attribute/standard/PrinterMakeAndModel.lo \ javax/print/attribute/standard/PrinterMessageFromOperator.lo \ - javax/print/attribute/standard/PrinterMoreInfo.lo \ - javax/print/attribute/standard/PrinterMoreInfoManufacturer.lo \ javax/print/attribute/standard/PrinterName.lo \ - javax/print/attribute/standard/PrinterResolution.lo \ - javax/print/attribute/standard/PrinterState.lo \ - javax/print/attribute/standard/PrinterStateReason.lo \ - javax/print/attribute/standard/PrinterStateReasons.lo \ - javax/print/attribute/standard/PrinterURI.lo \ javax/print/attribute/standard/QueuedJobCount.lo \ - javax/print/attribute/standard/ReferenceUriSchemesSupported.lo \ javax/print/attribute/standard/RequestingUserName.lo \ javax/print/attribute/standard/Severity.lo \ javax/print/attribute/standard/SheetCollate.lo \ @@ -3585,10 +3527,11 @@ am__objects_14 = $(am__objects_9) gnu/classpath/ServiceFactory.lo \ gnu/gcj/runtime/FinalizerThread.lo \ gnu/gcj/runtime/JNIWeakRef.lo gnu/gcj/runtime/MethodRef.lo \ gnu/gcj/runtime/NameFinder.lo \ + gnu/gcj/runtime/PersistentByteMap.lo \ gnu/gcj/runtime/SharedLibHelper.lo \ gnu/gcj/runtime/SharedLibLoader.lo \ gnu/gcj/runtime/StackTrace.lo gnu/gcj/runtime/StringBuffer.lo \ - gnu/gcj/runtime/VMClassLoader.lo \ + gnu/gcj/runtime/VMClassLoader.lo gnu/gcj/util/Debug.lo \ gnu/java/io/ASN1ParsingException.lo \ gnu/java/io/Base64InputStream.lo \ gnu/java/io/ClassLoaderObjectInputStream.lo \ @@ -4151,7 +4094,7 @@ am__objects_16 = java/lang/ConcreteProcess.lo \ @USING_POSIX_THREADS_TRUE@am__objects_24 = posix-threads.lo @USING_WIN32_THREADS_TRUE@am__objects_25 = win32-threads.lo @USING_NO_THREADS_TRUE@am__objects_26 = no-threads.lo -am_libgcj_la_OBJECTS = prims.lo jni.lo exception.lo resolve.lo \ +am_libgcj_la_OBJECTS = prims.lo jni.lo exception.lo link.lo \ defineclass.lo interpret.lo verify.lo $(am__objects_6) \ $(am__objects_7) $(am__objects_15) $(am__objects_16) \ $(am__objects_17) $(am__objects_18) $(am__objects_19) \ @@ -4163,6 +4106,8 @@ am_libgij_la_OBJECTS = gij.lo libgij_la_OBJECTS = $(am_libgij_la_OBJECTS) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_gcj_dbtool_OBJECTS = gnu/gcj/tools/gcj_dbtool/Main.$(OBJEXT) +gcj_dbtool_OBJECTS = $(am_gcj_dbtool_OBJECTS) am__gen_from_JIS_SOURCES_DIST = gnu/gcj/convert/gen-from-JIS.c \ gnu/gcj/convert/make-trie.c @MAINTAINER_MODE_TRUE@@NATIVE_TRUE@am_gen_from_JIS_OBJECTS = gnu/gcj/convert/gen-from-JIS.$(OBJEXT) \ @@ -4206,15 +4151,16 @@ SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) \ $(lib_gnu_java_awt_peer_gtk_la_SOURCES) \ $(lib_org_ietf_jgss_la_SOURCES) $(lib_org_w3c_dom_la_SOURCES) \ $(lib_org_xml_sax_la_SOURCES) $(libgcj_la_SOURCES) \ - $(libgij_la_SOURCES) $(gen_from_JIS_SOURCES) $(gij_SOURCES) \ - $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) + $(libgij_la_SOURCES) $(gcj_dbtool_SOURCES) \ + $(gen_from_JIS_SOURCES) $(gij_SOURCES) $(grmic_SOURCES) \ + $(grmiregistry_SOURCES) $(jv_convert_SOURCES) DIST_SOURCES = $(lib_gnu_awt_xlib_la_SOURCES) \ $(am__lib_gnu_java_awt_peer_gtk_la_SOURCES_DIST) \ $(lib_org_ietf_jgss_la_SOURCES) $(lib_org_w3c_dom_la_SOURCES) \ $(lib_org_xml_sax_la_SOURCES) $(am__libgcj_la_SOURCES_DIST) \ - $(libgij_la_SOURCES) $(am__gen_from_JIS_SOURCES_DIST) \ - $(gij_SOURCES) $(grmic_SOURCES) $(grmiregistry_SOURCES) \ - $(jv_convert_SOURCES) + $(libgij_la_SOURCES) $(gcj_dbtool_SOURCES) \ + $(am__gen_from_JIS_SOURCES_DIST) $(gij_SOURCES) \ + $(grmic_SOURCES) $(grmiregistry_SOURCES) $(jv_convert_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-exec-recursive install-info-recursive \ @@ -4314,6 +4260,7 @@ LIBGCJTESTSPEC = @LIBGCJTESTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ +LIBGCJ_LD_SYMBOLIC = @LIBGCJ_LD_SYMBOLIC@ LIBICONV = @LIBICONV@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ @@ -4546,7 +4493,7 @@ libgij_la_SOURCES = gij.cc libgij_la_LIBADD = libgcj.la libgij_la_DEPENDENCIES = libgcj.la libgcj.spec libgcj_la_SOURCES = prims.cc jni.cc exception.cc \ - resolve.cc defineclass.cc interpret.cc verify.cc \ + link.cc defineclass.cc interpret.cc verify.cc \ $(nat_source_files) $(math_c_source_files) $(java_source_files) \ $(built_java_source_files) \ $(BOEHMGC_SRC) $(NOGC_SRC) \ @@ -4686,7 +4633,7 @@ lib_gnu_java_awt_peer_gtk_la_GCJFLAGS = $(AM_GCJFLAGS) -fjni lib_gnu_java_awt_peer_gtk_la_LIBADD = $(GTK_LIBS) $(GLIB_LIBS) $(LIBART_LIBS) $(CAIRO_LIBS) $(PANGOFT2_LIBS) lib_gnu_java_awt_peer_gtk_la_DEPENDENCIES = $(gtk_jni_headers) libgcj-@gcc_version@.jar libgcj.la libgcj.spec lib_gnu_java_awt_peer_gtk_la_LDFLAGS = \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_java_awt_peer_gtk_la_LINK = $(LIBLINK) lib_org_ietf_jgss_la_SOURCES = \ @@ -4706,7 +4653,7 @@ lib_org_ietf_jgss_la_LIBADD = -L$(here)/.libs $(jgss_propertyo_files) \ libgcj.la lib_org_ietf_jgss_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_org_w3c_dom_la_SOURCES = org/w3c/dom/Attr.java \ org/w3c/dom/CDATASection.java \ @@ -4736,7 +4683,7 @@ org/w3c/dom/traversal/TreeWalker.java lib_org_w3c_dom_la_LIBADD = -L$(here)/.libs libgcj.la lib_org_w3c_dom_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_org_xml_sax_la_SOURCES = org/xml/sax/ext/DeclHandler.java \ org/xml/sax/ext/LexicalHandler.java \ @@ -4771,7 +4718,7 @@ org/xml/sax/XMLReader.java lib_org_xml_sax_la_LIBADD = -L$(here)/.libs libgcj.la lib_org_xml_sax_la_LDFLAGS = -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_awt_xlib_la_SOURCES = \ $(xlib_java_source_files) \ @@ -4787,7 +4734,7 @@ lib_gnu_awt_xlib_la_CPPFLAGS = \ lib_gnu_awt_xlib_la_LDFLAGS = ../libstdc++-v3/src/libstdc++.la \ @X_PRE_LIBS@ @X_LIBS@ -lX11 @X_EXTRA_LIBS@ \ -rpath $(toolexeclibdir) \ - -version-info `grep -v '^\#' $(srcdir)/libtool-version` + -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(LIBGCJ_LD_SYMBOLIC) lib_gnu_awt_xlib_la_LINK = $(LIBLINK) all_java_source_files = \ @@ -4851,6 +4798,13 @@ jv_convert_LDFLAGS = --main=gnu.gcj.convert.Convert \ jv_convert_LINK = $(GCJLINK) jv_convert_LDADD = -L$(here)/.libs libgcj.la jv_convert_DEPENDENCIES = libgcj.la libgcj.spec +gcj_dbtool_SOURCES = gnu/gcj/tools/gcj_dbtool/Main.java +gcj_dbtool_LDFLAGS = --main=gnu.gcj.tools.gcj_dbtool.Main \ + -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS) + +gcj_dbtool_LINK = $(GCJLINK) +gcj_dbtool_LDADD = -L$(here)/.libs libgcj.la +gcj_dbtool_DEPENDENCIES = libgcj.la libgcj.spec gij_SOURCES = gij_LDFLAGS = -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS) gij_LINK = $(GCJLINK) @@ -6022,65 +5976,35 @@ javax/print/attribute/SupportedValuesAttribute.java \ javax/print/attribute/TextSyntax.java \ javax/print/attribute/UnmodifiableSetException.java \ javax/print/attribute/URISyntax.java \ -javax/print/attribute/standard/ColorSupported.java \ -javax/print/attribute/standard/Compression.java \ javax/print/attribute/standard/Copies.java \ -javax/print/attribute/standard/CopiesSupported.java \ javax/print/attribute/standard/DateTimeAtCompleted.java \ javax/print/attribute/standard/DateTimeAtCreation.java \ javax/print/attribute/standard/DateTimeAtProcessing.java \ javax/print/attribute/standard/DocumentName.java \ -javax/print/attribute/standard/Fidelity.java \ -javax/print/attribute/standard/Finishings.java \ javax/print/attribute/standard/JobHoldUntil.java \ javax/print/attribute/standard/JobImpressions.java \ javax/print/attribute/standard/JobImpressionsCompleted.java \ -javax/print/attribute/standard/JobImpressionsSupported.java \ javax/print/attribute/standard/JobKOctets.java \ javax/print/attribute/standard/JobKOctetsProcessed.java \ -javax/print/attribute/standard/JobKOctetsSupported.java \ javax/print/attribute/standard/JobMediaSheets.java \ javax/print/attribute/standard/JobMediaSheetsCompleted.java \ -javax/print/attribute/standard/JobMediaSheetsSupported.java \ javax/print/attribute/standard/JobMessageFromOperator.java \ javax/print/attribute/standard/JobName.java \ javax/print/attribute/standard/JobOriginatingUserName.java \ javax/print/attribute/standard/JobPriority.java \ javax/print/attribute/standard/JobPrioritySupported.java \ -javax/print/attribute/standard/JobSheets.java \ -javax/print/attribute/standard/JobState.java \ -javax/print/attribute/standard/JobStateReason.java \ -javax/print/attribute/standard/JobStateReasons.java \ -javax/print/attribute/standard/Media.java \ -javax/print/attribute/standard/MediaSizeName.java \ -javax/print/attribute/standard/MultipleDocumentHandling.java \ javax/print/attribute/standard/NumberOfDocuments.java \ javax/print/attribute/standard/NumberOfInterveningJobs.java \ javax/print/attribute/standard/NumberUp.java \ -javax/print/attribute/standard/NumberUpSupported.java \ -javax/print/attribute/standard/OrientationRequested.java \ javax/print/attribute/standard/OutputDeviceAssigned.java \ -javax/print/attribute/standard/PDLOverrideSupported.java \ -javax/print/attribute/standard/PageRanges.java \ javax/print/attribute/standard/PagesPerMinute.java \ javax/print/attribute/standard/PagesPerMinuteColor.java \ -javax/print/attribute/standard/PresentationDirection.java \ -javax/print/attribute/standard/PrintQuality.java \ javax/print/attribute/standard/PrinterInfo.java \ -javax/print/attribute/standard/PrinterIsAcceptingJobs.java \ javax/print/attribute/standard/PrinterLocation.java \ javax/print/attribute/standard/PrinterMakeAndModel.java \ javax/print/attribute/standard/PrinterMessageFromOperator.java \ -javax/print/attribute/standard/PrinterMoreInfo.java \ -javax/print/attribute/standard/PrinterMoreInfoManufacturer.java \ javax/print/attribute/standard/PrinterName.java \ -javax/print/attribute/standard/PrinterResolution.java \ -javax/print/attribute/standard/PrinterState.java \ -javax/print/attribute/standard/PrinterStateReason.java \ -javax/print/attribute/standard/PrinterStateReasons.java \ -javax/print/attribute/standard/PrinterURI.java \ javax/print/attribute/standard/QueuedJobCount.java \ -javax/print/attribute/standard/ReferenceUriSchemesSupported.java \ javax/print/attribute/standard/RequestingUserName.java \ javax/print/attribute/standard/Severity.java \ javax/print/attribute/standard/SheetCollate.java \ @@ -6255,6 +6179,7 @@ java/lang/UnsupportedOperationException.java \ java/lang/VerifyError.java \ java/lang/VirtualMachineError.java \ java/lang/VMClassLoader.java \ +java/lang/VMCompiler.java \ java/lang/VMSecurityManager.java \ java/lang/VMThrowable.java \ java/lang/Void.java \ @@ -6437,11 +6362,13 @@ gnu/gcj/runtime/FinalizerThread.java \ gnu/gcj/runtime/JNIWeakRef.java \ gnu/gcj/runtime/MethodRef.java \ gnu/gcj/runtime/NameFinder.java \ +gnu/gcj/runtime/PersistentByteMap.java \ gnu/gcj/runtime/SharedLibHelper.java \ gnu/gcj/runtime/SharedLibLoader.java \ gnu/gcj/runtime/StackTrace.java \ gnu/gcj/runtime/StringBuffer.java \ gnu/gcj/runtime/VMClassLoader.java \ +gnu/gcj/util/Debug.java \ gnu/java/io/ASN1ParsingException.java \ gnu/java/io/Base64InputStream.java \ gnu/java/io/ClassLoaderObjectInputStream.java \ @@ -7147,6 +7074,7 @@ gnu/gcj/runtime/natSharedLibLoader.cc \ gnu/gcj/runtime/natStackTrace.cc \ gnu/gcj/runtime/natStringBuffer.cc \ gnu/gcj/runtime/natVMClassLoader.cc \ +gnu/gcj/util/natDebug.cc \ gnu/java/lang/natMainThread.cc \ gnu/java/net/natPlainDatagramSocketImpl.cc \ gnu/java/net/natPlainSocketImpl.cc \ @@ -8042,6 +7970,14 @@ gnu/gcj/runtime/natStringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) gnu/gcj/runtime/natVMClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/util/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/util + @: > gnu/gcj/util/$(am__dirstamp) +gnu/gcj/util/$(DEPDIR)/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/util/$(DEPDIR) + @: > gnu/gcj/util/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/util/natDebug.lo: gnu/gcj/util/$(am__dirstamp) \ + gnu/gcj/util/$(DEPDIR)/$(am__dirstamp) gnu/java/lang/$(am__dirstamp): @$(mkdir_p) gnu/java/lang @: > gnu/java/lang/$(am__dirstamp) @@ -8456,6 +8392,8 @@ java/lang/VirtualMachineError.lo: java/lang/$(am__dirstamp) \ java/lang/$(DEPDIR)/$(am__dirstamp) java/lang/VMClassLoader.lo: java/lang/$(am__dirstamp) \ java/lang/$(DEPDIR)/$(am__dirstamp) +java/lang/VMCompiler.lo: java/lang/$(am__dirstamp) \ + java/lang/$(DEPDIR)/$(am__dirstamp) java/lang/VMSecurityManager.lo: java/lang/$(am__dirstamp) \ java/lang/$(DEPDIR)/$(am__dirstamp) java/lang/VMThrowable.lo: java/lang/$(am__dirstamp) \ @@ -8852,6 +8790,8 @@ gnu/gcj/runtime/MethodRef.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) gnu/gcj/runtime/NameFinder.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/runtime/PersistentByteMap.lo: gnu/gcj/runtime/$(am__dirstamp) \ + gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) gnu/gcj/runtime/SharedLibHelper.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) gnu/gcj/runtime/SharedLibLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \ @@ -8862,6 +8802,8 @@ gnu/gcj/runtime/StringBuffer.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) gnu/gcj/runtime/VMClassLoader.lo: gnu/gcj/runtime/$(am__dirstamp) \ gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/util/Debug.lo: gnu/gcj/util/$(am__dirstamp) \ + gnu/gcj/util/$(DEPDIR)/$(am__dirstamp) gnu/java/io/$(am__dirstamp): @$(mkdir_p) gnu/java/io @: > gnu/java/io/$(am__dirstamp) @@ -13836,18 +13778,9 @@ javax/print/attribute/standard/$(am__dirstamp): javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp): @$(mkdir_p) javax/print/attribute/standard/$(DEPDIR) @: > javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/ColorSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/Compression.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/Copies.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/CopiesSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/DateTimeAtCompleted.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -13860,12 +13793,6 @@ javax/print/attribute/standard/DateTimeAtProcessing.lo: \ javax/print/attribute/standard/DocumentName.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/Fidelity.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/Finishings.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobHoldUntil.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -13875,27 +13802,18 @@ javax/print/attribute/standard/JobImpressions.lo: \ javax/print/attribute/standard/JobImpressionsCompleted.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobImpressionsSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobKOctets.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobKOctetsProcessed.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobKOctetsSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobMediaSheets.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobMediaSheetsCompleted.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobMediaSheetsSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/JobMessageFromOperator.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -13911,27 +13829,6 @@ javax/print/attribute/standard/JobPriority.lo: \ javax/print/attribute/standard/JobPrioritySupported.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobSheets.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobState.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobStateReason.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/JobStateReasons.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/Media.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/MediaSizeName.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/MultipleDocumentHandling.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/NumberOfDocuments.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -13941,39 +13838,18 @@ javax/print/attribute/standard/NumberOfInterveningJobs.lo: \ javax/print/attribute/standard/NumberUp.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/NumberUpSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/OrientationRequested.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/OutputDeviceAssigned.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PDLOverrideSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PageRanges.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/PagesPerMinute.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/PagesPerMinuteColor.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PresentationDirection.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrintQuality.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/PrinterInfo.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterIsAcceptingJobs.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/PrinterLocation.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -13983,36 +13859,12 @@ javax/print/attribute/standard/PrinterMakeAndModel.lo: \ javax/print/attribute/standard/PrinterMessageFromOperator.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterMoreInfo.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterMoreInfoManufacturer.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/PrinterName.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterResolution.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterState.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterStateReason.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterStateReasons.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/PrinterURI.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/QueuedJobCount.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) -javax/print/attribute/standard/ReferenceUriSchemesSupported.lo: \ - javax/print/attribute/standard/$(am__dirstamp) \ - javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) javax/print/attribute/standard/RequestingUserName.lo: \ javax/print/attribute/standard/$(am__dirstamp) \ javax/print/attribute/standard/$(DEPDIR)/$(am__dirstamp) @@ -14379,6 +14231,18 @@ clean-noinstPROGRAMS: echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done +gnu/gcj/tools/gcj_dbtool/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/tools/gcj_dbtool + @: > gnu/gcj/tools/gcj_dbtool/$(am__dirstamp) +gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/$(am__dirstamp): + @$(mkdir_p) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) + @: > gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/$(am__dirstamp) +gnu/gcj/tools/gcj_dbtool/Main.$(OBJEXT): \ + gnu/gcj/tools/gcj_dbtool/$(am__dirstamp) \ + gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/$(am__dirstamp) +gcj-dbtool$(EXEEXT): $(gcj_dbtool_OBJECTS) $(gcj_dbtool_DEPENDENCIES) + @rm -f gcj-dbtool$(EXEEXT) + $(gcj_dbtool_LINK) $(gcj_dbtool_LDFLAGS) $(gcj_dbtool_OBJECTS) $(gcj_dbtool_LDADD) $(LIBS) gnu/gcj/convert/gen-from-JIS.$(OBJEXT): \ gnu/gcj/convert/$(am__dirstamp) \ gnu/gcj/convert/$(DEPDIR)/$(am__dirstamp) @@ -14549,6 +14413,8 @@ mostlyclean-compile: -rm -f gnu/gcj/runtime/MethodRef.lo -rm -f gnu/gcj/runtime/NameFinder.$(OBJEXT) -rm -f gnu/gcj/runtime/NameFinder.lo + -rm -f gnu/gcj/runtime/PersistentByteMap.$(OBJEXT) + -rm -f gnu/gcj/runtime/PersistentByteMap.lo -rm -f gnu/gcj/runtime/SharedLibHelper.$(OBJEXT) -rm -f gnu/gcj/runtime/SharedLibHelper.lo -rm -f gnu/gcj/runtime/SharedLibLoader.$(OBJEXT) @@ -14571,6 +14437,11 @@ mostlyclean-compile: -rm -f gnu/gcj/runtime/natStringBuffer.lo -rm -f gnu/gcj/runtime/natVMClassLoader.$(OBJEXT) -rm -f gnu/gcj/runtime/natVMClassLoader.lo + -rm -f gnu/gcj/tools/gcj_dbtool/Main.$(OBJEXT) + -rm -f gnu/gcj/util/Debug.$(OBJEXT) + -rm -f gnu/gcj/util/Debug.lo + -rm -f gnu/gcj/util/natDebug.$(OBJEXT) + -rm -f gnu/gcj/util/natDebug.lo -rm -f gnu/gcj/xlib/Clip.$(OBJEXT) -rm -f gnu/gcj/xlib/Clip.lo -rm -f gnu/gcj/xlib/Colormap.$(OBJEXT) @@ -16531,6 +16402,8 @@ mostlyclean-compile: -rm -f java/lang/UnsupportedOperationException.lo -rm -f java/lang/VMClassLoader.$(OBJEXT) -rm -f java/lang/VMClassLoader.lo + -rm -f java/lang/VMCompiler.$(OBJEXT) + -rm -f java/lang/VMCompiler.lo -rm -f java/lang/VMSecurityManager.$(OBJEXT) -rm -f java/lang/VMSecurityManager.lo -rm -f java/lang/VMThrowable.$(OBJEXT) @@ -18259,14 +18132,8 @@ mostlyclean-compile: -rm -f javax/print/attribute/URISyntax.lo -rm -f javax/print/attribute/UnmodifiableSetException.$(OBJEXT) -rm -f javax/print/attribute/UnmodifiableSetException.lo - -rm -f javax/print/attribute/standard/ColorSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/ColorSupported.lo - -rm -f javax/print/attribute/standard/Compression.$(OBJEXT) - -rm -f javax/print/attribute/standard/Compression.lo -rm -f javax/print/attribute/standard/Copies.$(OBJEXT) -rm -f javax/print/attribute/standard/Copies.lo - -rm -f javax/print/attribute/standard/CopiesSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/CopiesSupported.lo -rm -f javax/print/attribute/standard/DateTimeAtCompleted.$(OBJEXT) -rm -f javax/print/attribute/standard/DateTimeAtCompleted.lo -rm -f javax/print/attribute/standard/DateTimeAtCreation.$(OBJEXT) @@ -18275,30 +18142,20 @@ mostlyclean-compile: -rm -f javax/print/attribute/standard/DateTimeAtProcessing.lo -rm -f javax/print/attribute/standard/DocumentName.$(OBJEXT) -rm -f javax/print/attribute/standard/DocumentName.lo - -rm -f javax/print/attribute/standard/Fidelity.$(OBJEXT) - -rm -f javax/print/attribute/standard/Fidelity.lo - -rm -f javax/print/attribute/standard/Finishings.$(OBJEXT) - -rm -f javax/print/attribute/standard/Finishings.lo -rm -f javax/print/attribute/standard/JobHoldUntil.$(OBJEXT) -rm -f javax/print/attribute/standard/JobHoldUntil.lo -rm -f javax/print/attribute/standard/JobImpressions.$(OBJEXT) -rm -f javax/print/attribute/standard/JobImpressions.lo -rm -f javax/print/attribute/standard/JobImpressionsCompleted.$(OBJEXT) -rm -f javax/print/attribute/standard/JobImpressionsCompleted.lo - -rm -f javax/print/attribute/standard/JobImpressionsSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobImpressionsSupported.lo -rm -f javax/print/attribute/standard/JobKOctets.$(OBJEXT) -rm -f javax/print/attribute/standard/JobKOctets.lo -rm -f javax/print/attribute/standard/JobKOctetsProcessed.$(OBJEXT) -rm -f javax/print/attribute/standard/JobKOctetsProcessed.lo - -rm -f javax/print/attribute/standard/JobKOctetsSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobKOctetsSupported.lo -rm -f javax/print/attribute/standard/JobMediaSheets.$(OBJEXT) -rm -f javax/print/attribute/standard/JobMediaSheets.lo -rm -f javax/print/attribute/standard/JobMediaSheetsCompleted.$(OBJEXT) -rm -f javax/print/attribute/standard/JobMediaSheetsCompleted.lo - -rm -f javax/print/attribute/standard/JobMediaSheetsSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobMediaSheetsSupported.lo -rm -f javax/print/attribute/standard/JobMessageFromOperator.$(OBJEXT) -rm -f javax/print/attribute/standard/JobMessageFromOperator.lo -rm -f javax/print/attribute/standard/JobName.$(OBJEXT) @@ -18309,74 +18166,30 @@ mostlyclean-compile: -rm -f javax/print/attribute/standard/JobPriority.lo -rm -f javax/print/attribute/standard/JobPrioritySupported.$(OBJEXT) -rm -f javax/print/attribute/standard/JobPrioritySupported.lo - -rm -f javax/print/attribute/standard/JobSheets.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobSheets.lo - -rm -f javax/print/attribute/standard/JobState.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobState.lo - -rm -f javax/print/attribute/standard/JobStateReason.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobStateReason.lo - -rm -f javax/print/attribute/standard/JobStateReasons.$(OBJEXT) - -rm -f javax/print/attribute/standard/JobStateReasons.lo - -rm -f javax/print/attribute/standard/Media.$(OBJEXT) - -rm -f javax/print/attribute/standard/Media.lo - -rm -f javax/print/attribute/standard/MediaSizeName.$(OBJEXT) - -rm -f javax/print/attribute/standard/MediaSizeName.lo - -rm -f javax/print/attribute/standard/MultipleDocumentHandling.$(OBJEXT) - -rm -f javax/print/attribute/standard/MultipleDocumentHandling.lo -rm -f javax/print/attribute/standard/NumberOfDocuments.$(OBJEXT) -rm -f javax/print/attribute/standard/NumberOfDocuments.lo -rm -f javax/print/attribute/standard/NumberOfInterveningJobs.$(OBJEXT) -rm -f javax/print/attribute/standard/NumberOfInterveningJobs.lo -rm -f javax/print/attribute/standard/NumberUp.$(OBJEXT) -rm -f javax/print/attribute/standard/NumberUp.lo - -rm -f javax/print/attribute/standard/NumberUpSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/NumberUpSupported.lo - -rm -f javax/print/attribute/standard/OrientationRequested.$(OBJEXT) - -rm -f javax/print/attribute/standard/OrientationRequested.lo -rm -f javax/print/attribute/standard/OutputDeviceAssigned.$(OBJEXT) -rm -f javax/print/attribute/standard/OutputDeviceAssigned.lo - -rm -f javax/print/attribute/standard/PDLOverrideSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/PDLOverrideSupported.lo - -rm -f javax/print/attribute/standard/PageRanges.$(OBJEXT) - -rm -f javax/print/attribute/standard/PageRanges.lo -rm -f javax/print/attribute/standard/PagesPerMinute.$(OBJEXT) -rm -f javax/print/attribute/standard/PagesPerMinute.lo -rm -f javax/print/attribute/standard/PagesPerMinuteColor.$(OBJEXT) -rm -f javax/print/attribute/standard/PagesPerMinuteColor.lo - -rm -f javax/print/attribute/standard/PresentationDirection.$(OBJEXT) - -rm -f javax/print/attribute/standard/PresentationDirection.lo - -rm -f javax/print/attribute/standard/PrintQuality.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrintQuality.lo -rm -f javax/print/attribute/standard/PrinterInfo.$(OBJEXT) -rm -f javax/print/attribute/standard/PrinterInfo.lo - -rm -f javax/print/attribute/standard/PrinterIsAcceptingJobs.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterIsAcceptingJobs.lo -rm -f javax/print/attribute/standard/PrinterLocation.$(OBJEXT) -rm -f javax/print/attribute/standard/PrinterLocation.lo -rm -f javax/print/attribute/standard/PrinterMakeAndModel.$(OBJEXT) -rm -f javax/print/attribute/standard/PrinterMakeAndModel.lo -rm -f javax/print/attribute/standard/PrinterMessageFromOperator.$(OBJEXT) -rm -f javax/print/attribute/standard/PrinterMessageFromOperator.lo - -rm -f javax/print/attribute/standard/PrinterMoreInfo.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterMoreInfo.lo - -rm -f javax/print/attribute/standard/PrinterMoreInfoManufacturer.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterMoreInfoManufacturer.lo -rm -f javax/print/attribute/standard/PrinterName.$(OBJEXT) -rm -f javax/print/attribute/standard/PrinterName.lo - -rm -f javax/print/attribute/standard/PrinterResolution.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterResolution.lo - -rm -f javax/print/attribute/standard/PrinterState.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterState.lo - -rm -f javax/print/attribute/standard/PrinterStateReason.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterStateReason.lo - -rm -f javax/print/attribute/standard/PrinterStateReasons.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterStateReasons.lo - -rm -f javax/print/attribute/standard/PrinterURI.$(OBJEXT) - -rm -f javax/print/attribute/standard/PrinterURI.lo -rm -f javax/print/attribute/standard/QueuedJobCount.$(OBJEXT) -rm -f javax/print/attribute/standard/QueuedJobCount.lo - -rm -f javax/print/attribute/standard/ReferenceUriSchemesSupported.$(OBJEXT) - -rm -f javax/print/attribute/standard/ReferenceUriSchemesSupported.lo -rm -f javax/print/attribute/standard/RequestingUserName.$(OBJEXT) -rm -f javax/print/attribute/standard/RequestingUserName.lo -rm -f javax/print/attribute/standard/Severity.$(OBJEXT) @@ -19490,12 +19303,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gij.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interpret.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jni.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/link.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/no-threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nogc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix-threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prims.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/verify.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32-threads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32.Plo@am__quote@ @@ -19564,6 +19377,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/JNIWeakRef.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/MethodRef.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/NameFinder.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/PersistentByteMap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibHelper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/SharedLibLoader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/StackTrace.Plo@am__quote@ @@ -19575,6 +19389,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStackTrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natStringBuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/runtime/$(DEPDIR)/natVMClassLoader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/Main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/util/$(DEPDIR)/Debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/util/$(DEPDIR)/natDebug.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/Clip.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/Colormap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/gcj/xlib/$(DEPDIR)/Display.Plo@am__quote@ @@ -20555,6 +20372,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/UnsupportedClassVersionError.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/UnsupportedOperationException.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/VMClassLoader.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/VMCompiler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/VMSecurityManager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/VMThrowable.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@java/lang/$(DEPDIR)/VerifyError.Plo@am__quote@ @@ -21419,65 +21237,35 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/$(DEPDIR)/TextSyntax.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/$(DEPDIR)/URISyntax.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/$(DEPDIR)/UnmodifiableSetException.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/ColorSupported.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Compression.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Copies.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/CopiesSupported.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/DateTimeAtCompleted.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/DateTimeAtCreation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/DateTimeAtProcessing.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/DocumentName.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Fidelity.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Finishings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobHoldUntil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobImpressions.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobImpressionsCompleted.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobImpressionsSupported.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobKOctets.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobKOctetsProcessed.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobKOctetsSupported.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobMediaSheets.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobMediaSheetsCompleted.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobMediaSheetsSupported.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobMessageFromOperator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobName.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobOriginatingUserName.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobPriority.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobPrioritySupported.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobSheets.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobState.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobStateReason.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/JobStateReasons.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Media.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/MediaSizeName.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/MultipleDocumentHandling.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/NumberOfDocuments.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/NumberOfInterveningJobs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/NumberUp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/NumberUpSupported.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/OrientationRequested.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/OutputDeviceAssigned.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PDLOverrideSupported.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PageRanges.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PagesPerMinute.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PagesPerMinuteColor.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PresentationDirection.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrintQuality.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterInfo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterIsAcceptingJobs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterLocation.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterMakeAndModel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterMessageFromOperator.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterMoreInfo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterMoreInfoManufacturer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterName.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterResolution.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterState.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterStateReason.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterStateReasons.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/PrinterURI.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/QueuedJobCount.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/ReferenceUriSchemesSupported.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/RequestingUserName.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/Severity.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@javax/print/attribute/standard/$(DEPDIR)/SheetCollate.Plo@am__quote@ @@ -22857,6 +22645,7 @@ clean-libtool: -rm -rf gnu/gcj/convert/.libs gnu/gcj/convert/_libs -rm -rf gnu/gcj/io/.libs gnu/gcj/io/_libs -rm -rf gnu/gcj/runtime/.libs gnu/gcj/runtime/_libs + -rm -rf gnu/gcj/util/.libs gnu/gcj/util/_libs -rm -rf gnu/gcj/xlib/.libs gnu/gcj/xlib/_libs -rm -rf gnu/java/awt/.libs gnu/java/awt/_libs -rm -rf gnu/java/awt/image/.libs gnu/java/awt/image/_libs @@ -23358,6 +23147,10 @@ distclean-generic: -rm -f gnu/gcj/io/$(am__dirstamp) -rm -f gnu/gcj/runtime/$(DEPDIR)/$(am__dirstamp) -rm -f gnu/gcj/runtime/$(am__dirstamp) + -rm -f gnu/gcj/tools/gcj_dbtool/$(DEPDIR)/$(am__dirstamp) + -rm -f gnu/gcj/tools/gcj_dbtool/$(am__dirstamp) + -rm -f gnu/gcj/util/$(DEPDIR)/$(am__dirstamp) + -rm -f gnu/gcj/util/$(am__dirstamp) -rm -f gnu/gcj/xlib/$(DEPDIR)/$(am__dirstamp) -rm -f gnu/gcj/xlib/$(am__dirstamp) -rm -f gnu/java/awt/$(DEPDIR)/$(am__dirstamp) @@ -23646,7 +23439,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \ distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf ./$(DEPDIR) gnu/awt/$(DEPDIR) gnu/awt/j2d/$(DEPDIR) gnu/awt/xlib/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/awt/$(DEPDIR) gnu/java/awt/image/$(DEPDIR) gnu/java/awt/peer/$(DEPDIR) gnu/java/awt/peer/gtk/$(DEPDIR) gnu/java/beans/$(DEPDIR) gnu/java/beans/editors/$(DEPDIR) gnu/java/beans/info/$(DEPDIR) gnu/java/io/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/lang/reflect/$(DEPDIR) gnu/java/locale/$(DEPDIR) gnu/java/math/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/net/protocol/file/$(DEPDIR) gnu/java/net/protocol/gcjlib/$(DEPDIR) gnu/java/net/protocol/http/$(DEPDIR) gnu/java/net/protocol/jar/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) gnu/java/nio/charset/$(DEPDIR) gnu/java/rmi/$(DEPDIR) gnu/java/rmi/dgc/$(DEPDIR) gnu/java/rmi/registry/$(DEPDIR) gnu/java/rmi/rmic/$(DEPDIR) gnu/java/rmi/server/$(DEPDIR) gnu/java/security/$(DEPDIR) gnu/java/security/action/$(DEPDIR) gnu/java/security/der/$(DEPDIR) gnu/java/security/provider/$(DEPDIR) gnu/java/security/util/$(DEPDIR) gnu/java/security/x509/$(DEPDIR) gnu/java/security/x509/ext/$(DEPDIR) gnu/java/text/$(DEPDIR) gnu/java/util/$(DEPDIR) gnu/java/util/prefs/$(DEPDIR) gnu/regexp/$(DEPDIR) java/applet/$(DEPDIR) java/awt/$(DEPDIR) java/awt/color/$(DEPDIR) java/awt/datatransfer/$(DEPDIR) java/awt/dnd/$(DEPDIR) java/awt/dnd/peer/$(DEPDIR) java/awt/event/$(DEPDIR) java/awt/font/$(DEPDIR) java/awt/geom/$(DEPDIR) java/awt/im/$(DEPDIR) java/awt/im/spi/$(DEPDIR) java/awt/image/$(DEPDIR) java/awt/image/renderable/$(DEPDIR) java/awt/peer/$(DEPDIR) java/awt/print/$(DEPDIR) java/beans/$(DEPDIR) java/beans/beancontext/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/math/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/nio/channels/spi/$(DEPDIR) java/nio/charset/$(DEPDIR) java/nio/charset/spi/$(DEPDIR) java/rmi/$(DEPDIR) java/rmi/activation/$(DEPDIR) java/rmi/dgc/$(DEPDIR) java/rmi/registry/$(DEPDIR) java/rmi/server/$(DEPDIR) java/security/$(DEPDIR) java/security/acl/$(DEPDIR) java/security/cert/$(DEPDIR) java/security/interfaces/$(DEPDIR) java/security/spec/$(DEPDIR) java/sql/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/jar/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/prefs/$(DEPDIR) java/util/regex/$(DEPDIR) java/util/zip/$(DEPDIR) javax/accessibility/$(DEPDIR) javax/crypto/$(DEPDIR) javax/crypto/interfaces/$(DEPDIR) javax/crypto/spec/$(DEPDIR) javax/imageio/$(DEPDIR) javax/imageio/event/$(DEPDIR) javax/imageio/metadata/$(DEPDIR) javax/imageio/spi/$(DEPDIR) javax/imageio/stream/$(DEPDIR) javax/naming/$(DEPDIR) javax/naming/directory/$(DEPDIR) javax/naming/event/$(DEPDIR) javax/naming/ldap/$(DEPDIR) javax/naming/spi/$(DEPDIR) javax/net/$(DEPDIR) javax/net/ssl/$(DEPDIR) javax/print/$(DEPDIR) javax/print/attribute/$(DEPDIR) javax/print/attribute/standard/$(DEPDIR) javax/print/event/$(DEPDIR) javax/security/auth/$(DEPDIR) javax/security/auth/callback/$(DEPDIR) javax/security/auth/login/$(DEPDIR) javax/security/auth/spi/$(DEPDIR) javax/security/auth/x500/$(DEPDIR) javax/security/cert/$(DEPDIR) javax/security/sasl/$(DEPDIR) javax/sql/$(DEPDIR) javax/swing/$(DEPDIR) javax/swing/border/$(DEPDIR) javax/swing/colorchooser/$(DEPDIR) javax/swing/event/$(DEPDIR) javax/swing/filechooser/$(DEPDIR) javax/swing/plaf/$(DEPDIR) javax/swing/plaf/basic/$(DEPDIR) javax/swing/plaf/metal/$(DEPDIR) javax/swing/table/$(DEPDIR) javax/swing/text/$(DEPDIR) javax/swing/text/html/$(DEPDIR) javax/swing/text/html/parser/$(DEPDIR) javax/swing/tree/$(DEPDIR) javax/swing/undo/$(DEPDIR) javax/transaction/$(DEPDIR) javax/transaction/xa/$(DEPDIR) jni/classpath/$(DEPDIR) jni/gtk-peer/$(DEPDIR) org/ietf/jgss/$(DEPDIR) org/w3c/dom/$(DEPDIR) org/w3c/dom/ranges/$(DEPDIR) org/w3c/dom/traversal/$(DEPDIR) org/xml/sax/$(DEPDIR) org/xml/sax/ext/$(DEPDIR) org/xml/sax/helpers/$(DEPDIR) sysdep/$(DEPDIR) + -rm -rf ./$(DEPDIR) gnu/awt/$(DEPDIR) gnu/awt/j2d/$(DEPDIR) gnu/awt/xlib/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/awt/$(DEPDIR) gnu/java/awt/image/$(DEPDIR) gnu/java/awt/peer/$(DEPDIR) gnu/java/awt/peer/gtk/$(DEPDIR) gnu/java/beans/$(DEPDIR) gnu/java/beans/editors/$(DEPDIR) gnu/java/beans/info/$(DEPDIR) gnu/java/io/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/lang/reflect/$(DEPDIR) gnu/java/locale/$(DEPDIR) gnu/java/math/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/net/protocol/file/$(DEPDIR) gnu/java/net/protocol/gcjlib/$(DEPDIR) gnu/java/net/protocol/http/$(DEPDIR) gnu/java/net/protocol/jar/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) gnu/java/nio/charset/$(DEPDIR) gnu/java/rmi/$(DEPDIR) gnu/java/rmi/dgc/$(DEPDIR) gnu/java/rmi/registry/$(DEPDIR) gnu/java/rmi/rmic/$(DEPDIR) gnu/java/rmi/server/$(DEPDIR) gnu/java/security/$(DEPDIR) gnu/java/security/action/$(DEPDIR) gnu/java/security/der/$(DEPDIR) gnu/java/security/provider/$(DEPDIR) gnu/java/security/util/$(DEPDIR) gnu/java/security/x509/$(DEPDIR) gnu/java/security/x509/ext/$(DEPDIR) gnu/java/text/$(DEPDIR) gnu/java/util/$(DEPDIR) gnu/java/util/prefs/$(DEPDIR) gnu/regexp/$(DEPDIR) java/applet/$(DEPDIR) java/awt/$(DEPDIR) java/awt/color/$(DEPDIR) java/awt/datatransfer/$(DEPDIR) java/awt/dnd/$(DEPDIR) java/awt/dnd/peer/$(DEPDIR) java/awt/event/$(DEPDIR) java/awt/font/$(DEPDIR) java/awt/geom/$(DEPDIR) java/awt/im/$(DEPDIR) java/awt/im/spi/$(DEPDIR) java/awt/image/$(DEPDIR) java/awt/image/renderable/$(DEPDIR) java/awt/peer/$(DEPDIR) java/awt/print/$(DEPDIR) java/beans/$(DEPDIR) java/beans/beancontext/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/math/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/nio/channels/spi/$(DEPDIR) java/nio/charset/$(DEPDIR) java/nio/charset/spi/$(DEPDIR) java/rmi/$(DEPDIR) java/rmi/activation/$(DEPDIR) java/rmi/dgc/$(DEPDIR) java/rmi/registry/$(DEPDIR) java/rmi/server/$(DEPDIR) java/security/$(DEPDIR) java/security/acl/$(DEPDIR) java/security/cert/$(DEPDIR) java/security/interfaces/$(DEPDIR) java/security/spec/$(DEPDIR) java/sql/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/jar/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/prefs/$(DEPDIR) java/util/regex/$(DEPDIR) java/util/zip/$(DEPDIR) javax/accessibility/$(DEPDIR) javax/crypto/$(DEPDIR) javax/crypto/interfaces/$(DEPDIR) javax/crypto/spec/$(DEPDIR) javax/imageio/$(DEPDIR) javax/imageio/event/$(DEPDIR) javax/imageio/metadata/$(DEPDIR) javax/imageio/spi/$(DEPDIR) javax/imageio/stream/$(DEPDIR) javax/naming/$(DEPDIR) javax/naming/directory/$(DEPDIR) javax/naming/event/$(DEPDIR) javax/naming/ldap/$(DEPDIR) javax/naming/spi/$(DEPDIR) javax/net/$(DEPDIR) javax/net/ssl/$(DEPDIR) javax/print/$(DEPDIR) javax/print/attribute/$(DEPDIR) javax/print/attribute/standard/$(DEPDIR) javax/print/event/$(DEPDIR) javax/security/auth/$(DEPDIR) javax/security/auth/callback/$(DEPDIR) javax/security/auth/login/$(DEPDIR) javax/security/auth/spi/$(DEPDIR) javax/security/auth/x500/$(DEPDIR) javax/security/cert/$(DEPDIR) javax/security/sasl/$(DEPDIR) javax/sql/$(DEPDIR) javax/swing/$(DEPDIR) javax/swing/border/$(DEPDIR) javax/swing/colorchooser/$(DEPDIR) javax/swing/event/$(DEPDIR) javax/swing/filechooser/$(DEPDIR) javax/swing/plaf/$(DEPDIR) javax/swing/plaf/basic/$(DEPDIR) javax/swing/plaf/metal/$(DEPDIR) javax/swing/table/$(DEPDIR) javax/swing/text/$(DEPDIR) javax/swing/text/html/$(DEPDIR) javax/swing/text/html/parser/$(DEPDIR) javax/swing/tree/$(DEPDIR) javax/swing/undo/$(DEPDIR) javax/transaction/$(DEPDIR) javax/transaction/xa/$(DEPDIR) jni/classpath/$(DEPDIR) jni/gtk-peer/$(DEPDIR) org/ietf/jgss/$(DEPDIR) org/w3c/dom/$(DEPDIR) org/w3c/dom/ranges/$(DEPDIR) org/w3c/dom/traversal/$(DEPDIR) org/xml/sax/$(DEPDIR) org/xml/sax/ext/$(DEPDIR) org/xml/sax/helpers/$(DEPDIR) sysdep/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-local distclean-tags @@ -23676,7 +23469,7 @@ installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf ./$(DEPDIR) gnu/awt/$(DEPDIR) gnu/awt/j2d/$(DEPDIR) gnu/awt/xlib/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/awt/$(DEPDIR) gnu/java/awt/image/$(DEPDIR) gnu/java/awt/peer/$(DEPDIR) gnu/java/awt/peer/gtk/$(DEPDIR) gnu/java/beans/$(DEPDIR) gnu/java/beans/editors/$(DEPDIR) gnu/java/beans/info/$(DEPDIR) gnu/java/io/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/lang/reflect/$(DEPDIR) gnu/java/locale/$(DEPDIR) gnu/java/math/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/net/protocol/file/$(DEPDIR) gnu/java/net/protocol/gcjlib/$(DEPDIR) gnu/java/net/protocol/http/$(DEPDIR) gnu/java/net/protocol/jar/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) gnu/java/nio/charset/$(DEPDIR) gnu/java/rmi/$(DEPDIR) gnu/java/rmi/dgc/$(DEPDIR) gnu/java/rmi/registry/$(DEPDIR) gnu/java/rmi/rmic/$(DEPDIR) gnu/java/rmi/server/$(DEPDIR) gnu/java/security/$(DEPDIR) gnu/java/security/action/$(DEPDIR) gnu/java/security/der/$(DEPDIR) gnu/java/security/provider/$(DEPDIR) gnu/java/security/util/$(DEPDIR) gnu/java/security/x509/$(DEPDIR) gnu/java/security/x509/ext/$(DEPDIR) gnu/java/text/$(DEPDIR) gnu/java/util/$(DEPDIR) gnu/java/util/prefs/$(DEPDIR) gnu/regexp/$(DEPDIR) java/applet/$(DEPDIR) java/awt/$(DEPDIR) java/awt/color/$(DEPDIR) java/awt/datatransfer/$(DEPDIR) java/awt/dnd/$(DEPDIR) java/awt/dnd/peer/$(DEPDIR) java/awt/event/$(DEPDIR) java/awt/font/$(DEPDIR) java/awt/geom/$(DEPDIR) java/awt/im/$(DEPDIR) java/awt/im/spi/$(DEPDIR) java/awt/image/$(DEPDIR) java/awt/image/renderable/$(DEPDIR) java/awt/peer/$(DEPDIR) java/awt/print/$(DEPDIR) java/beans/$(DEPDIR) java/beans/beancontext/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/math/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/nio/channels/spi/$(DEPDIR) java/nio/charset/$(DEPDIR) java/nio/charset/spi/$(DEPDIR) java/rmi/$(DEPDIR) java/rmi/activation/$(DEPDIR) java/rmi/dgc/$(DEPDIR) java/rmi/registry/$(DEPDIR) java/rmi/server/$(DEPDIR) java/security/$(DEPDIR) java/security/acl/$(DEPDIR) java/security/cert/$(DEPDIR) java/security/interfaces/$(DEPDIR) java/security/spec/$(DEPDIR) java/sql/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/jar/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/prefs/$(DEPDIR) java/util/regex/$(DEPDIR) java/util/zip/$(DEPDIR) javax/accessibility/$(DEPDIR) javax/crypto/$(DEPDIR) javax/crypto/interfaces/$(DEPDIR) javax/crypto/spec/$(DEPDIR) javax/imageio/$(DEPDIR) javax/imageio/event/$(DEPDIR) javax/imageio/metadata/$(DEPDIR) javax/imageio/spi/$(DEPDIR) javax/imageio/stream/$(DEPDIR) javax/naming/$(DEPDIR) javax/naming/directory/$(DEPDIR) javax/naming/event/$(DEPDIR) javax/naming/ldap/$(DEPDIR) javax/naming/spi/$(DEPDIR) javax/net/$(DEPDIR) javax/net/ssl/$(DEPDIR) javax/print/$(DEPDIR) javax/print/attribute/$(DEPDIR) javax/print/attribute/standard/$(DEPDIR) javax/print/event/$(DEPDIR) javax/security/auth/$(DEPDIR) javax/security/auth/callback/$(DEPDIR) javax/security/auth/login/$(DEPDIR) javax/security/auth/spi/$(DEPDIR) javax/security/auth/x500/$(DEPDIR) javax/security/cert/$(DEPDIR) javax/security/sasl/$(DEPDIR) javax/sql/$(DEPDIR) javax/swing/$(DEPDIR) javax/swing/border/$(DEPDIR) javax/swing/colorchooser/$(DEPDIR) javax/swing/event/$(DEPDIR) javax/swing/filechooser/$(DEPDIR) javax/swing/plaf/$(DEPDIR) javax/swing/plaf/basic/$(DEPDIR) javax/swing/plaf/metal/$(DEPDIR) javax/swing/table/$(DEPDIR) javax/swing/text/$(DEPDIR) javax/swing/text/html/$(DEPDIR) javax/swing/text/html/parser/$(DEPDIR) javax/swing/tree/$(DEPDIR) javax/swing/undo/$(DEPDIR) javax/transaction/$(DEPDIR) javax/transaction/xa/$(DEPDIR) jni/classpath/$(DEPDIR) jni/gtk-peer/$(DEPDIR) org/ietf/jgss/$(DEPDIR) org/w3c/dom/$(DEPDIR) org/w3c/dom/ranges/$(DEPDIR) org/w3c/dom/traversal/$(DEPDIR) org/xml/sax/$(DEPDIR) org/xml/sax/ext/$(DEPDIR) org/xml/sax/helpers/$(DEPDIR) sysdep/$(DEPDIR) + -rm -rf ./$(DEPDIR) gnu/awt/$(DEPDIR) gnu/awt/j2d/$(DEPDIR) gnu/awt/xlib/$(DEPDIR) gnu/classpath/$(DEPDIR) gnu/gcj/$(DEPDIR) gnu/gcj/convert/$(DEPDIR) gnu/gcj/io/$(DEPDIR) gnu/gcj/runtime/$(DEPDIR) gnu/gcj/tools/gcj_dbtool/$(DEPDIR) gnu/gcj/util/$(DEPDIR) gnu/gcj/xlib/$(DEPDIR) gnu/java/awt/$(DEPDIR) gnu/java/awt/image/$(DEPDIR) gnu/java/awt/peer/$(DEPDIR) gnu/java/awt/peer/gtk/$(DEPDIR) gnu/java/beans/$(DEPDIR) gnu/java/beans/editors/$(DEPDIR) gnu/java/beans/info/$(DEPDIR) gnu/java/io/$(DEPDIR) gnu/java/lang/$(DEPDIR) gnu/java/lang/reflect/$(DEPDIR) gnu/java/locale/$(DEPDIR) gnu/java/math/$(DEPDIR) gnu/java/net/$(DEPDIR) gnu/java/net/protocol/core/$(DEPDIR) gnu/java/net/protocol/file/$(DEPDIR) gnu/java/net/protocol/gcjlib/$(DEPDIR) gnu/java/net/protocol/http/$(DEPDIR) gnu/java/net/protocol/jar/$(DEPDIR) gnu/java/nio/$(DEPDIR) gnu/java/nio/channels/$(DEPDIR) gnu/java/nio/charset/$(DEPDIR) gnu/java/rmi/$(DEPDIR) gnu/java/rmi/dgc/$(DEPDIR) gnu/java/rmi/registry/$(DEPDIR) gnu/java/rmi/rmic/$(DEPDIR) gnu/java/rmi/server/$(DEPDIR) gnu/java/security/$(DEPDIR) gnu/java/security/action/$(DEPDIR) gnu/java/security/der/$(DEPDIR) gnu/java/security/provider/$(DEPDIR) gnu/java/security/util/$(DEPDIR) gnu/java/security/x509/$(DEPDIR) gnu/java/security/x509/ext/$(DEPDIR) gnu/java/text/$(DEPDIR) gnu/java/util/$(DEPDIR) gnu/java/util/prefs/$(DEPDIR) gnu/regexp/$(DEPDIR) java/applet/$(DEPDIR) java/awt/$(DEPDIR) java/awt/color/$(DEPDIR) java/awt/datatransfer/$(DEPDIR) java/awt/dnd/$(DEPDIR) java/awt/dnd/peer/$(DEPDIR) java/awt/event/$(DEPDIR) java/awt/font/$(DEPDIR) java/awt/geom/$(DEPDIR) java/awt/im/$(DEPDIR) java/awt/im/spi/$(DEPDIR) java/awt/image/$(DEPDIR) java/awt/image/renderable/$(DEPDIR) java/awt/peer/$(DEPDIR) java/awt/print/$(DEPDIR) java/beans/$(DEPDIR) java/beans/beancontext/$(DEPDIR) java/io/$(DEPDIR) java/lang/$(DEPDIR) java/lang/ref/$(DEPDIR) java/lang/reflect/$(DEPDIR) java/math/$(DEPDIR) java/net/$(DEPDIR) java/nio/$(DEPDIR) java/nio/channels/$(DEPDIR) java/nio/channels/spi/$(DEPDIR) java/nio/charset/$(DEPDIR) java/nio/charset/spi/$(DEPDIR) java/rmi/$(DEPDIR) java/rmi/activation/$(DEPDIR) java/rmi/dgc/$(DEPDIR) java/rmi/registry/$(DEPDIR) java/rmi/server/$(DEPDIR) java/security/$(DEPDIR) java/security/acl/$(DEPDIR) java/security/cert/$(DEPDIR) java/security/interfaces/$(DEPDIR) java/security/spec/$(DEPDIR) java/sql/$(DEPDIR) java/text/$(DEPDIR) java/util/$(DEPDIR) java/util/jar/$(DEPDIR) java/util/logging/$(DEPDIR) java/util/prefs/$(DEPDIR) java/util/regex/$(DEPDIR) java/util/zip/$(DEPDIR) javax/accessibility/$(DEPDIR) javax/crypto/$(DEPDIR) javax/crypto/interfaces/$(DEPDIR) javax/crypto/spec/$(DEPDIR) javax/imageio/$(DEPDIR) javax/imageio/event/$(DEPDIR) javax/imageio/metadata/$(DEPDIR) javax/imageio/spi/$(DEPDIR) javax/imageio/stream/$(DEPDIR) javax/naming/$(DEPDIR) javax/naming/directory/$(DEPDIR) javax/naming/event/$(DEPDIR) javax/naming/ldap/$(DEPDIR) javax/naming/spi/$(DEPDIR) javax/net/$(DEPDIR) javax/net/ssl/$(DEPDIR) javax/print/$(DEPDIR) javax/print/attribute/$(DEPDIR) javax/print/attribute/standard/$(DEPDIR) javax/print/event/$(DEPDIR) javax/security/auth/$(DEPDIR) javax/security/auth/callback/$(DEPDIR) javax/security/auth/login/$(DEPDIR) javax/security/auth/spi/$(DEPDIR) javax/security/auth/x500/$(DEPDIR) javax/security/cert/$(DEPDIR) javax/security/sasl/$(DEPDIR) javax/sql/$(DEPDIR) javax/swing/$(DEPDIR) javax/swing/border/$(DEPDIR) javax/swing/colorchooser/$(DEPDIR) javax/swing/event/$(DEPDIR) javax/swing/filechooser/$(DEPDIR) javax/swing/plaf/$(DEPDIR) javax/swing/plaf/basic/$(DEPDIR) javax/swing/plaf/metal/$(DEPDIR) javax/swing/table/$(DEPDIR) javax/swing/text/$(DEPDIR) javax/swing/text/html/$(DEPDIR) javax/swing/text/html/parser/$(DEPDIR) javax/swing/tree/$(DEPDIR) javax/swing/undo/$(DEPDIR) javax/transaction/$(DEPDIR) javax/transaction/xa/$(DEPDIR) jni/classpath/$(DEPDIR) jni/gtk-peer/$(DEPDIR) org/ietf/jgss/$(DEPDIR) org/w3c/dom/$(DEPDIR) org/w3c/dom/ranges/$(DEPDIR) org/w3c/dom/traversal/$(DEPDIR) org/xml/sax/$(DEPDIR) org/xml/sax/ext/$(DEPDIR) org/xml/sax/helpers/$(DEPDIR) sysdep/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/libjava/aclocal.m4 b/libjava/aclocal.m4 index 3afc98f67d2..ffc535707c8 100644 --- a/libjava/aclocal.m4 +++ b/libjava/aclocal.m4 @@ -417,7 +417,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # 02111-1307, USA. AC_DEFUN([AM_PROG_GCJ],[ -AC_CHECK_PROGS(GCJ, [gcj gcj-3.2 gcj-3.1 gcj-3.0 gcj-2.95], gcj) +AC_CHECK_PROGS(GCJ, gcj, gcj) test -z "$GCJ" && AC_MSG_ERROR([no acceptable gcj found in \$PATH]) if test "x${GCJFLAGS-unset}" = xunset; then GCJFLAGS="-g -O2" diff --git a/libjava/boehm.cc b/libjava/boehm.cc index c2a93a57b04..d2902326e81 100644 --- a/libjava/boehm.cc +++ b/libjava/boehm.cc @@ -1,6 +1,7 @@ // boehm.cc - interface between libjava and Boehm GC. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation This file is part of libgcj. @@ -10,6 +11,21 @@ details. */ #include <config.h> +#include <stdio.h> +#include <limits.h> + +#include <jvm.h> +#include <gcj/cni.h> + +#include <java/lang/Class.h> +#include <java/lang/reflect/Modifier.h> +#include <java-interp.h> + +// More nastiness: the GC wants to define TRUE and FALSE. We don't +// need the Java definitions (themselves a hack), so we undefine them. +#undef TRUE +#undef FALSE + extern "C" { #include <gc_config.h> @@ -27,26 +43,20 @@ extern "C" # define GC_REDIRECT_TO_LOCAL # include <gc_local_alloc.h> #endif -}; -#include <stdio.h> -#include <limits.h> - -#include <jvm.h> -#include <gcj/cni.h> - -#include <java/lang/Class.h> -#include <java/lang/reflect/Modifier.h> -#include <java-interp.h> + // From boehm's misc.c + void GC_enable(); + void GC_disable(); +}; -#define MAYBE_MARK(Obj, Top, Limit, Source, Exit) \ - Top=GC_MARK_AND_PUSH((GC_PTR)Obj, Top, Limit, (GC_PTR *)Source) +#define MAYBE_MARK(Obj, Top, Limit, Source) \ + Top=GC_MARK_AND_PUSH((GC_PTR) Obj, Top, Limit, (GC_PTR *) Source) // `kind' index used when allocating Java arrays. static int array_kind_x; // Freelist used for Java arrays. -static void * *array_free_list; +static void **array_free_list; @@ -54,7 +64,7 @@ static void * *array_free_list; // object. We use `void *' arguments and return, and not what the // Boehm GC wants, to avoid pollution in our headers. void * -_Jv_MarkObj (void *addr, void *msp, void *msl, void * env) +_Jv_MarkObj (void *addr, void *msp, void *msl, void *env) { struct GC_ms_entry *mark_stack_ptr = (struct GC_ms_entry *)msp; struct GC_ms_entry *mark_stack_limit = (struct GC_ms_entry *)msl; @@ -78,11 +88,11 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. p = (GC_PTR) obj->sync_info; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o1label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); # endif // Mark the object's class. p = (GC_PTR) klass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); if (__builtin_expect (klass == &java::lang::Class::class$, false)) { @@ -101,33 +111,35 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) jclass c = (jclass) addr; p = (GC_PTR) c->name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c3label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->superclass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c4label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); for (int i = 0; i < c->constants.size; ++i) { /* FIXME: We could make this more precise by using the tags -KKT */ p = (GC_PTR) c->constants.data[i].p; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } #ifdef INTERPRETER if (_Jv_IsInterpretedClass (c)) { p = (GC_PTR) c->constants.tags; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5alabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->constants.data; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5blabel); - p = (GC_PTR) c->vtable; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5clabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } #endif + // The vtable might be allocated even for compiled code. + p = (GC_PTR) c->vtable; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + // If the class is an array, then the methods field holds a // pointer to the element class. If the class is primitive, // then the methods field holds a pointer to the array class. p = (GC_PTR) c->methods; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c6label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); // The vtable might have been set, but the rest of the class // could still be uninitialized. If this is the case, then @@ -143,34 +155,35 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) for (int i = 0; i < c->method_count; ++i) { p = (GC_PTR) c->methods[i].name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, - cm1label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->methods[i].signature; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, - cm2label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + + // Note that we don't have to mark each individual throw + // separately, as these are stored in the constant pool. + p = (GC_PTR) c->methods[i].throws; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } } // Mark all the fields. p = (GC_PTR) c->fields; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); for (int i = 0; i < c->field_count; ++i) { _Jv_Field* field = &c->fields[i]; -#ifndef COMPACT_FIELDS p = (GC_PTR) field->name; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8alabel); -#endif + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) field->type; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8blabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); // For the interpreter, we also need to mark the memory // containing static members if ((field->flags & java::lang::reflect::Modifier::STATIC)) { p = (GC_PTR) field->u.addr; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8clabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); // also, if the static member is a reference, // mark also the value pointed to. We check for isResolved @@ -180,69 +193,110 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) { jobject val = *(jobject*) field->u.addr; p = (GC_PTR) val; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, - c, c8elabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } } } p = (GC_PTR) c->vtable; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c9label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->interfaces; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cAlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); for (int i = 0; i < c->interface_count; ++i) { p = (GC_PTR) c->interfaces[i]; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cClabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); } p = (GC_PTR) c->loader; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cBlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + + // The dispatch tables can be allocated at runtime. + p = (GC_PTR) c->ancestors; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + if (c->idt) + { + p = (GC_PTR) c->idt; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + + if (c->isInterface()) + { + p = (GC_PTR) c->idt->iface.ioffsets; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c->idt); + } + else if (! c->isPrimitive()) + { + // This field is only valid for ordinary classes. + p = (GC_PTR) c->idt->cls.itable; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c->idt); + } + } + p = (GC_PTR) c->arrayclass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cDlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->protectionDomain; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cPlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->hack_signers; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cSlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); p = (GC_PTR) c->aux_info; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cTlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); #ifdef INTERPRETER - if (_Jv_IsInterpretedClass (c)) + if (_Jv_IsInterpretedClass (c) && c->aux_info) { _Jv_InterpClass* ic = (_Jv_InterpClass*) c->aux_info; p = (GC_PTR) ic->interpreted_methods; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cElabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); for (int i = 0; i < c->method_count; i++) { + // The interpreter installs a heap-allocated trampoline + // here, so we'll mark it. + p = (GC_PTR) c->methods[i].ncode; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c); + + using namespace java::lang::reflect; + + // Mark the direct-threaded code. Note a subtlety here: + // when we add Miranda methods to a class, we don't + // resize its interpreted_methods array. If we try to + // reference one of these methods, we may crash. + // However, we know these are all abstract, and we know + // that abstract methods have nothing useful in this + // array. So, we skip all abstract methods to avoid the + // problem. FIXME: this is pretty obscure, it may be + // better to add a methods to the execution engine and + // resize the array. + if ((c->methods[i].accflags & Modifier::ABSTRACT) != 0) + continue; + p = (GC_PTR) ic->interpreted_methods[i]; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, \ - cFlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); - // Mark the direct-threaded code. - if ((c->methods[i].accflags - & java::lang::reflect::Modifier::NATIVE) == 0) + if ((c->methods[i].accflags & Modifier::NATIVE) != 0) + { + _Jv_JNIMethod *jm + = (_Jv_JNIMethod *) ic->interpreted_methods[i]; + if (jm) + { + p = (GC_PTR) jm->jni_arg_types; + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, p); + } + } + else { _Jv_InterpMethod *im = (_Jv_InterpMethod *) ic->interpreted_methods[i]; if (im) { p = (GC_PTR) im->prepared; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, \ - cFlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); } } - - // The interpreter installs a heap-allocated trampoline - // here, so we'll mark it. - p = (GC_PTR) c->methods[i].ncode; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, - cm3label); } p = (GC_PTR) ic->field_initializers; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cGlabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic); } #endif @@ -269,8 +323,7 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) { jobject val = JvGetObjectField (obj, field); p = (GC_PTR) val; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, - obj, elabel); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj); } field = field->getNextField (); } @@ -285,7 +338,7 @@ _Jv_MarkObj (void *addr, void *msp, void *msl, void * env) // array (of objects). We use `void *' arguments and return, and not // what the Boehm GC wants, to avoid pollution in our headers. void * -_Jv_MarkArray (void *addr, void *msp, void *msl, void * env) +_Jv_MarkArray (void *addr, void *msp, void *msl, void *env) { struct GC_ms_entry *mark_stack_ptr = (struct GC_ms_entry *)msp; struct GC_ms_entry *mark_stack_limit = (struct GC_ms_entry *)msl; @@ -306,17 +359,17 @@ _Jv_MarkArray (void *addr, void *msp, void *msl, void * env) # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. p = (GC_PTR) array->sync_info; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e1label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array); # endif // Mark the object's class. p = (GC_PTR) klass; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, &(dt -> clas), o2label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, &(dt -> clas)); for (int i = 0; i < JvGetArrayLength (array); ++i) { jobject obj = elements (array)[i]; p = (GC_PTR) obj; - MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e2label); + MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array); } return mark_stack_ptr; @@ -364,7 +417,7 @@ _Jv_BuildGCDescr(jclass self) // If we find a field outside the range of our bitmap, // fall back to procedure marker. The bottom 2 bits are // reserved. - if (off >= (unsigned)bits_per_word - 2) + if (off >= (unsigned) bits_per_word - 2) return (void *) (GCJ_DEFAULT_DESCR); desc |= 1ULL << (bits_per_word - off - 1); } @@ -514,10 +567,6 @@ _Jv_GCSetMaximumHeapSize (size_t size) GC_set_max_heap_size ((GC_word) size); } -// From boehm's misc.c -extern "C" void GC_enable(); -extern "C" void GC_disable(); - void _Jv_DisableGC (void) { @@ -585,7 +634,7 @@ _Jv_InitGC (void) proc = GC_new_proc((GC_mark_proc)_Jv_MarkArray); array_kind_x = GC_new_kind(array_free_list, GC_MAKE_PROC (proc, 0), 0, 1); - /* Arrange to have the GC print Java class names in backtraces, etc. */ + // Arrange to have the GC print Java class names in backtraces, etc. GC_register_describe_type_fn(GC_gcj_kind, gcj_describe_type_fn); GC_register_describe_type_fn(GC_gcj_debug_kind, gcj_describe_type_fn); } @@ -640,7 +689,11 @@ _Jv_GCInitializeFinalizers (void (*notifier) (void)) void _Jv_GCRegisterDisappearingLink (jobject *objp) { - GC_general_register_disappearing_link ((GC_PTR *) objp, (GC_PTR) *objp); + // This test helps to ensure that we meet a precondition of + // GC_general_register_disappearing_link, viz. "Obj must be a + // pointer to the first word of an object we allocated." + if (GC_base(*objp)) + GC_general_register_disappearing_link ((GC_PTR *) objp, (GC_PTR) *objp); } jboolean diff --git a/libjava/configure b/libjava/configure index 5929c250c52..cf52939df11 100755 --- a/libjava/configure +++ b/libjava/configure @@ -310,7 +310,7 @@ ac_includes_default="\ # include <unistd.h> #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS libgcj_basedir build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical LN_S mkinstalldirs CC ac_ct_CC EXEEXT OBJEXT CXX ac_ct_CXX CFLAGS CXXFLAGS LDFLAGS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE AS ac_ct_AS AR ac_ct_AR RANLIB ac_ct_RANLIB MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBGCJ_CFLAGS LIBGCJ_CXXFLAGS LIBGCJ_JAVAFLAGS INCLTDL LIBLTDL DIRLTDL LIBTOOL CXXCPP CPPFLAGS GCJ GCJFLAGS GCJDEPMODE am__fastdepGCJ_TRUE am__fastdepGCJ_FALSE subdirs COMPPATH TESTSUBDIR_TRUE TESTSUBDIR_FALSE ONESTEP_TRUE ONESTEP_FALSE LIBGCJDEBUG INTERPRETER LIBFFI LIBFFIINCS PLATFORM_INNER_NAT_HDRS CPP EGREP USING_WIN32_PLATFORM_TRUE USING_WIN32_PLATFORM_FALSE USING_POSIX_PLATFORM_TRUE USING_POSIX_PLATFORM_FALSE USING_ECOS_PLATFORM_TRUE USING_ECOS_PLATFORM_FALSE USING_DARWIN_CRT_TRUE USING_DARWIN_CRT_FALSE SYSTEMSPEC LIBGCJTESTSPEC ZLIBSPEC ZLIBTESTSPEC X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS TOOLKIT XLIB_AWT_TRUE XLIB_AWT_FALSE GTK_AWT_TRUE GTK_AWT_FALSE GTK_CAIRO_TRUE GTK_CAIRO_FALSE PKG_CONFIG CAIRO_CFLAGS CAIRO_LIBS PANGOFT2_CFLAGS PANGOFT2_LIBS GCLIBS GCINCS GCDEPS GCSPEC JC1GCSPEC GCTESTSPEC USING_BOEHMGC_TRUE USING_BOEHMGC_FALSE USING_NOGC_TRUE USING_NOGC_FALSE THREADLIBS THREADINCS THREADDEPS THREADSPEC THREADLDFLAGS THREADCXXFLAGS USING_POSIX_THREADS_TRUE USING_POSIX_THREADS_FALSE USING_WIN32_THREADS_TRUE USING_WIN32_THREADS_FALSE USING_NO_THREADS_TRUE USING_NO_THREADS_FALSE HASH_SYNC_SPEC USING_GCC_TRUE USING_GCC_FALSE tool_include_dir gcc_version LIBICONV LTLIBICONV GTK_CFLAGS GTK_LIBS GLIB_CFLAGS GLIB_LIBS LIBART_CFLAGS LIBART_LIBS SUPPLY_BACKTRACE_TRUE SUPPLY_BACKTRACE_FALSE GCJH ZIP CLASSPATH_SEPARATOR ac_ct_GCJ ZLIBS SYS_ZLIBS ZINCS DIVIDESPEC CHECKREFSPEC EXCEPTIONSPEC IEEESPEC NATIVE_TRUE NATIVE_FALSE NEEDS_DATA_START_TRUE NEEDS_DATA_START_FALSE GCC_UNWIND_INCLUDE toolexecdir toolexecmainlibdir toolexeclibdir GCJVERSION ALLOCA PERL BACKTRACESPEC SYSDEP_SOURCES here LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS libgcj_basedir build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os target_noncanonical LN_S mkinstalldirs CC ac_ct_CC EXEEXT OBJEXT CXX ac_ct_CXX CFLAGS CXXFLAGS LDFLAGS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE AS ac_ct_AS AR ac_ct_AR RANLIB ac_ct_RANLIB MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBGCJ_CFLAGS LIBGCJ_CXXFLAGS LIBGCJ_JAVAFLAGS LIBGCJ_LD_SYMBOLIC INCLTDL LIBLTDL DIRLTDL LIBTOOL CXXCPP CPPFLAGS GCJ GCJFLAGS GCJDEPMODE am__fastdepGCJ_TRUE am__fastdepGCJ_FALSE subdirs COMPPATH TESTSUBDIR_TRUE TESTSUBDIR_FALSE ONESTEP_TRUE ONESTEP_FALSE LIBGCJDEBUG INTERPRETER LIBFFI LIBFFIINCS PLATFORM_INNER_NAT_HDRS CPP EGREP USING_WIN32_PLATFORM_TRUE USING_WIN32_PLATFORM_FALSE USING_POSIX_PLATFORM_TRUE USING_POSIX_PLATFORM_FALSE USING_ECOS_PLATFORM_TRUE USING_ECOS_PLATFORM_FALSE USING_DARWIN_CRT_TRUE USING_DARWIN_CRT_FALSE SYSTEMSPEC LIBGCJTESTSPEC ZLIBSPEC ZLIBTESTSPEC X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS TOOLKIT XLIB_AWT_TRUE XLIB_AWT_FALSE GTK_AWT_TRUE GTK_AWT_FALSE GTK_CAIRO_TRUE GTK_CAIRO_FALSE PKG_CONFIG CAIRO_CFLAGS CAIRO_LIBS PANGOFT2_CFLAGS PANGOFT2_LIBS GCLIBS GCINCS GCDEPS GCSPEC JC1GCSPEC GCTESTSPEC USING_BOEHMGC_TRUE USING_BOEHMGC_FALSE USING_NOGC_TRUE USING_NOGC_FALSE THREADLIBS THREADINCS THREADDEPS THREADSPEC THREADLDFLAGS THREADCXXFLAGS USING_POSIX_THREADS_TRUE USING_POSIX_THREADS_FALSE USING_WIN32_THREADS_TRUE USING_WIN32_THREADS_FALSE USING_NO_THREADS_TRUE USING_NO_THREADS_FALSE HASH_SYNC_SPEC USING_GCC_TRUE USING_GCC_FALSE tool_include_dir gcc_version LIBICONV LTLIBICONV GTK_CFLAGS GTK_LIBS GLIB_CFLAGS GLIB_LIBS LIBART_CFLAGS LIBART_LIBS SUPPLY_BACKTRACE_TRUE SUPPLY_BACKTRACE_FALSE GCJH ZIP CLASSPATH_SEPARATOR ac_ct_GCJ ZLIBS SYS_ZLIBS ZINCS DIVIDESPEC CHECKREFSPEC EXCEPTIONSPEC IEEESPEC NATIVE_TRUE NATIVE_FALSE NEEDS_DATA_START_TRUE NEEDS_DATA_START_FALSE GCC_UNWIND_INCLUDE toolexecdir toolexecmainlibdir toolexeclibdir GCJVERSION ALLOCA PERL BACKTRACESPEC SYSDEP_SOURCES here LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -3983,6 +3983,8 @@ libgcj_javaflags= LIBGCJ_CFLAGS="${libgcj_cflags}" LIBGCJ_CXXFLAGS="${libgcj_cxxflags}" LIBGCJ_JAVAFLAGS="${libgcj_javaflags}" +LIBGCJ_LD_SYMBOLIC="${libgcj_ld_symbolic}" + @@ -4741,7 +4743,7 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 4744 "configure"' > conftest.$ac_ext + echo '#line 4746 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -5772,7 +5774,7 @@ if test "${enable_sjlj_exceptions+set}" = set; then : else cat > conftest.$ac_ext << EOF -#line 5775 "configure" +#line 5777 "configure" struct S { ~S(); }; void bar(); void foo() @@ -17182,6 +17184,7 @@ s,@MAINT@,$MAINT,;t t s,@LIBGCJ_CFLAGS@,$LIBGCJ_CFLAGS,;t t s,@LIBGCJ_CXXFLAGS@,$LIBGCJ_CXXFLAGS,;t t s,@LIBGCJ_JAVAFLAGS@,$LIBGCJ_JAVAFLAGS,;t t +s,@LIBGCJ_LD_SYMBOLIC@,$LIBGCJ_LD_SYMBOLIC,;t t s,@INCLTDL@,$INCLTDL,;t t s,@LIBLTDL@,$LIBLTDL,;t t s,@DIRLTDL@,$DIRLTDL,;t t diff --git a/libjava/configure.ac b/libjava/configure.ac index 269b64a3e6c..43156b7f68d 100644 --- a/libjava/configure.ac +++ b/libjava/configure.ac @@ -134,9 +134,11 @@ libgcj_javaflags= LIBGCJ_CFLAGS="${libgcj_cflags}" LIBGCJ_CXXFLAGS="${libgcj_cxxflags}" LIBGCJ_JAVAFLAGS="${libgcj_javaflags}" +LIBGCJ_LD_SYMBOLIC="${libgcj_ld_symbolic}" AC_SUBST(LIBGCJ_CFLAGS) AC_SUBST(LIBGCJ_CXXFLAGS) AC_SUBST(LIBGCJ_JAVAFLAGS) +AC_SUBST(LIBGCJ_LD_SYMBOLIC) AC_CONFIG_HEADERS([include/config.h gcj/libgcj-config.h]) diff --git a/libjava/configure.host b/libjava/configure.host index 437566a3079..e1eaa1bab1e 100644 --- a/libjava/configure.host +++ b/libjava/configure.host @@ -173,6 +173,7 @@ case "${host}" in hppa*-linux* | \ sh-linux* | sh[34]*-linux*) can_unwind_signal=yes + libgcj_ld_symbolic='-Wl,-Bsymbolic' if test x$slow_pthread_self = xyes \ && test x$cross_compiling != xyes; then cat > conftest.c <<EOF @@ -226,7 +227,6 @@ EOF mips*-*-linux* ) sysdeps_dir=mips can_unwind_signal=yes - libgcj_interpreter=yes libgcj_flags="${libgcj_flags} -mxgot" DIVIDESPEC=-fno-use-divide-subroutine case "${host}" in diff --git a/libjava/defineclass.cc b/libjava/defineclass.cc index 86df0d2aa72..1a0c4e4da60 100644 --- a/libjava/defineclass.cc +++ b/libjava/defineclass.cc @@ -1,6 +1,6 @@ // defineclass.cc - defining a class from .class format. -/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -26,6 +26,7 @@ details. */ #include <stdio.h> #include <java-cpool.h> #include <gcj/cni.h> +#include <execution.h> #include <java/lang/Class.h> #include <java/lang/Float.h> @@ -38,6 +39,7 @@ details. */ #include <java/lang/ClassCircularityError.h> #include <java/lang/IncompatibleClassChangeError.h> #include <java/lang/reflect/Modifier.h> +#include <java/security/ProtectionDomain.h> using namespace gcj; @@ -216,7 +218,8 @@ struct _Jv_ClassReader { throw_class_format_error ("erroneous type descriptor"); } - _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length) + _Jv_ClassReader (jclass klass, jbyteArray data, jint offset, jint length, + java::security::ProtectionDomain *pd) { if (klass == 0 || length < 0 || offset+length > data->length) throw_internal_error ("arguments to _Jv_DefineClass"); @@ -226,7 +229,10 @@ struct _Jv_ClassReader { len = length; pos = 0; def = klass; - def_interp = (_Jv_InterpClass *) def->aux_info; + def->size_in_bytes = -1; + def->vtable_method_count = -1; + def->engine = &_Jv_soleInterpreterEngine; + def->protectionDomain = pd; } /** and here goes the parser members defined out-of-line */ @@ -273,9 +279,10 @@ struct _Jv_ClassReader { }; void -_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length) +_Jv_DefineClass (jclass klass, jbyteArray data, jint offset, jint length, + java::security::ProtectionDomain *pd) { - _Jv_ClassReader reader (klass, data, offset, length); + _Jv_ClassReader reader (klass, data, offset, length, pd); reader.parse(); /* that's it! */ @@ -311,8 +318,13 @@ _Jv_ClassReader::parse () handleClassBegin (access_flags, this_class, super_class); + // Allocate our aux_info here, after the name is set, to fulfill our + // contract with the collector interface. + def->aux_info = (void *) _Jv_AllocBytes (sizeof (_Jv_InterpClass)); + def_interp = (_Jv_InterpClass *) def->aux_info; + int interfaces_count = read2u (); - + handleInterfacesBegin (interfaces_count); for (int i = 0; i < interfaces_count; i++) @@ -335,12 +347,11 @@ _Jv_ClassReader::parse () if (pos != len) throw_class_format_error ("unused data before end of file"); - // tell everyone we're done. - def->state = JV_STATE_LOADED; + // Tell everyone we're done. + def->state = JV_STATE_READ; if (gcj::verbose_class_flag) - fprintf (stderr, "[Loaded (bytecode) %s]\n", def->name->chars()); + _Jv_Linker::print_class_loaded (def); def->notifyAll (); - } void _Jv_ClassReader::read_constpool () @@ -517,30 +528,20 @@ void _Jv_ClassReader::read_one_method_attribute (int method_index) throw_class_format_error ("only one Exceptions attribute allowed per method"); int num_exceptions = read2u (); - // We use malloc here because the GC won't scan the method - // objects. FIXME this means a memory leak if we GC a class. - // (Currently we never do.) _Jv_Utf8Const **exceptions = - (_Jv_Utf8Const **) _Jv_Malloc ((num_exceptions + 1) * sizeof (_Jv_Utf8Const *)); + (_Jv_Utf8Const **) _Jv_AllocBytes ((num_exceptions + 1) + * sizeof (_Jv_Utf8Const *)); int out = 0; _Jv_word *pool_data = def->constants.data; for (int i = 0; i < num_exceptions; ++i) { - try + int ndx = read2u (); + // JLS 2nd Ed. 4.7.5 requires that the tag not be 0. + if (ndx != 0) { - int ndx = read2u (); - // JLS 2nd Ed. 4.7.5 requires that the tag not be 0. - if (ndx != 0) - { - check_tag (ndx, JV_CONSTANT_Class); - exceptions[out++] = pool_data[ndx].utf8; - } - } - catch (java::lang::Throwable *exc) - { - _Jv_Free (exceptions); - throw exc; + check_tag (ndx, JV_CONSTANT_Class); + exceptions[out++] = pool_data[ndx].utf8; } } exceptions[out] = NULL; @@ -854,8 +855,7 @@ _Jv_ClassReader::prepare_pool_entry (int index, unsigned char this_tag) void -_Jv_ClassReader::handleClassBegin - (int access_flags, int this_class, int super_class) +_Jv_ClassReader::handleClassBegin (int access_flags, int this_class, int super_class) { using namespace java::lang::reflect; @@ -950,23 +950,25 @@ _Jv_ClassReader::handleClassBegin def->notifyAll (); } -///// implements the checks described in sect. 5.3.5.3 +///// Implements the checks described in sect. 5.3.5.3 void _Jv_ClassReader::checkExtends (jclass sub, jclass super) { using namespace java::lang::reflect; - // having an interface or a final class as a superclass is no good + _Jv_Linker::wait_for_state (super, JV_STATE_LOADING); + + // Having an interface or a final class as a superclass is no good. if ((super->accflags & (Modifier::INTERFACE | Modifier::FINAL)) != 0) { throw_incompatible_class_change_error (sub->getName ()); } - // if the super class is not public, we need to check some more + // If the super class is not public, we need to check some more. if ((super->accflags & Modifier::PUBLIC) == 0) { - // With package scope, the classes must have the same - // class loader. + // With package scope, the classes must have the same class + // loader. if ( sub->loader != super->loader || !_Jv_ClassNameSamePackage (sub->name, super->name)) { @@ -974,7 +976,7 @@ _Jv_ClassReader::checkExtends (jclass sub, jclass super) } } - for (; super != 0; super = super->superclass) + for (; super != 0; super = super->getSuperclass ()) { if (super == sub) throw_class_circularity_error (sub->getName ()); @@ -1072,11 +1074,7 @@ void _Jv_ClassReader::handleField (int field_no, _Jv_Field *field = &def->fields[field_no]; _Jv_Utf8Const *field_name = pool_data[name].utf8; -#ifndef COMPACT_FIELDS field->name = field_name; -#else - field->nameIndex = name; -#endif // Ignore flags we don't know about. field->flags = flags & Modifier::ALL_FLAGS; @@ -1234,7 +1232,7 @@ void _Jv_ClassReader::handleMethod // ignore unknown flags method->accflags = accflags & Modifier::ALL_FLAGS; - // intialize... + // Initialize... method->ncode = 0; method->throws = NULL; @@ -1276,7 +1274,6 @@ void _Jv_ClassReader::handleCodeAttribute _Jv_InterpMethod *method = (_Jv_InterpMethod*) (_Jv_AllocBytes (size)); - method->deferred = NULL; method->max_stack = max_stack; method->max_locals = max_locals; method->code_length = code_length; @@ -1335,7 +1332,6 @@ void _Jv_ClassReader::handleMethodsEnd () m->self = method; m->function = NULL; def_interp->interpreted_methods[i] = m; - m->deferred = NULL; if ((method->accflags & Modifier::STATIC)) { @@ -1626,7 +1622,7 @@ _Jv_VerifyClassName (_Jv_Utf8Const *name) } /* Returns true, if NAME1 and NAME2 represent classes in the same - package. */ + package. Neither NAME2 nor NAME2 may name an array type. */ bool _Jv_ClassNameSamePackage (_Jv_Utf8Const *name1, _Jv_Utf8Const *name2) { diff --git a/libjava/gcj/Makefile.in b/libjava/gcj/Makefile.in index b4c32fb9ea1..b40dd2a398a 100644 --- a/libjava/gcj/Makefile.in +++ b/libjava/gcj/Makefile.in @@ -146,6 +146,7 @@ LIBGCJTESTSPEC = @LIBGCJTESTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ +LIBGCJ_LD_SYMBOLIC = @LIBGCJ_LD_SYMBOLIC@ LIBICONV = @LIBICONV@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ diff --git a/libjava/gcj/field.h b/libjava/gcj/field.h index bd6b2c38046..8421bc7e046 100644 --- a/libjava/gcj/field.h +++ b/libjava/gcj/field.h @@ -1,6 +1,6 @@ // field.h - Header file for fieldID instances. -*- c++ -*- -/* Copyright (C) 1998, 1999, 2000 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2004 Free Software Foundation This file is part of libgcj. @@ -21,9 +21,7 @@ details. */ struct _Jv_Field { -#ifndef COMPACT_FIELDS struct _Jv_Utf8Const* name; -#endif /* The type of the field, if isResolved(). If !isResolved(): The fields's signature as a (Utf8Const*). */ @@ -31,11 +29,7 @@ struct _Jv_Field _Jv_ushort flags; -#ifdef COMPACT_FIELDS - jshort nameIndex; /* offset in class's name table */ -#else _Jv_ushort bsize; /* not really needed ... */ -#endif union { jint boffset; /* offset in bytes for instance field */ @@ -91,13 +85,8 @@ struct _Jv_Field return flags & java::lang::reflect::Modifier::ALL_FLAGS; } -#ifdef COMPACT_FIELDS - _Jv_Utf8Const * getNameUtf8Const (jclass cls) - { return clas->fieldNames + nameIndex; } -#else _Jv_Utf8Const * getNameUtf8Const (jclass) { return name; } #endif -#endif }; #ifdef __cplusplus diff --git a/libjava/gcj/javaprims.h b/libjava/gcj/javaprims.h index 3120184650f..53c26fe1a8e 100644 --- a/libjava/gcj/javaprims.h +++ b/libjava/gcj/javaprims.h @@ -1,5 +1,6 @@ // javaprims.h - Main external header file for libgcj. -*- c++ -*- + /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation @@ -84,6 +85,7 @@ extern "Java" class LineNumberInputStream; class LineNumberReader; class MemberComparator; + class MyIOException; class NotActiveException; class NotSerializableException; class ObjectInput; @@ -214,6 +216,7 @@ extern "Java" class UnsupportedClassVersionError; class UnsupportedOperationException; class VMClassLoader; + class VMCompiler; class VMSecurityManager; class VMThrowable; class VerifyError; diff --git a/libjava/gij.cc b/libjava/gij.cc index 8c75fa6db7a..64457857a13 100644 --- a/libjava/gij.cc +++ b/libjava/gij.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -35,6 +35,7 @@ help () printf (" -X print help on supported -X options, then exit\n"); printf (" --ms=NUMBER set initial heap size\n"); printf (" --mx=NUMBER set maximum heap size\n"); + printf (" --verbose[:class] print information about class loading\n"); printf (" --showversion print version number, then keep going\n"); printf (" --version print version number, then exit\n"); printf ("\nOptions can be specified with `-' or `--'.\n"); @@ -133,7 +134,7 @@ main (int argc, const char **argv) // correct behavior. _Jv_Jar_Class_Path = argv[++i]; } - else if (! strcmp (arg, "-verbose:class")) + else if (! strcmp (arg, "-verbose") || ! strcmp (arg, "-verbose:class")) gcj::verbose_class_flag = true; else if (arg[1] == 'X') { diff --git a/libjava/gnu/gcj/runtime/PersistentByteMap.java b/libjava/gnu/gcj/runtime/PersistentByteMap.java new file mode 100644 index 00000000000..90b7d33a8f4 --- /dev/null +++ b/libjava/gnu/gcj/runtime/PersistentByteMap.java @@ -0,0 +1,484 @@ +/* Copyright (C) 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + + + +/* A PersistentByteMap maps a byte array to another byte array. It +uses a file that does not need to be serialized but may be +memory-mapped and read in-place. So, even if there are many instances +of gcj applications running, the can share PersistentByteMaps. + +The idea is to make searches as fast as possible: opening a +PersistentByteMap is cheap and search time doesn't grow with the +number of entries in the table. On the other hand, enumerating the +map is slow, but that is a relatively uncommon operation. + +The main use of this class is to provide a way to map the +MessageDigest of a class file to the location of a DSO that contains +the compiled version of that class. It is up the the installer of an +application to keep the DSO up to date with the jar. + +USAGE: + MessageDigest md = MessageDigest.getInstance("MD5"); + digest = md.digest(bytes); + + PersistentByteMap map + = new PersistentByteMap + (fileName, PersistentByteMap.AccessMode.READ_ONLY); + + byte[] soName = map.get(digest); + if (soName) + { + String SharedLibraryName = new String(soName); + +BUGS/FEATURES: + remove() isn't written yet. + + we can't change the capacity of a PersistentByteMap. + + 0x12345678 is a bad choice for the magic number. + + capacity is fixed once the map has been created. + + We use linear probing to resolve collisions. It might be + better to use a scheme that results in fewer probes to + determine that an item isn't found. However, even when the + table is half full there are only on average 1.5 probes for a + successful search and 2.5 probes for an unsuccessful one. + + We don't use unique strings. This wastes space. + + capacity should probably be prime, but we don't check that. + + we don't do any locking at all: adding to a PersistentByteMap + at runtime is possible, but it requires filesystem locks + around get(), put(), and remove(). +*/ + +package gnu.gcj.runtime; + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.security.MessageDigest; + +public class PersistentByteMap +{ + private MappedByteBuffer buf; + + static private final int MAGIC = 0; + static private final int VERSION = 4; + static private final int CAPACITY = 8; + static private final int TABLE_BASE = 12; + static private final int STRING_BASE = 16; + static private final int STRING_SIZE = 20; + static private final int FILE_SIZE = 24; + static private final int ELEMENTS = 28; + + static private final int INT_SIZE = 4; + + static private final int TABLE_ENTRY_SIZE = 2 * INT_SIZE; + + private int capacity; // number of entries + private int table_base; // offset from start of file, in bytes + private int string_base; // offset from start of file, in bytes + private int string_size; // size of string table, in bytes + private int file_size; // size of file, in bytes; + private int elements; // number of elements in table + + private long length; // the length of the underlying file + + static private final int UNUSED_ENTRY = -1; + + static public final int KEYS = 0; + static public final int VALUES = 1; + static public final int ENTRIES = 2; + + static final public class AccessMode + { + private final FileChannel.MapMode mapMode; + + static + { + READ_ONLY = new AccessMode(FileChannel.MapMode.READ_ONLY); + READ_WRITE = new AccessMode(FileChannel.MapMode.READ_WRITE); + } + + public static final AccessMode READ_ONLY; + public static final AccessMode READ_WRITE; + + private AccessMode(FileChannel.MapMode mode) + { + this.mapMode = mode; + } + } + + private PersistentByteMap() + { + } + + public PersistentByteMap(String filename, AccessMode mode) + throws IOException + { + this(new File(filename), mode); + } + + public PersistentByteMap(File f, AccessMode mode) + throws IOException + { + FileChannel fc; + + if (mode == AccessMode.READ_ONLY) + { + FileInputStream fis = new FileInputStream(f); + fc = fis.getChannel(); + } + else + { + RandomAccessFile fos = new RandomAccessFile(f, "rw"); + fc = fos.getChannel(); + } + + length = fc.size(); + buf = fc.map(mode.mapMode, 0, length); + + int magic = getWord (MAGIC); + if (magic != 0x12345678) + throw new IllegalArgumentException(f.getName()); + + table_base = getWord (TABLE_BASE); + capacity = getWord (CAPACITY); + string_base = getWord (STRING_BASE); + string_size = getWord (STRING_SIZE); + file_size = getWord (FILE_SIZE); + elements = getWord (ELEMENTS); + + // FIXME: Insert a bunch of sanity checks here + } + + private void init (PersistentByteMap m, File f, int capacity, int strtabSize) + throws IOException + { + f.createNewFile(); + RandomAccessFile raf = new RandomAccessFile(f, "rw"); + + this.capacity = capacity; + table_base = 64; + string_base = table_base + capacity * TABLE_ENTRY_SIZE; + string_size = 0; + file_size = string_base; + elements = 0; + + int totalFileSize = string_base + strtabSize; + + // Create the file; this rounds up the size of the file to a fixed + // number of 4k pages. + byte[] _4k = new byte[4096]; + for (long i = 0; i < totalFileSize; i+= 4096) + raf.write(_4k); + + FileChannel fc = raf.getChannel(); + buf = fc.map(FileChannel.MapMode.READ_WRITE, 0, raf.length()); + + for (int i = 0; i < capacity; i++) + putKeyPos(UNUSED_ENTRY, i); + + putWord(0x12345678, MAGIC); + putWord(0x01, VERSION); + putWord(capacity, CAPACITY); + putWord(table_base, TABLE_BASE); + putWord(string_base, STRING_BASE); + putWord(file_size, FILE_SIZE); + putWord(elements, ELEMENTS); + buf.force(); + } + + static public PersistentByteMap emptyPersistentByteMap(String filename, + int capacity, int strtabSize) + throws IOException + { + File f = new File(filename); + PersistentByteMap m = new PersistentByteMap(); + m.init(m, f, capacity, strtabSize); + return m; + } + + private int getWord (int index) + { + buf.position(index); + byte[] wordBuf = new byte[4]; + buf.get(wordBuf); + + int result = (int)wordBuf[0]&0xff; + result += ((int)wordBuf[1]&0xff) << 8; + result += ((int)wordBuf[2]&0xff) << 16; + result += ((int)wordBuf[3]&0xff) << 24; + return result; + } + + private void putWord (int word, int index) + { + buf.position(index); + byte[] wordBuf = new byte[4]; + wordBuf[0] = (byte)(word); + wordBuf[1] = (byte)(word >>> 8); + wordBuf[2] = (byte)(word >>> 16); + wordBuf[3] = (byte)(word >>> 24); + buf.put(wordBuf); + } + + public Set entrySet() + { + return null; + } + + private int getBucket(int n) + { + return table_base + (2*n * INT_SIZE); + } + + private int getKeyPos(int n) + { + return getWord(getBucket(n)); + } + + private int getValuePos(int n) + { + return getWord(getBucket(n) + INT_SIZE); + } + + private void putKeyPos(int index, int n) + { + putWord(index, getBucket(n)); + } + + private void putValuePos(int index, int n) + { + putWord(index, getBucket(n) + INT_SIZE); + } + + private byte[] getBytes(int n) + { + int len = getWord (string_base + n); + int base = string_base + n + INT_SIZE; + byte[] key = new byte[len]; + buf.position(base); + buf.get(key, 0, len); + return key; + } + + private int hash (byte[] b) + { + // We assume that the message digest is evenly distributed, so we + // only need to use a few bytes of it as the hash function. + long hashIndex + = ((b[0]&0xffL) + + ((b[1]&0xffL)<<8) + + ((b[2]&0xffL)<<16) + + ((b[3]&0xffL)<<24)); + long result = hashIndex % (long)capacity; + return (int)result; + } + + public byte[] get(byte[] digest) + { + int hashIndex = hash(digest); + + do + { + int k = getKeyPos(hashIndex); + if (k == UNUSED_ENTRY) + return null; + + if (Arrays.equals ((byte[])digest, getBytes(k))) + return getBytes(getValuePos(hashIndex)); + + // Use linear probing to resolve hash collisions. This may + // not be theoretically as good as open addressing, but it has + // good cache behviour. + hashIndex++; + hashIndex %= capacity; + } + while (true); + } + + public void put(byte[] digest, byte[] value) + throws IllegalAccessException + { + int hashIndex = hash(digest); + + // With the the table 2/3 full there will be on average 2 probes + // for a successful search and 5 probes for an unsuccessful one. + if (elements >= capacity * 2/3) + throw new IllegalAccessException("Table Full: " + elements); + + do + { + int k = getKeyPos(hashIndex); + if (k == UNUSED_ENTRY) + { + int newKey = addBytes(digest); + putKeyPos(newKey, hashIndex); + int newValue = addBytes(value); + putValuePos(newValue, hashIndex); + elements++; + putWord(elements, ELEMENTS); + return; + } + else if (Arrays.equals (digest, getBytes(k))) + { + int newValue = addBytes((byte[])value); + putValuePos(newValue, hashIndex); + return; + } + + hashIndex++; + hashIndex %= capacity; + } + while (true); + } + + private int addBytes (byte[] data) + throws IllegalAccessException + { + if (data.length + INT_SIZE >= this.length) + throw new IllegalAccessException("String table Full"); + + int extent = string_base+string_size; + int top = extent; + putWord(data.length, extent); + extent += INT_SIZE; + buf.position(extent); + buf.put(data, 0, data.length); + extent += data.length; + extent += INT_SIZE-1; + extent &= ~(INT_SIZE-1); // align + string_size = extent - string_base; + file_size = extent; + putWord (string_size, STRING_SIZE); + putWord (file_size, FILE_SIZE); + + return top - string_base; + } + + public Iterator iterator(int type) + { + return new HashIterator(type); + } + + public int size() + { + return elements; + } + + public int capacity() + { + return capacity; + } + + private final class HashIterator implements Iterator + { + /** Current index in the physical hash table. */ + + private int idx; + private int count; + private final int type; + + /** + * Construct a new HashIterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + HashIterator(int type) + { + this.type = type; + count = elements; + idx = 0; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + * @throws ConcurrentModificationException if the HashMap was modified + */ + public boolean hasNext() + { + return count > 0; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the HashMap was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + count--; + for (int i = idx; i < capacity; i++) + if (getKeyPos(i) != UNUSED_ENTRY) + { + idx = i+1; + if (type == VALUES) + return getBytes(getValuePos(i)); + if (type == KEYS) + return getBytes(getKeyPos(i)); + return new MapEntry(i, + getBytes(getKeyPos(i)), + getBytes(getValuePos(i))); + } + return null; + } + + /** + * Remove from the underlying collection the last element returned + * by next (optional operation). This method can be called only + * once after each call to <code>next()</code>. It does not affect + * what will be returned by subsequent calls to next. + * + * @throws IllegalStateException if next has not yet been called + * or remove has already been called since the last call + * to next. + * @throws UnsupportedOperationException if this Iterator does not + * support the remove operation. + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + static public final class MapEntry + { + private final Object key; + private final Object value; + private final int bucket; + + public MapEntry(int bucket, Object newKey, Object newValue) + { + this.key = newKey; + this.value = newValue; + this.bucket = bucket; + } + + public final Object getKey() + { + return key; + } + + public final Object getValue() + { + return value; + } + + public final int getBucket() + { + return bucket; + } + } +} diff --git a/libjava/gnu/gcj/runtime/SharedLibHelper.java b/libjava/gnu/gcj/runtime/SharedLibHelper.java index 9e170a120be..a0bfe68b83c 100644 --- a/libjava/gnu/gcj/runtime/SharedLibHelper.java +++ b/libjava/gnu/gcj/runtime/SharedLibHelper.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2003 Free Software Foundation +/* Copyright (C) 2001, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -13,6 +13,12 @@ import java.net.MalformedURLException; import java.util.HashMap; import java.security.*; import gnu.gcj.Core; +import java.util.Set; +import java.util.Iterator; +import java.util.HashSet; +import java.util.HashMap; +import java.nio.channels.FileChannel; +import java.io.*; public class SharedLibHelper { @@ -36,34 +42,82 @@ public class SharedLibHelper { synchronized (map) { - WeakReference ref = (WeakReference) map.get(libname); - if (ref != null) - return (SharedLibHelper) ref.get(); + Set s = (Set)map.get(libname); + if (s == null) + return null; + for (Iterator i=s.iterator(); i.hasNext();) + { + WeakReference ref = (WeakReference)i.next(); + if (ref != null) + return (SharedLibHelper) ref.get(); + } return null; } } + static void copyFile (File in, File out) throws IOException + { + FileChannel source = new FileInputStream(in).getChannel(); + FileChannel destination = new FileOutputStream(out).getChannel(); + source.transferTo(0, source.size(), destination); + source.close(); + destination.close(); + } + public static SharedLibHelper findHelper (ClassLoader loader, String libname, CodeSource source) { synchronized (map) { SharedLibHelper result; - WeakReference ref = (WeakReference) map.get(libname); - if (ref != null) + Set s = (Set)map.get(libname); + if (s == null) + { + s = new HashSet(); + map.put(libname, s); + } + else { - result = (SharedLibHelper) ref.get(); - if (result != null) + for (Iterator i=s.iterator(); i.hasNext();) { - if (result.loader != loader) - // FIXME - throw new UnknownError(); - return result; + WeakReference ref = (WeakReference)i.next(); + if (ref != null) + { + result = (SharedLibHelper) ref.get(); + if (result != null) + { + // A match succeeds if the library is already + // loaded by LOADER or any of its ancestors. + ClassLoader l = loader; + do + { + if (result.loader == l) + return result; + l = l.getParent(); + } + while (l != null); + } + } } - } + // Oh dear. We've already mapped this shared library, but + // with a different class loader. We need to copy it. + try + { + File copy + = File.createTempFile(new File(libname).getName(), + ".so", new File ("/tmp")); + File src = new File(libname); + copyFile (src, copy); + libname = copy.getPath(); + } + catch (IOException e) + { + return null; + } + } result = new SharedLibHelper(libname, loader, source, 0); - map.put(libname, new WeakReference(result)); + s.add(new WeakReference(result)); return result; } } @@ -73,7 +127,15 @@ public class SharedLibHelper public Class findClass(String name) { ensureInit(); - return (Class) classMap.get(name); + Class result = (Class) classMap.get(name); + if (result != null) + { + // We never want to return a class without its supers linked. + // It isn't clear from the spec, but this is what other + // implementations do in practice. + ensureSupersLinked(result); + } + return result; } public URL findResource (String name) @@ -106,6 +168,12 @@ public class SharedLibHelper native boolean hasResource(String name); native void init(); + native void ensureSupersLinked(Class k); + + public String toString () + { + return "shared object " + baseName; + } /** Called during dlopen's processing of the init section. */ void registerClass(String name, Class cls) diff --git a/libjava/gnu/gcj/runtime/VMClassLoader.java b/libjava/gnu/gcj/runtime/VMClassLoader.java index 1fc7081bb78..f9ef872b30a 100644 --- a/libjava/gnu/gcj/runtime/VMClassLoader.java +++ b/libjava/gnu/gcj/runtime/VMClassLoader.java @@ -105,7 +105,8 @@ public final class VMClassLoader extends java.net.URLClassLoader /** This is overridden to search the internal hash table, which * will only search existing linked-in classes. This will make * the default implementation of loadClass (in ClassLoader) work right. - * The implementation of this method is in java/lang/natClassLoader.cc. + * The implementation of this method is in + * gnu/gcj/runtime/natVMClassLoader.cc. */ protected native Class findClass(String name) throws java.lang.ClassNotFoundException; diff --git a/libjava/gnu/gcj/runtime/natSharedLibLoader.cc b/libjava/gnu/gcj/runtime/natSharedLibLoader.cc index 46eef755a09..184692e1040 100644 --- a/libjava/gnu/gcj/runtime/natSharedLibLoader.cc +++ b/libjava/gnu/gcj/runtime/natSharedLibLoader.cc @@ -1,6 +1,6 @@ // natSharedLibLoader.cc - Implementation of SharedLibHelper native methods. -/* Copyright (C) 2001, 2003 Free Software Foundation +/* Copyright (C) 2001, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -12,6 +12,8 @@ details. */ #include <gcj/cni.h> #include <jvm.h> +#include <execution.h> + #include <gnu/gcj/runtime/SharedLibHelper.h> #include <java/io/IOException.h> #include <java/lang/UnsupportedOperationException.h> @@ -30,9 +32,10 @@ typedef void (*CoreHookFunc) (_Jv_core_chain *); void _Jv_sharedlib_register_hook (jclass cls) { - curHelper->registerClass(cls->getName(), cls); cls->protectionDomain = curHelper->domain; cls->loader = curLoader; + cls->engine = &_Jv_soleCompiledEngine; + curHelper->registerClass(cls->getName(), cls); } static void @@ -122,3 +125,9 @@ gnu::gcj::runtime::SharedLibHelper::finalize() dlclose (handler); #endif } + +void +gnu::gcj::runtime::SharedLibHelper::ensureSupersLinked(jclass k) +{ + _Jv_Linker::wait_for_state (k, JV_STATE_LOADING); +} diff --git a/libjava/gnu/gcj/tools/gcj_dbtool/Main.java b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java new file mode 100644 index 00000000000..a478f934297 --- /dev/null +++ b/libjava/gnu/gcj/tools/gcj_dbtool/Main.java @@ -0,0 +1,272 @@ +/* Copyright (C) 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package gnu.gcj.tools.gcj_dbtool; + + +import gnu.gcj.runtime.PersistentByteMap; +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.security.MessageDigest; +import java.math.BigInteger; + +public class Main +{ + public static void main (String[] s) + { + insist (s.length >= 1); + if (s[0].equals("-v")) + { + insist (s.length == 1); + System.out.println("jv-dbtool (" + + System.getProperty("java.vm.name") + + ") " + + System.getProperty("java.vm.version")); + System.out.println(); + System.out.println("Copyright 2004 Free Software Foundation, Inc."); + System.out.println("This is free software; see the source for copying conditions. There is NO"); + System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); + return; + } + + if (s[0].equals("-n")) + { + insist (s.length >= 2 && s.length <= 3); + + int capacity = 32749; + + if (s.length == 3) + { + // The user has explicitly provided a size for the table. + // We're going to make that size prime. This isn't + // strictly necessary but it can't hurt. + + BigInteger size = new BigInteger(s[2], 10); + BigInteger two = BigInteger.ONE.add(BigInteger.ONE); + + if (size.getLowestSetBit() != 0) // A hard way to say isEven() + size = size.add(BigInteger.ONE); + + while (! size.isProbablePrime(10)) + size = size.add(two); + + capacity = size.intValue(); + + if (capacity <= 2) + { + usage(); + System.exit(1); + } + } + + try + { + PersistentByteMap b + = PersistentByteMap.emptyPersistentByteMap (s[1], capacity, capacity*64); + } + catch (Exception e) + { + System.err.println ("error: could not create " + + s[1] + ": " + e.toString()); + System.exit(2); + } + return; + } + + if (s[0].equals("-a")) + { + try + { + insist (s.length == 4); + File jar = new File(s[2]); + PersistentByteMap b + = new PersistentByteMap(new File(s[1]), + PersistentByteMap.AccessMode.READ_WRITE); + File soFile = new File(s[3]); + if (! soFile.isFile()) + throw new IllegalArgumentException(s[3] + " is not a file"); + + addJar(jar, b, soFile); + } + catch (Exception e) + { + System.err.println ("error: could not update " + s[1] + + ": " + e.toString()); + System.exit(2); + } + return; + } + + if (s[0].equals("-t")) + { + try + { + insist (s.length == 2); + PersistentByteMap b + = new PersistentByteMap(new File(s[1]), + PersistentByteMap.AccessMode.READ_ONLY); + Iterator iterator = b.iterator(PersistentByteMap.ENTRIES); + + while (iterator.hasNext()) + { + PersistentByteMap.MapEntry entry + = (PersistentByteMap.MapEntry)iterator.next(); + byte[] key = (byte[])entry.getKey(); + byte[] value = (byte[])b.get(key); + if (! Arrays.equals (value, (byte[])entry.getValue())) + { + String err + = ("Key " + bytesToString(key) + " at bucket " + + entry.getBucket()); + + throw new RuntimeException(err); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + System.exit(3); + } + return; + } + + if (s[0].equals("-l")) + { + insist (s.length == 2); + try + { + PersistentByteMap b + = new PersistentByteMap(new File(s[1]), + PersistentByteMap.AccessMode.READ_ONLY); + + System.out.println ("Capacity: " + b.capacity()); + System.out.println ("Size: " + b.size()); + System.out.println (); + + System.out.println ("Elements: "); + Iterator iterator = b.iterator(PersistentByteMap.ENTRIES); + + while (iterator.hasNext()) + { + PersistentByteMap.MapEntry entry + = (PersistentByteMap.MapEntry)iterator.next(); + byte[] digest = (byte[])entry.getKey(); + System.out.print ("[" + entry.getBucket() + "] " + + bytesToString(digest) + + " -> "); + System.out.println (new String((byte[])entry.getValue())); + } + } + catch (Exception e) + { + System.err.println ("error: could not list " + + s[1] + ": " + e.toString()); + System.exit(2); + } + return; + } + + if (s[0].equals("-d")) + { + insist (s.length == 2); + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + PersistentByteMap b + = new PersistentByteMap(new File(s[1]), + PersistentByteMap.AccessMode.READ_WRITE); + int N = b.capacity(); + byte[] bytes = new byte[1]; + byte digest[] = md.digest(bytes); + for (int i = 0; i < N; i++) + { + digest = md.digest(digest); + b.put(digest, digest); + } + } + catch (Exception e) + { + e.printStackTrace(); + System.exit(3); + } + return; + } + + usage(); + System.exit(1); + } + + private static void insist(boolean ok) + { + if (! ok) + { + usage(); + System.exit(1); + } + } + + private static void usage() + { + System.err.println + ("jv-dbtool: Manipulate gcj map database files\n" + + "\n" + + " Usage: \n" + + " jv-dbtool -n file.gcjdb [size] - Create a new gcj map database\n" + + " jv-dbtool -a file.gcjdb file.jar file.so\n" + + " - Add the contents of file.jar to the database\n" + + " jv-dbtool -t file.gcjdb - Test a gcj map database\n" + + " jv-dbtool -l file.gcjdb - List a gcj map database\n"); + } + + + private static void addJar(File f, PersistentByteMap b, File soFile) + throws Exception + { + MessageDigest md = MessageDigest.getInstance("MD5"); + + JarFile jar = new JarFile (f); + Enumeration entries = jar.entries(); + + while (entries.hasMoreElements()) + { + JarEntry classfile = (JarEntry)entries.nextElement(); + if (classfile.getName().endsWith(".class")) + { + InputStream str = jar.getInputStream(classfile); + long length = classfile.getSize(); + if (length == -1) + throw new EOFException(); + + byte[] data = new byte[length]; + int pos = 0; + while (length - pos > 0) + { + int len = str.read(data, pos, (int)(length - pos)); + if (len == -1) + throw new EOFException("Not enough data reading from: " + + classfile.getName()); + pos += len; + } + b.put(md.digest(data), + soFile.getCanonicalPath().getBytes()); + } + } + } + + static String bytesToString(byte[] b) + { + StringBuffer hexBytes = new StringBuffer(); + int length = b.length; + for (int i = 0; i < length; ++i) + hexBytes.append(Integer.toHexString(b[i] & 0xff)); + return hexBytes.toString(); + } +} + diff --git a/libjava/include/Makefile.in b/libjava/include/Makefile.in index 426f958b262..82cef6f29a2 100644 --- a/libjava/include/Makefile.in +++ b/libjava/include/Makefile.in @@ -145,6 +145,7 @@ LIBGCJTESTSPEC = @LIBGCJTESTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ +LIBGCJ_LD_SYMBOLIC = @LIBGCJ_LD_SYMBOLIC@ LIBICONV = @LIBICONV@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ diff --git a/libjava/include/execution.h b/libjava/include/execution.h new file mode 100644 index 00000000000..b8f47468fc7 --- /dev/null +++ b/libjava/include/execution.h @@ -0,0 +1,146 @@ +// execution.h - Execution engines. -*- c++ -*- + +/* Copyright (C) 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#ifndef __JAVA_EXECUTION_H__ +#define __JAVA_EXECUTION_H__ + +// This represents one execution engine. Note that we use function +// pointers and not virtual methods to avoid calls to +// __cxa_call_unexpected and the like. +struct _Jv_ExecutionEngine +{ + public: + + void (*unregister) (jclass); + // FIXME: probably should handle this elsewhere, see how + // interpreter does it. + bool (*need_resolve_string_fields) (); + void (*verify) (jclass); + void (*allocate_static_fields) (jclass, int); + void (*create_ncode) (jclass); + _Jv_ResolvedMethod *(*resolve_method) (_Jv_Method *, jclass, + jboolean, jint); + void (*post_miranda_hook) (jclass); +}; + +// This handles all gcj-compiled code, including BC ABI. +struct _Jv_CompiledEngine : public _Jv_ExecutionEngine +{ + public: + + static void do_unregister (jclass) + { + } + + static bool do_need_resolve_string_fields () + { + return true; + } + + static void do_verify (jclass klass) + { + _Jv_Linker::verify_type_assertions (klass); + } + + static _Jv_ResolvedMethod *do_resolve_method (_Jv_Method *, jclass, + jboolean, jint) + { + return NULL; + } + + static void do_allocate_static_fields (jclass, int) + { + // Compiled classes don't need this. + } + + static void do_create_ncode (jclass) + { + // Not needed. + } + + static void do_post_miranda_hook (jclass) + { + // Not needed. + } + + _Jv_CompiledEngine () + { + unregister = do_unregister; + need_resolve_string_fields = do_need_resolve_string_fields; + verify = do_verify; + allocate_static_fields = do_allocate_static_fields; + create_ncode = do_create_ncode; + resolve_method = do_resolve_method; + post_miranda_hook = do_post_miranda_hook; + } + + // These operators make it so we don't have to link in libstdc++. + void *operator new (size_t bytes) + { + return _Jv_Malloc(bytes); + } + + void operator delete (void *mem) + { + _Jv_Free(mem); + } +}; + +// This handles interpreted code. +class _Jv_InterpreterEngine : public _Jv_ExecutionEngine +{ + public: + + static void do_verify (jclass); + static void do_allocate_static_fields (jclass, int); + static void do_create_ncode (jclass); + static _Jv_ResolvedMethod *do_resolve_method (_Jv_Method *, jclass, + jboolean, jint); + + static bool do_need_resolve_string_fields () + { + return false; + } + + static void do_unregister(jclass klass) + { + _Jv_UnregisterClass(klass); + } + + static void do_post_miranda_hook (jclass); + + _Jv_InterpreterEngine () + { + unregister = do_unregister; + need_resolve_string_fields = do_need_resolve_string_fields; + verify = do_verify; + allocate_static_fields = do_allocate_static_fields; + create_ncode = do_create_ncode; + resolve_method = do_resolve_method; + post_miranda_hook = do_post_miranda_hook; + } + + // These operators make it so we don't have to link in libstdc++. + void *operator new (size_t bytes) + { + return _Jv_Malloc(bytes); + } + + void operator delete (void *mem) + { + _Jv_Free(mem); + } +}; + + +extern _Jv_InterpreterEngine _Jv_soleInterpreterEngine; +extern _Jv_CompiledEngine _Jv_soleCompiledEngine; + +#endif // __JAVA_EXECUTION_H__ diff --git a/libjava/include/java-interp.h b/libjava/include/java-interp.h index 12bc21f2436..c8e041ae387 100644 --- a/libjava/include/java-interp.h +++ b/libjava/include/java-interp.h @@ -1,6 +1,6 @@ // java-interp.h - Header file for the bytecode interpreter. -*- c++ -*- -/* Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -36,7 +36,8 @@ _Jv_IsInterpretedClass (jclass c) struct _Jv_ResolvedMethod; void _Jv_InitInterpreter (); -void _Jv_DefineClass (jclass, jbyteArray, jint, jint); +void _Jv_DefineClass (jclass, jbyteArray, jint, jint, + java::security::ProtectionDomain *); void _Jv_InitField (jobject, jclass, int); void * _Jv_AllocMethodInvocation (jsize size); @@ -88,11 +89,7 @@ protected: // Size of raw arguments. _Jv_ushort args_raw_size; - // Chain of addresses to fill in. See _Jv_Defer_Resolution. - void *deferred; - - friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); - friend void _Jv_PrepareClass(jclass); + friend class _Jv_InterpreterEngine; public: _Jv_Method *get_method () @@ -150,10 +147,9 @@ class _Jv_InterpMethod : public _Jv_MethodBase friend class _Jv_BytecodeVerifier; friend class gnu::gcj::runtime::NameFinder; friend class gnu::gcj::runtime::StackTrace; + friend class _Jv_InterpreterEngine; - friend void _Jv_PrepareClass(jclass); - #ifdef JV_MARKOBJ_DECL friend JV_MARKOBJ_DECL; #endif @@ -166,43 +162,15 @@ class _Jv_InterpClass friend class _Jv_ClassReader; friend class _Jv_InterpMethod; - friend void _Jv_PrepareClass(jclass); - friend void _Jv_PrepareMissingMethods (jclass base2, jclass iface_class); + friend class _Jv_InterpreterEngine; friend void _Jv_InitField (jobject, jclass, int); #ifdef JV_MARKOBJ_DECL friend JV_MARKOBJ_DECL; #endif friend _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass); - friend void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); }; -// We have an interpreted class CL and we're trying to find the -// address of the ncode of a method METH. That interpreted class -// hasn't yet been prepared, so we defer fixups until they are ready. -// To do this, we create a chain of fixups that will be resolved by -// _Jv_PrepareClass. -extern inline void -_Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **address) -{ - int i; - jclass self = (jclass) cl; - _Jv_InterpClass *interp_cl = (_Jv_InterpClass*) self->aux_info; - - for (i = 0; i < self->method_count; i++) - { - _Jv_Method *m = &self->methods[i]; - if (m == meth) - { - _Jv_MethodBase *imeth = interp_cl->interpreted_methods[i]; - *address = imeth->deferred; - imeth->deferred = address; - return; - } - } - return; -} - extern inline _Jv_MethodBase ** _Jv_GetFirstMethod (_Jv_InterpClass *klass) { @@ -240,7 +208,11 @@ class _Jv_JNIMethod : public _Jv_MethodBase void *ncode (); friend class _Jv_ClassReader; - friend void _Jv_PrepareClass(jclass); + friend class _Jv_InterpreterEngine; + +#ifdef JV_MARKOBJ_DECL + friend JV_MARKOBJ_DECL; +#endif public: // FIXME: this is ugly. diff --git a/libjava/include/java-stack.h b/libjava/include/java-stack.h new file mode 100644 index 00000000000..6c3103ce056 --- /dev/null +++ b/libjava/include/java-stack.h @@ -0,0 +1,84 @@ +// java-stack.h - Definitions for unwinding & inspecting the call stack. + +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#ifndef __JV_STACKTRACE_H__ +#define __JV_STACKTRACE_H__ + +#include <unwind.h> + +#include <gcj/cni.h> +#include <gcj/javaprims.h> + +#include <java-interp.h> + +#include <java/lang/Class.h> +#include <java/lang/StackTraceElement.h> +#include <java/lang/Throwable.h> + +#include <gnu/gcj/runtime/NameFinder.h> + +using namespace gnu::gcj::runtime; + +enum _Jv_FrameType +{ + frame_native, + frame_interpreter +}; + +#ifdef INTERPRETER +struct _Jv_InterpFrameInfo +{ + _Jv_InterpMethod *meth; + pc_t pc; +}; +#endif + +union _Jv_FrameInfo +{ +}; + +struct _Jv_StackFrame +{ + _Jv_FrameType type; /* Native or interpreted. */ + union { +#ifdef INTERPRETER + _Jv_InterpFrameInfo interp; +#endif + void *ip; + }; +// _Jv_FrameInfo info; /* Frame-type specific data. */ + jclass klass; + _Jv_Method *meth; +}; + +class _Jv_StackTrace +{ +private: + int length; + _Jv_StackFrame frames[]; + + static void UpdateNCodeMap (); + static jclass ClassForIP (void *ip, void **ncode); + static void FillInFrameInfo (_Jv_StackFrame *frame); + static void getLineNumberForFrame(_Jv_StackFrame *frame, NameFinder *finder, + jstring *sourceFileName, jint *lineNum); + + static _Unwind_Reason_Code UnwindTraceFn (struct _Unwind_Context *context, + void *state_ptr); + +public: + static _Jv_StackTrace *GetStackTrace (void); + static JArray< ::java::lang::StackTraceElement *>* + GetStackTraceElements (_Jv_StackTrace *trace, + java::lang::Throwable *throwable); + static jclass GetCallingClass (void); +}; + +#endif /* __JV_STACKTRACE_H__ */ diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 55799515c05..a3d06e7b09f 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -1,6 +1,6 @@ // jvm.h - Header file for private implementation information. -*- c++ -*- -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -231,9 +231,6 @@ inline _Jv_TempUTFString::~_Jv_TempUTFString () char utfstr##_buf[utfstr##_len <= 256 ? utfstr##_len : 0]; \ _Jv_TempUTFString utfstr(utfstr##thejstr, sizeof(utfstr##_buf)==0 ? 0 : utfstr##_buf) -// FIXME: remove this define. -#define StringClass java::lang::String::class$ - namespace gcj { /* Some constants used during lookup of special class methods. */ @@ -249,6 +246,43 @@ namespace gcj extern bool verbose_class_flag; } +// This class handles all aspects of class preparation and linking. +class _Jv_Linker +{ +private: + static void prepare_constant_time_tables(jclass); + static jshort get_interfaces(jclass, _Jv_ifaces *); + static void link_symbol_table(jclass); + static void link_exception_table(jclass); + static void layout_interface_methods(jclass); + static void layout_vtable_methods(jclass); + static void set_vtable_entries(jclass, _Jv_VTable *); + static void make_vtable(jclass); + static void ensure_fields_laid_out(jclass); + static void ensure_class_linked(jclass); + static void ensure_supers_installed(jclass); + static void add_miranda_methods(jclass, jclass); + static void ensure_method_table_complete(jclass); + static void verify_class(jclass); + static jshort find_iindex(jclass *, jshort *, jshort); + static jshort indexof(void *, void **, jshort); + static int get_alignment_from_class(jclass); + static void generate_itable(jclass, _Jv_ifaces *, jshort *); + static jshort append_partial_itable(jclass, jclass, void **, jshort); + static _Jv_Method *search_method_in_class (jclass, jclass, + _Jv_Utf8Const *, + _Jv_Utf8Const *); + +public: + + static void print_class_loaded (jclass); + static void resolve_class_ref (jclass, jclass *); + static void wait_for_state(jclass, int); + static _Jv_word resolve_pool_entry (jclass, int); + static void resolve_field (_Jv_Field *, java::lang::ClassLoader *); + static void verify_type_assertions (jclass); +}; + /* Type of pointer used as finalizer. */ typedef void _Jv_FinalizerFunc (jobject); @@ -416,7 +450,6 @@ extern "C" void _Jv_RegisterClasses_Counted (const jclass *classes, size_t count); extern "C" void _Jv_RegisterResource (void *vptr); extern void _Jv_UnregisterClass (_Jv_Utf8Const*, java::lang::ClassLoader*); -extern void _Jv_ResolveField (_Jv_Field *, java::lang::ClassLoader*); extern jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader); diff --git a/libjava/interpret.cc b/libjava/interpret.cc index 0446c729623..91d4b194774 100644 --- a/libjava/interpret.cc +++ b/libjava/interpret.cc @@ -11,6 +11,7 @@ details. */ /* Author: Kresten Krab Thorup <krab@gnu.org> */ #include <config.h> +#include <platform.h> // Define this to get the direct-threaded interpreter. If undefined, // we revert to a basic bytecode interpreter. The former is faster @@ -38,9 +39,15 @@ details. */ #include <java/lang/Thread.h> #include <java-insns.h> #include <java-signal.h> +#include <java/lang/ClassFormatError.h> +#include <execution.h> +#include <java/lang/reflect/Modifier.h> #ifdef INTERPRETER +// Execution engine for interpreted code. +_Jv_InterpreterEngine _Jv_soleInterpreterEngine; + #include <stdlib.h> using namespace gcj; @@ -54,6 +61,11 @@ static void throw_null_pointer_exception () __attribute__ ((__noreturn__)); #endif +static void throw_class_format_error (jstring msg) + __attribute__ ((__noreturn__)); +static void throw_class_format_error (char *msg) + __attribute__ ((__noreturn__)); + #ifdef DIRECT_THREADED // Lock to ensure that methods are not compiled concurrently. // We could use a finer-grained lock here, however it is not safe to use @@ -765,8 +777,9 @@ _Jv_InterpMethod::compile (const void * const *insn_targets) exc[i].start_pc.p = &insns[pc_mapping[exc[i].start_pc.i]]; exc[i].end_pc.p = &insns[pc_mapping[exc[i].end_pc.i]]; exc[i].handler_pc.p = &insns[pc_mapping[exc[i].handler_pc.i]]; - jclass handler = (_Jv_ResolvePoolEntry (defining_class, - exc[i].handler_type.i)).clazz; + jclass handler + = (_Jv_Linker::resolve_pool_entry (defining_class, + exc[i].handler_type.i)).clazz; exc[i].handler_type.p = handler; } @@ -1113,13 +1126,14 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - /* _Jv_ResolvePoolEntry returns immediately if the value already - * is resolved. If we want to clutter up the code here to gain - * a little performance, then we can check the corresponding bit - * JV_CONSTANT_ResolvedFlag in the tag directly. For now, I - * don't think it is worth it. */ + /* _Jv_Linker::resolve_pool_entry returns immediately if the + * value already is resolved. If we want to clutter up the + * code here to gain a little performance, then we can check + * the corresponding bit JV_CONSTANT_ResolvedFlag in the tag + * directly. For now, I don't think it is worth it. */ - rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; + rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).rmethod; sp -= rmeth->stack_item_count; // We don't use NULLCHECK here because we can't rely on that @@ -2409,7 +2423,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_getstatic: { jint fieldref_index = GET2U (); - _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & Modifier::STATIC) == 0) @@ -2496,7 +2510,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_getfield: { jint fieldref_index = GET2U (); - _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; if ((field->flags & Modifier::STATIC) != 0) @@ -2612,7 +2626,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_putstatic: { jint fieldref_index = GET2U (); - _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; jclass type = field->type; @@ -2699,7 +2713,7 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_putfield: { jint fieldref_index = GET2U (); - _Jv_ResolvePoolEntry (defining_class, fieldref_index); + _Jv_Linker::resolve_pool_entry (defining_class, fieldref_index); _Jv_Field *field = pool_data[fieldref_index].field; jclass type = field->type; @@ -2825,7 +2839,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; + rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).rmethod; sp -= rmeth->stack_item_count; @@ -2863,7 +2878,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; + rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).rmethod; sp -= rmeth->stack_item_count; @@ -2892,7 +2908,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { int index = GET2U (); - rmeth = (_Jv_ResolvePoolEntry (defining_class, index)).rmethod; + rmeth = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).rmethod; sp -= rmeth->stack_item_count; @@ -2935,7 +2952,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_new: { int index = GET2U (); - jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; + jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).clazz; jobject res = _Jv_AllocObject (klass); PUSHA (res); @@ -2968,7 +2986,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) insn_anewarray: { int index = GET2U (); - jclass klass = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; + jclass klass = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).clazz; int size = POPI(); jobject result = _Jv_NewObjectArray (size, klass, 0); PUSHA (result); @@ -3010,7 +3029,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { jobject value = POPA(); jint index = GET2U (); - jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; + jclass to = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).clazz; if (value != NULL && ! to->isInstance (value)) throw new java::lang::ClassCastException (to->getName()); @@ -3040,7 +3060,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) { jobject value = POPA(); jint index = GET2U (); - jclass to = (_Jv_ResolvePoolEntry (defining_class, index)).clazz; + jclass to = (_Jv_Linker::resolve_pool_entry (defining_class, + index)).clazz; PUSHI (to->isInstance (value)); #ifdef DIRECT_THREADED @@ -3102,7 +3123,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) int dim = GET1U (); jclass type - = (_Jv_ResolvePoolEntry (defining_class, kind_index)).clazz; + = (_Jv_Linker::resolve_pool_entry (defining_class, + kind_index)).clazz; jint *sizes = (jint*) __builtin_alloca (sizeof (jint)*dim); for (int i = dim - 1; i >= 0; i--) @@ -3203,8 +3225,8 @@ _Jv_InterpMethod::run (void *retp, ffi_raw *args) #else jclass handler = NULL; if (exc[i].handler_type.i != 0) - handler = (_Jv_ResolvePoolEntry (defining_class, - exc[i].handler_type.i)).clazz; + handler = (_Jv_Linker::resolve_pool_entry (defining_class, + exc[i].handler_type.i)).clazz; #endif /* DIRECT_THREADED */ if (handler == NULL || handler->isAssignableFrom (exc_class)) @@ -3250,4 +3272,547 @@ throw_null_pointer_exception () } #endif +/** Do static initialization for fields with a constant initializer */ +void +_Jv_InitField (jobject obj, jclass klass, int index) +{ + using namespace java::lang::reflect; + + if (obj != 0 && klass == 0) + klass = obj->getClass (); + + if (!_Jv_IsInterpretedClass (klass)) + return; + + _Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info; + + _Jv_Field * field = (&klass->fields[0]) + index; + + if (index > klass->field_count) + throw_internal_error ("field out of range"); + + int init = iclass->field_initializers[index]; + if (init == 0) + return; + + _Jv_Constants *pool = &klass->constants; + int tag = pool->tags[init]; + + if (! field->isResolved ()) + throw_internal_error ("initializing unresolved field"); + + if (obj==0 && ((field->flags & Modifier::STATIC) == 0)) + throw_internal_error ("initializing non-static field with no object"); + + void *addr = 0; + + if ((field->flags & Modifier::STATIC) != 0) + addr = (void*) field->u.addr; + else + addr = (void*) (((char*)obj) + field->u.boffset); + + switch (tag) + { + case JV_CONSTANT_String: + { + jstring str; + str = _Jv_NewStringUtf8Const (pool->data[init].utf8); + pool->data[init].string = str; + pool->tags[init] = JV_CONSTANT_ResolvedString; + } + /* fall through */ + + case JV_CONSTANT_ResolvedString: + if (! (field->type == &java::lang::String::class$ + || field->type == &java::lang::Class::class$)) + throw_class_format_error ("string initialiser to non-string field"); + + *(jstring*)addr = pool->data[init].string; + break; + + case JV_CONSTANT_Integer: + { + int value = pool->data[init].i; + + if (field->type == JvPrimClass (boolean)) + *(jboolean*)addr = (jboolean)value; + + else if (field->type == JvPrimClass (byte)) + *(jbyte*)addr = (jbyte)value; + + else if (field->type == JvPrimClass (char)) + *(jchar*)addr = (jchar)value; + + else if (field->type == JvPrimClass (short)) + *(jshort*)addr = (jshort)value; + + else if (field->type == JvPrimClass (int)) + *(jint*)addr = (jint)value; + + else + throw_class_format_error ("erroneous field initializer"); + } + break; + + case JV_CONSTANT_Long: + if (field->type != JvPrimClass (long)) + throw_class_format_error ("erroneous field initializer"); + + *(jlong*)addr = _Jv_loadLong (&pool->data[init]); + break; + + case JV_CONSTANT_Float: + if (field->type != JvPrimClass (float)) + throw_class_format_error ("erroneous field initializer"); + + *(jfloat*)addr = pool->data[init].f; + break; + + case JV_CONSTANT_Double: + if (field->type != JvPrimClass (double)) + throw_class_format_error ("erroneous field initializer"); + + *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]); + break; + + default: + throw_class_format_error ("erroneous field initializer"); + } +} + +inline static unsigned char* +skip_one_type (unsigned char* ptr) +{ + int ch = *ptr++; + + while (ch == '[') + { + ch = *ptr++; + } + + if (ch == 'L') + { + do { ch = *ptr++; } while (ch != ';'); + } + + return ptr; +} + +static ffi_type* +get_ffi_type_from_signature (unsigned char* ptr) +{ + switch (*ptr) + { + case 'L': + case '[': + return &ffi_type_pointer; + break; + + case 'Z': + // On some platforms a bool is a byte, on others an int. + if (sizeof (jboolean) == sizeof (jbyte)) + return &ffi_type_sint8; + else + { + JvAssert (sizeof (jbyte) == sizeof (jint)); + return &ffi_type_sint32; + } + break; + + case 'B': + return &ffi_type_sint8; + break; + + case 'C': + return &ffi_type_uint16; + break; + + case 'S': + return &ffi_type_sint16; + break; + + case 'I': + return &ffi_type_sint32; + break; + + case 'J': + return &ffi_type_sint64; + break; + + case 'F': + return &ffi_type_float; + break; + + case 'D': + return &ffi_type_double; + break; + + case 'V': + return &ffi_type_void; + break; + } + + throw_internal_error ("unknown type in signature"); +} + +/* this function yields the number of actual arguments, that is, if the + * function is non-static, then one is added to the number of elements + * found in the signature */ + +int +_Jv_count_arguments (_Jv_Utf8Const *signature, + jboolean staticp) +{ + unsigned char *ptr = (unsigned char*) signature->chars(); + int arg_count = staticp ? 0 : 1; + + /* first, count number of arguments */ + + // skip '(' + ptr++; + + // count args + while (*ptr != ')') + { + ptr = skip_one_type (ptr); + arg_count += 1; + } + + return arg_count; +} + +/* This beast will build a cif, given the signature. Memory for + * the cif itself and for the argument types must be allocated by the + * caller. + */ + +static int +init_cif (_Jv_Utf8Const* signature, + int arg_count, + jboolean staticp, + ffi_cif *cif, + ffi_type **arg_types, + ffi_type **rtype_p) +{ + unsigned char *ptr = (unsigned char*) signature->chars(); + + int arg_index = 0; // arg number + int item_count = 0; // stack-item count + + // setup receiver + if (!staticp) + { + arg_types[arg_index++] = &ffi_type_pointer; + item_count += 1; + } + + // skip '(' + ptr++; + + // assign arg types + while (*ptr != ')') + { + arg_types[arg_index++] = get_ffi_type_from_signature (ptr); + + if (*ptr == 'J' || *ptr == 'D') + item_count += 2; + else + item_count += 1; + + ptr = skip_one_type (ptr); + } + + // skip ')' + ptr++; + ffi_type *rtype = get_ffi_type_from_signature (ptr); + + ptr = skip_one_type (ptr); + if (ptr != (unsigned char*)signature->chars() + signature->len()) + throw_internal_error ("did not find end of signature"); + + if (ffi_prep_cif (cif, FFI_DEFAULT_ABI, + arg_count, rtype, arg_types) != FFI_OK) + throw_internal_error ("ffi_prep_cif failed"); + + if (rtype_p != NULL) + *rtype_p = rtype; + + return item_count; +} + +#if FFI_NATIVE_RAW_API +# define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure +# define FFI_RAW_SIZE ffi_raw_size +#else +# define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure +# define FFI_RAW_SIZE ffi_java_raw_size +#endif + +/* we put this one here, and not in interpret.cc because it + * calls the utility routines _Jv_count_arguments + * which are static to this module. The following struct defines the + * layout we use for the stubs, it's only used in the ncode method. */ + +typedef struct { + ffi_raw_closure closure; + ffi_cif cif; + ffi_type *arg_types[0]; +} ncode_closure; + +typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*); + +void * +_Jv_InterpMethod::ncode () +{ + using namespace java::lang::reflect; + + if (self->ncode != 0) + return self->ncode; + + jboolean staticp = (self->accflags & Modifier::STATIC) != 0; + int arg_count = _Jv_count_arguments (self->signature, staticp); + + ncode_closure *closure = + (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) + + arg_count * sizeof (ffi_type*)); + + init_cif (self->signature, + arg_count, + staticp, + &closure->cif, + &closure->arg_types[0], + NULL); + + ffi_closure_fun fun; + + args_raw_size = FFI_RAW_SIZE (&closure->cif); + + JvAssert ((self->accflags & Modifier::NATIVE) == 0); + + if ((self->accflags & Modifier::SYNCHRONIZED) != 0) + { + if (staticp) + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; + else + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; + } + else + { + if (staticp) + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class; + else + fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal; + } + + FFI_PREP_RAW_CLOSURE (&closure->closure, + &closure->cif, + fun, + (void*)this); + + self->ncode = (void*)closure; + return self->ncode; +} + +void * +_Jv_JNIMethod::ncode () +{ + using namespace java::lang::reflect; + + if (self->ncode != 0) + return self->ncode; + + jboolean staticp = (self->accflags & Modifier::STATIC) != 0; + int arg_count = _Jv_count_arguments (self->signature, staticp); + + ncode_closure *closure = + (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) + + arg_count * sizeof (ffi_type*)); + + ffi_type *rtype; + init_cif (self->signature, + arg_count, + staticp, + &closure->cif, + &closure->arg_types[0], + &rtype); + + ffi_closure_fun fun; + + args_raw_size = FFI_RAW_SIZE (&closure->cif); + + // Initialize the argument types and CIF that represent the actual + // underlying JNI function. + int extra_args = 1; + if ((self->accflags & Modifier::STATIC)) + ++extra_args; + jni_arg_types = (ffi_type **) _Jv_AllocBytes ((extra_args + arg_count) + * sizeof (ffi_type *)); + int offset = 0; + jni_arg_types[offset++] = &ffi_type_pointer; + if ((self->accflags & Modifier::STATIC)) + jni_arg_types[offset++] = &ffi_type_pointer; + memcpy (&jni_arg_types[offset], &closure->arg_types[0], + arg_count * sizeof (ffi_type *)); + + if (ffi_prep_cif (&jni_cif, _Jv_platform_ffi_abi, + extra_args + arg_count, rtype, + jni_arg_types) != FFI_OK) + throw_internal_error ("ffi_prep_cif failed for JNI function"); + + JvAssert ((self->accflags & Modifier::NATIVE) != 0); + + // FIXME: for now we assume that all native methods for + // interpreted code use JNI. + fun = (ffi_closure_fun) &_Jv_JNIMethod::call; + + FFI_PREP_RAW_CLOSURE (&closure->closure, + &closure->cif, + fun, + (void*) this); + + self->ncode = (void *) closure; + return self->ncode; +} + +static void +throw_class_format_error (jstring msg) +{ + throw (msg + ? new java::lang::ClassFormatError (msg) + : new java::lang::ClassFormatError); +} + +static void +throw_class_format_error (char *msg) +{ + throw_class_format_error (JvNewStringLatin1 (msg)); +} + + + +void +_Jv_InterpreterEngine::do_verify (jclass klass) +{ + _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info; + for (int i = 0; i < klass->method_count; i++) + { + using namespace java::lang::reflect; + _Jv_MethodBase *imeth = iclass->interpreted_methods[i]; + _Jv_ushort accflags = klass->methods[i].accflags; + if ((accflags & (Modifier::NATIVE | Modifier::ABSTRACT)) == 0) + { + _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); + _Jv_VerifyMethod (im); + } + } +} + +void +_Jv_InterpreterEngine::do_create_ncode (jclass klass) +{ + _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info; + for (int i = 0; i < klass->method_count; i++) + { + // Just skip abstract methods. This is particularly important + // because we don't resize the interpreted_methods array when + // miranda methods are added to it. + if ((klass->methods[i].accflags + & java::lang::reflect::Modifier::ABSTRACT) + != 0) + continue; + + _Jv_MethodBase *imeth = iclass->interpreted_methods[i]; + + if ((klass->methods[i].accflags & java::lang::reflect::Modifier::NATIVE) + != 0) + { + // You might think we could use a virtual `ncode' method in + // the _Jv_MethodBase and unify the native and non-native + // cases. Well, we can't, because we don't allocate these + // objects using `new', and thus they don't get a vtable. + _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth); + klass->methods[i].ncode = jnim->ncode (); + } + else if (imeth != 0) // it could be abstract + { + _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); + klass->methods[i].ncode = im->ncode (); + } + } +} + +void +_Jv_InterpreterEngine::do_allocate_static_fields (jclass klass, + int static_size) +{ + _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info; + + char *static_data = (char *) _Jv_AllocBytes (static_size); + memset (static_data, 0, static_size); + + for (int i = 0; i < klass->field_count; i++) + { + _Jv_Field *field = &klass->fields[i]; + + if ((field->flags & java::lang::reflect::Modifier::STATIC) != 0) + { + field->u.addr = static_data + field->u.boffset; + + if (iclass->field_initializers[i] != 0) + { + _Jv_Linker::resolve_field (field, klass->loader); + _Jv_InitField (0, klass, i); + } + } + } + + // Now we don't need the field_initializers anymore, so let the + // collector get rid of it. + iclass->field_initializers = 0; +} + +_Jv_ResolvedMethod * +_Jv_InterpreterEngine::do_resolve_method (_Jv_Method *method, jclass klass, + jboolean staticp, jint vtable_index) +{ + int arg_count = _Jv_count_arguments (method->signature, staticp); + + _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*) + _Jv_AllocBytes (sizeof (_Jv_ResolvedMethod) + + arg_count*sizeof (ffi_type*)); + + result->stack_item_count + = init_cif (method->signature, + arg_count, + staticp, + &result->cif, + &result->arg_types[0], + NULL); + + result->vtable_index = vtable_index; + result->method = method; + result->klass = klass; + + return result; +} + +void +_Jv_InterpreterEngine::do_post_miranda_hook (jclass klass) +{ + _Jv_InterpClass *iclass = (_Jv_InterpClass *) klass->aux_info; + for (int i = 0; i < klass->method_count; i++) + { + // Just skip abstract methods. This is particularly important + // because we don't resize the interpreted_methods array when + // miranda methods are added to it. + if ((klass->methods[i].accflags + & java::lang::reflect::Modifier::ABSTRACT) + != 0) + continue; + // Miranda method additions mean that the `methods' array moves. + // We cache a pointer into this array, so we have to update. + iclass->interpreted_methods[i]->self = &klass->methods[i]; + } +} + #endif // INTERPRETER diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index 646eaebe4c7..0c79d332700 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -121,15 +121,15 @@ public class ObjectInputStream extends InputStream */ public final Object readObject() throws ClassNotFoundException, IOException { - if (callersClassLoader == null) - { - callersClassLoader = getCallersClassLoader (); - if (Configuration.DEBUG && dump) - { - dumpElementln ("CallersClassLoader = " + callersClassLoader); - } - } - + if (callersClassLoader == null) + { + callersClassLoader = getCallersClassLoader (); + if (Configuration.DEBUG && dump) + { + dumpElementln ("CallersClassLoader = " + callersClassLoader); + } + } + if (this.useSubclassMethod) return readObjectOverride(); @@ -271,7 +271,7 @@ public class ObjectInputStream extends InputStream readArrayElements(array, componentType); if(dump) for (int i = 0, len = Array.getLength(array); i < len; i++) - dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); ret_val = processResolution(null, array, handle); break; } @@ -398,6 +398,8 @@ public class ObjectInputStream extends InputStream setBlockDataMode(old_mode); this.isDeserializing = was_deserializing; + + depth -= 2; depth -= 2; @@ -1806,6 +1808,7 @@ public class ObjectInputStream extends InputStream * @param sm SecurityManager instance which should be called. * @return The current class loader in the calling stack. */ + private static native ClassLoader currentClassLoader (SecurityManager sm); private native ClassLoader getCallersClassLoader(); @@ -1875,7 +1878,7 @@ public class ObjectInputStream extends InputStream private int depth = 0; private void dumpElement (String msg) - { + { System.out.print(msg); } diff --git a/libjava/java/io/ObjectOutputStream.java b/libjava/java/io/ObjectOutputStream.java index 6a5eed7a24c..3482225232a 100644 --- a/libjava/java/io/ObjectOutputStream.java +++ b/libjava/java/io/ObjectOutputStream.java @@ -347,8 +347,8 @@ public class ObjectOutputStream extends OutputStream fieldsAlreadyWritten = false; if (currentObjectStreamClass.hasWriteMethod()) { - if (dump) - dumpElementln ("WRITE METHOD CALLED FOR: " + obj); + if (dump) + dumpElementln ("WRITE METHOD CALLED FOR: " + obj); setBlockDataMode(true); callWriteMethod(obj, currentObjectStreamClass); setBlockDataMode(false); @@ -358,10 +358,10 @@ public class ObjectOutputStream extends OutputStream } else { - if (dump) - dumpElementln ("WRITE FIELDS CALLED FOR: " + obj); - writeFields(obj, currentObjectStreamClass); - } + if (dump) + dumpElementln ("WRITE FIELDS CALLED FOR: " + obj); + writeFields(obj, currentObjectStreamClass); + } } this.currentObject = prevObject; diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index a60e80a22d9..320b09965d0 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -42,13 +42,15 @@ enum JV_STATE_PRELOADING = 1, // Can do _Jv_FindClass. JV_STATE_LOADING = 3, // Has super installed. - JV_STATE_COMPILED = 5, // This was a compiled class. + JV_STATE_READ = 4, // Has been completely defined. + JV_STATE_LOADED = 5, // Has Miranda methods defined. + + JV_STATE_COMPILED = 6, // This was a compiled class. - JV_STATE_LOADED = 6, // Is complete. JV_STATE_PREPARED = 7, // Layout & static init done. JV_STATE_LINKED = 9, // Strings interned. - JV_STATE_IN_PROGRESS = 10, // <Clinit> running. + JV_STATE_IN_PROGRESS = 10, // <clinit> running. JV_STATE_ERROR = 12, @@ -59,6 +61,9 @@ struct _Jv_Field; struct _Jv_VTable; union _Jv_word; struct _Jv_ArrayVTable; +class _Jv_ExecutionEngine; +class _Jv_CompiledEngine; +class _Jv_InterpreterEngine; struct _Jv_Constants { @@ -106,7 +111,7 @@ union _Jv_IDispatchTable } iface; }; -// Used by _Jv_GetInterfaces () +// Used by _Jv_Linker::get_interfaces () struct _Jv_ifaces { jclass *list; @@ -139,6 +144,23 @@ struct _Jv_CatchClass _Jv_Utf8Const *classname; }; +// Possible values for the assertion_code field in the type assertion table. +enum +{ + JV_ASSERT_END_OF_TABLE = 0, + JV_ASSERT_TYPES_COMPATIBLE = 1, + JV_ASSERT_IS_INSTANTIABLE = 2 +}; + +// Entry in the type assertion table, used to validate type constraints +// for binary compatibility. +struct _Jv_TypeAssertion +{ + jint assertion_code; + _Jv_Utf8Const *op1; + _Jv_Utf8Const *op2; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -149,11 +171,11 @@ struct _Jv_CatchClass _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); jboolean _Jv_IsAssignableFrom (jclass, jclass); +jboolean _Jv_IsAssignableFromSlow (jclass, jclass); jboolean _Jv_InterfaceAssignableFrom (jclass, jclass); -void _Jv_InitClass (jclass klass); _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, - _Jv_Utf8Const*); + _Jv_Utf8Const*, jclass * = NULL); jfieldID JvGetFirstInstanceField (jclass); jint JvNumInstanceFields (jclass); jfieldID JvGetFirstStaticField (jclass); @@ -183,10 +205,6 @@ class java::io::ObjectOutputStream; class java::io::ObjectInputStream; class java::io::ObjectStreamClass; -void _Jv_WaitForState (jclass, int); -void _Jv_RegisterClasses (const jclass *classes); -void _Jv_RegisterClasses_Counted (const jclass *classes, - size_t count); void _Jv_RegisterClassHookDefault (jclass klass); void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); void _Jv_UnregisterClass (jclass); @@ -205,19 +223,7 @@ void _Jv_InitNewClassFields (jclass klass); // Friend functions and classes in prims.cc void _Jv_InitPrimClass (jclass, char *, char, int); -void _Jv_PrepareCompiledClass (jclass); -void _Jv_PrepareConstantTimeTables (jclass); -jshort _Jv_GetInterfaces (jclass, _Jv_ifaces *); -void _Jv_GenerateITable (jclass, _Jv_ifaces *, jshort *); jstring _Jv_GetMethodString (jclass, _Jv_Utf8Const *); -jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort); -jshort _Jv_FindIIndex (jclass *, jshort *, jshort); -void _Jv_LinkSymbolTable (jclass); -void _Jv_LayoutInterfaceMethods (jclass); -void _Jv_LayoutVTableMethods (jclass klass); -void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); -void _Jv_MakeVTable (jclass); -void _Jv_linkExceptionClassTable (jclass); jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags); @@ -225,25 +231,14 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader); #ifdef INTERPRETER jboolean _Jv_IsInterpretedClass (jclass); -void _Jv_InitField (jobject, jclass, _Jv_Field*); void _Jv_InitField (jobject, jclass, int); -_Jv_word _Jv_ResolvePoolEntry (jclass, int); -_Jv_Method *_Jv_SearchMethodInClass (jclass cls, jclass klass, - _Jv_Utf8Const *method_name, - _Jv_Utf8Const *method_signature); -void _Jv_PrepareClass (jclass); -void _Jv_PrepareMissingMethods (jclass base, jclass iface_class); - -void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); - class _Jv_ClassReader; class _Jv_InterpClass; class _Jv_InterpMethod; #endif class _Jv_BytecodeVerifier; -class _Jv_StackTrace; class gnu::gcj::runtime::StackTrace; class java::io::VMObjectStreamClass; @@ -316,9 +311,14 @@ public: void setSigners(JArray<jobject> *); inline jclass getSuperclass (void) - { - return superclass; - } + { + return superclass; + } + + inline jclass getInterface (jint n) + { + return interfaces[n]; + } inline jboolean isArray (void) { @@ -351,9 +351,16 @@ public: // FIXME: this probably shouldn't be public. jint size (void) - { - return size_in_bytes; - } + { + return size_in_bytes; + } + + // The index of the first method we declare ourself (as opposed to + // inheriting). + inline jint firstMethodIndex (void) + { + return vtable_method_count - method_count; + } // finalization void finalize (); @@ -372,10 +379,17 @@ private: static jstring getPackagePortion (jstring); + void set_state (jint nstate) + { + state = nstate; + notifyAll (); + } + // Friend functions implemented in natClass.cc. friend _Jv_Method *::_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); friend jboolean (::_Jv_IsAssignableFrom) (jclass, jclass); + friend jboolean (::_Jv_IsAssignableFromSlow) (jclass, jclass); friend jboolean (::_Jv_InterfaceAssignableFrom) (jclass, jclass); friend void *::_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx); @@ -383,7 +397,7 @@ private: friend void ::_Jv_InitClass (jclass klass); friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, - _Jv_Utf8Const*); + _Jv_Utf8Const*, jclass *); friend jfieldID (::JvGetFirstInstanceField) (jclass); friend jint (::JvNumInstanceFields) (jclass); friend jfieldID (::JvGetFirstStaticField) (jclass); @@ -413,7 +427,6 @@ private: friend class java::io::ObjectInputStream; friend class java::io::ObjectStreamClass; - friend void ::_Jv_WaitForState (jclass, int); friend void ::_Jv_RegisterClasses (const jclass *classes); friend void ::_Jv_RegisterClasses_Counted (const jclass *classes, size_t count); @@ -436,40 +449,22 @@ private: // in prims.cc friend void ::_Jv_InitPrimClass (jclass, char *, char, int); - friend void ::_Jv_PrepareCompiledClass (jclass); - friend void ::_Jv_PrepareConstantTimeTables (jclass); - friend jshort (::_Jv_GetInterfaces) (jclass, _Jv_ifaces *); - friend void ::_Jv_GenerateITable (jclass, _Jv_ifaces *, jshort *); friend jstring (::_Jv_GetMethodString) (jclass, _Jv_Utf8Const *); - friend jshort (::_Jv_AppendPartialITable) (jclass, jclass, void **, jshort); - friend jshort (::_Jv_FindIIndex) (jclass *, jshort *, jshort); - friend void ::_Jv_LinkSymbolTable (jclass); - friend void ::_Jv_LayoutInterfaceMethods (jclass); - friend void ::_Jv_LayoutVTableMethods (jclass klass); - friend void ::_Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); - friend void ::_Jv_MakeVTable (jclass); - friend void ::_Jv_linkExceptionClassTable (jclass); friend jboolean (::_Jv_CheckAccess) (jclass self_klass, jclass other_klass, jint flags); + + friend bool _Jv_getInterfaceMethod(jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); friend jclass (::_Jv_GetArrayClass) (jclass klass, java::lang::ClassLoader *loader); #ifdef INTERPRETER friend jboolean (::_Jv_IsInterpretedClass) (jclass); - friend void ::_Jv_InitField (jobject, jclass, _Jv_Field*); friend void ::_Jv_InitField (jobject, jclass, int); - friend _Jv_word (::_Jv_ResolvePoolEntry) (jclass, int); - friend _Jv_Method *::_Jv_SearchMethodInClass (jclass cls, jclass klass, - _Jv_Utf8Const *method_name, - _Jv_Utf8Const *method_signature); - friend void ::_Jv_PrepareClass (jclass); - friend void ::_Jv_PrepareMissingMethods (jclass base, jclass iface_class); - - friend void ::_Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); - friend class ::_Jv_ClassReader; friend class ::_Jv_InterpClass; friend class ::_Jv_InterpMethod; @@ -480,10 +475,14 @@ private: #endif friend class ::_Jv_BytecodeVerifier; - friend class ::_Jv_StackTrace; friend class gnu::gcj::runtime::StackTrace; friend class java::io::VMObjectStreamClass; + friend class _Jv_Linker; + friend class _Jv_ExecutionEngine; + friend class _Jv_CompiledEngine; + friend class _Jv_InterpreterEngine; + friend void ::_Jv_sharedlib_register_hook (jclass klass); // Chain for class pool. @@ -518,8 +517,12 @@ private: _Jv_OffsetTable *otable; // Offset table symbols. _Jv_MethodSymbol *otable_syms; + // Address table _Jv_AddressTable *atable; _Jv_MethodSymbol *atable_syms; + // Interface table + _Jv_AddressTable *itable; + _Jv_MethodSymbol *itable_syms; _Jv_CatchClass *catch_classes; // Interfaces implemented by this class. jclass *interfaces; @@ -542,13 +545,17 @@ private: jclass arrayclass; // Security Domain to which this class belongs (or null). java::security::ProtectionDomain *protectionDomain; + // Pointer to the type assertion table for this class. + _Jv_TypeAssertion *assertion_table; // Signers of this class (or null). JArray<jobject> *hack_signers; // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace. jclass chain; - // Additional data, specific to the generator (JIT, native, interpreter) of this - // class. + // Additional data, specific to the generator (JIT, native, + // interpreter) of this class. void *aux_info; + // Execution engine. + _Jv_ExecutionEngine *engine; }; // Inline functions that are friends of java::lang::Class diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 75f07169f39..648afca5435 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -288,6 +288,8 @@ public abstract class ClassLoader if (c != null) return c; + ClassNotFoundException ex = null; + // Can the class be loaded by a parent? try { @@ -304,9 +306,20 @@ public abstract class ClassLoader } catch (ClassNotFoundException e) { + ex = e; } // Still not found, we have to do it ourself. - c = findClass(name); + try + { + c = findClass(name); + } + catch (ClassNotFoundException cause) + { + if (ex != null) + throw new ClassNotFoundException(ex.toString(), cause); + else + throw cause; + } if (resolve) resolveClass(c); return c; @@ -435,8 +448,9 @@ public abstract class ClassLoader domain = defaultProtectionDomain; if (! initialized) throw new SecurityException("attempt to define class from uninitialized class loader"); + Class retval = VMClassLoader.defineClass(this, name, data, - offset, len, domain); + offset, len, domain); loadedClasses.put(retval.getName(), retval); return retval; } diff --git a/libjava/java/lang/Compiler.java b/libjava/java/lang/Compiler.java index f520a7e0dda..858f63ee993 100644 --- a/libjava/java/lang/Compiler.java +++ b/libjava/java/lang/Compiler.java @@ -1,5 +1,5 @@ /* Compiler.java -- placeholder for Java-to-native runtime compilers - Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -76,8 +76,7 @@ public final class Compiler */ public static boolean compileClass(Class oneClass) { - // Never succeed. - return false; + return VMCompiler.compileClass(oneClass); } /** @@ -90,8 +89,7 @@ public final class Compiler */ public static boolean compileClasses(String classNames) { - // Note the incredibly lame interface. Always fail. - return false; + return VMCompiler.compileClasses(classNames); } /** @@ -105,8 +103,7 @@ public final class Compiler */ public static Object command(Object arg) { - // Our implementation defines this to a no-op. - return null; + return VMCompiler.command(arg); } /** @@ -116,6 +113,7 @@ public final class Compiler */ public static void enable() { + VMCompiler.enable(); } /** @@ -124,5 +122,6 @@ public final class Compiler */ public static void disable() { + VMCompiler.disable(); } } diff --git a/libjava/java/lang/SecurityManager.java b/libjava/java/lang/SecurityManager.java index 2e82a475b5f..972b312d943 100644 --- a/libjava/java/lang/SecurityManager.java +++ b/libjava/java/lang/SecurityManager.java @@ -324,7 +324,7 @@ public class SecurityManager public void checkPermission(Permission perm) { // XXX Should be: AccessController.checkPermission(perm); - throw new SecurityException("Operation not allowed"); + //.throw new SecurityException("Operation not allowed"); } /** @@ -553,7 +553,7 @@ public class SecurityManager // throw new SecurityException("Missing context"); // AccessControlContext ac = (AccessControlContext) context; // ac.checkPermission(new FilePermission(filename, "read")); - throw new SecurityException("Cannot read files via file names."); + // throw new SecurityException("Cannot read files via file names."); } /** @@ -677,7 +677,7 @@ public class SecurityManager // // Use the toString() hack to do the null check. // ac.checkPermission(new SocketPermission(host.toString + ":" +port, // "connect")); - throw new SecurityException("Cannot make network connections."); + // throw new SecurityException("Cannot make network connections."); } /** diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java index ac7a05e3cd9..8f78f9bb666 100644 --- a/libjava/java/lang/VMClassLoader.java +++ b/libjava/java/lang/VMClassLoader.java @@ -97,44 +97,31 @@ final class VMClassLoader ProtectionDomain pd) throws ClassFormatError; - static final native void linkClass0 (Class klass); - static final native void markClassErrorState0 (Class klass); - /** * Helper to resolve all references to other classes from this class. * * @param c the class to resolve */ - static final void resolveClass(Class clazz) + static final native void resolveClass(Class clazz); + + static final void transformException(Class clazz, Throwable x) { - synchronized (clazz) + LinkageError e; + if (x instanceof LinkageError) + e = (LinkageError) x; + else if (x instanceof ClassNotFoundException) { - try - { - linkClass0 (clazz); - } - catch (Throwable x) - { - markClassErrorState0 (clazz); - - LinkageError e; - if (x instanceof LinkageError) - e = (LinkageError) x; - else if (x instanceof ClassNotFoundException) - { - e = new NoClassDefFoundError("while resolving class: " - + clazz.getName()); - e.initCause (x); - } - else - { - e = new LinkageError ("unexpected exception during linking: " - + clazz.getName()); - e.initCause (x); - } - throw e; - } + e = new NoClassDefFoundError("while resolving class: " + + clazz.getName()); + e.initCause (x); + } + else + { + e = new LinkageError ("unexpected exception during linking: " + + clazz.getName()); + e.initCause (x); } + throw e; } /** diff --git a/libjava/java/lang/VMCompiler.java b/libjava/java/lang/VMCompiler.java new file mode 100644 index 00000000000..98efc7ee44f --- /dev/null +++ b/libjava/java/lang/VMCompiler.java @@ -0,0 +1,332 @@ +/* VMClassLoader.java -- Reference implementation of compiler interface + Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath 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) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.security.ProtectionDomain; +import java.security.NoSuchAlgorithmException; +import java.util.WeakHashMap; +import java.util.HashSet; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; +import gnu.gcj.runtime.SharedLibHelper; +import gnu.gcj.runtime.PersistentByteMap; + +/** + * This class is just a per-VM reflection of java.lang.Compiler. + * All methods are defined identically. + */ +final class VMCompiler +{ + // True if we want to use gcj-jit. + public static boolean useCompiler = true; + + // True if we're able to use gcj-jit. + public static final boolean canUseCompiler; + + // Compiler to use. + public static String gcjJitCompiler; + + // Compiler options. + public static String gcjJitCompilerOptions; + + // Temporary directory to use. + public static String gcjJitTmpdir; + + // This maps a ClassLoader to a set of SharedLibHelper objects that + // it has used. We do things this way to ensure that a + // SharedLibHelper is collected if and only if the ClassLoader is. + private static WeakHashMap sharedHelperMap = new WeakHashMap(); + + private static Vector precompiledMapFiles; + + static + { + gcjJitCompiler = System.getProperty("gnu.gcj.jit.compiler"); + if (gcjJitCompiler == null) + canUseCompiler = false; + else + { + gcjJitCompilerOptions = System.getProperty("gnu.gcj.jit.options", + "-g"); + gcjJitTmpdir = System.getProperty("gnu.gcj.jit.cachedir"); + // Note that we *don't* choose java.io.tmpdir as a default -- + // that would allow easy attacks against the VM. + if (gcjJitTmpdir == null) + canUseCompiler = false; + else + canUseCompiler = true; + } + + String prop = System.getProperty ("gnu.gcj.precompiled.db.path"); + if (prop != null) + { + precompiledMapFiles = new Vector(); + // Add the + StringTokenizer st + = new StringTokenizer (prop, + System.getProperty ("path.separator", ":")); + { + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + PersistentByteMap map + = new PersistentByteMap + (e, PersistentByteMap.AccessMode.READ_ONLY); + precompiledMapFiles.add(map); + } + catch (IllegalArgumentException _) + { + // Not a map file + } + catch (java.io.IOException _) + { + } + } + } + } + } + + /** + * Don't allow new `Compiler's to be made. + */ + private VMCompiler() + { + } + + private static Class loadSharedLibrary(ClassLoader loader, + String fileName, + ProtectionDomain domain, + String className) + { + Class c = null; + SharedLibHelper helper + = SharedLibHelper.findHelper (loader, fileName, domain.getCodeSource()); + c = helper.findClass (className); + if (c != null) + { + HashSet hs = (HashSet) sharedHelperMap.get(loader); + if (hs == null) + { + hs = new HashSet(); + sharedHelperMap.put(loader, hs); + } + hs.add(helper); + } + return c; + } + + /** + * Compile a class given the bytes for it. Returns the Class, or + * null if compilation failed or otherwise could not be done. + */ + public static Class compileClass(ClassLoader loader, + String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + { + if (precompiledMapFiles == null + && (! useCompiler || ! canUseCompiler)) + return null; + + byte digest[]; + + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + digest = md.digest(data); + } + catch (NoSuchAlgorithmException _) + { + return null; + } + + // We use lookaside cache files to determine whether these bytes + // correspond to a class file that is part of a precompiled DSO. + if (precompiledMapFiles != null) + { + try + { + Enumeration elements = precompiledMapFiles.elements(); + while (elements.hasMoreElements()) + { + PersistentByteMap map = (PersistentByteMap)elements.nextElement(); + byte[] soName = map.get(digest); + if (soName != null) + return loadSharedLibrary(loader, + new String(soName), + domain, name); + } + } + catch (Exception _) + { + } + } + + if (! useCompiler || ! canUseCompiler) + return null; + + try + { + // FIXME: Make sure that the class represented by the + // bytes in DATA really is the class named in NAME. Make + // sure it's not "java.*". + StringBuffer hexBytes = new StringBuffer(gcjJitTmpdir); + hexBytes.append(File.separatorChar); + int digestLength = digest.length; + for (int i = 0; i < digestLength; ++i) + hexBytes.append(Integer.toHexString(digest[i] & 0xff)); + + // FIXME: use System.mapLibraryName? + // I'm thinking we should use that, plus a class specified + // via a property that determines lookup policy. + File soFile = new File(hexBytes + ".so"); + if (soFile.isFile()) + return loadSharedLibrary (loader, soFile.toString(), domain, + name); + + File classFile = new File(hexBytes + ".class"); + classFile.delete(); + if (classFile.createNewFile() != true) + return null; + + FileOutputStream f = new FileOutputStream (classFile); + // FIXME: race condition if bytes change... ? + f.write(data, offset, len); + + // Invoke the compiler. + StringBuffer command = new StringBuffer(gcjJitCompiler); + command.append(" "); + command.append(classFile); + command.append(" "); + command.append(gcjJitCompilerOptions); + // These options are required. + command.append(" -findirect-dispatch -fjni -shared -fPIC -o "); + command.append(soFile); + Process p = Runtime.getRuntime().exec(command.toString()); + + // Read the process' stderr into a string. + StringBuffer err = new StringBuffer(); + InputStreamReader stderr = new InputStreamReader (p.getErrorStream()); + char[] inBuf = new char[500]; + int bytesRead; + while ((bytesRead = stderr.read (inBuf)) != -1) + err.append(inBuf, 0, bytesRead); + + if (p.waitFor() != 0) + { + // FIXME: we could log err.toString() somewhere... + return null; + } + + return loadSharedLibrary(loader, soFile.toString(), domain, name); + } + catch (Exception _) + { + return null; + } + } + + /** + * Compile the class named by <code>oneClass</code>. + * + * @param oneClass the class to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if oneClass is null + */ + public static boolean compileClass(Class oneClass) + { + // Never succeed. + return false; + } + + /** + * Compile the classes whose name matches <code>classNames</code>. + * + * @param classNames the name of classes to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if classNames is null + */ + public static boolean compileClasses(String classNames) + { + // Note the incredibly lame interface. Always fail. + return false; + } + + /** + * This method examines the argument and performs an operation + * according to the compilers documentation. No specific operation + * is required. + * + * @param arg a compiler-specific argument + * @return a compiler-specific value, including null + * @throws NullPointerException if the compiler doesn't like a null arg + */ + public static Object command(Object arg) + { + // Our implementation defines this to a no-op. + return null; + } + + /** + * Calling <code>Compiler.enable()</code> will cause the compiler + * to resume operation if it was previously disabled; provided that a + * compiler even exists. + */ + public static void enable() + { + useCompiler = true; + } + + /** + * Calling <code>Compiler.disable()</code> will cause the compiler + * to be suspended; provided that a compiler even exists. + */ + public static void disable() + { + useCompiler = false; + } +} diff --git a/libjava/java/lang/VMSecurityManager.java b/libjava/java/lang/VMSecurityManager.java index f6f0645ac75..604f8ecb428 100644 --- a/libjava/java/lang/VMSecurityManager.java +++ b/libjava/java/lang/VMSecurityManager.java @@ -54,11 +54,12 @@ class VMSecurityManager // The docs above are wrong. See the online docs. // FIXME this implementation is a bit wrong too -- the docs say we // must also consider ancestors of the system class loader. + ClassLoader systemClassLoader = VMClassLoader.getSystemClassLoader(); Class[] classStack = getClassContext (); for (int i = 0; i < classStack.length; i++) { ClassLoader loader = classStack[i].getClassLoader(); - if (loader != null) + if (loader != null && loader != systemClassLoader) return loader; } diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 920245cd586..0e9c26c7b4f 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -14,6 +14,7 @@ details. */ #include <limits.h> #include <string.h> #include <stddef.h> +#include <stdio.h> #pragma implementation "Class.h" @@ -56,16 +57,17 @@ details. */ #include <gcj/method.h> #include <gnu/gcj/runtime/MethodRef.h> #include <gnu/gcj/RawData.h> +#include <java/lang/VerifyError.h> #include <java-cpool.h> #include <java-interp.h> +#include <java-assert.h> +#include <execution.h> using namespace gcj; -bool gcj::verbose_class_flag; - jclass java::lang::Class::forName (jstring className, jboolean initialize, java::lang::ClassLoader *loader) @@ -485,7 +487,12 @@ java::lang::Class::getInterfaces (void) jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL); jobject *data = elements (r); for (int i = 0; i < interface_count; ++i) - data[i] = interfaces[i]; + { + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + data[i] = interfaces[i]; + if ((uaddr)data[i] < (uaddr)constants.size) + fprintf (stderr, "ERROR !!!\n"); + } return reinterpret_cast<JArray<jclass> *> (r); } @@ -495,7 +502,8 @@ java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types) jstring partial_sig = getSignature (param_types, false); jint p_len = partial_sig->length(); _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); - for (Class *klass = this; klass; klass = klass->getSuperclass()) + + for (Class *klass = this; klass; klass = klass->getSuperclass()) { int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) @@ -699,10 +707,7 @@ java::lang::Class::newInstance (void) void java::lang::Class::finalize (void) { -#ifdef INTERPRETER - JvAssert (_Jv_IsInterpretedClass (this)); - _Jv_UnregisterClass (this); -#endif + engine->unregister(this); } // This implements the initialization process for a class. From Spec @@ -710,67 +715,37 @@ java::lang::Class::finalize (void) void java::lang::Class::initializeClass (void) { - // short-circuit to avoid needless locking. + // Short-circuit to avoid needless locking. if (state == JV_STATE_DONE) return; - // Step 1. - _Jv_MonitorEnter (this); + // Step 1. We introduce a new scope so we can synchronize more + // easily. + { + JvSynchronize sync (this); - if (state < JV_STATE_LINKED) - { -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (this)) - { - // this can throw exceptions, so exit the monitor as a precaution. - _Jv_MonitorExit (this); - java::lang::VMClassLoader::resolveClass (this); - _Jv_MonitorEnter (this); - } - else -#endif - { - _Jv_PrepareCompiledClass (this); - } - } - - // Step 2. - java::lang::Thread *self = java::lang::Thread::currentThread(); - // FIXME: `self' can be null at startup. Hence this nasty trick. - self = (java::lang::Thread *) ((long) self | 1); - while (state == JV_STATE_IN_PROGRESS && thread && thread != self) - wait (); - - // Steps 3 & 4. - if (state == JV_STATE_DONE) - { - _Jv_MonitorExit (this); - return; - } - if (state == JV_STATE_IN_PROGRESS) - { - _Jv_MonitorExit (this); + if (state < JV_STATE_LINKED) + java::lang::VMClassLoader::resolveClass (this); - /* Initialization in progress. The class is linked now, - so ensure internal tables are built. */ - _Jv_PrepareConstantTimeTables (this); - _Jv_MakeVTable(this); - _Jv_LinkSymbolTable(this); + // Step 2. + java::lang::Thread *self = java::lang::Thread::currentThread(); + self = (java::lang::Thread *) ((long) self | 1); + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) + wait (); + // Steps 3 & 4. + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS) return; - } - // Step 5. - if (state == JV_STATE_ERROR) - { - _Jv_MonitorExit (this); + // Step 5. + if (state == JV_STATE_ERROR) throw new java::lang::NoClassDefFoundError (getName()); - } - // Step 6. - thread = self; - state = JV_STATE_IN_PROGRESS; - _Jv_MonitorExit (this); + // Step 6. + thread = self; + _Jv_Linker::wait_for_state (this, JV_STATE_LINKED); + state = JV_STATE_IN_PROGRESS; + } // Step 7. if (! isInterface () && superclass) @@ -782,24 +757,13 @@ java::lang::Class::initializeClass (void) catch (java::lang::Throwable *except) { // Caught an exception. - _Jv_MonitorEnter (this); + JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); - _Jv_MonitorExit (this); throw except; } } - _Jv_PrepareConstantTimeTables (this); - - if (vtable == NULL) - _Jv_MakeVTable(this); - - if (otable || atable) - _Jv_LinkSymbolTable(this); - - _Jv_linkExceptionClassTable (this); - // Steps 8, 9, 10, 11. try { @@ -821,17 +785,91 @@ java::lang::Class::initializeClass (void) except = t; } } - _Jv_MonitorEnter (this); + + JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); - _Jv_MonitorExit (this); throw except; } - _Jv_MonitorEnter (this); + JvSynchronize sync (this); state = JV_STATE_DONE; notifyAll (); - _Jv_MonitorExit (this); +} + +// Only used by serialization +java::lang::reflect::Field * +java::lang::Class::getPrivateField (jstring name) +{ + int hash = name->hashCode (); + + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getPrivateField(name); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getPrivateField (name); + return rfield; +} + +// Only used by serialization +java::lang::reflect::Method * +java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + throw new java::lang::NoSuchMethodException (name); +} + +// Private accessor method for Java code to retrieve the protection domain. +java::security::ProtectionDomain * +java::lang::Class::getProtectionDomain0 () +{ + return protectionDomain; +} + +JArray<jobject> * +java::lang::Class::getSigners() +{ + return hack_signers; +} + +void +java::lang::Class::setSigners(JArray<jobject> *s) +{ + hack_signers = s; } @@ -857,14 +895,19 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Method * _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, - _Jv_Utf8Const *signature) + _Jv_Utf8Const *signature, + jclass *declarer_result) { for (; klass; klass = klass->getSuperclass()) { _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); if (meth) - return meth; + { + if (declarer_result) + *declarer_result = klass; + return meth; + } } return NULL; @@ -886,7 +929,7 @@ _Jv_FindMethodInCache (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { - int index = name->hash16() & MCACHE_SIZE; + int index = name->hash16 () & MCACHE_SIZE; _Jv_mcache *mc = method_cache + index; _Jv_Method *m = mc->method; @@ -904,7 +947,7 @@ _Jv_AddMethodToCache (jclass klass, { _Jv_MonitorEnter (&java::lang::Class::class$); - int index = method->name->hash16() & MCACHE_SIZE; + int index = method->name->hash16 () & MCACHE_SIZE; method_cache[index].method = method; method_cache[index].klass = klass; @@ -1085,898 +1128,104 @@ _Jv_CheckArrayStore (jobject arr, jobject obj) } } -#define INITIAL_IOFFSETS_LEN 4 -#define INITIAL_IFACES_LEN 4 - -static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} }; - -// Generate tables for constant-time assignment testing and interface -// method lookup. This implements the technique described by Per Bothner -// <per@bothner.com> on the java-discuss mailing list on 1999-09-02: -// http://gcc.gnu.org/ml/java/1999-q3/msg00377.html -void -_Jv_PrepareConstantTimeTables (jclass klass) -{ - if (klass->isPrimitive () || klass->isInterface ()) - return; - - // Short-circuit in case we've been called already. - if ((klass->idt != NULL) || klass->depth != 0) - return; - - // Calculate the class depth and ancestor table. The depth of a class - // is how many "extends" it is removed from Object. Thus the depth of - // java.lang.Object is 0, but the depth of java.io.FilterOutputStream - // is 2. Depth is defined for all regular and array classes, but not - // interfaces or primitive types. - - jclass klass0 = klass; - jboolean has_interfaces = 0; - while (klass0 != &java::lang::Object::class$) - { - has_interfaces += klass0->interface_count; - klass0 = klass0->superclass; - klass->depth++; - } - - // We do class member testing in constant time by using a small table - // of all the ancestor classes within each class. The first element is - // a pointer to the current class, and the rest are pointers to the - // classes ancestors, ordered from the current class down by decreasing - // depth. We do not include java.lang.Object in the table of ancestors, - // since it is redundant. - - klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass)); - klass0 = klass; - for (int index = 0; index < klass->depth; index++) - { - klass->ancestors[index] = klass0; - klass0 = klass0->superclass; - } - - if (java::lang::reflect::Modifier::isAbstract (klass->accflags)) - return; - - // Optimization: If class implements no interfaces, use a common - // predefined interface table. - if (!has_interfaces) - { - klass->idt = &null_idt; - return; - } - - klass->idt = - (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); - - _Jv_ifaces ifaces; - - ifaces.count = 0; - ifaces.len = INITIAL_IFACES_LEN; - ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *)); - - int itable_size = _Jv_GetInterfaces (klass, &ifaces); - - if (ifaces.count > 0) - { - klass->idt->cls.itable = - (void **) _Jv_Malloc (itable_size * sizeof (void *)); - klass->idt->cls.itable_length = itable_size; - - jshort *itable_offsets = - (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort)); - - _Jv_GenerateITable (klass, &ifaces, itable_offsets); - - jshort cls_iindex = - _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count); - - for (int i=0; i < ifaces.count; i++) - { - ifaces.list[i]->idt->iface.ioffsets[cls_iindex] = - itable_offsets[i]; - } - - klass->idt->cls.iindex = cls_iindex; - - _Jv_Free (ifaces.list); - _Jv_Free (itable_offsets); - } - else - { - klass->idt->cls.iindex = SHRT_MAX; - } -} - -// Return index of item in list, or -1 if item is not present. -inline jshort -_Jv_IndexOf (void *item, void **list, jshort list_len) +jboolean +_Jv_IsAssignableFromSlow (jclass target, jclass source) { - for (int i=0; i < list_len; i++) + // First, strip arrays. + while (target->isArray ()) { - if (list[i] == item) - return i; + // If target is array, source must be as well. + if (! source->isArray ()) + return false; + target = target->getComponentType (); + source = source->getComponentType (); } - return -1; -} -// Find all unique interfaces directly or indirectly implemented by klass. -// Returns the size of the interface dispatch table (itable) for klass, which -// is the number of unique interfaces plus the total number of methods that -// those interfaces declare. May extend ifaces if required. -jshort -_Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces) -{ - jshort result = 0; - - for (int i=0; i < klass->interface_count; i++) - { - jclass iface = klass->interfaces[i]; - - /* Make sure interface is linked. */ - _Jv_WaitForState(iface, JV_STATE_LINKED); + // Quick success. + if (target == &java::lang::Object::class$) + return true; - if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1) - { - if (ifaces->count + 1 >= ifaces->len) - { - /* Resize ifaces list */ - ifaces->len = ifaces->len * 2; - ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, - ifaces->len * sizeof(jclass)); - } - ifaces->list[ifaces->count] = iface; - ifaces->count++; + // Ensure that the classes have their supers installed. + _Jv_Linker::wait_for_state (source, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (target, JV_STATE_LOADING); - result += _Jv_GetInterfaces (klass->interfaces[i], ifaces); - } - } - - if (klass->isInterface()) - { - result += klass->method_count + 1; - } - else + do { - if (klass->superclass) - { - result += _Jv_GetInterfaces (klass->superclass, ifaces); - } + if (source == target) + return true; + + if (target->isPrimitive () || source->isPrimitive ()) + return false; + + if (target->isInterface ()) + { + for (int i = 0; i < source->interface_count; ++i) + { + // We use a recursive call because we also need to + // check superinterfaces. + if (_Jv_IsAssignableFromSlow (target, source->getInterface (i))) + return true; + } + } + source = source->getSuperclass (); } - return result; -} - -// Fill out itable in klass, resolving method declarations in each ifaces. -// itable_offsets is filled out with the position of each iface in itable, -// such that itable[itable_offsets[n]] == ifaces.list[n]. -void -_Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets) -{ - void **itable = klass->idt->cls.itable; - jshort itable_pos = 0; - - for (int i=0; i < ifaces->count; i++) - { - jclass iface = ifaces->list[i]; - itable_offsets[i] = itable_pos; - itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos); - - /* Create interface dispatch table for iface */ - if (iface->idt == NULL) - { - iface->idt = - (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); - - // The first element of ioffsets is its length (itself included). - jshort *ioffsets = - (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort)); - ioffsets[0] = INITIAL_IOFFSETS_LEN; - for (int i=1; i < INITIAL_IOFFSETS_LEN; i++) - ioffsets[i] = -1; - - iface->idt->iface.ioffsets = ioffsets; - } - } -} - -// Format method name for use in error messages. -jstring -_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name) -{ - jstring r = klass->name->toString(); - r = r->concat (JvNewStringUTF (".")); - r = r->concat (name->toString()); - return r; -} - -void -_Jv_ThrowNoSuchMethodError () -{ - throw new java::lang::NoSuchMethodError; -} - -// Each superinterface of a class (i.e. each interface that the class -// directly or indirectly implements) has a corresponding "Partial -// Interface Dispatch Table" whose size is (number of methods + 1) words. -// The first word is a pointer to the interface (i.e. the java.lang.Class -// instance for that interface). The remaining words are pointers to the -// actual methods that implement the methods declared in the interface, -// in order of declaration. -// -// Append partial interface dispatch table for "iface" to "itable", at -// position itable_pos. -// Returns the offset at which the next partial ITable should be appended. -jshort -_Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, - jshort pos) -{ - using namespace java::lang::reflect; - - itable[pos++] = (void *) iface; - _Jv_Method *meth; - - for (int j=0; j < iface->method_count; j++) - { - meth = NULL; - for (jclass cl = klass; cl; cl = cl->getSuperclass()) - { - meth = _Jv_GetMethodLocal (cl, iface->methods[j].name, - iface->methods[j].signature); - - if (meth) - break; - } + while (source != NULL); - if (meth && (meth->name->first() == '<')) - { - // leave a placeholder in the itable for hidden init methods. - itable[pos] = NULL; - } - else if (meth) - { - if (Modifier::isStatic(meth->accflags)) - throw new java::lang::IncompatibleClassChangeError - (_Jv_GetMethodString (klass, meth->name)); - if (Modifier::isAbstract(meth->accflags)) - throw new java::lang::AbstractMethodError - (_Jv_GetMethodString (klass, meth->name)); - if (! Modifier::isPublic(meth->accflags)) - throw new java::lang::IllegalAccessError - (_Jv_GetMethodString (klass, meth->name)); - - itable[pos] = meth->ncode; - } - else - { - // The method doesn't exist in klass. Binary compatibility rules - // permit this, so we delay the error until runtime using a pointer - // to a method which throws an exception. - itable[pos] = (void *) _Jv_ThrowNoSuchMethodError; - } - pos++; - } - - return pos; + return false; } -static _Jv_Mutex_t iindex_mutex; -static bool iindex_mutex_initialized = false; - -// We need to find the correct offset in the Class Interface Dispatch -// Table for a given interface. Once we have that, invoking an interface -// method just requires combining the Method's index in the interface -// (known at compile time) to get the correct method. Doing a type test -// (cast or instanceof) is the same problem: Once we have a possible Partial -// Interface Dispatch Table, we just compare the first element to see if it -// matches the desired interface. So how can we find the correct offset? -// Our solution is to keep a vector of candiate offsets in each interface -// (idt->iface.ioffsets), and in each class we have an index -// (idt->cls.iindex) used to select the correct offset from ioffsets. +// Lookup an interface method by name. This is very similar to +// purpose to _getMethod, but the interfaces are quite different. It +// might be a good idea for _getMethod to call this function. // -// Calculate and return iindex for a new class. -// ifaces is a vector of num interfaces that the class implements. -// offsets[j] is the offset in the interface dispatch table for the -// interface corresponding to ifaces[j]. -// May extend the interface ioffsets if required. -jshort -_Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num) -{ - int i; - int j; - - // Acquire a global lock to prevent itable corruption in case of multiple - // classes that implement an intersecting set of interfaces being linked - // simultaneously. We can assume that the mutex will be initialized - // single-threaded. - if (! iindex_mutex_initialized) - { - _Jv_MutexInit (&iindex_mutex); - iindex_mutex_initialized = true; - } - - _Jv_MutexLock (&iindex_mutex); - - for (i=1;; i++) /* each potential position in ioffsets */ - { - for (j=0;; j++) /* each iface */ - { - if (j >= num) - goto found; - if (i >= ifaces[j]->idt->iface.ioffsets[0]) - continue; - int ioffset = ifaces[j]->idt->iface.ioffsets[i]; - /* We can potentially share this position with another class. */ - if (ioffset >= 0 && ioffset != offsets[j]) - break; /* Nope. Try next i. */ - } - } - found: - for (j = 0; j < num; j++) - { - int len = ifaces[j]->idt->iface.ioffsets[0]; - if (i >= len) - { - /* Resize ioffsets. */ - int newlen = 2 * len; - if (i >= newlen) - newlen = i + 3; - jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets; - jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, - newlen * sizeof(jshort)); - new_ioffsets[0] = newlen; - - while (len < newlen) - new_ioffsets[len++] = -1; - - ifaces[j]->idt->iface.ioffsets = new_ioffsets; - } - ifaces[j]->idt->iface.ioffsets[i] = offsets[j]; - } - - _Jv_MutexUnlock (&iindex_mutex); - - return i; -} - -// Only used by serialization -java::lang::reflect::Field * -java::lang::Class::getPrivateField (jstring name) +// Return true of the method is found, with the class in FOUND_CLASS +// and the index in INDEX. +bool +_Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index, + const _Jv_Utf8Const *utf_name, + const _Jv_Utf8Const *utf_sig) { - int hash = name->hashCode (); - - java::lang::reflect::Field* rfield; - for (int i = 0; i < field_count; i++) + for (jclass klass = search_class; klass; klass = klass->getSuperclass()) { - _Jv_Field *field = &fields[i]; - if (! _Jv_equal (field->name, name, hash)) - continue; - rfield = new java::lang::reflect::Field (); - rfield->offset = (char*) field - (char*) fields; - rfield->declaringClass = this; - rfield->name = name; - return rfield; - } - jclass superclass = getSuperclass(); - if (superclass == NULL) - return NULL; - rfield = superclass->getPrivateField(name); - for (int i = 0; i < interface_count && rfield == NULL; ++i) - rfield = interfaces[i]->getPrivateField (name); - return rfield; -} - -// Only used by serialization -java::lang::reflect::Method * -java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) -{ - jstring partial_sig = getSignature (param_types, false); - jint p_len = partial_sig->length(); - _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); - for (Class *klass = this; klass; klass = klass->getSuperclass()) - { - int i = klass->isPrimitive () ? 0 : klass->method_count; + // FIXME: Throw an exception? + if (!klass->isInterface ()) + return false; + + int i = klass->method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) - && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig)) { // Found it. using namespace java::lang::reflect; - Method *rmethod = new Method (); - rmethod->offset = ((char *) (&klass->methods[i]) - - (char *) klass->methods); - rmethod->declaringClass = klass; - return rmethod; - } - } - } - throw new java::lang::NoSuchMethodException (name); -} - -// Private accessor method for Java code to retrieve the protection domain. -java::security::ProtectionDomain * -java::lang::Class::getProtectionDomain0 () -{ - return protectionDomain; -} - -JArray<jobject> * -java::lang::Class::getSigners() -{ - return hack_signers; -} - -void -java::lang::Class::setSigners(JArray<jobject> *s) -{ - hack_signers = s; -} - -// Functions for indirect dispatch (symbolic virtual binding) support. - -// There are two tables, atable and otable. atable is an array of -// addresses, and otable is an array of offsets, and these are used -// for static and virtual members respectively. - -// {a,o}table_syms is an array of _Jv_MethodSymbols. Each such symbol -// is a tuple of {classname, member name, signature}. -// _Jv_LinkSymbolTable() scans these two arrays and fills in the -// corresponding atable and otable with the addresses of static -// members and the offsets of virtual members. - -// The offset (in bytes) for each resolved method or field is placed -// at the corresponding position in the virtual method offset table -// (klass->otable). - -// The same otable and atable may be shared by many classes. - -void -_Jv_LinkSymbolTable(jclass klass) -{ - //// FIXME: Need to lock the tables //// - - int index = 0; - _Jv_MethodSymbol sym; - if (klass->otable == NULL - || klass->otable->state != 0) - goto atable; - - klass->otable->state = 1; - - for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++) - { - // FIXME: Why are we passing NULL as the class loader? - jclass target_class = _Jv_FindClass (sym.class_name, NULL); - _Jv_Method *meth = NULL; - - const _Jv_Utf8Const *signature = sym.signature; - - { - static char *bounce = (char *)_Jv_ThrowNoSuchMethodError; - ptrdiff_t offset = (char *)(klass->vtable) - bounce; - klass->otable->offsets[index] = offset; - } - - if (target_class == NULL) - continue; - - if (target_class->isInterface()) - { - // FIXME: This does not yet fully conform to binary compatibility - // rules. It will break if a declaration is moved into a - // superinterface. - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i=0; i < cls->method_count; i++) - { - meth = &cls->methods[i]; - if (_Jv_equalUtf8Consts (sym.name, meth->name) - && _Jv_equalUtf8Consts (signature, meth->signature)) - { - klass->otable->offsets[index] = i + 1; - goto found; - } - } - - } - found: - continue; - } - - // We're looking for a field or a method, and we can tell - // which is needed by looking at the signature. - if (signature->first() == '(' && signature->len() >= 2) - { - // If the target class does not have a vtable_method_count yet, - // then we can't tell the offsets for its methods, so we must lay - // it out now. - if (target_class->vtable_method_count == -1) - { - JvSynchronize sync (target_class); - _Jv_LayoutVTableMethods (target_class); - } - - meth = _Jv_LookupDeclaredMethod(target_class, sym.name, - sym.signature); - - if (meth != NULL) - { - klass->otable->offsets[index] = - _Jv_VTable::idx_to_offset (meth->index); - } - - continue; - } - - // try fields - { - _Jv_Field *the_field = NULL; - - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i = 0; i < cls->field_count; i++) - { - _Jv_Field *field = &cls->fields[i]; - if (! _Jv_equalUtf8Consts (field->name, sym.name)) - continue; - - // FIXME: What access checks should we perform here? -// if (_Jv_CheckAccess (klass, cls, field->flags)) -// { - - if (!field->isResolved ()) - _Jv_ResolveField (field, cls->loader); - -// if (field_type != 0 && field->type != field_type) -// throw new java::lang::LinkageError -// (JvNewStringLatin1 -// ("field type mismatch with different loaders")); - - the_field = field; - goto end_of_field_search; - } - } - end_of_field_search: - if (the_field != NULL) - { - if (the_field->flags & 0x0008 /* Modifier::STATIC */) - { - throw new java::lang::IncompatibleClassChangeError; - } - else - { - klass->otable->offsets[index] = the_field->u.boffset; - } - } - else - { - throw new java::lang::NoSuchFieldError - (_Jv_NewStringUtf8Const (sym.name)); - } - } - } - - atable: - if (klass->atable == NULL - || klass->atable->state != 0) - return; - - klass->atable->state = 1; - - for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++) - { - // FIXME: Why are we passing NULL as the class loader? - jclass target_class = _Jv_FindClass (sym.class_name, NULL); - _Jv_Method *meth = NULL; - const _Jv_Utf8Const *signature = sym.signature; - - // ??? Setting this pointer to null will at least get us a - // NullPointerException - klass->atable->addresses[index] = NULL; - - if (target_class == NULL) - continue; - - // We're looking for a static field or a static method, and we - // can tell which is needed by looking at the signature. - if (signature->first() == '(' && signature->len() >= 2) - { - // If the target class does not have a vtable_method_count yet, - // then we can't tell the offsets for its methods, so we must lay - // it out now. - if (target_class->vtable_method_count == -1) - { - JvSynchronize sync (target_class); - _Jv_LayoutVTableMethods (target_class); - } - - meth = _Jv_LookupDeclaredMethod(target_class, sym.name, - sym.signature); - - if (meth != NULL) - { - if (meth->ncode) // Maybe abstract? - klass->atable->addresses[index] = meth->ncode; -#ifdef INTERPRETER - else if (_Jv_IsInterpretedClass (target_class)) - _Jv_Defer_Resolution (target_class, meth, - &klass->atable->addresses[index]); -#endif - } - else - klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError; - - continue; - } - - // try fields - { - _Jv_Field *the_field = NULL; - - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i = 0; i < cls->field_count; i++) - { - _Jv_Field *field = &cls->fields[i]; - if (! _Jv_equalUtf8Consts (field->name, sym.name)) - continue; - - // FIXME: What access checks should we perform here? -// if (_Jv_CheckAccess (klass, cls, field->flags)) -// { - - if (!field->isResolved ()) - _Jv_ResolveField (field, cls->loader); - -// if (field_type != 0 && field->type != field_type) -// throw new java::lang::LinkageError -// (JvNewStringLatin1 -// ("field type mismatch with different loaders")); - - the_field = field; - goto end_of_static_field_search; - } - } - end_of_static_field_search: - if (the_field != NULL) - { - if (the_field->flags & 0x0008 /* Modifier::STATIC */) - { - klass->atable->addresses[index] = the_field->u.addr; - } - else - { - throw new java::lang::IncompatibleClassChangeError; - } - } - else - { - throw new java::lang::NoSuchFieldError - (_Jv_NewStringUtf8Const (sym.name)); - } - } - } -} - - -// For each catch_record in the list of caught classes, fill in the -// address field. -void -_Jv_linkExceptionClassTable (jclass self) -{ - struct _Jv_CatchClass *catch_record = self->catch_classes; - if (!catch_record || catch_record->classname) - return; - catch_record++; - while (catch_record->classname) - { - jclass target_class = _Jv_FindClass (catch_record->classname, - self->getClassLoaderInternal ()); - *catch_record->address = target_class; - catch_record++; - } - self->catch_classes->classname = (_Jv_Utf8Const *)-1; -} - -// This is put in empty vtable slots. -static void -_Jv_abstractMethodError (void) -{ - throw new java::lang::AbstractMethodError(); -} - -// Set itable method indexes for members of interface IFACE. -void -_Jv_LayoutInterfaceMethods (jclass iface) -{ - if (! iface->isInterface()) - return; - - // itable indexes start at 1. - // FIXME: Static initalizers currently get a NULL placeholder entry in the - // itable so they are also assigned an index here. - for (int i = 0; i < iface->method_count; i++) - iface->methods[i].index = i + 1; -} - -// Prepare virtual method declarations in KLASS, and any superclasses as -// required, by determining their vtable index, setting method->index, and -// finally setting the class's vtable_method_count. Must be called with the -// lock for KLASS held. -void -_Jv_LayoutVTableMethods (jclass klass) -{ - if (klass->vtable != NULL || klass->isInterface() - || klass->vtable_method_count != -1) - return; - - jclass superclass = klass->superclass; - - typedef unsigned int uaddr __attribute__ ((mode (pointer))); + // FIXME: Method must be public. Throw an exception? + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; - // If superclass looks like a constant pool entry, - // resolve it now. - if ((uaddr) superclass < (uaddr) klass->constants.size) - { - if (klass->state < JV_STATE_LINKED) - { - _Jv_Utf8Const *name = klass->constants.data[(uaddr) superclass].utf8; - superclass = _Jv_FindClass (name, klass->loader); - if (! superclass) - { - throw new java::lang::NoClassDefFoundError (name->toString()); + found_class = klass; + // Interface method indexes count from 1. + index = i+1; + return true; } } - else - superclass = klass->constants.data[(uaddr) superclass].clazz; - } - - if (superclass != NULL && superclass->vtable_method_count == -1) - { - JvSynchronize sync (superclass); - _Jv_LayoutVTableMethods (superclass); - } - - int index = (superclass == NULL ? 0 : superclass->vtable_method_count); - - for (int i = 0; i < klass->method_count; ++i) - { - _Jv_Method *meth = &klass->methods[i]; - _Jv_Method *super_meth = NULL; - - if (! _Jv_isVirtualMethod (meth)) - continue; - - // FIXME: Must check that we don't override: - // - Package-private method where superclass is in different package. - // - Final or less-accessible declaration in superclass (check binary - // spec, do we allocate new vtable entry or put throw node in vtable?) - // - Static or private method in superclass. - - if (superclass != NULL) - { - super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, - meth->signature); - } - - if (super_meth) - meth->index = super_meth->index; - else - meth->index = index++; - } - - klass->vtable_method_count = index; -} - -// Set entries in VTABLE for virtual methods declared in KLASS. If -// KLASS has an immediate abstract parent, recursively do its methods -// first. FLAGS is used to determine which slots we've actually set. -void -_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags) -{ - using namespace java::lang::reflect; - - jclass superclass = klass->getSuperclass(); - - if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT)) - _Jv_SetVTableEntries (superclass, vtable, flags); - - for (int i = klass->method_count - 1; i >= 0; i--) - { - _Jv_Method *meth = &klass->methods[i]; - if (meth->index == (_Jv_ushort) -1) - continue; - if ((meth->accflags & Modifier::ABSTRACT)) - { - vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError); - flags[meth->index] = false; - } - else - { - vtable->set_method(meth->index, meth->ncode); - flags[meth->index] = true; - } } -} - -// Allocate and lay out the virtual method table for KLASS. This will also -// cause vtables to be generated for any non-abstract superclasses, and -// virtual method layout to occur for any abstract superclasses. Must be -// called with monitor lock for KLASS held. -void -_Jv_MakeVTable (jclass klass) -{ - using namespace java::lang::reflect; - if (klass->vtable != NULL || klass->isInterface() - || (klass->accflags & Modifier::ABSTRACT)) - return; - - // Class must be laid out before we can create a vtable. - if (klass->vtable_method_count == -1) - _Jv_LayoutVTableMethods (klass); - - // Allocate the new vtable. - _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count); - klass->vtable = vtable; - - jboolean flags[klass->vtable_method_count]; - for (int i = 0; i < klass->vtable_method_count; ++i) - flags[i] = false; - - // Copy the vtable of the closest non-abstract superclass. - jclass superclass = klass->superclass; - if (superclass != NULL) + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (search_class->isInterface()) { - while ((superclass->accflags & Modifier::ABSTRACT) != 0) - superclass = superclass->superclass; - - if (superclass->vtable == NULL) - { - JvSynchronize sync (superclass); - _Jv_MakeVTable (superclass); - } - - for (int i = 0; i < superclass->vtable_method_count; ++i) + for (int i = 0; i < search_class->interface_count; ++i) { - vtable->set_method (i, superclass->vtable->get_method (i)); - flags[i] = true; + using namespace java::lang::reflect; + bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], + found_class, index, + utf_name, utf_sig); + if (found) + return true; } } - // Set the class pointer and GC descriptor. - vtable->clas = klass; - vtable->gc_descr = _Jv_BuildGCDescr (klass); - - // For each virtual declared in klass and any immediate abstract - // superclasses, set new vtable entry or override an old one. - _Jv_SetVTableEntries (klass, vtable, flags); - - // It is an error to have an abstract method in a concrete class. - if (! (klass->accflags & Modifier::ABSTRACT)) - { - for (int i = 0; i < klass->vtable_method_count; ++i) - if (! flags[i]) - { - using namespace java::lang; - while (klass != NULL) - { - for (int j = 0; j < klass->method_count; ++j) - { - if (klass->methods[i].index == i) - { - StringBuffer *buf = new StringBuffer (); - buf->append (_Jv_NewStringUtf8Const (klass->methods[i].name)); - buf->append ((jchar) ' '); - buf->append (_Jv_NewStringUtf8Const (klass->methods[i].signature)); - throw new AbstractMethodError (buf->toString ()); - } - } - klass = klass->getSuperclass (); - } - // Couldn't find the name, which is weird. - // But we still must throw the error. - throw new AbstractMethodError (); - } - } + return false; } diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 5a0898a93c4..dd5cd463cfa 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -18,6 +18,7 @@ details. */ #include <gcj/cni.h> #include <jvm.h> +#include <execution.h> #include <java-threads.h> #include <java-interp.h> @@ -33,6 +34,7 @@ details. */ #include <java/lang/ClassNotFoundException.h> #include <java/lang/ClassCircularityError.h> #include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/ClassFormatError.h> #include <java/lang/VirtualMachineError.h> #include <java/lang/VMClassLoader.h> #include <java/lang/reflect/Modifier.h> @@ -41,156 +43,6 @@ details. */ #include <java/io/Serializable.h> #include <java/lang/Cloneable.h> -void -_Jv_WaitForState (jclass klass, int state) -{ - if (klass->state >= state) - return; - - _Jv_MonitorEnter (klass) ; - - if (klass->state == JV_STATE_COMPILED) - { - klass->state = JV_STATE_LOADED; - if (gcj::verbose_class_flag) - fprintf (stderr, "[Loaded (pre-compiled) %s]\n", klass->name->chars()); - } - if (state == JV_STATE_LINKED) - { - // Must call _Jv_PrepareCompiledClass while holding the class - // mutex. -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (klass)) - _Jv_PrepareClass (klass); -#endif - _Jv_PrepareCompiledClass (klass); - _Jv_MonitorExit (klass); - return; - } - - java::lang::Thread *self = java::lang::Thread::currentThread(); - - // this is similar to the strategy for class initialization. - // if we already hold the lock, just leave. - while (klass->state <= state - && klass->thread - && klass->thread != self) - klass->wait (); - - _Jv_MonitorExit (klass); - - if (klass->state == JV_STATE_ERROR) - throw new java::lang::LinkageError; -} - -typedef unsigned int uaddr __attribute__ ((mode (pointer))); - -/** This function does class-preparation for compiled classes. - NOTE: It contains replicated functionality from - _Jv_ResolvePoolEntry, and this is intentional, since that function - lives in resolve.cc which is entirely conditionally compiled. - */ -void -_Jv_PrepareCompiledClass (jclass klass) -{ - jint state = klass->state; - if (state >= JV_STATE_LINKED) - return; - - // Short-circuit, so that mutually dependent classes are ok. - klass->state = JV_STATE_LINKED; - - _Jv_Constants *pool = &klass->constants; - - // Resolve class constants first, since other constant pool - // entries may rely on these. - for (int index = 1; index < pool->size; ++index) - { - if (pool->tags[index] == JV_CONSTANT_Class) - { - _Jv_Utf8Const *name = pool->data[index].utf8; - - jclass found; - if (name->first() == '[') - found = _Jv_FindClassFromSignature (name->chars(), - klass->loader); - else - found = _Jv_FindClass (name, klass->loader); - - if (! found) - { - jstring str = name->toString(); - throw new java::lang::NoClassDefFoundError (str); - } - - pool->data[index].clazz = found; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - } - - // If superclass looks like a constant pool entry, - // resolve it now. - if ((uaddr) klass->superclass < pool->size) - klass->superclass = pool->data[(uaddr) klass->superclass].clazz; - - // Likewise for interfaces. - for (int i = 0; i < klass->interface_count; i++) - if ((uaddr) klass->interfaces[i] < pool->size) - klass->interfaces[i] = pool->data[(uaddr) klass->interfaces[i]].clazz; - - // Resolve the remaining constant pool entries. - for (int index = 1; index < pool->size; ++index) - { - if (pool->tags[index] == JV_CONSTANT_String) - { - jstring str; - - str = _Jv_NewStringUtf8Const (pool->data[index].utf8); - pool->data[index].o = str; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - } - -#ifdef INTERPRETER - // FIXME: although the comment up top says that this function is - // only called for compiled classes, it is actually called for every - // class. - if (! _Jv_IsInterpretedClass (klass)) - { -#endif /* INTERPRETER */ - jfieldID f = JvGetFirstStaticField (klass); - for (int n = JvNumStaticFields (klass); n > 0; --n) - { - int mod = f->getModifiers (); - // If we have a static String field with a non-null initial - // value, we know it points to a Utf8Const. - _Jv_ResolveField(f, klass->loader); - if (f->getClass () == &java::lang::String::class$ - && java::lang::reflect::Modifier::isStatic (mod)) - { - jstring *strp = (jstring *) f->u.addr; - if (*strp) - *strp = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) *strp); - } - f = f->getNextField (); - } -#ifdef INTERPRETER - } -#endif /* INTERPRETER */ - - if (klass->isInterface ()) - _Jv_LayoutInterfaceMethods (klass); - - if (state == JV_STATE_COMPILED && gcj::verbose_class_flag) - fprintf (stderr, "[Loaded (pre-compiled) %s]\n", - klass->name->chars()); - - klass->notifyAll (); - - _Jv_PushClass (klass); -} - - // // A single class can have many "initiating" class loaders, // and a single "defining" class loader. The Defining @@ -221,6 +73,8 @@ static _Jv_LoaderInfo *initiated_classes[HASH_LEN]; static jclass loaded_classes[HASH_LEN]; // This is the root of a linked list of classes +static jclass stack_head; + @@ -323,11 +177,6 @@ _Jv_RegisterClasses (const jclass *classes) jclass klass = *classes; (*_Jv_RegisterClassHook) (klass); - - // registering a compiled class causes - // it to be immediately "prepared". - if (klass->state == JV_STATE_NOTHING) - klass->state = JV_STATE_COMPILED; } } @@ -341,11 +190,6 @@ _Jv_RegisterClasses_Counted (const jclass * classes, size_t count) jclass klass = classes[i]; (*_Jv_RegisterClassHook) (klass); - - // registering a compiled class causes - // it to be immediately "prepared". - if (klass->state == JV_STATE_NOTHING) - klass->state = JV_STATE_COMPILED; } } @@ -354,8 +198,10 @@ _Jv_RegisterClassHookDefault (jclass klass) { jint hash = HASH_UTF (klass->name); - jclass check_class = loaded_classes[hash]; - + // The BC ABI makes this check unnecessary: we always resolve all + // data references via the appropriate class loader, so the kludge + // that required this check has gone. +#if 0 // If the class is already registered, don't re-register it. while (check_class != NULL) { @@ -381,7 +227,11 @@ _Jv_RegisterClassHookDefault (jclass klass) check_class = check_class->next; } +#endif + // FIXME: this is really bogus! + if (! klass->engine) + klass->engine = &_Jv_soleCompiledEngine; klass->next = loaded_classes[hash]; loaded_classes[hash] = klass; } @@ -442,7 +292,7 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) { // we need classes to be in the hash while // we're loading, so that they can refer to themselves. - _Jv_WaitForState (klass, JV_STATE_LOADED); + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADED); } return klass; @@ -555,7 +405,7 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, // cache one and reuse it. It is not necessary to synchronize this. if (!array_idt) { - _Jv_PrepareConstantTimeTables (array_class); + _Jv_Linker::wait_for_state(array_class, JV_STATE_PREPARED); array_idt = array_class->idt; array_depth = array_class->depth; array_ancestors = array_class->ancestors; @@ -569,19 +419,19 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, using namespace java::lang::reflect; { - // Array classes are "abstract final"... - _Jv_ushort accflags = Modifier::FINAL | Modifier::ABSTRACT; - // ... and inherit accessibility from element type, per vmspec 5.3.3.2 - accflags |= (element->accflags & Modifier::PUBLIC); - accflags |= (element->accflags & Modifier::PROTECTED); - accflags |= (element->accflags & Modifier::PRIVATE); + // Array classes are "abstract final" and inherit accessibility + // from element type, per vmspec 5.3.3.2 + _Jv_ushort accflags = (Modifier::FINAL | Modifier::ABSTRACT + | (element->accflags + & (Modifier::PUBLIC | Modifier::PROTECTED + | Modifier::PRIVATE))); array_class->accflags = accflags; } // An array class has no visible instance fields. "length" is invisible to // reflection. - // say this class is initialized and ready to go! + // Say this class is initialized and ready to go! array_class->state = JV_STATE_DONE; // vmspec, section 5.3.3 describes this @@ -591,8 +441,6 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, element->arrayclass = array_class; } -static jclass stack_head; - // These two functions form a stack of classes. When a class is loaded // it is pushed onto the stack by the class loader; this is so that // StackTrace can quickly determine which classes have been loaded. diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 1e57f50113d..332f2c7b625 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -1,6 +1,6 @@ // natRuntime.cc - Implementation of native side of Runtime class. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -388,8 +388,11 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val)) // A mixture of the Java Product Versioning Specification - // (introduced in 1.2), and earlier versioning properties. - SET ("java.version", GCJVERSION); + // (introduced in 1.2), and earlier versioning properties. Some + // programs rely on seeing values that they expect, so we claim to + // be a 1.4-ish VM for their sake. + SET ("java.version", "1.4.2"); + SET ("java.runtime.version", "1.4.2"); SET ("java.vendor", "Free Software Foundation, Inc."); SET ("java.vendor.url", "http://gcc.gnu.org/java/"); SET ("java.class.version", "46.0"); @@ -399,7 +402,7 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) SET ("java.vm.version", __VERSION__); SET ("java.vm.vendor", "Free Software Foundation, Inc."); SET ("java.vm.name", "GNU libgcj"); - SET ("java.specification.version", "1.3"); + SET ("java.specification.version", "1.4"); SET ("java.specification.name", "Java(tm) Platform API Specification"); SET ("java.specification.vendor", "Sun Microsystems Inc."); diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc index cba0976bd95..e2558f4f747 100644 --- a/libjava/java/lang/natString.cc +++ b/libjava/java/lang/natString.cc @@ -1,7 +1,6 @@ // natString.cc - Implementation of java.lang.String native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -57,7 +56,7 @@ static int strhash_size = 0; /* Number of slots available in strhash. jstring* _Jv_StringFindSlot (jchar* data, jint len, jint hash) { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); int start_index = hash & (strhash_size - 1); int deleted_index = -1; @@ -120,7 +119,7 @@ _Jv_StringGetSlot (jstring str) static void rehash () { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (strhash == NULL) { @@ -167,7 +166,7 @@ rehash () jstring java::lang::String::intern() { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) rehash(); jstring* ptr = _Jv_StringGetSlot(this); @@ -194,7 +193,7 @@ java::lang::String::intern() void _Jv_FinalizeString (jobject obj) { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); // We might not actually have intern()d any strings at all, if // we're being called from Reference. @@ -286,9 +285,9 @@ _Jv_NewStringUtf8Const (Utf8Const* str) } chrs -= length; - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) - rehash (); + rehash(); jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); if (*ptr != NULL && *ptr != DELETED_STRING) return (jstring) UNMASK_PTR (*ptr); @@ -527,7 +526,7 @@ java::lang::String::equals(jobject anObject) return false; if (anObject == this) return true; - if (anObject->getClass() != &StringClass) + if (anObject->getClass() != &java::lang::String::class$) return false; jstring other = (jstring) anObject; if (count != other->count) diff --git a/libjava/java/lang/natVMClassLoader.cc b/libjava/java/lang/natVMClassLoader.cc index 1ed3851fbb3..841b3e0789e 100644 --- a/libjava/java/lang/natVMClassLoader.cc +++ b/libjava/java/lang/natVMClassLoader.cc @@ -22,6 +22,7 @@ details. */ #include <java-interp.h> #include <java/lang/VMClassLoader.h> +#include <java/lang/VMCompiler.h> #include <gnu/gcj/runtime/VMClassLoader.h> #include <java/lang/ClassLoader.h> #include <java/lang/Class.h> @@ -29,6 +30,21 @@ details. */ #include <java/security/ProtectionDomain.h> #include <java/lang/ClassFormatError.h> +void +java::lang::VMClassLoader::resolveClass (jclass klass) +{ + JvSynchronize sync (klass); + try + { + _Jv_Linker::wait_for_state (klass, JV_STATE_LINKED); + } + catch (java::lang::Throwable *x) + { + klass->set_state(JV_STATE_ERROR); + transformException(klass, x); + } +} + java::lang::Class * java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, jstring name, @@ -37,72 +53,61 @@ java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, jint length, java::security::ProtectionDomain *pd) { -#ifdef INTERPRETER - jclass klass; - klass = new java::lang::Class (); - klass->aux_info = (void *) _Jv_AllocBytes (sizeof (_Jv_InterpClass)); - - // Synchronize on the class, so that it is not attempted initialized - // until we're done loading. - JvSynchronize sync (klass); - - // Record the defining loader. For the system class loader, we - // record NULL. - if (loader != java::lang::ClassLoader::getSystemClassLoader()) - klass->loader = loader; - - if (name != 0) - { - _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); - - if (! _Jv_VerifyClassName (name2)) - throw new java::lang::ClassFormatError - (JvNewStringLatin1 ("erroneous class name")); - - klass->name = name2; - } + jclass klass = VMCompiler::compileClass(loader, name, data, + offset, length, pd); - try + if (klass != NULL) { - _Jv_DefineClass (klass, data, offset, length); + JvSynchronize sync (&java::lang::Class::class$); + _Jv_RegisterClass (klass); } - catch (java::lang::Throwable *ex) +#ifdef INTERPRETER + else { - klass->state = JV_STATE_ERROR; - klass->notifyAll (); - - _Jv_UnregisterClass (klass); - - // If EX is not a ClassNotFoundException, that's ok, because we - // account for the possibility in defineClass(). - throw ex; + klass = new java::lang::Class (); + + // Synchronize on the class, so that it is not attempted initialized + // until we're done loading. + JvSynchronize sync (klass); + + // Record the defining loader. For the system class loader, we + // record NULL. + if (loader != java::lang::ClassLoader::getSystemClassLoader()) + klass->loader = loader; + + if (name != 0) + { + _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); + + if (! _Jv_VerifyClassName (name2)) + throw new java::lang::ClassFormatError + (JvNewStringLatin1 ("erroneous class name")); + + klass->name = name2; + } + + try + { + _Jv_DefineClass (klass, data, offset, length, pd); + } + catch (java::lang::Throwable *ex) + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + _Jv_UnregisterClass (klass); + + // If EX is not a ClassNotFoundException, that's ok, because we + // account for the possibility in defineClass(). + throw ex; + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_LOADED); } - - klass->protectionDomain = pd; - - // if everything proceeded sucessfully, we're loaded. - JvAssert (klass->state == JV_STATE_LOADED); +#endif // INTERPRETER return klass; - -#else // INTERPRETER - - return 0; -#endif -} - -// Finish linking a class. Only called from ClassLoader::resolveClass. -void -java::lang::VMClassLoader::linkClass0 (java::lang::Class *klass) -{ - _Jv_WaitForState (klass, JV_STATE_LINKED); -} - -void -java::lang::VMClassLoader::markClassErrorState0 (java::lang::Class *klass) -{ - klass->state = JV_STATE_ERROR; - klass->notifyAll (); } java::lang::ClassLoader * @@ -125,9 +130,16 @@ jclass java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve) { _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name); - // FIXME: we culd make _Jv_FindClassFromSignature a template. jclass klass = _Jv_FindClassInCache (utf, NULL); - if (klass && resolve) - _Jv_InitClass (klass); + if (klass) + { + // We never want to return a class without its supers linked. + // It isn't clear from the spec, but this is what other + // implementations do in practice. + if (resolve) + _Jv_InitClass (klass); + else + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + } return klass; } diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index 469cf74de8e..7eb032227ab 100644 --- a/libjava/java/lang/reflect/natField.cc +++ b/libjava/java/lang/reflect/natField.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -47,7 +47,7 @@ java::lang::reflect::Field::getType () { jfieldID fld = _Jv_FromReflectedField (this); JvSynchronize sync (declaringClass); - _Jv_ResolveField (fld, declaringClass->getClassLoaderInternal ()); + _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ()); return fld->type; } diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 8c6efc487cd..b194067300b 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -149,7 +149,6 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) getType (); jmethodID meth = _Jv_FromReflectedMethod (this); - jclass objClass; if (Modifier::isStatic(meth->accflags)) { @@ -157,12 +156,10 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) // here and not in _Jv_CallAnyMethodA because JNI initializes a // class whenever a method lookup is done. _Jv_InitClass (declaringClass); - objClass = declaringClass; } else { - objClass = JV_CLASS (obj); - + jclass objClass = JV_CLASS (obj); if (! _Jv_IsAssignableFrom (declaringClass, objClass)) throw new java::lang::IllegalArgumentException; } @@ -184,7 +181,7 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) { } - if (! _Jv_CheckAccess(caller, objClass, meth->accflags)) + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) throw new IllegalAccessException; } diff --git a/libjava/java/net/URLClassLoader.java b/libjava/java/net/URLClassLoader.java index 4ffd4c532db..3efc5dca76f 100644 --- a/libjava/java/net/URLClassLoader.java +++ b/libjava/java/net/URLClassLoader.java @@ -54,6 +54,8 @@ import java.security.SecureClassLoader; import java.security.cert.Certificate; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarEntry; @@ -144,9 +146,10 @@ public class URLClassLoader extends SecureClassLoader private final Vector urls = new Vector(); /** - * Store pre-parsed information for each url into this vector - * each element is a URL loader, corresponding to the URL of - * the same index in "urls" + * Store pre-parsed information for each url into this vector: each + * element is a URL loader. A jar file has its own class-path + * attribute which adds to the URLs that will be searched, but this + * does not add to the list of urls. */ private final Vector urlinfos = new Vector(); @@ -189,9 +192,14 @@ public class URLClassLoader extends SecureClassLoader URLLoader(URLClassLoader classloader, URL baseURL) { + this(classloader, baseURL, baseURL); + } + + URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) + { this.classloader = classloader; this.baseURL = baseURL; - this.noCertCodeSource = new CodeSource(baseURL, null); + this.noCertCodeSource = new CodeSource(overrideURL, null); } /** @@ -221,6 +229,11 @@ public class URLClassLoader extends SecureClassLoader { return null; } + + Vector getClassPath() + { + return null; + } } /** @@ -290,6 +303,10 @@ public class URLClassLoader extends SecureClassLoader final JarFile jarfile; // The jar file for this url final URL baseJarURL; // Base jar: url for all resources loaded from jar + Vector classPath; // The "Class-Path" attribute of this Jar's manifest + + SoURLLoader soURLLoader; + public JarURLLoader(URLClassLoader classloader, URL baseURL) { super(classloader, baseURL); @@ -302,25 +319,87 @@ public class URLClassLoader extends SecureClassLoader sb.append("!/"); String jarURL = sb.toString(); + this.soURLLoader = null; + this.classPath = null; URL baseJarURL = null; JarFile jarfile = null; try - { - baseJarURL = - new URL(null, jarURL, classloader.getURLStreamHandler("jar")); - - jarfile = - ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); - } + { + baseJarURL + = new URL(null, jarURL, classloader.getURLStreamHandler("jar")); + jarfile + = ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + if (jarfile != null) + { + String fileName = baseURL.getFile(); + if (fileName != null) + { + File f = new File(fileName); + String libDirName = f.getCanonicalFile().getParent() + + File.separator + "GCJLIBS"; + File libDir = new File(libDirName); + if (libDir != null && (libDir.isDirectory())) + { + File soFile = new File (libDirName + + File.separator + f.getName() + + ".so"); + if (soFile != null && soFile.isFile()) + this.soURLLoader + = new SoURLLoader (classloader, soFile.toURL(), + baseURL); + } + } + + Manifest manifest; + Attributes attributes; + String classPathString; + + if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new Vector(); + + StringTokenizer st + = new StringTokenizer + (classPathString, + System.getProperty ("path.separator", ":")); + + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL url = new URL(baseURL, e); + this.classPath.add(url); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + } catch (IOException ioe) { - /* ignored */ + /* ignored */ } this.baseJarURL = baseJarURL; this.jarfile = jarfile; } + Class getClass(String className) + { + if (soURLLoader != null) + return soURLLoader.getClass(className); + return null; + } + /** get resource with the name "name" in the jar url */ Resource getResource(String name) { @@ -337,6 +416,11 @@ public class URLClassLoader extends SecureClassLoader return null; } + public String toString () + { + return "jarfile " + jarfile.getName(); + } + Manifest getManifest() { try @@ -348,6 +432,11 @@ public class URLClassLoader extends SecureClassLoader return null; } } + + Vector getClassPath() + { + return classPath; + } } static final class JarURLResource extends Resource @@ -486,7 +575,12 @@ public class URLClassLoader extends SecureClassLoader SoURLLoader(URLClassLoader classloader, URL url) { - super(classloader, url); + this(classloader, url, url); + } + + SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL) + { + super(classloader, url, overrideURL); helper = SharedLibHelper.findHelper(classloader, url.getFile(), noCertCodeSource); } @@ -577,6 +671,11 @@ public class URLClassLoader extends SecureClassLoader return (int) file.length(); } + public String toString () + { + return "file " +file.getAbsolutePath(); + } + public URL getURL() { try @@ -729,6 +828,7 @@ public class URLClassLoader extends SecureClassLoader */ protected void addURL(URL newUrl) { + urls.add(newUrl); addURLImpl(newUrl); } @@ -761,8 +861,21 @@ public class URLClassLoader extends SecureClassLoader urlloaders.put(newUrl, loader); } - urls.add(newUrl); - urlinfos.add(loader); + urlinfos.add(loader); + + Vector extraUrls = loader.getClassPath(); + if (extraUrls != null) + { + Iterator it = extraUrls.iterator(); + while (it.hasNext()) + { + URL url = (URL)it.next(); + URLLoader extraLoader = (URLLoader) urlloaders.get(url); + if (! urlinfos.contains (extraLoader)) + addURLImpl(url); + } + } + } } @@ -773,7 +886,7 @@ public class URLClassLoader extends SecureClassLoader private void addURLs(URL[] newUrls) { for (int i = 0; i < newUrls.length; i++) - addURLImpl(newUrls[i]); + addURL(newUrls[i]); } /** @@ -830,7 +943,7 @@ public class URLClassLoader extends SecureClassLoader { // Just try to find the resource by the (almost) same name String resourceName = className.replace('.', '/') + ".class"; - int max = urls.size(); + int max = urlinfos.size(); Resource resource = null; for (int i = 0; i < max && resource == null; i++) { @@ -939,7 +1052,7 @@ public class URLClassLoader extends SecureClassLoader */ private Resource findURLResource(String resourceName) { - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i); @@ -1010,7 +1123,7 @@ public class URLClassLoader extends SecureClassLoader throws IOException { Vector resources = new Vector(); - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i); diff --git a/libjava/jni.cc b/libjava/jni.cc index 6bfc4812d96..6138334ebaf 100644 --- a/libjava/jni.cc +++ b/libjava/jni.cc @@ -563,11 +563,12 @@ _Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message) NULL); jclass *elts = elements (argtypes); - elts[0] = &StringClass; + elts[0] = &java::lang::String::class$; Constructor *cons = clazz->getConstructor (argtypes); - jobjectArray values = JvNewObjectArray (1, &StringClass, NULL); + jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$, + NULL); jobject *velts = elements (values); velts[0] = JvNewStringUTF (message); @@ -1204,7 +1205,7 @@ _Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz, // The field might be resolved or it might not be. It // is much simpler to always resolve it. - _Jv_ResolveField (field, loader); + _Jv_Linker::resolve_field (field, loader); if (_Jv_equalUtf8Consts (f_name, a_name) && field->getClass() == field_class) return field; diff --git a/libjava/link.cc b/libjava/link.cc new file mode 100644 index 00000000000..39ade1481a3 --- /dev/null +++ b/libjava/link.cc @@ -0,0 +1,1764 @@ +// link.cc - Code for linking and resolving classes and pool entries. + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> +#include <platform.h> + +#include <java-interp.h> + +#include <jvm.h> +#include <gcj/cni.h> +#include <string.h> +#include <java-cpool.h> +#include <execution.h> +#include <java/lang/Class.h> +#include <java/lang/String.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/Thread.h> +#include <java/lang/InternalError.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/VerifyError.h> +#include <java/lang/NoSuchFieldError.h> +#include <java/lang/NoSuchMethodError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/AbstractMethodError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/VerifyError.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/reflect/Modifier.h> +#include <java/security/CodeSource.h> + +using namespace gcj; + +// When true, print debugging information about class loading. +bool gcj::verbose_class_flag; + +typedef unsigned int uaddr __attribute__ ((mode (pointer))); + +template<typename T> +struct aligner +{ + char c; + T field; +}; + +#define ALIGNOF(TYPE) (offsetof (aligner<TYPE>, field)) + +// This returns the alignment of a type as it would appear in a +// structure. This can be different from the alignment of the type +// itself. For instance on x86 double is 8-aligned but struct{double} +// is 4-aligned. +int +_Jv_Linker::get_alignment_from_class (jclass klass) +{ + if (klass == JvPrimClass (byte)) + return ALIGNOF (jbyte); + else if (klass == JvPrimClass (short)) + return ALIGNOF (jshort); + else if (klass == JvPrimClass (int)) + return ALIGNOF (jint); + else if (klass == JvPrimClass (long)) + return ALIGNOF (jlong); + else if (klass == JvPrimClass (boolean)) + return ALIGNOF (jboolean); + else if (klass == JvPrimClass (char)) + return ALIGNOF (jchar); + else if (klass == JvPrimClass (float)) + return ALIGNOF (jfloat); + else if (klass == JvPrimClass (double)) + return ALIGNOF (jdouble); + else + return ALIGNOF (jobject); +} + +void +_Jv_Linker::resolve_field (_Jv_Field *field, java::lang::ClassLoader *loader) +{ + if (! field->isResolved ()) + { + _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type; + field->type = _Jv_FindClassFromSignature (sig->chars(), loader); + field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; + } +} + +_Jv_word +_Jv_Linker::resolve_pool_entry (jclass klass, int index) +{ + using namespace java::lang::reflect; + + _Jv_Constants *pool = &klass->constants; + + if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) + return pool->data[index]; + + switch (pool->tags[index]) + { + case JV_CONSTANT_Class: + { + _Jv_Utf8Const *name = pool->data[index].utf8; + + jclass found; + if (name->first() == '[') + found = _Jv_FindClassFromSignature (name->chars(), + klass->loader); + else + found = _Jv_FindClass (name, klass->loader); + + if (! found) + throw new java::lang::NoClassDefFoundError (name->toString()); + + // Check accessibility, but first strip array types as + // _Jv_ClassNameSamePackage can't handle arrays. + jclass check; + for (check = found; + check && check->isArray(); + check = check->getComponentType()) + ; + if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC + || (_Jv_ClassNameSamePackage (check->name, + klass->name))) + { + pool->data[index].clazz = found; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + else + { + java::lang::StringBuffer *sb = new java::lang::StringBuffer (); + sb->append(klass->getName()); + sb->append(JvNewStringLatin1(" can't access class ")); + sb->append(found->getName()); + throw new java::lang::IllegalAccessError(sb->toString()); + } + } + break; + + case JV_CONSTANT_String: + { + jstring str; + str = _Jv_NewStringUtf8Const (pool->data[index].utf8); + pool->data[index].o = str; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + + case JV_CONSTANT_Fieldref: + { + _Jv_ushort class_index, name_and_type_index; + _Jv_loadIndexes (&pool->data[index], + class_index, + name_and_type_index); + jclass owner = (resolve_pool_entry (klass, class_index)).clazz; + + if (owner != klass) + _Jv_InitClass (owner); + + _Jv_ushort name_index, type_index; + _Jv_loadIndexes (&pool->data[name_and_type_index], + name_index, + type_index); + + _Jv_Utf8Const *field_name = pool->data[name_index].utf8; + _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8; + + // FIXME: The implementation of this function + // (_Jv_FindClassFromSignature) will generate an instance of + // _Jv_Utf8Const for each call if the field type is a class name + // (Lxx.yy.Z;). This may be too expensive to do for each and + // every fieldref being resolved. For now, we fix the problem by + // only doing it when we have a loader different from the class + // declaring the field. + + jclass field_type = 0; + + if (owner->loader != klass->loader) + field_type = _Jv_FindClassFromSignature (field_type_name->chars(), + klass->loader); + + _Jv_Field* the_field = 0; + + for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->field_count; i++) + { + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, field_name)) + continue; + + if (_Jv_CheckAccess (klass, cls, field->flags)) + { + // Resolve the field using the class' own loader if + // necessary. + + if (!field->isResolved ()) + resolve_field (field, cls->loader); + + if (field_type != 0 && field->type != field_type) + throw new java::lang::LinkageError + (JvNewStringLatin1 + ("field type mismatch with different loaders")); + + the_field = field; + goto end_of_field_search; + } + else + { + java::lang::StringBuffer *sb + = new java::lang::StringBuffer (); + sb->append(klass->getName()); + sb->append(JvNewStringLatin1(": ")); + sb->append(cls->getName()); + sb->append(JvNewStringLatin1(".")); + sb->append(_Jv_NewStringUtf8Const (field_name)); + throw new java::lang::IllegalAccessError(sb->toString()); + } + } + } + + end_of_field_search: + if (the_field == 0) + { + java::lang::StringBuffer *sb = new java::lang::StringBuffer(); + sb->append(JvNewStringLatin1("field ")); + sb->append(owner->getName()); + sb->append(JvNewStringLatin1(".")); + sb->append(_Jv_NewStringUTF(field_name->chars())); + sb->append(JvNewStringLatin1(" was not found.")); + throw + new java::lang::IncompatibleClassChangeError (sb->toString()); + } + + pool->data[index].field = the_field; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + + case JV_CONSTANT_Methodref: + case JV_CONSTANT_InterfaceMethodref: + { + _Jv_ushort class_index, name_and_type_index; + _Jv_loadIndexes (&pool->data[index], + class_index, + name_and_type_index); + jclass owner = (resolve_pool_entry (klass, class_index)).clazz; + + if (owner != klass) + _Jv_InitClass (owner); + + _Jv_ushort name_index, type_index; + _Jv_loadIndexes (&pool->data[name_and_type_index], + name_index, + type_index); + + _Jv_Utf8Const *method_name = pool->data[name_index].utf8; + _Jv_Utf8Const *method_signature = pool->data[type_index].utf8; + + _Jv_Method *the_method = 0; + jclass found_class = 0; + + // We're going to cache a pointer to the _Jv_Method object + // when we find it. So, to ensure this doesn't get moved from + // beneath us, we first put all the needed Miranda methods + // into the target class. + wait_for_state (klass, JV_STATE_LOADED); + + // First search the class itself. + the_method = search_method_in_class (owner, klass, + method_name, method_signature); + + if (the_method != 0) + { + found_class = owner; + goto end_of_method_search; + } + + // If we are resolving an interface method, search the + // interface's superinterfaces (A superinterface is not an + // interface's superclass - a superinterface is implemented by + // the interface). + if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) + { + _Jv_ifaces ifaces; + ifaces.count = 0; + ifaces.len = 4; + ifaces.list = (jclass *) _Jv_Malloc (ifaces.len + * sizeof (jclass *)); + + get_interfaces (owner, &ifaces); + + for (int i = 0; i < ifaces.count; i++) + { + jclass cls = ifaces.list[i]; + the_method = search_method_in_class (cls, klass, method_name, + method_signature); + if (the_method != 0) + { + found_class = cls; + break; + } + } + + _Jv_Free (ifaces.list); + + if (the_method != 0) + goto end_of_method_search; + } + + // Finally, search superclasses. + for (jclass cls = owner->getSuperclass (); cls != 0; + cls = cls->getSuperclass ()) + { + the_method = search_method_in_class (cls, klass, method_name, + method_signature); + if (the_method != 0) + { + found_class = cls; + break; + } + } + + end_of_method_search: + + // FIXME: if (cls->loader != klass->loader), then we + // must actually check that the types of arguments + // correspond. That is, for each argument type, and + // the return type, doing _Jv_FindClassFromSignature + // with either loader should produce the same result, + // i.e., exactly the same jclass object. JVMS 5.4.3.3 + + if (the_method == 0) + { + java::lang::StringBuffer *sb = new java::lang::StringBuffer(); + sb->append(JvNewStringLatin1("method ")); + sb->append(owner->getName()); + sb->append(JvNewStringLatin1(".")); + sb->append(_Jv_NewStringUTF(method_name->chars())); + sb->append(JvNewStringLatin1(" with signature ")); + sb->append(_Jv_NewStringUTF(method_signature->chars())); + sb->append(JvNewStringLatin1(" was not found.")); + throw new java::lang::NoSuchMethodError (sb->toString()); + } + + int vtable_index = -1; + if (pool->tags[index] != JV_CONSTANT_InterfaceMethodref) + vtable_index = (jshort)the_method->index; + + pool->data[index].rmethod + = klass->engine->resolve_method(the_method, + found_class, + ((the_method->accflags + & Modifier::STATIC) != 0), + vtable_index); + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + break; + } + return pool->data[index]; +} + +// This function is used to lazily locate superclasses and +// superinterfaces. This must be called with the class lock held. +void +_Jv_Linker::resolve_class_ref (jclass klass, jclass *classref) +{ + jclass ret = *classref; + + // If superclass looks like a constant pool entry, resolve it now. + if (ret && (uaddr) ret < (uaddr) klass->constants.size) + { + if (klass->state < JV_STATE_LINKED) + { + _Jv_Utf8Const *name = klass->constants.data[(uaddr) *classref].utf8; + ret = _Jv_FindClass (name, klass->loader); + if (! ret) + { + throw new java::lang::NoClassDefFoundError (name->toString()); + } + } + else + ret = klass->constants.data[(uaddr) classref].clazz; + *classref = ret; + } +} + +// Find a method declared in the cls that is referenced from klass and +// perform access checks. +_Jv_Method * +_Jv_Linker::search_method_in_class (jclass cls, jclass klass, + _Jv_Utf8Const *method_name, + _Jv_Utf8Const *method_signature) +{ + using namespace java::lang::reflect; + + for (int i = 0; i < cls->method_count; i++) + { + _Jv_Method *method = &cls->methods[i]; + if ( (!_Jv_equalUtf8Consts (method->name, + method_name)) + || (!_Jv_equalUtf8Consts (method->signature, + method_signature))) + continue; + + if (_Jv_CheckAccess (klass, cls, method->accflags)) + return method; + else + { + java::lang::StringBuffer *sb = new java::lang::StringBuffer(); + sb->append(klass->getName()); + sb->append(JvNewStringLatin1(": ")); + sb->append(cls->getName()); + sb->append(JvNewStringLatin1(".")); + sb->append(_Jv_NewStringUTF(method_name->chars())); + sb->append(_Jv_NewStringUTF(method_signature->chars())); + throw new java::lang::IllegalAccessError (sb->toString()); + } + } + return 0; +} + + +#define INITIAL_IOFFSETS_LEN 4 +#define INITIAL_IFACES_LEN 4 + +static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} }; + +// Generate tables for constant-time assignment testing and interface +// method lookup. This implements the technique described by Per Bothner +// <per@bothner.com> on the java-discuss mailing list on 1999-09-02: +// http://gcc.gnu.org/ml/java/1999-q3/msg00377.html +void +_Jv_Linker::prepare_constant_time_tables (jclass klass) +{ + if (klass->isPrimitive () || klass->isInterface ()) + return; + + // Short-circuit in case we've been called already. + if ((klass->idt != NULL) || klass->depth != 0) + return; + + // Calculate the class depth and ancestor table. The depth of a class + // is how many "extends" it is removed from Object. Thus the depth of + // java.lang.Object is 0, but the depth of java.io.FilterOutputStream + // is 2. Depth is defined for all regular and array classes, but not + // interfaces or primitive types. + + jclass klass0 = klass; + jboolean has_interfaces = 0; + while (klass0 != &java::lang::Object::class$) + { + has_interfaces += klass0->interface_count; + klass0 = klass0->superclass; + klass->depth++; + } + + // We do class member testing in constant time by using a small table + // of all the ancestor classes within each class. The first element is + // a pointer to the current class, and the rest are pointers to the + // classes ancestors, ordered from the current class down by decreasing + // depth. We do not include java.lang.Object in the table of ancestors, + // since it is redundant. + + // FIXME: _Jv_AllocBytes + klass->ancestors = (jclass *) _Jv_Malloc (klass->depth + * sizeof (jclass)); + klass0 = klass; + for (int index = 0; index < klass->depth; index++) + { + klass->ancestors[index] = klass0; + klass0 = klass0->superclass; + } + + if ((klass->accflags & java::lang::reflect::Modifier::ABSTRACT) != 0) + return; + + // Optimization: If class implements no interfaces, use a common + // predefined interface table. + if (!has_interfaces) + { + klass->idt = &null_idt; + return; + } + + // FIXME: _Jv_AllocBytes + klass->idt = + (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); + + _Jv_ifaces ifaces; + ifaces.count = 0; + ifaces.len = INITIAL_IFACES_LEN; + ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *)); + + int itable_size = get_interfaces (klass, &ifaces); + + if (ifaces.count > 0) + { + klass->idt->cls.itable = + // FIXME: _Jv_AllocBytes + (void **) _Jv_Malloc (itable_size * sizeof (void *)); + klass->idt->cls.itable_length = itable_size; + + jshort *itable_offsets = + (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort)); + + generate_itable (klass, &ifaces, itable_offsets); + + jshort cls_iindex = find_iindex (ifaces.list, itable_offsets, + ifaces.count); + + for (int i = 0; i < ifaces.count; i++) + { + ifaces.list[i]->idt->iface.ioffsets[cls_iindex] = + itable_offsets[i]; + } + + klass->idt->cls.iindex = cls_iindex; + + _Jv_Free (ifaces.list); + _Jv_Free (itable_offsets); + } + else + { + klass->idt->cls.iindex = SHRT_MAX; + } +} + +// Return index of item in list, or -1 if item is not present. +inline jshort +_Jv_Linker::indexof (void *item, void **list, jshort list_len) +{ + for (int i=0; i < list_len; i++) + { + if (list[i] == item) + return i; + } + return -1; +} + +// Find all unique interfaces directly or indirectly implemented by klass. +// Returns the size of the interface dispatch table (itable) for klass, which +// is the number of unique interfaces plus the total number of methods that +// those interfaces declare. May extend ifaces if required. +jshort +_Jv_Linker::get_interfaces (jclass klass, _Jv_ifaces *ifaces) +{ + jshort result = 0; + + for (int i = 0; i < klass->interface_count; i++) + { + jclass iface = klass->interfaces[i]; + + /* Make sure interface is linked. */ + wait_for_state(iface, JV_STATE_LINKED); + + if (indexof (iface, (void **) ifaces->list, ifaces->count) == -1) + { + if (ifaces->count + 1 >= ifaces->len) + { + /* Resize ifaces list */ + ifaces->len = ifaces->len * 2; + ifaces->list + = (jclass *) _Jv_Realloc (ifaces->list, + ifaces->len * sizeof(jclass)); + } + ifaces->list[ifaces->count] = iface; + ifaces->count++; + + result += get_interfaces (klass->interfaces[i], ifaces); + } + } + + if (klass->isInterface()) + result += klass->method_count + 1; + else if (klass->superclass) + result += get_interfaces (klass->superclass, ifaces); + return result; +} + +// Fill out itable in klass, resolving method declarations in each ifaces. +// itable_offsets is filled out with the position of each iface in itable, +// such that itable[itable_offsets[n]] == ifaces.list[n]. +void +_Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces, + jshort *itable_offsets) +{ + void **itable = klass->idt->cls.itable; + jshort itable_pos = 0; + + for (int i = 0; i < ifaces->count; i++) + { + jclass iface = ifaces->list[i]; + itable_offsets[i] = itable_pos; + itable_pos = append_partial_itable (klass, iface, itable, itable_pos); + + /* Create interface dispatch table for iface */ + if (iface->idt == NULL) + { + // FIXME: _Jv_AllocBytes + iface->idt + = (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); + + // The first element of ioffsets is its length (itself included). + // FIXME: _Jv_AllocBytes + jshort *ioffsets = (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN + * sizeof (jshort)); + ioffsets[0] = INITIAL_IOFFSETS_LEN; + for (int i = 1; i < INITIAL_IOFFSETS_LEN; i++) + ioffsets[i] = -1; + + iface->idt->iface.ioffsets = ioffsets; + } + } +} + +// Format method name for use in error messages. +jstring +_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name) +{ + jstring r = klass->name->toString(); + r = r->concat (JvNewStringUTF (".")); + r = r->concat (name->toString()); + return r; +} + +void +_Jv_ThrowNoSuchMethodError () +{ + throw new java::lang::NoSuchMethodError; +} + +// Each superinterface of a class (i.e. each interface that the class +// directly or indirectly implements) has a corresponding "Partial +// Interface Dispatch Table" whose size is (number of methods + 1) words. +// The first word is a pointer to the interface (i.e. the java.lang.Class +// instance for that interface). The remaining words are pointers to the +// actual methods that implement the methods declared in the interface, +// in order of declaration. +// +// Append partial interface dispatch table for "iface" to "itable", at +// position itable_pos. +// Returns the offset at which the next partial ITable should be appended. +jshort +_Jv_Linker::append_partial_itable (jclass klass, jclass iface, + void **itable, jshort pos) +{ + using namespace java::lang::reflect; + + itable[pos++] = (void *) iface; + _Jv_Method *meth; + + for (int j=0; j < iface->method_count; j++) + { + meth = NULL; + for (jclass cl = klass; cl; cl = cl->getSuperclass()) + { + meth = _Jv_GetMethodLocal (cl, iface->methods[j].name, + iface->methods[j].signature); + + if (meth) + break; + } + + if (meth && (meth->name->first() == '<')) + { + // leave a placeholder in the itable for hidden init methods. + itable[pos] = NULL; + } + else if (meth) + { + if ((meth->accflags & Modifier::STATIC) != 0) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (klass, meth->name)); + if ((meth->accflags & Modifier::ABSTRACT) != 0) + throw new java::lang::AbstractMethodError + (_Jv_GetMethodString (klass, meth->name)); + if ((meth->accflags & Modifier::PUBLIC) == 0) + throw new java::lang::IllegalAccessError + (_Jv_GetMethodString (klass, meth->name)); + + itable[pos] = meth->ncode; + } + else + { + // The method doesn't exist in klass. Binary compatibility rules + // permit this, so we delay the error until runtime using a pointer + // to a method which throws an exception. + itable[pos] = (void *) _Jv_ThrowNoSuchMethodError; + } + pos++; + } + + return pos; +} + +static _Jv_Mutex_t iindex_mutex; +static bool iindex_mutex_initialized = false; + +// We need to find the correct offset in the Class Interface Dispatch +// Table for a given interface. Once we have that, invoking an interface +// method just requires combining the Method's index in the interface +// (known at compile time) to get the correct method. Doing a type test +// (cast or instanceof) is the same problem: Once we have a possible Partial +// Interface Dispatch Table, we just compare the first element to see if it +// matches the desired interface. So how can we find the correct offset? +// Our solution is to keep a vector of candiate offsets in each interface +// (idt->iface.ioffsets), and in each class we have an index +// (idt->cls.iindex) used to select the correct offset from ioffsets. +// +// Calculate and return iindex for a new class. +// ifaces is a vector of num interfaces that the class implements. +// offsets[j] is the offset in the interface dispatch table for the +// interface corresponding to ifaces[j]. +// May extend the interface ioffsets if required. +jshort +_Jv_Linker::find_iindex (jclass *ifaces, jshort *offsets, jshort num) +{ + int i; + int j; + + // Acquire a global lock to prevent itable corruption in case of multiple + // classes that implement an intersecting set of interfaces being linked + // simultaneously. We can assume that the mutex will be initialized + // single-threaded. + if (! iindex_mutex_initialized) + { + _Jv_MutexInit (&iindex_mutex); + iindex_mutex_initialized = true; + } + + _Jv_MutexLock (&iindex_mutex); + + for (i=1;; i++) /* each potential position in ioffsets */ + { + for (j=0;; j++) /* each iface */ + { + if (j >= num) + goto found; + if (i >= ifaces[j]->idt->iface.ioffsets[0]) + continue; + int ioffset = ifaces[j]->idt->iface.ioffsets[i]; + /* We can potentially share this position with another class. */ + if (ioffset >= 0 && ioffset != offsets[j]) + break; /* Nope. Try next i. */ + } + } + found: + for (j = 0; j < num; j++) + { + int len = ifaces[j]->idt->iface.ioffsets[0]; + if (i >= len) + { + // Resize ioffsets. + int newlen = 2 * len; + if (i >= newlen) + newlen = i + 3; + jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets; + // FIXME: _Jv_AllocBytes + jshort *new_ioffsets = (jshort *) _Jv_Malloc (newlen + * sizeof(jshort)); + memcpy (&new_ioffsets[1], &old_ioffsets[1], + (len - 1) * sizeof (jshort)); + new_ioffsets[0] = newlen; + + while (len < newlen) + new_ioffsets[len++] = -1; + + ifaces[j]->idt->iface.ioffsets = new_ioffsets; + } + ifaces[j]->idt->iface.ioffsets[i] = offsets[j]; + } + + _Jv_MutexUnlock (&iindex_mutex); + + return i; +} + + +// Functions for indirect dispatch (symbolic virtual binding) support. + +// There are three tables, atable otable and itable. atable is an +// array of addresses, and otable is an array of offsets, and these +// are used for static and virtual members respectively. itable is an +// array of pairs {address, index} where each address is a pointer to +// an interface. + +// {a,o,i}table_syms is an array of _Jv_MethodSymbols. Each such +// symbol is a tuple of {classname, member name, signature}. + +// Set this to true to enable debugging of indirect dispatch tables/linking. +static bool debug_link = false; + +// link_symbol_table() scans these two arrays and fills in the +// corresponding atable and otable with the addresses of static +// members and the offsets of virtual members. + +// The offset (in bytes) for each resolved method or field is placed +// at the corresponding position in the virtual method offset table +// (klass->otable). + +// The same otable and atable may be shared by many classes. + +// This must be called while holding the class lock. + +void +_Jv_Linker::link_symbol_table (jclass klass) +{ + int index = 0; + _Jv_MethodSymbol sym; + if (klass->otable == NULL + || klass->otable->state != 0) + goto atable; + + klass->otable->state = 1; + + if (debug_link) + fprintf (stderr, "Fixing up otable in %s:\n", klass->name->chars()); + for (index = 0; + (sym = klass->otable_syms[index]).class_name != NULL; + ++index) + { + jclass target_class = _Jv_FindClass (sym.class_name, klass->loader); + _Jv_Method *meth = NULL; + + _Jv_Utf8Const *signature = sym.signature; + + { + static char *bounce = (char *)_Jv_ThrowNoSuchMethodError; + ptrdiff_t offset = (char *)(klass->vtable) - bounce; + klass->otable->offsets[index] = offset; + } + + if (target_class == NULL) + throw new java::lang::NoClassDefFoundError + (_Jv_NewStringUTF (sym.class_name->chars())); + + // We're looking for a field or a method, and we can tell + // which is needed by looking at the signature. + if (signature->first() == '(' && signature->len() >= 2) + { + // Looks like someone is trying to invoke an interface method + if (target_class->isInterface()) + { + using namespace java::lang; + StringBuffer *sb = new StringBuffer(); + sb->append(JvNewStringLatin1("found interface ")); + sb->append(target_class->getName()); + sb->append(JvNewStringLatin1(" when searching for a class")); + throw new VerifyError(sb->toString()); + } + + // If the target class does not have a vtable_method_count yet, + // then we can't tell the offsets for its methods, so we must lay + // it out now. + wait_for_state(target_class, JV_STATE_PREPARED); + + meth = _Jv_LookupDeclaredMethod(target_class, sym.name, + sym.signature); + + if (meth != NULL) + { + int offset = _Jv_VTable::idx_to_offset (meth->index); + if (offset == -1) + JvFail ("Bad method index"); + JvAssert (meth->index < target_class->vtable_method_count); + klass->otable->offsets[index] = offset; + } + if (debug_link) + fprintf (stderr, " offsets[%d] = %d (class %s@%p : %s(%s))\n", + (int)index, + (int)klass->otable->offsets[index], + (const char*)target_class->name->chars(), + target_class, + (const char*)sym.name->chars(), + (const char*)signature->chars()); + continue; + } + + // try fields + { + _Jv_Field *the_field = NULL; + + wait_for_state(target_class, JV_STATE_PREPARED); + for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->field_count; i++) + { + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, sym.name)) + continue; + + // FIXME: What access checks should we perform here? +// if (_Jv_CheckAccess (klass, cls, field->flags)) +// { + + if (!field->isResolved ()) + resolve_field (field, cls->loader); + +// if (field_type != 0 && field->type != field_type) +// throw new java::lang::LinkageError +// (JvNewStringLatin1 +// ("field type mismatch with different loaders")); + + the_field = field; + if (debug_link) + fprintf (stderr, " offsets[%d] = %d (class %s@%p : %s)\n", + (int)index, + (int)field->u.boffset, + (const char*)cls->name->chars(), + cls, + (const char*)field->name->chars()); + goto end_of_field_search; + } + } + end_of_field_search: + if (the_field != NULL) + { + if ((the_field->flags & java::lang::reflect::Modifier::STATIC)) + throw new java::lang::IncompatibleClassChangeError; + else + klass->otable->offsets[index] = the_field->u.boffset; + } + else + { + throw new java::lang::NoSuchFieldError + (_Jv_NewStringUtf8Const (sym.name)); + } + } + } + + atable: + if (klass->atable == NULL || klass->atable->state != 0) + goto itable; + + klass->atable->state = 1; + + for (index = 0; + (sym = klass->atable_syms[index]).class_name != NULL; + ++index) + { + jclass target_class = _Jv_FindClass (sym.class_name, klass->loader); + _Jv_Method *meth = NULL; + _Jv_Utf8Const *signature = sym.signature; + + // ??? Setting this pointer to null will at least get us a + // NullPointerException + klass->atable->addresses[index] = NULL; + + if (target_class == NULL) + throw new java::lang::NoClassDefFoundError + (_Jv_NewStringUTF (sym.class_name->chars())); + + // We're looking for a static field or a static method, and we + // can tell which is needed by looking at the signature. + if (signature->first() == '(' && signature->len() >= 2) + { + // If the target class does not have a vtable_method_count yet, + // then we can't tell the offsets for its methods, so we must lay + // it out now. + wait_for_state (target_class, JV_STATE_PREPARED); + + // Interface methods cannot have bodies. + if (target_class->isInterface()) + { + using namespace java::lang; + StringBuffer *sb = new StringBuffer(); + sb->append(JvNewStringLatin1("class ")); + sb->append(target_class->getName()); + sb->append(JvNewStringLatin1(" is an interface: " + "class expected")); + throw new VerifyError(sb->toString()); + } + + meth = _Jv_LookupDeclaredMethod(target_class, sym.name, + sym.signature); + + if (meth != NULL) + { + if (meth->ncode) // Maybe abstract? + { + klass->atable->addresses[index] = meth->ncode; + if (debug_link) + fprintf (stderr, " addresses[%d] = %p (class %s@%p : %s(%s))\n", + index, + &klass->atable->addresses[index], + (const char*)target_class->name->chars(), + klass, + (const char*)sym.name->chars(), + (const char*)signature->chars()); + } + } + else + klass->atable->addresses[index] + = (void *)_Jv_ThrowNoSuchMethodError; + + continue; + } + + // try fields + { + _Jv_Field *the_field = NULL; + + wait_for_state(target_class, JV_STATE_PREPARED); + for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) + { + for (int i = 0; i < cls->field_count; i++) + { + _Jv_Field *field = &cls->fields[i]; + if (! _Jv_equalUtf8Consts (field->name, sym.name)) + continue; + + // FIXME: What access checks should we perform here? +// if (_Jv_CheckAccess (klass, cls, field->flags)) +// { + + if (!field->isResolved ()) + resolve_field (field, cls->loader); + +// if (field_type != 0 && field->type != field_type) +// throw new java::lang::LinkageError +// (JvNewStringLatin1 +// ("field type mismatch with different loaders")); + + the_field = field; + goto end_of_static_field_search; + } + } + end_of_static_field_search: + if (the_field != NULL) + { + if ((the_field->flags & java::lang::reflect::Modifier::STATIC)) + klass->atable->addresses[index] = the_field->u.addr; + else + throw new java::lang::IncompatibleClassChangeError; + } + else + { + throw new java::lang::NoSuchFieldError + (_Jv_NewStringUtf8Const (sym.name)); + } + } + } + + itable: + if (klass->itable == NULL + || klass->itable->state != 0) + return; + + klass->itable->state = 1; + + for (index = 0; + (sym = klass->itable_syms[index]).class_name != NULL; + ++index) + { + jclass target_class = _Jv_FindClass (sym.class_name, klass->loader); + _Jv_Utf8Const *signature = sym.signature; + + jclass cls; + int i; + + wait_for_state(target_class, JV_STATE_LOADED); + bool found = _Jv_getInterfaceMethod (target_class, cls, i, + sym.name, sym.signature); + + if (found) + { + klass->itable->addresses[index * 2] = cls; + klass->itable->addresses[index * 2 + 1] = (void *)(intptr_t) i; + if (debug_link) + { + fprintf (stderr, " interfaces[%d] = %p (interface %s@%p : %s(%s))\n", + index, + klass->itable->addresses[index * 2], + (const char*)cls->name->chars(), + cls, + (const char*)sym.name->chars(), + (const char*)signature->chars()); + fprintf (stderr, " [%d] = offset %d\n", + index + 1, + (int)(intptr_t)klass->itable->addresses[index * 2 + 1]); + } + + } + else + throw new java::lang::IncompatibleClassChangeError; + } + +} + +// For each catch_record in the list of caught classes, fill in the +// address field. +void +_Jv_Linker::link_exception_table (jclass self) +{ + struct _Jv_CatchClass *catch_record = self->catch_classes; + if (!catch_record || catch_record->classname) + return; + catch_record++; + while (catch_record->classname) + { + try + { + jclass target_class + = _Jv_FindClass (catch_record->classname, + self->getClassLoaderInternal ()); + *catch_record->address = target_class; + } + catch (::java::lang::Throwable *t) + { + // FIXME: We need to do something better here. + *catch_record->address = 0; + } + catch_record++; + } + self->catch_classes->classname = (_Jv_Utf8Const *)-1; +} + +// This is put in empty vtable slots. +static void +_Jv_abstractMethodError (void) +{ + throw new java::lang::AbstractMethodError(); +} + +// Set itable method indexes for members of interface IFACE. +void +_Jv_Linker::layout_interface_methods (jclass iface) +{ + if (! iface->isInterface()) + return; + + // itable indexes start at 1. + // FIXME: Static initalizers currently get a NULL placeholder entry in the + // itable so they are also assigned an index here. + for (int i = 0; i < iface->method_count; i++) + iface->methods[i].index = i + 1; +} + +// Prepare virtual method declarations in KLASS, and any superclasses +// as required, by determining their vtable index, setting +// method->index, and finally setting the class's vtable_method_count. +// Must be called with the lock for KLASS held. +void +_Jv_Linker::layout_vtable_methods (jclass klass) +{ + if (klass->vtable != NULL || klass->isInterface() + || klass->vtable_method_count != -1) + return; + + jclass superclass = klass->getSuperclass(); + + if (superclass != NULL && superclass->vtable_method_count == -1) + { + JvSynchronize sync (superclass); + layout_vtable_methods (superclass); + } + + int index = (superclass == NULL ? 0 : superclass->vtable_method_count); + + for (int i = 0; i < klass->method_count; ++i) + { + _Jv_Method *meth = &klass->methods[i]; + _Jv_Method *super_meth = NULL; + + if (! _Jv_isVirtualMethod (meth)) + continue; + + if (superclass != NULL) + { + jclass declarer; + super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, + meth->signature, &declarer); + // See if this method actually overrides the other method + // we've found. + if (super_meth) + { + if (! _Jv_isVirtualMethod (super_meth) + || ! _Jv_CheckAccess (klass, declarer, + super_meth->accflags)) + super_meth = NULL; + else if ((super_meth->accflags + & java::lang::reflect::Modifier::FINAL) != 0) + { + using namespace java::lang; + StringBuffer *sb = new StringBuffer(); + sb->append(JvNewStringLatin1("method ")); + sb->append(_Jv_GetMethodString(klass, meth->name)); + sb->append(JvNewStringLatin1(" overrides final method ")); + sb->append(_Jv_GetMethodString(declarer, super_meth->name)); + throw new VerifyError(sb->toString()); + } + } + } + + if (super_meth) + meth->index = super_meth->index; + else + meth->index = index++; + } + + klass->vtable_method_count = index; +} + +// Set entries in VTABLE for virtual methods declared in KLASS. +void +_Jv_Linker::set_vtable_entries (jclass klass, _Jv_VTable *vtable) +{ + for (int i = klass->method_count - 1; i >= 0; i--) + { + using namespace java::lang::reflect; + + _Jv_Method *meth = &klass->methods[i]; + if (meth->index == (_Jv_ushort) -1) + continue; + if ((meth->accflags & Modifier::ABSTRACT)) + vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError); + else + vtable->set_method(meth->index, meth->ncode); + } +} + +// Allocate and lay out the virtual method table for KLASS. This will +// also cause vtables to be generated for any non-abstract +// superclasses, and virtual method layout to occur for any abstract +// superclasses. Must be called with monitor lock for KLASS held. +void +_Jv_Linker::make_vtable (jclass klass) +{ + using namespace java::lang::reflect; + + // If the vtable exists, or for interface classes, do nothing. All + // other classes, including abstract classes, need a vtable. + if (klass->vtable != NULL || klass->isInterface()) + return; + + // Ensure all the `ncode' entries are set. + klass->engine->create_ncode(klass); + + // Class must be laid out before we can create a vtable. + if (klass->vtable_method_count == -1) + layout_vtable_methods (klass); + + // Allocate the new vtable. + _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count); + klass->vtable = vtable; + + // Copy the vtable of the closest superclass. + jclass superclass = klass->superclass; + { + JvSynchronize sync (superclass); + make_vtable (superclass); + } + for (int i = 0; i < superclass->vtable_method_count; ++i) + vtable->set_method (i, superclass->vtable->get_method (i)); + + // Set the class pointer and GC descriptor. + vtable->clas = klass; + vtable->gc_descr = _Jv_BuildGCDescr (klass); + + // For each virtual declared in klass, set new vtable entry or + // override an old one. + set_vtable_entries (klass, vtable); + + // It is an error to have an abstract method in a concrete class. + if (! (klass->accflags & Modifier::ABSTRACT)) + { + for (int i = 0; i < klass->vtable_method_count; ++i) + if (vtable->get_method(i) == (void *) &_Jv_abstractMethodError) + { + using namespace java::lang; + while (klass != NULL) + { + for (int j = 0; j < klass->method_count; ++j) + { + if (klass->methods[j].index == i) + { + StringBuffer *buf = new StringBuffer (); + buf->append (_Jv_NewStringUtf8Const (klass->methods[j].name)); + buf->append ((jchar) ' '); + buf->append (_Jv_NewStringUtf8Const (klass->methods[j].signature)); + throw new AbstractMethodError (buf->toString ()); + } + } + klass = klass->getSuperclass (); + } + // Couldn't find the name, which is weird. + // But we still must throw the error. + throw new AbstractMethodError (); + } + } +} + +// Lay out the class, allocating space for static fields and computing +// offsets of instance fields. The class lock must be held by the +// caller. +void +_Jv_Linker::ensure_fields_laid_out (jclass klass) +{ + if (klass->size_in_bytes != -1) + return; + + // Compute the alignment for this type by searching through the + // superclasses and finding the maximum required alignment. We + // could consider caching this in the Class. + int max_align = __alignof__ (java::lang::Object); + jclass super = klass->getSuperclass(); + while (super != NULL) + { + // Ensure that our super has its super installed before + // recursing. + wait_for_state(super, JV_STATE_LOADING); + ensure_fields_laid_out(super); + int num = JvNumInstanceFields (super); + _Jv_Field *field = JvGetFirstInstanceField (super); + while (num > 0) + { + int field_align = get_alignment_from_class (field->type); + if (field_align > max_align) + max_align = field_align; + ++field; + --num; + } + super = super->getSuperclass(); + } + + int instance_size; + int static_size = 0; + + // Although java.lang.Object is never interpreted, an interface can + // have a null superclass. Note that we have to lay out an + // interface because it might have static fields. + if (klass->superclass) + instance_size = klass->superclass->size(); + else + instance_size = java::lang::Object::class$.size(); + + for (int i = 0; i < klass->field_count; i++) + { + int field_size; + int field_align; + + _Jv_Field *field = &klass->fields[i]; + + if (! field->isRef ()) + { + // It is safe to resolve the field here, since it's a + // primitive class, which does not cause loading to happen. + resolve_field (field, klass->loader); + + field_size = field->type->size (); + field_align = get_alignment_from_class (field->type); + } + else + { + field_size = sizeof (jobject); + field_align = __alignof__ (jobject); + } + + field->bsize = field_size; + + if ((field->flags & java::lang::reflect::Modifier::STATIC)) + { + if (field->u.addr == NULL) + { + // This computes an offset into a region we'll allocate + // shortly, and then add this offset to the start + // address. + static_size = ROUND (static_size, field_align); + field->u.boffset = static_size; + static_size += field_size; + } + } + else + { + instance_size = ROUND (instance_size, field_align); + field->u.boffset = instance_size; + instance_size += field_size; + if (field_align > max_align) + max_align = field_align; + } + } + + if (static_size != 0) + klass->engine->allocate_static_fields (klass, static_size); + + // Set the instance size for the class. Note that first we round it + // to the alignment required for this object; this keeps us in sync + // with our current ABI. + instance_size = ROUND (instance_size, max_align); + klass->size_in_bytes = instance_size; +} + +// This takes the class to state JV_STATE_LINKED. The class lock must +// be held when calling this. +void +_Jv_Linker::ensure_class_linked (jclass klass) +{ + if (klass->state >= JV_STATE_LINKED) + return; + + int state = klass->state; + try + { + // Short-circuit, so that mutually dependent classes are ok. + klass->state = JV_STATE_LINKED; + + _Jv_Constants *pool = &klass->constants; + + // Compiled classes require that their class constants be + // resolved here. However, interpreted classes need their + // constants to be resolved lazily. If we resolve an + // interpreted class' constants eagerly, we can end up with + // spurious IllegalAccessErrors when the constant pool contains + // a reference to a class we can't access. This can validly + // occur in an obscure case involving the InnerClasses + // attribute. + if (! _Jv_IsInterpretedClass (klass)) + { + // Resolve class constants first, since other constant pool + // entries may rely on these. + for (int index = 1; index < pool->size; ++index) + { + if (pool->tags[index] == JV_CONSTANT_Class) + resolve_pool_entry (klass, index); + } + } + +#if 0 // Should be redundant now + // If superclass looks like a constant pool entry, + // resolve it now. + if ((uaddr) klass->superclass < (uaddr) pool->size) + klass->superclass = pool->data[(uaddr) klass->superclass].clazz; + + // Likewise for interfaces. + for (int i = 0; i < klass->interface_count; i++) + { + if ((uaddr) klass->interfaces[i] < (uaddr) pool->size) + klass->interfaces[i] + = pool->data[(uaddr) klass->interfaces[i]].clazz; + } +#endif + + // Resolve the remaining constant pool entries. + for (int index = 1; index < pool->size; ++index) + { + if (pool->tags[index] == JV_CONSTANT_String) + { + jstring str; + + str = _Jv_NewStringUtf8Const (pool->data[index].utf8); + pool->data[index].o = str; + pool->tags[index] |= JV_CONSTANT_ResolvedFlag; + } + } + + if (klass->engine->need_resolve_string_fields()) + { + jfieldID f = JvGetFirstStaticField (klass); + for (int n = JvNumStaticFields (klass); n > 0; --n) + { + int mod = f->getModifiers (); + // If we have a static String field with a non-null initial + // value, we know it points to a Utf8Const. + resolve_field(f, klass->loader); + if (f->getClass () == &java::lang::String::class$ + && (mod & java::lang::reflect::Modifier::STATIC) != 0) + { + jstring *strp = (jstring *) f->u.addr; + if (*strp) + *strp = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) *strp); + } + f = f->getNextField (); + } + } + + klass->notifyAll (); + + _Jv_PushClass (klass); + } + catch (java::lang::Throwable *t) + { + klass->state = state; + throw t; + } +} + +// This ensures that symbolic superclass and superinterface references +// are resolved for the indicated class. This must be called with the +// class lock held. +void +_Jv_Linker::ensure_supers_installed (jclass klass) +{ + resolve_class_ref (klass, &klass->superclass); + // An interface won't have a superclass. + if (klass->superclass) + wait_for_state (klass->superclass, JV_STATE_LOADING); + + for (int i = 0; i < klass->interface_count; ++i) + { + resolve_class_ref (klass, &klass->interfaces[i]); + wait_for_state (klass->interfaces[i], JV_STATE_LOADING); + } +} + +// This adds missing `Miranda methods' to a class. +void +_Jv_Linker::add_miranda_methods (jclass base, jclass iface_class) +{ + // Note that at this point, all our supers, and the supers of all + // our superclasses and superinterfaces, will have been installed. + + for (int i = 0; i < iface_class->interface_count; ++i) + { + jclass interface = iface_class->interfaces[i]; + + for (int j = 0; j < interface->method_count; ++j) + { + _Jv_Method *meth = &interface->methods[j]; + // Don't bother with <clinit>. + if (meth->name->first() == '<') + continue; + _Jv_Method *new_meth = _Jv_LookupDeclaredMethod (base, meth->name, + meth->signature); + if (! new_meth) + { + // We assume that such methods are very unlikely, so we + // just reallocate the method array each time one is + // found. This greatly simplifies the searching -- + // otherwise we have to make sure that each such method + // found is really unique among all superinterfaces. + int new_count = base->method_count + 1; + _Jv_Method *new_m + = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) + * new_count); + memcpy (new_m, base->methods, + sizeof (_Jv_Method) * base->method_count); + + // Add new method. + new_m[base->method_count] = *meth; + new_m[base->method_count].index = (_Jv_ushort) -1; + new_m[base->method_count].accflags + |= java::lang::reflect::Modifier::INVISIBLE; + + base->methods = new_m; + base->method_count = new_count; + } + } + + wait_for_state (interface, JV_STATE_LOADED); + add_miranda_methods (base, interface); + } +} + +// This ensures that the class' method table is "complete". This must +// be called with the class lock held. +void +_Jv_Linker::ensure_method_table_complete (jclass klass) +{ + if (klass->vtable != NULL || klass->isInterface()) + return; + + // We need our superclass to have its own Miranda methods installed. + wait_for_state (klass->getSuperclass (), JV_STATE_LOADED); + + // A class might have so-called "Miranda methods". This is a method + // that is declared in an interface and not re-declared in an + // abstract class. Some compilers don't emit declarations for such + // methods in the class; this will give us problems since we expect + // a declaration for any method requiring a vtable entry. We handle + // this here by searching for such methods and constructing new + // internal declarations for them. Note that we do this + // unconditionally, and not just for abstract classes, to correctly + // account for cases where a class is modified to be concrete and + // still incorrectly inherits an abstract method. + int pre_count = klass->method_count; + add_miranda_methods (klass, klass); + + // Let the execution engine know that we've added methods. + if (klass->method_count != pre_count) + klass->engine->post_miranda_hook(klass); +} + +// Verify a class. Must be called with class lock held. +void +_Jv_Linker::verify_class (jclass klass) +{ + klass->engine->verify(klass); +} + +// Check the assertions contained in the type assertion table for KLASS. +// This is the equivilent of bytecode verification for native, BC-ABI code. +void +_Jv_Linker::verify_type_assertions (jclass klass) +{ + if (debug_link) + fprintf (stderr, "Evaluating type assertions for %s:\n", + klass->name->chars()); + + if (klass->assertion_table == NULL) + return; + + for (int i = 0;; i++) + { + int assertion_code = klass->assertion_table[i].assertion_code; + _Jv_Utf8Const *op1 = klass->assertion_table[i].op1; + _Jv_Utf8Const *op2 = klass->assertion_table[i].op2; + + if (assertion_code == JV_ASSERT_END_OF_TABLE) + return; + else if (assertion_code == JV_ASSERT_TYPES_COMPATIBLE) + { + if (debug_link) + { + fprintf (stderr, " code=%i, operand A=%s B=%s\n", + assertion_code, op1->chars(), op2->chars()); + } + + // The operands are class signatures. op1 is the source, + // op2 is the target. + jclass cl1 = _Jv_FindClassFromSignature (op1->chars(), + klass->getClassLoaderInternal()); + jclass cl2 = _Jv_FindClassFromSignature (op2->chars(), + klass->getClassLoaderInternal()); + + // If the class doesn't exist, ignore the assertion. An exception + // will be thrown later if an attempt is made to actually + // instantiate the class. + if (cl1 == NULL || cl2 == NULL) + continue; + + if (! _Jv_IsAssignableFromSlow (cl2, cl1)) + { + jstring s = JvNewStringUTF ("Incompatible types: In class "); + s = s->concat (klass->getName()); + s = s->concat (JvNewStringUTF (": ")); + s = s->concat (cl1->getName()); + s = s->concat (JvNewStringUTF (" is not assignable to ")); + s = s->concat (cl2->getName()); + throw new java::lang::VerifyError (s); + } + } + else if (assertion_code == JV_ASSERT_IS_INSTANTIABLE) + { + // TODO: Implement this. + } + // Unknown assertion codes are ignored, for forwards-compatibility. + } +} + +void +_Jv_Linker::print_class_loaded (jclass klass) +{ + char *codesource = NULL; + if (klass->protectionDomain != NULL) + { + java::security::CodeSource *cs + = klass->protectionDomain->getCodeSource(); + if (cs != NULL) + { + jstring css = cs->toString(); + int len = JvGetStringUTFLength(css); + codesource = (char *) _Jv_AllocBytes(len + 1); + JvGetStringUTFRegion(css, 0, css->length(), codesource); + codesource[len] = '\0'; + } + } + if (codesource == NULL) + codesource = "<no code source>"; + + // We use a somewhat bogus test for the ABI here. + char *abi; + if (_Jv_IsInterpretedClass (klass)) + abi = "bytecode"; + else if (klass->state == JV_STATE_PRELOADING) + abi = "BC-compiled"; + else + abi = "pre-compiled"; + + fprintf (stderr, "[Loaded (%s) %s from %s]\n", abi, klass->name->chars(), + codesource); +} + +// FIXME: mention invariants and stuff. +void +_Jv_Linker::wait_for_state (jclass klass, int state) +{ + if (klass->state >= state) + return; + + JvSynchronize sync (klass); + + // This is similar to the strategy for class initialization. If we + // already hold the lock, just leave. + java::lang::Thread *self = java::lang::Thread::currentThread(); + while (klass->state <= state + && klass->thread + && klass->thread != self) + klass->wait (); + + java::lang::Thread *save = klass->thread; + klass->thread = self; + + // Print some debugging info if requested. Interpreted classes are + // handled in defineclass, so we only need to handle the two + // pre-compiled cases here. + if (gcj::verbose_class_flag + && (klass->state == JV_STATE_COMPILED + || klass->state == JV_STATE_PRELOADING) + && ! _Jv_IsInterpretedClass (klass)) + print_class_loaded (klass); + + try + { + if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING) + { + ensure_supers_installed (klass); + klass->set_state(JV_STATE_LOADING); + } + + if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED) + { + ensure_method_table_complete (klass); + klass->set_state(JV_STATE_LOADED); + } + + if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED) + { + ensure_fields_laid_out (klass); + make_vtable (klass); + layout_interface_methods (klass); + prepare_constant_time_tables (klass); + klass->set_state(JV_STATE_PREPARED); + } + + if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED) + { + verify_class (klass); + + ensure_class_linked (klass); + link_exception_table (klass); + link_symbol_table (klass); + klass->set_state(JV_STATE_LINKED); + } + } + catch (java::lang::Throwable *exc) + { + klass->thread = save; + klass->set_state(JV_STATE_ERROR); + throw exc; + } + + klass->thread = save; + + if (klass->state == JV_STATE_ERROR) + throw new java::lang::LinkageError; +} diff --git a/libjava/prims.cc b/libjava/prims.cc index 70ede2765cb..e3d5750cd1c 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -61,12 +61,16 @@ details. */ #include <java/lang/VirtualMachineError.h> #include <gnu/gcj/runtime/VMClassLoader.h> #include <gnu/gcj/runtime/FinalizerThread.h> +#include <execution.h> #include <gnu/java/lang/MainThread.h> #ifdef USE_LTDL #include <ltdl.h> #endif +// Execution engine for compiled code. +_Jv_CompiledEngine _Jv_soleCompiledEngine; + // We allocate a single OutOfMemoryError exception which we keep // around for use if we run out of memory. static java::lang::OutOfMemoryError *no_memory; @@ -723,7 +727,7 @@ JvConvertArgv (int argc, const char **argv) { if (argc < 0) argc = 0; - jobjectArray ar = JvNewObjectArray(argc, &StringClass, NULL); + jobjectArray ar = JvNewObjectArray(argc, &java::lang::String::class$, NULL); jobject *ptr = elements(ar); jbyteArray bytes = NULL; for (int i = 0; i < argc; i++) @@ -1204,7 +1208,7 @@ _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags) return ((self_klass == other_klass) || ((flags & Modifier::PUBLIC) != 0) || (((flags & Modifier::PROTECTED) != 0) - && other_klass->isAssignableFrom (self_klass)) + && _Jv_IsAssignableFromSlow (other_klass, self_klass)) || (((flags & Modifier::PRIVATE) == 0) && _Jv_ClassNameSamePackage (self_klass->name, other_klass->name))); diff --git a/libjava/resolve.cc b/libjava/resolve.cc deleted file mode 100644 index 5ebefebecef..00000000000 --- a/libjava/resolve.cc +++ /dev/null @@ -1,1125 +0,0 @@ -// resolve.cc - Code for linking and resolving classes and pool entries. - -/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation - - This file is part of libgcj. - -This software is copyrighted work licensed under the terms of the -Libgcj License. Please consult the file "LIBGCJ_LICENSE" for -details. */ - -/* Author: Kresten Krab Thorup <krab@gnu.org> */ - -#include <config.h> -#include <platform.h> - -#include <java-interp.h> - -#include <jvm.h> -#include <gcj/cni.h> -#include <string.h> -#include <java-cpool.h> -#include <java/lang/Class.h> -#include <java/lang/String.h> -#include <java/lang/StringBuffer.h> -#include <java/lang/Thread.h> -#include <java/lang/InternalError.h> -#include <java/lang/VirtualMachineError.h> -#include <java/lang/NoSuchFieldError.h> -#include <java/lang/NoSuchMethodError.h> -#include <java/lang/ClassFormatError.h> -#include <java/lang/IllegalAccessError.h> -#include <java/lang/AbstractMethodError.h> -#include <java/lang/NoClassDefFoundError.h> -#include <java/lang/IncompatibleClassChangeError.h> -#include <java/lang/VMClassLoader.h> -#include <java/lang/reflect/Modifier.h> - -using namespace gcj; - -void -_Jv_ResolveField (_Jv_Field *field, java::lang::ClassLoader *loader) -{ - if (! field->isResolved ()) - { - _Jv_Utf8Const *sig = (_Jv_Utf8Const*)field->type; - field->type = _Jv_FindClassFromSignature (sig->chars(), loader); - field->flags &= ~_Jv_FIELD_UNRESOLVED_FLAG; - } -} - -#ifdef INTERPRETER - -static void throw_internal_error (char *msg) - __attribute__ ((__noreturn__)); -static void throw_class_format_error (jstring msg) - __attribute__ ((__noreturn__)); -static void throw_class_format_error (char *msg) - __attribute__ ((__noreturn__)); - -static int get_alignment_from_class (jclass); - -static _Jv_ResolvedMethod* -_Jv_BuildResolvedMethod (_Jv_Method*, - jclass, - jboolean, - jint); - - -static void throw_incompatible_class_change_error (jstring msg) -{ - throw new java::lang::IncompatibleClassChangeError (msg); -} - -_Jv_word -_Jv_ResolvePoolEntry (jclass klass, int index) -{ - using namespace java::lang::reflect; - - _Jv_Constants *pool = &klass->constants; - - if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0) - return pool->data[index]; - - switch (pool->tags[index]) { - case JV_CONSTANT_Class: - { - _Jv_Utf8Const *name = pool->data[index].utf8; - - jclass found; - if (name->first() == '[') - found = _Jv_FindClassFromSignature (name->chars(), - klass->loader); - else - found = _Jv_FindClass (name, klass->loader); - - if (! found) - { - jstring str = name->toString(); - // This exception is specified in JLS 2nd Ed, section 5.1. - throw new java::lang::NoClassDefFoundError (str); - } - - if ((found->accflags & Modifier::PUBLIC) == Modifier::PUBLIC - || (_Jv_ClassNameSamePackage (found->name, - klass->name))) - { - pool->data[index].clazz = found; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - else - { - throw new java::lang::IllegalAccessError (found->getName()); - } - } - break; - - case JV_CONSTANT_String: - { - jstring str; - str = _Jv_NewStringUtf8Const (pool->data[index].utf8); - pool->data[index].o = str; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - break; - - - case JV_CONSTANT_Fieldref: - { - _Jv_ushort class_index, name_and_type_index; - _Jv_loadIndexes (&pool->data[index], - class_index, - name_and_type_index); - jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz; - - if (owner != klass) - _Jv_InitClass (owner); - - _Jv_ushort name_index, type_index; - _Jv_loadIndexes (&pool->data[name_and_type_index], - name_index, - type_index); - - _Jv_Utf8Const *field_name = pool->data[name_index].utf8; - _Jv_Utf8Const *field_type_name = pool->data[type_index].utf8; - - // FIXME: The implementation of this function - // (_Jv_FindClassFromSignature) will generate an instance of - // _Jv_Utf8Const for each call if the field type is a class name - // (Lxx.yy.Z;). This may be too expensive to do for each and - // every fieldref being resolved. For now, we fix the problem by - // only doing it when we have a loader different from the class - // declaring the field. - - jclass field_type = 0; - - if (owner->loader != klass->loader) - field_type = _Jv_FindClassFromSignature (field_type_name->chars(), - klass->loader); - - _Jv_Field* the_field = 0; - - for (jclass cls = owner; cls != 0; cls = cls->getSuperclass ()) - { - for (int i = 0; i < cls->field_count; i++) - { - _Jv_Field *field = &cls->fields[i]; - if (! _Jv_equalUtf8Consts (field->name, field_name)) - continue; - - if (_Jv_CheckAccess (klass, cls, field->flags)) - { - /* resove the field using the class' own loader - if necessary */ - - if (!field->isResolved ()) - _Jv_ResolveField (field, cls->loader); - - if (field_type != 0 && field->type != field_type) - throw new java::lang::LinkageError - (JvNewStringLatin1 - ("field type mismatch with different loaders")); - - the_field = field; - goto end_of_field_search; - } - else - { - java::lang::StringBuffer *sb - = new java::lang::StringBuffer (); - sb->append(klass->getName()); - sb->append(JvNewStringLatin1(": ")); - sb->append(cls->getName()); - sb->append(JvNewStringLatin1(".")); - sb->append(_Jv_NewStringUtf8Const (field_name)); - throw new java::lang::IllegalAccessError(sb->toString()); - } - } - } - - end_of_field_search: - if (the_field == 0) - { - java::lang::StringBuffer *sb = new java::lang::StringBuffer(); - sb->append(JvNewStringLatin1("field ")); - sb->append(owner->getName()); - sb->append(JvNewStringLatin1(".")); - sb->append(field_name->toString()); - sb->append(JvNewStringLatin1(" was not found.")); - throw_incompatible_class_change_error(sb->toString()); - } - - pool->data[index].field = the_field; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - break; - - case JV_CONSTANT_Methodref: - case JV_CONSTANT_InterfaceMethodref: - { - _Jv_ushort class_index, name_and_type_index; - _Jv_loadIndexes (&pool->data[index], - class_index, - name_and_type_index); - jclass owner = (_Jv_ResolvePoolEntry (klass, class_index)).clazz; - - if (owner != klass) - _Jv_InitClass (owner); - - _Jv_ushort name_index, type_index; - _Jv_loadIndexes (&pool->data[name_and_type_index], - name_index, - type_index); - - _Jv_Utf8Const *method_name = pool->data[name_index].utf8; - _Jv_Utf8Const *method_signature = pool->data[type_index].utf8; - - _Jv_Method *the_method = 0; - jclass found_class = 0; - - // First search the class itself. - the_method = _Jv_SearchMethodInClass (owner, klass, - method_name, method_signature); - - if (the_method != 0) - { - found_class = owner; - goto end_of_method_search; - } - - // If we are resolving an interface method, search the - // interface's superinterfaces (A superinterface is not an - // interface's superclass - a superinterface is implemented by - // the interface). - if (pool->tags[index] == JV_CONSTANT_InterfaceMethodref) - { - _Jv_ifaces ifaces; - ifaces.count = 0; - ifaces.len = 4; - ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *)); - - _Jv_GetInterfaces (owner, &ifaces); - - for (int i = 0; i < ifaces.count; i++) - { - jclass cls = ifaces.list[i]; - the_method = _Jv_SearchMethodInClass (cls, klass, method_name, - method_signature); - if (the_method != 0) - { - found_class = cls; - break; - } - } - - _Jv_Free (ifaces.list); - - if (the_method != 0) - goto end_of_method_search; - } - - // Finally, search superclasses. - for (jclass cls = owner->getSuperclass (); cls != 0; - cls = cls->getSuperclass ()) - { - the_method = _Jv_SearchMethodInClass (cls, klass, - method_name, method_signature); - if (the_method != 0) - { - found_class = cls; - break; - } - } - - end_of_method_search: - - // FIXME: if (cls->loader != klass->loader), then we - // must actually check that the types of arguments - // correspond. That is, for each argument type, and - // the return type, doing _Jv_FindClassFromSignature - // with either loader should produce the same result, - // i.e., exactly the same jclass object. JVMS 5.4.3.3 - - if (the_method == 0) - { - java::lang::StringBuffer *sb = new java::lang::StringBuffer(); - sb->append(JvNewStringLatin1("method ")); - sb->append(owner->getName()); - sb->append(JvNewStringLatin1(".")); - sb->append(method_name->toString()); - sb->append(JvNewStringLatin1(" was not found.")); - throw new java::lang::NoSuchMethodError (sb->toString()); - } - - int vtable_index = -1; - if (pool->tags[index] != JV_CONSTANT_InterfaceMethodref) - vtable_index = (jshort)the_method->index; - - pool->data[index].rmethod = - _Jv_BuildResolvedMethod(the_method, - found_class, - (the_method->accflags & Modifier::STATIC) != 0, - vtable_index); - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - break; - - } - - return pool->data[index]; -} - -// Find a method declared in the cls that is referenced from klass and -// perform access checks. -_Jv_Method * -_Jv_SearchMethodInClass (jclass cls, jclass klass, - _Jv_Utf8Const *method_name, - _Jv_Utf8Const *method_signature) -{ - using namespace java::lang::reflect; - - for (int i = 0; i < cls->method_count; i++) - { - _Jv_Method *method = &cls->methods[i]; - if ( (!_Jv_equalUtf8Consts (method->name, - method_name)) - || (!_Jv_equalUtf8Consts (method->signature, - method_signature))) - continue; - - if (_Jv_CheckAccess (klass, cls, method->accflags)) - return method; - else - { - java::lang::StringBuffer *sb = new java::lang::StringBuffer(); - sb->append(klass->getName()); - sb->append(JvNewStringLatin1(": ")); - sb->append(cls->getName()); - sb->append(JvNewStringLatin1(".")); - sb->append(method_name->toString()); - sb->append(method_signature->toString()); - throw new java::lang::IllegalAccessError (sb->toString()); - } - } - return 0; -} - -// A helper for _Jv_PrepareClass. This adds missing `Miranda methods' -// to a class. -void -_Jv_PrepareMissingMethods (jclass base, jclass iface_class) -{ - _Jv_InterpClass *interp_base = (_Jv_InterpClass *) base->aux_info; - for (int i = 0; i < iface_class->interface_count; ++i) - { - for (int j = 0; j < iface_class->interfaces[i]->method_count; ++j) - { - _Jv_Method *meth = &iface_class->interfaces[i]->methods[j]; - // Don't bother with <clinit>. - if (meth->name->first() == '<') - continue; - _Jv_Method *new_meth = _Jv_LookupDeclaredMethod (base, meth->name, - meth->signature); - if (! new_meth) - { - // We assume that such methods are very unlikely, so we - // just reallocate the method array each time one is - // found. This greatly simplifies the searching -- - // otherwise we have to make sure that each such method - // found is really unique among all superinterfaces. - int new_count = base->method_count + 1; - _Jv_Method *new_m - = (_Jv_Method *) _Jv_AllocBytes (sizeof (_Jv_Method) - * new_count); - memcpy (new_m, base->methods, - sizeof (_Jv_Method) * base->method_count); - - // Add new method. - new_m[base->method_count] = *meth; - new_m[base->method_count].index = (_Jv_ushort) -1; - new_m[base->method_count].accflags - |= java::lang::reflect::Modifier::INVISIBLE; - - _Jv_MethodBase **new_im - = (_Jv_MethodBase **) _Jv_AllocBytes (sizeof (_Jv_MethodBase *) - * new_count); - memcpy (new_im, interp_base->interpreted_methods, - sizeof (_Jv_MethodBase *) * base->method_count); - - base->methods = new_m; - interp_base->interpreted_methods = new_im; - base->method_count = new_count; - } - } - - _Jv_PrepareMissingMethods (base, iface_class->interfaces[i]); - } -} - -void -_Jv_PrepareClass(jclass klass) -{ - using namespace java::lang::reflect; - - /* - * The job of this function is to: 1) assign storage to fields, and 2) - * build the vtable. static fields are assigned real memory, instance - * fields are assigned offsets. - * - * NOTE: we have a contract with the garbage collector here. Static - * reference fields must not be resolved, until after they have storage - * assigned which is the check used by the collector to see if it - * should indirect the static field reference and mark the object - * pointed to. - * - * Most fields are resolved lazily (i.e. have their class-type - * assigned) when they are accessed the first time by calling as part - * of _Jv_ResolveField, which is allways called after _Jv_PrepareClass. - * Static fields with initializers are resolved as part of this - * function, as are fields with primitive types. - */ - - if (! _Jv_IsInterpretedClass (klass)) - return; - - if (klass->state >= JV_STATE_PREPARED) - return; - - // Make sure super-class is linked. This involves taking a lock on - // the super class, so we use the Java method resolveClass, which - // will unlock it properly, should an exception happen. If there's - // no superclass, do nothing -- Object will already have been - // resolved. - - if (klass->superclass) - java::lang::VMClassLoader::resolveClass (klass->superclass); - - _Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info; - - /************ PART ONE: OBJECT LAYOUT ***************/ - - // Compute the alignment for this type by searching through the - // superclasses and finding the maximum required alignment. We - // could consider caching this in the Class. - int max_align = __alignof__ (java::lang::Object); - jclass super = klass->superclass; - while (super != NULL) - { - int num = JvNumInstanceFields (super); - _Jv_Field *field = JvGetFirstInstanceField (super); - while (num > 0) - { - int field_align = get_alignment_from_class (field->type); - if (field_align > max_align) - max_align = field_align; - ++field; - --num; - } - super = super->superclass; - } - - int instance_size; - int static_size = 0; - - // Although java.lang.Object is never interpreted, an interface can - // have a null superclass. Note that we have to lay out an - // interface because it might have static fields. - if (klass->superclass) - instance_size = klass->superclass->size(); - else - instance_size = java::lang::Object::class$.size(); - - for (int i = 0; i < klass->field_count; i++) - { - int field_size; - int field_align; - - _Jv_Field *field = &klass->fields[i]; - - if (! field->isRef ()) - { - // it's safe to resolve the field here, since it's - // a primitive class, which does not cause loading to happen. - _Jv_ResolveField (field, klass->loader); - - field_size = field->type->size (); - field_align = get_alignment_from_class (field->type); - } - else - { - field_size = sizeof (jobject); - field_align = __alignof__ (jobject); - } - -#ifndef COMPACT_FIELDS - field->bsize = field_size; -#endif - - if (field->flags & Modifier::STATIC) - { - /* this computes an offset into a region we'll allocate - shortly, and then add this offset to the start address */ - - static_size = ROUND (static_size, field_align); - field->u.boffset = static_size; - static_size += field_size; - } - else - { - instance_size = ROUND (instance_size, field_align); - field->u.boffset = instance_size; - instance_size += field_size; - if (field_align > max_align) - max_align = field_align; - } - } - - // Set the instance size for the class. Note that first we round it - // to the alignment required for this object; this keeps us in sync - // with our current ABI. - instance_size = ROUND (instance_size, max_align); - klass->size_in_bytes = instance_size; - - // allocate static memory - if (static_size != 0) - { - char *static_data = (char*)_Jv_AllocBytes (static_size); - - memset (static_data, 0, static_size); - - for (int i = 0; i < klass->field_count; i++) - { - _Jv_Field *field = &klass->fields[i]; - - if ((field->flags & Modifier::STATIC) != 0) - { - field->u.addr = static_data + field->u.boffset; - - if (iclass->field_initializers[i] != 0) - { - _Jv_ResolveField (field, klass->loader); - _Jv_InitField (0, klass, i); - } - } - } - - // now we don't need the field_initializers anymore, so let the - // collector get rid of it! - - iclass->field_initializers = 0; - } - - /************ PART TWO: VTABLE LAYOUT ***************/ - - /* preparation: build the vtable stubs (even interfaces can) - have code -- for static constructors. */ - for (int i = 0; i < klass->method_count; i++) - { - _Jv_MethodBase *imeth = iclass->interpreted_methods[i]; - - if ((klass->methods[i].accflags & Modifier::NATIVE) != 0) - { - // You might think we could use a virtual `ncode' method in - // the _Jv_MethodBase and unify the native and non-native - // cases. Well, we can't, because we don't allocate these - // objects using `new', and thus they don't get a vtable. - _Jv_JNIMethod *jnim = reinterpret_cast<_Jv_JNIMethod *> (imeth); - klass->methods[i].ncode = jnim->ncode (); - } - else if (imeth != 0) // it could be abstract - { - _Jv_InterpMethod *im = reinterpret_cast<_Jv_InterpMethod *> (imeth); - _Jv_VerifyMethod (im); - klass->methods[i].ncode = im->ncode (); - - // Resolve ctable entries pointing to this method. See - // _Jv_Defer_Resolution. - void **code = (void **)imeth->deferred; - while (code) - { - void **target = (void **)*code; - *code = klass->methods[i].ncode; - code = target; - } - } - } - - if ((klass->accflags & Modifier::INTERFACE)) - { - klass->state = JV_STATE_PREPARED; - klass->notifyAll (); - return; - } - - // A class might have so-called "Miranda methods". This is a method - // that is declared in an interface and not re-declared in an - // abstract class. Some compilers don't emit declarations for such - // methods in the class; this will give us problems since we expect - // a declaration for any method requiring a vtable entry. We handle - // this here by searching for such methods and constructing new - // internal declarations for them. We only need to do this for - // abstract classes. - if ((klass->accflags & Modifier::ABSTRACT)) - _Jv_PrepareMissingMethods (klass, klass); - - klass->vtable_method_count = -1; - _Jv_MakeVTable (klass); - - /* wooha! we're done. */ - klass->state = JV_STATE_PREPARED; - klass->notifyAll (); -} - -/** Do static initialization for fields with a constant initializer */ -void -_Jv_InitField (jobject obj, jclass klass, int index) -{ - using namespace java::lang::reflect; - - if (obj != 0 && klass == 0) - klass = obj->getClass (); - - if (!_Jv_IsInterpretedClass (klass)) - return; - - _Jv_InterpClass *iclass = (_Jv_InterpClass*)klass->aux_info; - - _Jv_Field * field = (&klass->fields[0]) + index; - - if (index > klass->field_count) - throw_internal_error ("field out of range"); - - int init = iclass->field_initializers[index]; - if (init == 0) - return; - - _Jv_Constants *pool = &klass->constants; - int tag = pool->tags[init]; - - if (! field->isResolved ()) - throw_internal_error ("initializing unresolved field"); - - if (obj==0 && ((field->flags & Modifier::STATIC) == 0)) - throw_internal_error ("initializing non-static field with no object"); - - void *addr = 0; - - if ((field->flags & Modifier::STATIC) != 0) - addr = (void*) field->u.addr; - else - addr = (void*) (((char*)obj) + field->u.boffset); - - switch (tag) - { - case JV_CONSTANT_String: - { - _Jv_MonitorEnter (klass); - jstring str; - str = _Jv_NewStringUtf8Const (pool->data[init].utf8); - pool->data[init].string = str; - pool->tags[init] = JV_CONSTANT_ResolvedString; - _Jv_MonitorExit (klass); - } - /* fall through */ - - case JV_CONSTANT_ResolvedString: - if (! (field->type == &StringClass - || field->type == &java::lang::Class::class$)) - throw_class_format_error ("string initialiser to non-string field"); - - *(jstring*)addr = pool->data[init].string; - break; - - case JV_CONSTANT_Integer: - { - int value = pool->data[init].i; - - if (field->type == JvPrimClass (boolean)) - *(jboolean*)addr = (jboolean)value; - - else if (field->type == JvPrimClass (byte)) - *(jbyte*)addr = (jbyte)value; - - else if (field->type == JvPrimClass (char)) - *(jchar*)addr = (jchar)value; - - else if (field->type == JvPrimClass (short)) - *(jshort*)addr = (jshort)value; - - else if (field->type == JvPrimClass (int)) - *(jint*)addr = (jint)value; - - else - throw_class_format_error ("erroneous field initializer"); - } - break; - - case JV_CONSTANT_Long: - if (field->type != JvPrimClass (long)) - throw_class_format_error ("erroneous field initializer"); - - *(jlong*)addr = _Jv_loadLong (&pool->data[init]); - break; - - case JV_CONSTANT_Float: - if (field->type != JvPrimClass (float)) - throw_class_format_error ("erroneous field initializer"); - - *(jfloat*)addr = pool->data[init].f; - break; - - case JV_CONSTANT_Double: - if (field->type != JvPrimClass (double)) - throw_class_format_error ("erroneous field initializer"); - - *(jdouble*)addr = _Jv_loadDouble (&pool->data[init]); - break; - - default: - throw_class_format_error ("erroneous field initializer"); - } -} - -template<typename T> -struct aligner -{ - T field; -}; - -#define ALIGNOF(TYPE) (__alignof__ (((aligner<TYPE> *) 0)->field)) - -// This returns the alignment of a type as it would appear in a -// structure. This can be different from the alignment of the type -// itself. For instance on x86 double is 8-aligned but struct{double} -// is 4-aligned. -static int -get_alignment_from_class (jclass klass) -{ - if (klass == JvPrimClass (byte)) - return ALIGNOF (jbyte); - else if (klass == JvPrimClass (short)) - return ALIGNOF (jshort); - else if (klass == JvPrimClass (int)) - return ALIGNOF (jint); - else if (klass == JvPrimClass (long)) - return ALIGNOF (jlong); - else if (klass == JvPrimClass (boolean)) - return ALIGNOF (jboolean); - else if (klass == JvPrimClass (char)) - return ALIGNOF (jchar); - else if (klass == JvPrimClass (float)) - return ALIGNOF (jfloat); - else if (klass == JvPrimClass (double)) - return ALIGNOF (jdouble); - else - return ALIGNOF (jobject); -} - - -inline static unsigned char* -skip_one_type (unsigned char* ptr) -{ - int ch = *ptr++; - - while (ch == '[') - { - ch = *ptr++; - } - - if (ch == 'L') - { - do { ch = *ptr++; } while (ch != ';'); - } - - return ptr; -} - -static ffi_type* -get_ffi_type_from_signature (unsigned char* ptr) -{ - switch (*ptr) - { - case 'L': - case '[': - return &ffi_type_pointer; - break; - - case 'Z': - // On some platforms a bool is a byte, on others an int. - if (sizeof (jboolean) == sizeof (jbyte)) - return &ffi_type_sint8; - else - { - JvAssert (sizeof (jbyte) == sizeof (jint)); - return &ffi_type_sint32; - } - break; - - case 'B': - return &ffi_type_sint8; - break; - - case 'C': - return &ffi_type_uint16; - break; - - case 'S': - return &ffi_type_sint16; - break; - - case 'I': - return &ffi_type_sint32; - break; - - case 'J': - return &ffi_type_sint64; - break; - - case 'F': - return &ffi_type_float; - break; - - case 'D': - return &ffi_type_double; - break; - - case 'V': - return &ffi_type_void; - break; - } - - throw_internal_error ("unknown type in signature"); -} - -/* this function yields the number of actual arguments, that is, if the - * function is non-static, then one is added to the number of elements - * found in the signature */ - -int -_Jv_count_arguments (_Jv_Utf8Const *signature, - jboolean staticp) -{ - unsigned char *ptr = (unsigned char*) signature->chars(); - int arg_count = staticp ? 0 : 1; - - /* first, count number of arguments */ - - // skip '(' - ptr++; - - // count args - while (*ptr != ')') - { - ptr = skip_one_type (ptr); - arg_count += 1; - } - - return arg_count; -} - -/* This beast will build a cif, given the signature. Memory for - * the cif itself and for the argument types must be allocated by the - * caller. - */ - -static int -init_cif (_Jv_Utf8Const* signature, - int arg_count, - jboolean staticp, - ffi_cif *cif, - ffi_type **arg_types, - ffi_type **rtype_p) -{ - unsigned char *ptr = (unsigned char*) signature->chars(); - - int arg_index = 0; // arg number - int item_count = 0; // stack-item count - - // setup receiver - if (!staticp) - { - arg_types[arg_index++] = &ffi_type_pointer; - item_count += 1; - } - - // skip '(' - ptr++; - - // assign arg types - while (*ptr != ')') - { - arg_types[arg_index++] = get_ffi_type_from_signature (ptr); - - if (*ptr == 'J' || *ptr == 'D') - item_count += 2; - else - item_count += 1; - - ptr = skip_one_type (ptr); - } - - // skip ')' - ptr++; - ffi_type *rtype = get_ffi_type_from_signature (ptr); - - ptr = skip_one_type (ptr); - if (ptr != (unsigned char*)signature->chars() + signature->len()) - throw_internal_error ("did not find end of signature"); - - if (ffi_prep_cif (cif, FFI_DEFAULT_ABI, - arg_count, rtype, arg_types) != FFI_OK) - throw_internal_error ("ffi_prep_cif failed"); - - if (rtype_p != NULL) - *rtype_p = rtype; - - return item_count; -} - -#if FFI_NATIVE_RAW_API -# define FFI_PREP_RAW_CLOSURE ffi_prep_raw_closure -# define FFI_RAW_SIZE ffi_raw_size -#else -# define FFI_PREP_RAW_CLOSURE ffi_prep_java_raw_closure -# define FFI_RAW_SIZE ffi_java_raw_size -#endif - -/* we put this one here, and not in interpret.cc because it - * calls the utility routines _Jv_count_arguments - * which are static to this module. The following struct defines the - * layout we use for the stubs, it's only used in the ncode method. */ - -typedef struct { - ffi_raw_closure closure; - ffi_cif cif; - ffi_type *arg_types[0]; -} ncode_closure; - -typedef void (*ffi_closure_fun) (ffi_cif*,void*,ffi_raw*,void*); - -void * -_Jv_InterpMethod::ncode () -{ - using namespace java::lang::reflect; - - if (self->ncode != 0) - return self->ncode; - - jboolean staticp = (self->accflags & Modifier::STATIC) != 0; - int arg_count = _Jv_count_arguments (self->signature, staticp); - - ncode_closure *closure = - (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) - + arg_count * sizeof (ffi_type*)); - - init_cif (self->signature, - arg_count, - staticp, - &closure->cif, - &closure->arg_types[0], - NULL); - - ffi_closure_fun fun; - - args_raw_size = FFI_RAW_SIZE (&closure->cif); - - JvAssert ((self->accflags & Modifier::NATIVE) == 0); - - if ((self->accflags & Modifier::SYNCHRONIZED) != 0) - { - if (staticp) - fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class; - else - fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; - } - else - { - if (staticp) - fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class; - else - fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal; - } - - FFI_PREP_RAW_CLOSURE (&closure->closure, - &closure->cif, - fun, - (void*)this); - - self->ncode = (void*)closure; - return self->ncode; -} - -void * -_Jv_JNIMethod::ncode () -{ - using namespace java::lang::reflect; - - if (self->ncode != 0) - return self->ncode; - - jboolean staticp = (self->accflags & Modifier::STATIC) != 0; - int arg_count = _Jv_count_arguments (self->signature, staticp); - - ncode_closure *closure = - (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure) - + arg_count * sizeof (ffi_type*)); - - ffi_type *rtype; - init_cif (self->signature, - arg_count, - staticp, - &closure->cif, - &closure->arg_types[0], - &rtype); - - ffi_closure_fun fun; - - args_raw_size = FFI_RAW_SIZE (&closure->cif); - - // Initialize the argument types and CIF that represent the actual - // underlying JNI function. - int extra_args = 1; - if ((self->accflags & Modifier::STATIC)) - ++extra_args; - jni_arg_types = (ffi_type **) _Jv_Malloc ((extra_args + arg_count) - * sizeof (ffi_type *)); - int offset = 0; - jni_arg_types[offset++] = &ffi_type_pointer; - if ((self->accflags & Modifier::STATIC)) - jni_arg_types[offset++] = &ffi_type_pointer; - memcpy (&jni_arg_types[offset], &closure->arg_types[0], - arg_count * sizeof (ffi_type *)); - - if (ffi_prep_cif (&jni_cif, _Jv_platform_ffi_abi, - extra_args + arg_count, rtype, - jni_arg_types) != FFI_OK) - throw_internal_error ("ffi_prep_cif failed for JNI function"); - - JvAssert ((self->accflags & Modifier::NATIVE) != 0); - - // FIXME: for now we assume that all native methods for - // interpreted code use JNI. - fun = (ffi_closure_fun) &_Jv_JNIMethod::call; - - FFI_PREP_RAW_CLOSURE (&closure->closure, - &closure->cif, - fun, - (void*) this); - - self->ncode = (void *) closure; - return self->ncode; -} - - -/* A _Jv_ResolvedMethod is what is put in the constant pool for a - * MethodRef or InterfacemethodRef. */ -static _Jv_ResolvedMethod* -_Jv_BuildResolvedMethod (_Jv_Method* method, - jclass klass, - jboolean staticp, - jint vtable_index) -{ - int arg_count = _Jv_count_arguments (method->signature, staticp); - - _Jv_ResolvedMethod* result = (_Jv_ResolvedMethod*) - _Jv_AllocBytes (sizeof (_Jv_ResolvedMethod) - + arg_count*sizeof (ffi_type*)); - - result->stack_item_count - = init_cif (method->signature, - arg_count, - staticp, - &result->cif, - &result->arg_types[0], - NULL); - - result->vtable_index = vtable_index; - result->method = method; - result->klass = klass; - - return result; -} - - -static void -throw_class_format_error (jstring msg) -{ - throw (msg - ? new java::lang::ClassFormatError (msg) - : new java::lang::ClassFormatError); -} - -static void -throw_class_format_error (char *msg) -{ - throw_class_format_error (JvNewStringLatin1 (msg)); -} - -static void -throw_internal_error (char *msg) -{ - throw new java::lang::InternalError (JvNewStringLatin1 (msg)); -} - - -#endif /* INTERPRETER */ diff --git a/libjava/testsuite/Makefile.in b/libjava/testsuite/Makefile.in index 2e51cd9e63a..2fe07c88e31 100644 --- a/libjava/testsuite/Makefile.in +++ b/libjava/testsuite/Makefile.in @@ -134,6 +134,7 @@ LIBGCJTESTSPEC = @LIBGCJTESTSPEC@ LIBGCJ_CFLAGS = @LIBGCJ_CFLAGS@ LIBGCJ_CXXFLAGS = @LIBGCJ_CXXFLAGS@ LIBGCJ_JAVAFLAGS = @LIBGCJ_JAVAFLAGS@ +LIBGCJ_LD_SYMBOLIC = @LIBGCJ_LD_SYMBOLIC@ LIBICONV = @LIBICONV@ LIBLTDL = @LIBLTDL@ LIBOBJS = @LIBOBJS@ diff --git a/libjava/testsuite/libjava.lang/assign2.java b/libjava/testsuite/libjava.lang/assign2.java new file mode 100644 index 00000000000..41fdcb594d9 --- /dev/null +++ b/libjava/testsuite/libjava.lang/assign2.java @@ -0,0 +1,21 @@ +// Test for an array assignment bug we've had. + +public class assign2 +{ + public static Object[][] c () { return new Long[5][5]; } + + public static Object[] d () { return new Integer[3]; } + + public static void main(String[] args) + { + try + { + Object[][] x = c(); + x[0] = d(); + } + catch (ArrayStoreException _) + { + System.out.println("good"); + } + } +} diff --git a/libjava/testsuite/libjava.lang/assign2.out b/libjava/testsuite/libjava.lang/assign2.out new file mode 100644 index 00000000000..12799ccbe7c --- /dev/null +++ b/libjava/testsuite/libjava.lang/assign2.out @@ -0,0 +1 @@ +good diff --git a/libjava/testsuite/libjava.loader/loader.exp b/libjava/testsuite/libjava.loader/loader.exp index e306a312c83..86e518170c4 100644 --- a/libjava/testsuite/libjava.loader/loader.exp +++ b/libjava/testsuite/libjava.loader/loader.exp @@ -1,5 +1,15 @@ # Tests for ClassLoader and native library loader code. +# Compute the correct name for an object file. +# This is an awful hack. +proc gcj_object_file_name {compiler base} { + verbose "OBJECT: compiler = $compiler" + if {[string match *libtool* $compiler]} { + return $base.lo + } + return $base.o +} + # Do all the work for a single JNI test. Return 0 on failure. proc gcj_loader_test_one {srcfile} { global objdir srcdir subdir @@ -9,9 +19,9 @@ proc gcj_loader_test_one {srcfile} { regsub "^.*/(\[^/.\]+)\[.\]\[^/]*$" "$srcfile" "\\1" out set executable "${objdir}/$out.exe" - set errname [file rootname [file tail $srcfile]] - set args [libjava_arguments link] - lappend args "additional_flags=--main=[file rootname [file tail $srcfile]] $srcdir/$subdir/MyLoader.java $objdir/dummy.o" + set errname [file rootname [file tail $srcfile]] + set args [libjava_arguments link] + lappend args "additional_flags=--main=[file rootname [file tail $srcfile]] $srcdir/$subdir/MyLoader.java $objdir/[gcj_object_file_name $args dummy]" set x [libjava_prune_warnings \ [libjava_tcompile $srcfile "$executable" executable $args]] @@ -47,7 +57,7 @@ proc gcj_loader_run {} { set args [libjava_arguments compile] lappend args "additional_flags=--resource $objdir/dummy.class" set x [libjava_prune_warnings \ - [libjava_tcompile "$objdir/dummy.class" "$objdir/dummy.o" object $args]] + [libjava_tcompile "$objdir/dummy.class" "$objdir/[gcj_object_file_name $args dummy]" object $args]] if { $x != "" } { verbose "resource compilation failed: $x" 2 diff --git a/libjava/verify.cc b/libjava/verify.cc index 63857d0341e..988b5aab67e 100644 --- a/libjava/verify.cc +++ b/libjava/verify.cc @@ -553,7 +553,7 @@ private: { // We use a recursive call because we also need to // check superinterfaces. - if (is_assignable_from_slow (target, source->interfaces[i])) + if (is_assignable_from_slow (target, source->getInterface (i))) return true; } } |