# HG changeset patch # User jrose # Date 1299911627 28800 # Node ID e9fef2a9bef717904fe2c8a3c0d0cdc935773a49 # Parent 303a2149d371ab74c145997803b02217d2ac379a 6839872: remove implementation inheritance from JSR 292 APIs Summary: consolidate runtime support in java.dyn.MethodHandleNatives; include transitional compatibility logic Reviewed-by: twisti diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,12 +146,14 @@ break; case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType : - if (!EnableMethodHandles || - _major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { + if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { classfile_parse_error( - (!EnableMethodHandles ? - "This JVM does not support constant tag %u in class file %s" : - "Class file version does not support constant tag %u in class file %s"), + "Class file version does not support constant tag %u in class file %s", + tag, CHECK); + } + if (!EnableMethodHandles) { + classfile_parse_error( + "This JVM does not support constant tag %u in class file %s", tag, CHECK); } if (tag == JVM_CONSTANT_MethodHandle) { @@ -170,12 +172,14 @@ case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles case JVM_CONSTANT_InvokeDynamic : { - if (!EnableInvokeDynamic || - _major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { + if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { classfile_parse_error( - (!EnableInvokeDynamic ? - "This JVM does not support constant tag %u in class file %s" : - "Class file version does not support constant tag %u in class file %s"), + "Class file version does not support constant tag %u in class file %s", + tag, CHECK); + } + if (!EnableInvokeDynamic) { + classfile_parse_error( + "This JVM does not support constant tag %u in class file %s", tag, CHECK); } cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags @@ -2823,6 +2827,7 @@ } } + if (AllowTransitionalJSR292 && word_sig_index == 0) return; if (word_sig_index == 0) THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing I or J signature (for vmentry) in java.dyn.MethodHandle"); @@ -2862,6 +2867,7 @@ } } + if (AllowTransitionalJSR292 && !found_vmentry) return; if (!found_vmentry) THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing vmentry byte field in java.dyn.MethodHandle"); @@ -3230,7 +3236,12 @@ } // adjust the vmentry field declaration in java.dyn.MethodHandle - if (EnableMethodHandles && class_name == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { + if (EnableMethodHandles && class_name == vmSymbols::java_dyn_MethodHandle() && class_loader.is_null()) { + java_dyn_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); + } + if (AllowTransitionalJSR292 && + EnableMethodHandles && class_name == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { + // allow vmentry field in MethodHandleImpl also java_dyn_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); } diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,6 +66,28 @@ return ik->find_local_field(name_symbol, signature_symbol, fd); } +static bool find_hacked_field(instanceKlass* ik, + Symbol* name_symbol, Symbol* signature_symbol, + fieldDescriptor* fd, + bool allow_super = false) { + bool found = find_field(ik, name_symbol, signature_symbol, fd, allow_super); + if (!found && AllowTransitionalJSR292) { + Symbol* backup_sig = SystemDictionary::find_backup_signature(signature_symbol); + if (backup_sig != NULL) { + found = find_field(ik, name_symbol, backup_sig, fd, allow_super); + if (TraceMethodHandles) { + ResourceMark rm; + tty->print_cr("MethodHandles: %s.%s: backup for %s => %s%s", + ik->name()->as_C_string(), name_symbol->as_C_string(), + signature_symbol->as_C_string(), backup_sig->as_C_string(), + (found ? "" : " (NOT FOUND)")); + } + } + } + return found; +} +#define find_field find_hacked_field /* remove after AllowTransitionalJSR292 */ + // Helpful routine for computing field offsets at run time rather than hardcoding them static void compute_offset(int &dest_offset, @@ -2200,13 +2222,15 @@ void java_dyn_MethodHandle::compute_offsets() { klassOop k = SystemDictionary::MethodHandle_klass(); if (k != NULL && EnableMethodHandles) { - compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true); - compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), true); - compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), true); + bool allow_super = false; + if (AllowTransitionalJSR292) allow_super = true; // temporary, to access sun.dyn.MethodHandleImpl + compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), allow_super); + compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), allow_super); + compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), allow_super); // Note: MH.vmslots (if it is present) is a hoisted copy of MH.type.form.vmslots. // It is optional pending experiments to keep or toss. - compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true); + compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), allow_super); } } @@ -2504,16 +2528,12 @@ // Support for java_dyn_CallSite int java_dyn_CallSite::_target_offset; -int java_dyn_CallSite::_caller_method_offset; -int java_dyn_CallSite::_caller_bci_offset; void java_dyn_CallSite::compute_offsets() { if (!EnableInvokeDynamic) return; klassOop k = SystemDictionary::CallSite_klass(); if (k != NULL) { compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature()); - compute_offset(_caller_method_offset, k, vmSymbols::vmmethod_name(), vmSymbols::sun_dyn_MemberName_signature()); - compute_offset(_caller_bci_offset, k, vmSymbols::vmindex_name(), vmSymbols::int_signature()); } } @@ -2525,22 +2545,6 @@ site->obj_field_put(_target_offset, target); } -oop java_dyn_CallSite::caller_method(oop site) { - return site->obj_field(_caller_method_offset); -} - -void java_dyn_CallSite::set_caller_method(oop site, oop ref) { - site->obj_field_put(_caller_method_offset, ref); -} - -jint java_dyn_CallSite::caller_bci(oop site) { - return site->int_field(_caller_bci_offset); -} - -void java_dyn_CallSite::set_caller_bci(oop site, jint bci) { - site->int_field_put(_caller_bci_offset, bci); -} - // Support for java_security_AccessControlContext diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1887,27 +1887,99 @@ 0 }; +Symbol* SystemDictionary::find_backup_symbol(Symbol* symbol, + const char* from_prefix, + const char* to_prefix) { + assert(AllowTransitionalJSR292, ""); // delete this subroutine + Symbol* backup_symbol = NULL; + size_t from_len = strlen(from_prefix); + if (strncmp((const char*) symbol->base(), from_prefix, from_len) != 0) + return NULL; + char buf[100]; + size_t to_len = strlen(to_prefix); + size_t tail_len = symbol->utf8_length() - from_len; + size_t new_len = to_len + tail_len; + guarantee(new_len < sizeof(buf), "buf too small"); + memcpy(buf, to_prefix, to_len); + memcpy(buf + to_len, symbol->base() + from_len, tail_len); + buf[new_len] = '\0'; + vmSymbols::SID backup_sid = vmSymbols::find_sid(buf); + if (backup_sid != vmSymbols::NO_SID) { + backup_symbol = vmSymbols::symbol_at(backup_sid); + } + return backup_symbol; +} + +Symbol* SystemDictionary::find_backup_class_name(Symbol* symbol) { + assert(AllowTransitionalJSR292, ""); // delete this subroutine + if (symbol == NULL) return NULL; + Symbol* backup_symbol = find_backup_symbol(symbol, "java/lang/invoke/", "java/dyn/"); // AllowTransitionalJSR292 ONLY + if (backup_symbol == NULL) + backup_symbol = find_backup_symbol(symbol, "java/dyn/", "sun/dyn/"); // AllowTransitionalJSR292 ONLY + return backup_symbol; +} + +Symbol* SystemDictionary::find_backup_signature(Symbol* symbol) { + assert(AllowTransitionalJSR292, ""); // delete this subroutine + if (symbol == NULL) return NULL; + return find_backup_symbol(symbol, "Ljava/lang/invoke/", "Ljava/dyn/"); +} + bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) { assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob"); int info = wk_init_info[id - FIRST_WKID]; int sid = (info >> CEIL_LG_OPTION_LIMIT); Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); klassOop* klassp = &_well_known_klasses[id]; - bool must_load = (init_opt < SystemDictionary::Opt); - bool try_load = true; + bool pre_load = (init_opt < SystemDictionary::Opt); + bool try_load = true; if (init_opt == SystemDictionary::Opt_Kernel) { #ifndef KERNEL try_load = false; #endif //KERNEL } - if ((*klassp) == NULL && try_load) { + Symbol* backup_symbol = NULL; // symbol to try if the current symbol fails + if (init_opt == SystemDictionary::Pre_JSR292) { + if (!EnableMethodHandles) try_load = false; // do not bother to load such classes + if (AllowTransitionalJSR292) { + backup_symbol = find_backup_class_name(symbol); + if (try_load && PreferTransitionalJSR292) { + while (backup_symbol != NULL) { + (*klassp) = resolve_or_null(backup_symbol, CHECK_0); // try backup early + if (TraceMethodHandles) { + ResourceMark rm; + tty->print_cr("MethodHandles: try backup first for %s => %s (%s)", + symbol->as_C_string(), backup_symbol->as_C_string(), + ((*klassp) == NULL) ? "no such class" : "backup load succeeded"); + } + if ((*klassp) != NULL) return true; + backup_symbol = find_backup_class_name(backup_symbol); // find next backup + } + } + } + } + if ((*klassp) != NULL) return true; + if (!try_load) return false; + while (symbol != NULL) { + bool must_load = (pre_load && (backup_symbol == NULL)); if (must_load) { (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class } else { (*klassp) = resolve_or_null(symbol, CHECK_0); // load optional klass } + if ((*klassp) != NULL) return true; + // Go around again. Example of long backup sequence: + // java.lang.invoke.MemberName, java.dyn.MemberName, sun.dyn.MemberName, ONLY if AllowTransitionalJSR292 + if (TraceMethodHandles && (backup_symbol != NULL)) { + ResourceMark rm; + tty->print_cr("MethodHandles: backup for %s => %s", + symbol->as_C_string(), backup_symbol->as_C_string()); + } + symbol = backup_symbol; + if (AllowTransitionalJSR292) + backup_symbol = find_backup_class_name(symbol); } - return ((*klassp) != NULL); + return false; } void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) { @@ -2348,6 +2420,8 @@ if (THREAD->is_Compiler_thread()) return NULL; // do not attempt from within compiler bool for_invokeGeneric = (name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name)); + if (AllowInvokeForInvokeGeneric && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name)) + for_invokeGeneric = true; bool found_on_bcp = false; Handle mt = find_method_handle_type(signature, accessing_klass, for_invokeGeneric, @@ -2531,10 +2605,14 @@ args.push_oop(caller_mname()); args.push_int(caller_bci); JavaValue result(T_OBJECT); + Symbol* makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_signature(); + if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandleNatives_klass()->name() == vmSymbols::sun_dyn_MethodHandleNatives()) { + makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_TRANS_signature(); + } JavaCalls::call_static(&result, SystemDictionary::MethodHandleNatives_klass(), vmSymbols::makeDynamicCallSite_name(), - vmSymbols::makeDynamicCallSite_signature(), + makeDynamicCallSite_signature, &args, CHECK_(empty)); oop call_site_oop = (oop) result.get_jobject(); assert(call_site_oop->is_oop() diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Mar 11 22:33:47 2011 -0800 @@ -144,18 +144,18 @@ template(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \ \ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ - template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \ - template(MemberName_klass, sun_dyn_MemberName, Opt) \ - template(MethodHandleImpl_klass, sun_dyn_MethodHandleImpl, Opt) \ - template(MethodHandleNatives_klass, sun_dyn_MethodHandleNatives, Opt) \ - template(AdapterMethodHandle_klass, sun_dyn_AdapterMethodHandle, Opt) \ - template(BoundMethodHandle_klass, sun_dyn_BoundMethodHandle, Opt) \ - template(DirectMethodHandle_klass, sun_dyn_DirectMethodHandle, Opt) \ - template(MethodType_klass, java_dyn_MethodType, Opt) \ - template(MethodTypeForm_klass, java_dyn_MethodTypeForm, Opt) \ - template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \ - template(Linkage_klass, java_dyn_Linkage, Opt) \ - template(CallSite_klass, java_dyn_CallSite, Opt) \ + template(MethodHandle_klass, java_dyn_MethodHandle, Pre_JSR292) \ + template(MemberName_klass, java_dyn_MemberName, Pre_JSR292) \ + template(MethodHandleImpl_klass, java_dyn_MethodHandleImpl, Pre_JSR292) /* AllowTransitionalJSR292 ONLY */ \ + template(MethodHandleNatives_klass, java_dyn_MethodHandleNatives, Pre_JSR292) \ + template(AdapterMethodHandle_klass, java_dyn_AdapterMethodHandle, Pre_JSR292) \ + template(BoundMethodHandle_klass, java_dyn_BoundMethodHandle, Pre_JSR292) \ + template(DirectMethodHandle_klass, java_dyn_DirectMethodHandle, Pre_JSR292) \ + template(MethodType_klass, java_dyn_MethodType, Pre_JSR292) \ + template(MethodTypeForm_klass, java_dyn_MethodTypeForm, Pre_JSR292) \ + template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Pre_JSR292) \ + template(Linkage_klass, java_dyn_Linkage, Pre_JSR292) \ + template(CallSite_klass, java_dyn_CallSite, Pre_JSR292) \ /* Note: MethodHandle must be first, and CallSite last in group */ \ \ template(StringBuffer_klass, java_lang_StringBuffer, Pre) \ @@ -207,6 +207,7 @@ enum InitOption { Pre, // preloaded; error if not present + Pre_JSR292, // preloaded if EnableMethodHandles // Order is significant. Options before this point require resolve_or_fail. // Options after this point will use resolve_or_null instead. @@ -401,6 +402,7 @@ } static klassOop check_klass_Pre(klassOop k) { return check_klass(k); } + static klassOop check_klass_Pre_JSR292(klassOop k) { return EnableInvokeDynamic ? check_klass(k) : k; } static klassOop check_klass_Opt(klassOop k) { return k; } static klassOop check_klass_Opt_Kernel(klassOop k) { return k; } //== Opt static klassOop check_klass_Opt_Only_JDK15(klassOop k) { @@ -420,6 +422,8 @@ initialize_wk_klasses_until((WKID) limit, start_id, THREAD); } + static Symbol* find_backup_symbol(Symbol* symbol, const char* from_prefix, const char* to_prefix); + public: #define WK_KLASS_DECLARE(name, ignore_symbol, option) \ static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); } @@ -441,6 +445,9 @@ static void load_abstract_ownable_synchronizer_klass(TRAPS); + static Symbol* find_backup_class_name(Symbol* class_name_symbol); + static Symbol* find_backup_signature(Symbol* signature_symbol); + private: // Tells whether ClassLoader.loadClassInternal is present static bool has_loadClassInternal() { return _has_loadClassInternal; } diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/vmSymbols.cpp --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -277,6 +277,12 @@ return sid; } +vmSymbols::SID vmSymbols::find_sid(const char* symbol_name) { + Symbol* symbol = SymbolTable::probe(symbol_name, (int) strlen(symbol_name)); + if (symbol == NULL) return NO_SID; + return find_sid(symbol); +} + static vmIntrinsics::ID wrapper_intrinsic(BasicType type, bool unboxing) { #define TYPE2(type, unboxing) ((int)(type)*2 + ((unboxing) ? 1 : 0)) switch (TYPE2(type, unboxing)) { diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Fri Mar 11 22:33:47 2011 -0800 @@ -240,13 +240,18 @@ /* internal classes known only to the JVM: */ \ template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") \ template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") \ - template(sun_dyn_MemberName, "sun/dyn/MemberName") \ - template(sun_dyn_MemberName_signature, "Lsun/dyn/MemberName;") \ - template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") \ - template(sun_dyn_MethodHandleNatives, "sun/dyn/MethodHandleNatives") \ - template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \ - template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \ - template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \ + template(java_dyn_MemberName, "java/dyn/MemberName") \ + template(java_dyn_MethodHandleImpl, "java/dyn/MethodHandleImpl") \ + template(java_dyn_MethodHandleNatives, "java/dyn/MethodHandleNatives") \ + template(java_dyn_AdapterMethodHandle, "java/dyn/AdapterMethodHandle") \ + template(java_dyn_BoundMethodHandle, "java/dyn/BoundMethodHandle") \ + template(java_dyn_DirectMethodHandle, "java/dyn/DirectMethodHandle") \ + template(sun_dyn_MemberName, "sun/dyn/MemberName") /* AllowTransitionalJSR292 ONLY */ \ + template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") /* AllowTransitionalJSR292 ONLY */ \ + template(sun_dyn_MethodHandleNatives, "sun/dyn/MethodHandleNatives") /* AllowTransitionalJSR292 ONLY */ \ + template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ + template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ + template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") /* AllowTransitionalJSR292 ONLY */ \ /* internal up-calls made only by the JVM, via class sun.dyn.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/dyn/MethodType;") \ @@ -255,7 +260,8 @@ template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \ template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/dyn/MethodHandle;") \ template(makeDynamicCallSite_name, "makeDynamicCallSite") \ - template(makeDynamicCallSite_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Lsun/dyn/MemberName;I)Ljava/dyn/CallSite;") \ + template(makeDynamicCallSite_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Ljava/dyn/MemberName;I)Ljava/dyn/CallSite;") \ + template(makeDynamicCallSite_TRANS_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Lsun/dyn/MemberName;I)Ljava/dyn/CallSite;") /* AllowTransitionalJSR292 ONLY */ \ NOT_LP64( do_alias(machine_word_signature, int_signature) ) \ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \ \ @@ -882,7 +888,8 @@ \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_object_array_object_signature, F_R) \ /* (symbols invoke_name and invoke_signature defined above) */ \ - do_intrinsic(_checkSpreadArgument, sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \ + do_intrinsic(_checkSpreadArgument, java_dyn_MethodHandleNatives, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \ + do_intrinsic(_checkSpreadArgument_TRANS, sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) /* AllowTransitionalJSR292 ONLY */ \ do_name( checkSpreadArgument_name, "checkSpreadArgument") \ do_name( checkSpreadArgument_signature, "(Ljava/lang/Object;I)V") \ do_intrinsic(_invokeExact, java_dyn_MethodHandle, invokeExact_name, object_array_object_signature, F_RN) \ @@ -995,6 +1002,7 @@ // Returns symbol's SID if one is assigned, else NO_SID. static SID find_sid(Symbol* symbol); + static SID find_sid(const char* symbol_name); #ifndef PRODUCT // No need for this in the product: diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,9 @@ // Make sure the Java part of the runtime has been booted up. klassOop natives = SystemDictionary::MethodHandleNatives_klass(); if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) { - SystemDictionary::resolve_or_fail(vmSymbols::sun_dyn_MethodHandleNatives(), + Symbol* natives_name = vmSymbols::java_dyn_MethodHandleNatives(); + if (natives != NULL && AllowTransitionalJSR292) natives_name = Klass::cast(natives)->name(); + SystemDictionary::resolve_or_fail(natives_name, Handle(), Handle(), true, diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Mar 11 22:33:47 2011 -0800 @@ -194,7 +194,7 @@ // Implementors of this interface (not valid if it overflows) klassOop _implementors[implementors_limit]; // invokedynamic bootstrap method (a java.dyn.MethodHandle) - oop _bootstrap_method; + oop _bootstrap_method; // AllowTransitionalJSR292 ONLY // Annotations for this class, or null if none. typeArrayOop _class_annotations; // Annotation objects (byte arrays) for fields, or null if no annotations. @@ -529,7 +529,7 @@ _enclosing_method_method_index = method_index; } // JSR 292 support - oop bootstrap_method() const { return _bootstrap_method; } + oop bootstrap_method() const { return _bootstrap_method; } // AllowTransitionalJSR292 ONLY void set_bootstrap_method(oop mh) { oop_store(&_bootstrap_method, mh); } // jmethodID support @@ -817,7 +817,7 @@ oop* adr_signers() const { return (oop*)&this->_signers;} oop* adr_inner_classes() const { return (oop*)&this->_inner_classes;} oop* adr_implementors() const { return (oop*)&this->_implementors[0];} - oop* adr_bootstrap_method() const { return (oop*)&this->_bootstrap_method;} + oop* adr_bootstrap_method() const { return (oop*)&this->_bootstrap_method;} // AllowTransitionalJSR292 ONLY oop* adr_methods_jmethod_ids() const { return (oop*)&this->_methods_jmethod_ids;} oop* adr_methods_cached_itable_indices() const { return (oop*)&this->_methods_cached_itable_indices;} oop* adr_class_annotations() const { return (oop*)&this->_class_annotations;} diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/oops/methodOop.cpp --- a/hotspot/src/share/vm/oops/methodOop.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/oops/methodOop.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -855,7 +855,7 @@ case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name): return true; } - if (AllowTransitionalJSR292 + if ((AllowTransitionalJSR292 || AllowInvokeForInvokeGeneric) && name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name)) return true; return false; @@ -1127,7 +1127,8 @@ id = vmIntrinsics::_invokeExact; break; case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name): - if (AllowTransitionalJSR292) id = vmIntrinsics::_invokeExact; + if (AllowInvokeForInvokeGeneric) id = vmIntrinsics::_invokeGeneric; + else if (AllowTransitionalJSR292) id = vmIntrinsics::_invokeExact; break; } break; diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/prims/methodHandleWalk.cpp --- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -100,7 +100,6 @@ BasicType MethodHandleChain::compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS) { // There is no direct indication of whether the argument is primitive or not. // It is implied by the _vmentry code, and by the MethodType of the target. - // FIXME: Make it explicit MethodHandleImpl refactors out from MethodHandle BasicType arg_type = T_VOID; if (target != NULL) { oop mtype = java_dyn_MethodHandle::type(target); @@ -960,6 +959,13 @@ if (m == NULL) { // Get the intrinsic methodOop. m = vmIntrinsics::method_for(iid); + if (m == NULL && iid == vmIntrinsics::_checkSpreadArgument && AllowTransitionalJSR292) { + m = vmIntrinsics::method_for(vmIntrinsics::_checkSpreadArgument_TRANS); + } + if (m == NULL) { + ArgToken zero; + lose(vmIntrinsics::name_at(iid), CHECK_(zero)); + } } klassOop klass = m->method_holder(); diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -2523,17 +2523,16 @@ JVM_END JVM_ENTRY(jobject, MHI_getBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh)) { + if (!AllowTransitionalJSR292) + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "getBootstrap: transitional only"); instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD); return JNIHandles::make_local(THREAD, ik->bootstrap_method()); } JVM_END JVM_ENTRY(void, MHI_setCallSiteTarget(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) { - // No special action required, yet. - oop site_oop = JNIHandles::resolve(site_jh); - if (!java_dyn_CallSite::is_instance(site_oop)) - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "not a CallSite"); - java_dyn_CallSite::set_target(site_oop, JNIHandles::resolve(target_jh)); + if (!AllowTransitionalJSR292) + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "setCallSite: transitional only"); } JVM_END @@ -2543,8 +2542,10 @@ #define ADR "J" #define LANG "Ljava/lang/" -#define JDYN "Ljava/dyn/" -#define IDYN "Lsun/dyn/" +#define JLINV "Ljava/lang/invoke/" /* standard package */ +#define JDYN "Ljava/dyn/" /* alternative package to JLINV if AllowTransitionalJSR292 */ +#define IDYN "Lsun/dyn/" /* alternative package to JDYN if AllowTransitionalJSR292 */ +// FIXME: After AllowTransitionalJSR292 is removed, replace JDYN and IDYN by JLINV. #define OBJ LANG"Object;" #define CLS LANG"Class;" @@ -2552,7 +2553,6 @@ #define CST JDYN"CallSite;" #define MT JDYN"MethodType;" #define MH JDYN"MethodHandle;" -#define MHI IDYN"MethodHandleImpl;" #define MEM IDYN"MemberName;" #define AMH IDYN"AdapterMethodHandle;" #define BMH IDYN"BoundMethodHandle;" @@ -2581,12 +2581,38 @@ }; // More entry points specifically for EnableInvokeDynamic. +// FIXME: Remove methods2 after AllowTransitionalJSR292 is removed. static JNINativeMethod methods2[] = { {CC"registerBootstrap", CC"("CLS MH")V", FN_PTR(MHI_registerBootstrap)}, {CC"getBootstrap", CC"("CLS")"MH, FN_PTR(MHI_getBootstrap)}, {CC"setCallSiteTarget", CC"("CST MH")V", FN_PTR(MHI_setCallSiteTarget)} }; +static void hack_signatures(JNINativeMethod* methods, jint num_methods, const char* from_sig, const char* to_sig) { + for (int i = 0; i < num_methods; i++) { + const char* sig = methods[i].signature; + if (!strstr(sig, from_sig)) continue; + size_t buflen = strlen(sig) + 100; + char* buf = NEW_C_HEAP_ARRAY(char, buflen); + char* bufp = buf; + const char* sigp = sig; + size_t from_len = strlen(from_sig), to_len = strlen(to_sig); + while (*sigp != '\0') { + assert(bufp < buf + buflen - to_len - 1, "oob"); + if (strncmp(sigp, from_sig, from_len) != 0) { + *bufp++ = *sigp++; + } else { + strcpy(bufp, to_sig); + bufp += to_len; + sigp += from_len; + } + } + *bufp = '\0'; + methods[i].signature = buf; // replace with new signature + if (TraceMethodHandles) + tty->print_cr("MethodHandleNatives: %s: change signature %s => %s", methods[i].name, sig, buf); + } +} // This one function is exported, used by NativeLookup. @@ -2600,45 +2626,76 @@ return; // bind nothing } + if (SystemDictionary::MethodHandleNatives_klass() != NULL && + SystemDictionary::MethodHandleNatives_klass() != java_lang_Class::as_klassOop(JNIHandles::resolve(MHN_class))) { + warning("multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292"); + THROW_MSG(vmSymbols::java_lang_InternalError(), "multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292"); + } + bool enable_MH = true; - { + // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed. + bool registered_natives = false; + bool try_plain = true, try_JDYN = true, try_IDYN = true; + for (;;) { ThreadToNativeFromVM ttnfv(thread); + if (try_plain) { try_plain = false; } + else if (try_JDYN) { try_JDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), IDYN, JDYN); } + else if (try_IDYN) { try_IDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), JDYN, JLINV); } + else { break; } int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod)); if (env->ExceptionOccurred()) { - MethodHandles::set_enabled(false); - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - enable_MH = false; env->ExceptionClear(); + // and try again... + } else { + registered_natives = true; + break; } } + if (!registered_natives) { + MethodHandles::set_enabled(false); + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); + enable_MH = false; + } if (enable_MH) { + bool found_raise_exception = false; + KlassHandle MHN_klass = SystemDictionaryHandles::MethodHandleNatives_klass(); KlassHandle MHI_klass = SystemDictionaryHandles::MethodHandleImpl_klass(); - if (MHI_klass.not_null()) { + // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed. + bool try_MHN = true, try_MHI = AllowTransitionalJSR292; + for (;;) { + KlassHandle try_klass; + if (try_MHN) { try_MHN = false; try_klass = MHN_klass; } + else if (try_MHI) { try_MHI = false; try_klass = MHI_klass; } + else { break; } + if (try_klass.is_null()) continue; TempNewSymbol raiseException_name = SymbolTable::new_symbol("raiseException", CHECK); TempNewSymbol raiseException_sig = SymbolTable::new_symbol("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK); - methodOop raiseException_method = instanceKlass::cast(MHI_klass->as_klassOop()) + methodOop raiseException_method = instanceKlass::cast(try_klass->as_klassOop()) ->find_method(raiseException_name, raiseException_sig); if (raiseException_method != NULL && raiseException_method->is_static()) { MethodHandles::set_raise_exception_method(raiseException_method); - } else { - warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); - enable_MH = false; + found_raise_exception = true; + break; } - } else { + } + if (!found_raise_exception) { + warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); enable_MH = false; } } if (enable_MH) { - // We need to link the MethodHandleImpl klass before we generate - // the method handle adapters as the _raise_exception adapter uses - // one of its methods (and its c2i-adapter). - KlassHandle k = SystemDictionaryHandles::MethodHandleImpl_klass(); - instanceKlass* ik = instanceKlass::cast(k()); - ik->link_class(CHECK); + if (AllowTransitionalJSR292) { + // We need to link the MethodHandleImpl klass before we generate + // the method handle adapters as the _raise_exception adapter uses + // one of its methods (and its c2i-adapter). + KlassHandle k = SystemDictionaryHandles::MethodHandleImpl_klass(); + instanceKlass* ik = instanceKlass::cast(k()); + ik->link_class(CHECK); + } MethodHandles::generate_adapters(); MethodHandles::set_enabled(true); @@ -2649,7 +2706,7 @@ return; // bind nothing } - { + if (AllowTransitionalJSR292) { ThreadToNativeFromVM ttnfv(thread); int status = env->RegisterNatives(MHN_class, methods2, sizeof(methods2)/sizeof(JNINativeMethod)); @@ -2657,8 +2714,6 @@ MethodHandles::set_enabled(false); warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); env->ExceptionClear(); - } else { - MethodHandles::set_enabled(true); } } } diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/prims/nativeLookup.cpp --- a/hotspot/src/share/vm/prims/nativeLookup.cpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp Fri Mar 11 22:33:47 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,29 +107,29 @@ void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); } +#define CC (char*) /* cast a literal from (const char*) */ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) + +static JNINativeMethod lookup_special_native_methods[] = { + // Next two functions only exist for compatibility with 1.3.1 and earlier. + { CC"Java_java_io_ObjectOutputStream_getPrimitiveFieldValues", NULL, FN_PTR(JVM_GetPrimitiveFieldValues) }, // intercept ObjectOutputStream getPrimitiveFieldValues for faster serialization + { CC"Java_java_io_ObjectInputStream_setPrimitiveFieldValues", NULL, FN_PTR(JVM_SetPrimitiveFieldValues) }, // intercept ObjectInputStream setPrimitiveFieldValues for faster serialization + + { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, + { CC"Java_sun_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292 + { CC"Java_java_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292 + { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) } +}; + static address lookup_special_native(char* jni_name) { - // NB: To ignore the jni prefix and jni postfix strstr is used matching. - if (!JDK_Version::is_gte_jdk14x_version()) { - // These functions only exist for compatibility with 1.3.1 and earlier - // Intercept ObjectOutputStream getPrimitiveFieldValues for faster serialization - if (strstr(jni_name, "Java_java_io_ObjectOutputStream_getPrimitiveFieldValues") != NULL) { - return CAST_FROM_FN_PTR(address, JVM_GetPrimitiveFieldValues); - } - // Intercept ObjectInputStream setPrimitiveFieldValues for faster serialization - if (strstr(jni_name, "Java_java_io_ObjectInputStream_setPrimitiveFieldValues") != NULL) { - return CAST_FROM_FN_PTR(address, JVM_SetPrimitiveFieldValues); + int i = !JDK_Version::is_gte_jdk14x_version() ? 0 : 2; // see comment in lookup_special_native_methods + int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); + for (; i < count; i++) { + // NB: To ignore the jni prefix and jni postfix strstr is used matching. + if (strstr(jni_name, lookup_special_native_methods[i].name) != NULL) { + return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr); } } - if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) { - return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods); - } - if (strstr(jni_name, "Java_sun_dyn_MethodHandleNatives_registerNatives") != NULL) { - return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods); - } - if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) { - return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods); - } - return NULL; } diff -r 303a2149d371 -r e9fef2a9bef7 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Fri Mar 11 21:19:15 2011 -0800 +++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Mar 11 22:33:47 2011 -0800 @@ -3719,6 +3719,13 @@ experimental(bool, AllowTransitionalJSR292, true, \ "recognize pre-PFD formats of invokedynamic") \ \ + experimental(bool, PreferTransitionalJSR292, false, \ + "prefer pre-PFD APIs on boot class path, if they exist") \ + \ + experimental(bool, AllowInvokeForInvokeGeneric, false, \ + "accept MethodHandle.invoke and MethodHandle.invokeGeneric " \ + "as equivalent methods") \ + \ develop(bool, TraceInvokeDynamic, false, \ "trace internal invoke dynamic operations") \ \