--- a/hotspot/src/share/vm/prims/methodHandles.cpp Fri May 06 12:12:29 2011 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Fri May 06 16:33:13 2011 -0700
@@ -66,8 +66,8 @@
"adapter_drop_args",
"adapter_collect_args",
"adapter_spread_args",
- "adapter_flyby",
- "adapter_ricochet",
+ "adapter_fold_args",
+ "adapter_unused_13",
// optimized adapter types:
"adapter_swap_args/1",
@@ -83,9 +83,76 @@
"adapter_prim_to_prim/f2d",
"adapter_ref_to_prim/unboxi",
"adapter_ref_to_prim/unboxl",
- "adapter_spread_args/0",
- "adapter_spread_args/1",
- "adapter_spread_args/more",
+
+ // return value handlers for collect/filter/fold adapters:
+ "return/ref",
+ "return/int",
+ "return/long",
+ "return/float",
+ "return/double",
+ "return/void",
+ "return/S0/ref",
+ "return/S1/ref",
+ "return/S2/ref",
+ "return/S3/ref",
+ "return/S4/ref",
+ "return/S5/ref",
+ "return/any",
+
+ // spreading (array length cases 0, 1, ...)
+ "adapter_spread/0",
+ "adapter_spread/1/ref",
+ "adapter_spread/2/ref",
+ "adapter_spread/3/ref",
+ "adapter_spread/4/ref",
+ "adapter_spread/5/ref",
+ "adapter_spread/ref",
+ "adapter_spread/byte",
+ "adapter_spread/char",
+ "adapter_spread/short",
+ "adapter_spread/int",
+ "adapter_spread/long",
+ "adapter_spread/float",
+ "adapter_spread/double",
+
+ // blocking filter/collect conversions:
+ "adapter_collect/ref",
+ "adapter_collect/int",
+ "adapter_collect/long",
+ "adapter_collect/float",
+ "adapter_collect/double",
+ "adapter_collect/void",
+ "adapter_collect/0/ref",
+ "adapter_collect/1/ref",
+ "adapter_collect/2/ref",
+ "adapter_collect/3/ref",
+ "adapter_collect/4/ref",
+ "adapter_collect/5/ref",
+ "adapter_filter/S0/ref",
+ "adapter_filter/S1/ref",
+ "adapter_filter/S2/ref",
+ "adapter_filter/S3/ref",
+ "adapter_filter/S4/ref",
+ "adapter_filter/S5/ref",
+ "adapter_collect/2/S0/ref",
+ "adapter_collect/2/S1/ref",
+ "adapter_collect/2/S2/ref",
+ "adapter_collect/2/S3/ref",
+ "adapter_collect/2/S4/ref",
+ "adapter_collect/2/S5/ref",
+
+ // blocking fold conversions:
+ "adapter_fold/ref",
+ "adapter_fold/int",
+ "adapter_fold/long",
+ "adapter_fold/float",
+ "adapter_fold/double",
+ "adapter_fold/void",
+ "adapter_fold/1/ref",
+ "adapter_fold/2/ref",
+ "adapter_fold/3/ref",
+ "adapter_fold/4/ref",
+ "adapter_fold/5/ref",
NULL
};
@@ -96,13 +163,23 @@
jobject MethodHandles::_raise_exception_method;
+address MethodHandles::_adapter_return_handlers[CONV_TYPE_MASK+1];
+
#ifdef ASSERT
bool MethodHandles::spot_check_entry_names() {
assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
assert(!strcmp(entry_name(_bound_ref_mh), "bound_ref"), "");
assert(!strcmp(entry_name(_adapter_retype_only), "adapter_retype_only"), "");
- assert(!strcmp(entry_name(_adapter_ricochet), "adapter_ricochet"), "");
+ assert(!strcmp(entry_name(_adapter_fold_args), "adapter_fold_args"), "");
assert(!strcmp(entry_name(_adapter_opt_unboxi), "adapter_ref_to_prim/unboxi"), "");
+ assert(!strcmp(entry_name(_adapter_opt_spread_char), "adapter_spread/char"), "");
+ assert(!strcmp(entry_name(_adapter_opt_spread_double), "adapter_spread/double"), "");
+ assert(!strcmp(entry_name(_adapter_opt_collect_int), "adapter_collect/int"), "");
+ assert(!strcmp(entry_name(_adapter_opt_collect_0_ref), "adapter_collect/0/ref"), "");
+ assert(!strcmp(entry_name(_adapter_opt_collect_2_S3_ref), "adapter_collect/2/S3/ref"), "");
+ assert(!strcmp(entry_name(_adapter_opt_filter_S5_ref), "adapter_filter/S5/ref"), "");
+ assert(!strcmp(entry_name(_adapter_opt_fold_3_ref), "adapter_fold/3/ref"), "");
+ assert(!strcmp(entry_name(_adapter_opt_fold_void), "adapter_fold/void"), "");
return true;
}
#endif
@@ -112,6 +189,9 @@
// MethodHandles::generate_adapters
//
void MethodHandles::generate_adapters() {
+#ifdef TARGET_ARCH_NYI_6939861
+ if (FLAG_IS_DEFAULT(UseRicochetFrames)) UseRicochetFrames = false;
+#endif
if (!EnableInvokeDynamic || SystemDictionary::MethodHandle_klass() == NULL) return;
assert(_adapter_code == NULL, "generate only once");
@@ -126,7 +206,6 @@
g.generate();
}
-
//------------------------------------------------------------------------------
// MethodHandlesAdapterGenerator::generate
//
@@ -135,12 +214,62 @@
for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
ek < MethodHandles::_EK_LIMIT;
ek = MethodHandles::EntryKind(1 + (int)ek)) {
- StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
- MethodHandles::generate_method_handle_stub(_masm, ek);
+ if (MethodHandles::ek_supported(ek)) {
+ StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
+ MethodHandles::generate_method_handle_stub(_masm, ek);
+ }
}
}
+#ifdef TARGET_ARCH_NYI_6939861
+// these defs belong in methodHandles_<arch>.cpp
+frame MethodHandles::ricochet_frame_sender(const frame& fr, RegisterMap *map) {
+ ShouldNotCallThis();
+ return fr;
+}
+void MethodHandles::ricochet_frame_oops_do(const frame& fr, OopClosure* f, const RegisterMap* reg_map) {
+ ShouldNotCallThis();
+}
+#endif //TARGET_ARCH_NYI_6939861
+
+
+//------------------------------------------------------------------------------
+// MethodHandles::ek_supported
+//
+bool MethodHandles::ek_supported(MethodHandles::EntryKind ek) {
+ MethodHandles::EntryKind ek_orig = MethodHandles::ek_original_kind(ek);
+ switch (ek_orig) {
+ case _adapter_unused_13:
+ return false; // not defined yet
+ case _adapter_prim_to_ref:
+ return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_REF);
+ case _adapter_collect_args:
+ return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS);
+ case _adapter_fold_args:
+ return UseRicochetFrames && conv_op_supported(java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS);
+ case _adapter_opt_return_any:
+ return UseRicochetFrames;
+#ifdef TARGET_ARCH_NYI_6939861
+ // ports before 6939861 supported only three kinds of spread ops
+ case _adapter_spread_args:
+ // restrict spreads to three kinds:
+ switch (ek) {
+ case _adapter_opt_spread_0:
+ case _adapter_opt_spread_1:
+ case _adapter_opt_spread_more:
+ break;
+ default:
+ return false;
+ break;
+ }
+ break;
+#endif //TARGET_ARCH_NYI_6939861
+ }
+ return true;
+}
+
+
void MethodHandles::set_enabled(bool z) {
if (_enabled != z) {
guarantee(z && EnableInvokeDynamic, "can only enable once, and only if -XX:+EnableInvokeDynamic");
@@ -1564,6 +1693,8 @@
if (m->is_abstract()) { THROW(vmSymbols::java_lang_AbstractMethodError()); }
java_lang_invoke_MethodHandle::init_vmslots(mh());
+ int vmargslot = m->size_of_parameters() - 1;
+ assert(java_lang_invoke_BoundMethodHandle::vmargslot(mh()) == vmargslot, "");
if (VerifyMethodHandles) {
verify_BoundMethodHandle_with_receiver(mh, m, CHECK);
@@ -1642,14 +1773,9 @@
DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
if (direct_to_method) {
assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
- assert(slots_pushed <= MethodHandlePushLimit, "");
} else {
int target_pushes = decode_MethodHandle_stack_pushes(target());
assert(this_pushes == slots_pushed + target_pushes, "BMH stack motion must be correct");
- // do not blow the stack; use a Java-based adapter if this limit is exceeded
- // FIXME
- // if (slots_pushed + target_pushes > MethodHandlePushLimit)
- // err = "too many bound parameters";
}
}
@@ -1672,10 +1798,11 @@
}
java_lang_invoke_MethodHandle::init_vmslots(mh());
+ int argslot = java_lang_invoke_BoundMethodHandle::vmargslot(mh());
if (VerifyMethodHandles) {
int insert_after = argnum - 1;
- verify_vmargslot(mh, insert_after, java_lang_invoke_BoundMethodHandle::vmargslot(mh()), CHECK);
+ verify_vmargslot(mh, insert_after, argslot, CHECK);
verify_vmslots(mh, CHECK);
}
@@ -1769,6 +1896,7 @@
Handle target(THREAD, java_lang_invoke_AdapterMethodHandle::vmtarget(mh()));
Handle src_mtype(THREAD, java_lang_invoke_MethodHandle::type(mh()));
Handle dst_mtype(THREAD, java_lang_invoke_MethodHandle::type(target()));
+ Handle arg_mtype;
const char* err = NULL;
@@ -1777,25 +1905,29 @@
switch (ek) {
case _adapter_check_cast: // target type of cast
case _adapter_ref_to_prim: // wrapper type from which to unbox
- case _adapter_prim_to_ref: // wrapper type to box into
- case _adapter_collect_args: // array type to collect into
case _adapter_spread_args: // array type to spread from
if (!java_lang_Class::is_instance(argument())
|| java_lang_Class::is_primitive(argument()))
{ err = "adapter requires argument of type java.lang.Class"; break; }
- if (ek == _adapter_collect_args ||
- ek == _adapter_spread_args) {
+ if (ek == _adapter_spread_args) {
// Make sure it is a suitable collection type. (Array, for now.)
Klass* ak = Klass::cast(java_lang_Class::as_klassOop(argument()));
- if (!ak->oop_is_objArray()) {
- { err = "adapter requires argument of type java.lang.Class<Object[]>"; break; }
- }
+ if (!ak->oop_is_array())
+ { err = "spread adapter requires argument representing an array class"; break; }
+ BasicType et = arrayKlass::cast(ak->as_klassOop())->element_type();
+ if (et != dest && stack_move <= 0)
+ { err = "spread adapter requires array class argument of correct type"; break; }
}
break;
- case _adapter_flyby:
- case _adapter_ricochet:
+ case _adapter_prim_to_ref: // boxer MH to use
+ case _adapter_collect_args: // method handle which collects the args
+ case _adapter_fold_args: // method handle which collects the args
+ if (!UseRicochetFrames) {
+ { err = "box/collect/fold operators are not supported"; break; }
+ }
if (!java_lang_invoke_MethodHandle::is_instance(argument()))
{ err = "MethodHandle adapter argument required"; break; }
+ arg_mtype = Handle(THREAD, java_lang_invoke_MethodHandle::type(argument()));
break;
default:
if (argument.not_null())
@@ -1806,6 +1938,7 @@
if (err == NULL) {
// Check that the src/dest types are supplied if needed.
+ // Also check relevant parameter or return types.
switch (ek) {
case _adapter_check_cast:
if (src != T_OBJECT || dest != T_OBJECT) {
@@ -1828,8 +1961,7 @@
}
break;
case _adapter_prim_to_ref:
- if (!is_java_primitive(src) || dest != T_OBJECT
- || argument() != Klass::cast(SystemDictionary::box_klass(src))->java_mirror()) {
+ if (!is_java_primitive(src) || dest != T_OBJECT) {
err = "adapter requires primitive src conversion subfield"; break;
}
break;
@@ -1840,14 +1972,12 @@
err = "adapter requires src/dest conversion subfields for swap"; break;
}
int swap_size = type2size[src];
- oop src_mtype = java_lang_invoke_AdapterMethodHandle::type(mh());
- oop dest_mtype = java_lang_invoke_AdapterMethodHandle::type(target());
- int slot_limit = java_lang_invoke_AdapterMethodHandle::vmslots(target());
+ int slot_limit = java_lang_invoke_MethodHandle::vmslots(target());
int src_slot = argslot;
int dest_slot = vminfo;
bool rotate_up = (src_slot > dest_slot); // upward rotation
int src_arg = argnum;
- int dest_arg = argument_slot_to_argnum(dest_mtype, dest_slot);
+ int dest_arg = argument_slot_to_argnum(dst_mtype(), dest_slot);
verify_vmargslot(mh, dest_arg, dest_slot, CHECK);
if (!(dest_slot >= src_slot + swap_size) &&
!(src_slot >= dest_slot + swap_size)) {
@@ -1855,8 +1985,8 @@
} else if (ek == _adapter_swap_args && !(src_slot > dest_slot)) {
err = "source of swap must be deeper in stack";
} else if (ek == _adapter_swap_args) {
- err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, dest_arg),
- java_lang_invoke_MethodType::ptype(dest_mtype, src_arg),
+ err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), dest_arg),
+ java_lang_invoke_MethodType::ptype(dst_mtype(), src_arg),
dest_arg);
} else if (ek == _adapter_rot_args) {
if (rotate_up) {
@@ -1864,8 +1994,8 @@
// rotate up: [dest_slot..src_slot-ss] --> [dest_slot+ss..src_slot]
// that is: [src_arg+1..dest_arg] --> [src_arg..dest_arg-1]
for (int i = src_arg+1; i <= dest_arg && err == NULL; i++) {
- err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, i),
- java_lang_invoke_MethodType::ptype(dest_mtype, i-1),
+ err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), i),
+ java_lang_invoke_MethodType::ptype(dst_mtype(), i-1),
i);
}
} else { // rotate down
@@ -1873,28 +2003,54 @@
// rotate down: [src_slot+ss..dest_slot] --> [src_slot..dest_slot-ss]
// that is: [dest_arg..src_arg-1] --> [dst_arg+1..src_arg]
for (int i = dest_arg; i <= src_arg-1 && err == NULL; i++) {
- err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, i),
- java_lang_invoke_MethodType::ptype(dest_mtype, i+1),
+ err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), i),
+ java_lang_invoke_MethodType::ptype(dst_mtype(), i+1),
i);
}
}
}
if (err == NULL)
- err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype, src_arg),
- java_lang_invoke_MethodType::ptype(dest_mtype, dest_arg),
+ err = check_argument_type_change(java_lang_invoke_MethodType::ptype(src_mtype(), src_arg),
+ java_lang_invoke_MethodType::ptype(dst_mtype(), dest_arg),
src_arg);
}
break;
+ case _adapter_spread_args:
case _adapter_collect_args:
- case _adapter_spread_args:
+ case _adapter_fold_args:
{
- BasicType coll_type = (ek == _adapter_collect_args) ? dest : src;
- BasicType elem_type = (ek == _adapter_collect_args) ? src : dest;
- if (coll_type != T_OBJECT || elem_type != T_OBJECT) {
- err = "adapter requires src/dest subfields"; break;
- // later:
- // - consider making coll be a primitive array
- // - consider making coll be a heterogeneous collection
+ bool is_spread = (ek == _adapter_spread_args);
+ bool is_fold = (ek == _adapter_fold_args);
+ BasicType coll_type = is_spread ? src : dest;
+ BasicType elem_type = is_spread ? dest : src;
+ // coll_type is type of args in collected form (or T_VOID if none)
+ // elem_type is common type of args in spread form (or T_VOID if missing or heterogeneous)
+ if (coll_type == 0 || elem_type == 0) {
+ err = "adapter requires src/dest subfields for spread or collect"; break;
+ }
+ if (is_spread && coll_type != T_OBJECT) {
+ err = "spread adapter requires object type for argument bundle"; break;
+ }
+ Handle spread_mtype = (is_spread ? dst_mtype : src_mtype);
+ int spread_slot = argslot;
+ int spread_arg = argnum;
+ int slots_pushed = stack_move / stack_move_unit();
+ int coll_slot_count = type2size[coll_type];
+ int spread_slot_count = (is_spread ? slots_pushed : -slots_pushed) + coll_slot_count;
+ if (is_fold) spread_slot_count = argument_slot_count(arg_mtype());
+ if (!is_spread) {
+ int init_slots = argument_slot_count(src_mtype());
+ int coll_slots = argument_slot_count(arg_mtype());
+ if (spread_slot_count > init_slots ||
+ spread_slot_count != coll_slots) {
+ err = "collect adapter has inconsistent arg counts"; break;
+ }
+ int next_slots = argument_slot_count(dst_mtype());
+ int unchanged_slots_in = (init_slots - spread_slot_count);
+ int unchanged_slots_out = (next_slots - coll_slot_count - (is_fold ? spread_slot_count : 0));
+ if (unchanged_slots_in != unchanged_slots_out) {
+ err = "collect adapter continuation has inconsistent arg counts"; break;
+ }
}
}
break;
@@ -1929,8 +2085,9 @@
}
break;
case _adapter_collect_args:
- if (slots_pushed > 1) {
- err = "adapter requires conversion subfield slots_pushed <= 1";
+ case _adapter_fold_args:
+ if (slots_pushed > 2) {
+ err = "adapter requires conversion subfield slots_pushed <= 2";
}
break;
case _adapter_spread_args:
@@ -1950,32 +2107,36 @@
}
if (err == NULL) {
- // Make sure this adapter does not push too deeply.
+ // Make sure this adapter's stack pushing is accurately recorded.
int slots_pushed = stack_move / stack_move_unit();
int this_vmslots = java_lang_invoke_MethodHandle::vmslots(mh());
int target_vmslots = java_lang_invoke_MethodHandle::vmslots(target());
+ int target_pushes = decode_MethodHandle_stack_pushes(target());
if (slots_pushed != (target_vmslots - this_vmslots)) {
err = "stack_move inconsistent with previous and current MethodType vmslots";
- } else if (slots_pushed > 0) {
- // verify stack_move against MethodHandlePushLimit
- int target_pushes = decode_MethodHandle_stack_pushes(target());
- // do not blow the stack; use a Java-based adapter if this limit is exceeded
- if (slots_pushed + target_pushes > MethodHandlePushLimit) {
- err = "adapter pushes too many parameters";
+ } else {
+ int this_pushes = decode_MethodHandle_stack_pushes(mh());
+ if (slots_pushed + target_pushes != this_pushes) {
+ if (this_pushes == 0)
+ err = "adapter push count not initialized";
+ else
+ err = "adapter push count is wrong";
}
}
// While we're at it, check that the stack motion decoder works:
- DEBUG_ONLY(int target_pushes = decode_MethodHandle_stack_pushes(target()));
DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
assert(this_pushes == slots_pushed + target_pushes, "AMH stack motion must be correct");
}
if (err == NULL && vminfo != 0) {
switch (ek) {
- case _adapter_swap_args:
- case _adapter_rot_args:
- break; // OK
+ case _adapter_swap_args:
+ case _adapter_rot_args:
+ case _adapter_prim_to_ref:
+ case _adapter_collect_args:
+ case _adapter_fold_args:
+ break; // OK
default:
err = "vminfo subfield is reserved to the JVM";
}
@@ -2026,6 +2187,7 @@
// adjust the adapter code to the internal EntryKind enumeration:
EntryKind ek_orig = adapter_entry_kind(conv_op);
EntryKind ek_opt = ek_orig; // may be optimized
+ EntryKind ek_try; // temp
// Finalize the vmtarget field (Java initialized it to null).
if (!java_lang_invoke_MethodHandle::is_instance(target())) {
@@ -2034,17 +2196,23 @@
}
java_lang_invoke_AdapterMethodHandle::set_vmtarget(mh(), target());
- if (VerifyMethodHandles) {
- verify_AdapterMethodHandle(mh, argnum, CHECK);
- }
-
int stack_move = adapter_conversion_stack_move(conversion);
BasicType src = adapter_conversion_src_type(conversion);
BasicType dest = adapter_conversion_dest_type(conversion);
int vminfo = adapter_conversion_vminfo(conversion); // should be zero
+ int slots_pushed = stack_move / stack_move_unit();
+
+ if (VerifyMethodHandles) {
+ verify_AdapterMethodHandle(mh, argnum, CHECK);
+ }
+
const char* err = NULL;
+ if (!conv_op_supported(conv_op)) {
+ err = "adapter not yet implemented in the JVM";
+ }
+
// Now it's time to finish the case analysis and pick a MethodHandleEntry.
switch (ek_orig) {
case _adapter_retype_only:
@@ -2077,7 +2245,7 @@
}
break;
case 1 *4+ 2:
- if (src == T_INT && dest == T_LONG) {
+ if ((src == T_INT || is_subword_type(src)) && dest == T_LONG) {
ek_opt = _adapter_opt_i2l;
} else if (src == T_FLOAT && dest == T_DOUBLE) {
ek_opt = _adapter_opt_f2d;
@@ -2110,7 +2278,44 @@
break;
case _adapter_prim_to_ref:
- goto throw_not_impl; // allocates, hence could block
+ {
+ assert(UseRicochetFrames, "else don't come here");
+ // vminfo will be the location to insert the return value
+ vminfo = argslot;
+ ek_opt = _adapter_opt_collect_ref;
+ ensure_vmlayout_field(target, CHECK);
+ if (!OptimizeMethodHandles) break;
+ switch (type2size[src]) {
+ case 1:
+ ek_try = EntryKind(_adapter_opt_filter_S0_ref + argslot);
+ if (ek_try < _adapter_opt_collect_LAST &&
+ ek_adapter_opt_collect_slot(ek_try) == argslot) {
+ assert(ek_adapter_opt_collect_count(ek_try) == 1 &&
+ ek_adapter_opt_collect_type(ek_try) == T_OBJECT, "");
+ ek_opt = ek_try;
+ break;
+ }
+ // else downgrade to variable slot:
+ ek_opt = _adapter_opt_collect_1_ref;
+ break;
+ case 2:
+ ek_try = EntryKind(_adapter_opt_collect_2_S0_ref + argslot);
+ if (ek_try < _adapter_opt_collect_LAST &&
+ ek_adapter_opt_collect_slot(ek_try) == argslot) {
+ assert(ek_adapter_opt_collect_count(ek_try) == 2 &&
+ ek_adapter_opt_collect_type(ek_try) == T_OBJECT, "");
+ ek_opt = ek_try;
+ break;
+ }
+ // else downgrade to variable slot:
+ ek_opt = _adapter_opt_collect_2_ref;
+ break;
+ default:
+ assert(false, "");
+ break;
+ }
+ }
+ break;
case _adapter_swap_args:
case _adapter_rot_args:
@@ -2136,29 +2341,180 @@
}
break;
- case _adapter_collect_args:
- goto throw_not_impl; // allocates, hence could block
-
case _adapter_spread_args:
{
+#ifdef TARGET_ARCH_NYI_6939861
+ // ports before 6939861 supported only three kinds of spread ops
+ if (!UseRicochetFrames) {
+ int array_size = slots_pushed + 1;
+ assert(array_size >= 0, "");
+ vminfo = array_size;
+ switch (array_size) {
+ case 0: ek_opt = _adapter_opt_spread_0; break;
+ case 1: ek_opt = _adapter_opt_spread_1; break;
+ default: ek_opt = _adapter_opt_spread_more; break;
+ }
+ break;
+ }
+#endif //TARGET_ARCH_NYI_6939861
// vminfo will be the required length of the array
- int slots_pushed = stack_move / stack_move_unit();
- int array_size = slots_pushed + 1;
- assert(array_size >= 0, "");
+ int array_size = (slots_pushed + 1) / (type2size[dest] == 2 ? 2 : 1);
vminfo = array_size;
- switch (array_size) {
- case 0: ek_opt = _adapter_opt_spread_0; break;
- case 1: ek_opt = _adapter_opt_spread_1; break;
- default: ek_opt = _adapter_opt_spread_more; break;
+ // general case
+ switch (dest) {
+ case T_BOOLEAN : // fall through to T_BYTE:
+ case T_BYTE : ek_opt = _adapter_opt_spread_byte; break;
+ case T_CHAR : ek_opt = _adapter_opt_spread_char; break;
+ case T_SHORT : ek_opt = _adapter_opt_spread_short; break;
+ case T_INT : ek_opt = _adapter_opt_spread_int; break;
+ case T_LONG : ek_opt = _adapter_opt_spread_long; break;
+ case T_FLOAT : ek_opt = _adapter_opt_spread_float; break;
+ case T_DOUBLE : ek_opt = _adapter_opt_spread_double; break;
+ case T_OBJECT : ek_opt = _adapter_opt_spread_ref; break;
+ case T_VOID : if (array_size != 0) goto throw_not_impl;
+ ek_opt = _adapter_opt_spread_ref; break;
+ default : goto throw_not_impl;
}
- if ((vminfo & CONV_VMINFO_MASK) != vminfo)
- goto throw_not_impl; // overflow
+ assert(array_size == 0 || // it doesn't matter what the spreader is
+ (ek_adapter_opt_spread_count(ek_opt) == -1 &&
+ (ek_adapter_opt_spread_type(ek_opt) == dest ||
+ (ek_adapter_opt_spread_type(ek_opt) == T_BYTE && dest == T_BOOLEAN))),
+ err_msg("dest=%d ek_opt=%d", dest, ek_opt));
+
+ if (array_size <= 0) {
+ // since the general case does not handle length 0, this case is required:
+ ek_opt = _adapter_opt_spread_0;
+ break;
+ }
+ if (dest == T_OBJECT) {
+ ek_try = EntryKind(_adapter_opt_spread_1_ref - 1 + array_size);
+ if (ek_try < _adapter_opt_spread_LAST &&
+ ek_adapter_opt_spread_count(ek_try) == array_size) {
+ assert(ek_adapter_opt_spread_type(ek_try) == dest, "");
+ ek_opt = ek_try;
+ break;
+ }
+ }
+ break;
}
break;
- case _adapter_flyby:
- case _adapter_ricochet:
- goto throw_not_impl; // runs Java code, hence could block
+ case _adapter_collect_args:
+ {
+ assert(UseRicochetFrames, "else don't come here");
+ int elem_slots = argument_slot_count(
+ java_lang_invoke_MethodHandle::type(
+ java_lang_invoke_AdapterMethodHandle::argument(mh()) ) );
+ // vminfo will be the location to insert the return value
+ vminfo = argslot;
+ ensure_vmlayout_field(target, CHECK);
+
+ // general case:
+ switch (dest) {
+ default : if (!is_subword_type(dest)) goto throw_not_impl;
+ // else fall through:
+ case T_INT : ek_opt = _adapter_opt_collect_int; break;
+ case T_LONG : ek_opt = _adapter_opt_collect_long; break;
+ case T_FLOAT : ek_opt = _adapter_opt_collect_float; break;
+ case T_DOUBLE : ek_opt = _adapter_opt_collect_double; break;
+ case T_OBJECT : ek_opt = _adapter_opt_collect_ref; break;
+ case T_VOID : ek_opt = _adapter_opt_collect_void; break;
+ }
+ assert(ek_adapter_opt_collect_slot(ek_opt) == -1 &&
+ ek_adapter_opt_collect_count(ek_opt) == -1 &&
+ (ek_adapter_opt_collect_type(ek_opt) == dest ||
+ ek_adapter_opt_collect_type(ek_opt) == T_INT && is_subword_type(dest)),
+ "");
+
+ if (dest == T_OBJECT && elem_slots == 1 && OptimizeMethodHandles) {
+ // filter operation on a ref
+ ek_try = EntryKind(_adapter_opt_filter_S0_ref + argslot);
+ if (ek_try < _adapter_opt_collect_LAST &&
+ ek_adapter_opt_collect_slot(ek_try) == argslot) {
+ assert(ek_adapter_opt_collect_count(ek_try) == elem_slots &&
+ ek_adapter_opt_collect_type(ek_try) == dest, "");
+ ek_opt = ek_try;
+ break;
+ }
+ ek_opt = _adapter_opt_collect_1_ref;
+ break;
+ }
+
+ if (dest == T_OBJECT && elem_slots == 2 && OptimizeMethodHandles) {
+ // filter of two arguments
+ ek_try = EntryKind(_adapter_opt_collect_2_S0_ref + argslot);
+ if (ek_try < _adapter_opt_collect_LAST &&
+ ek_adapter_opt_collect_slot(ek_try) == argslot) {
+ assert(ek_adapter_opt_collect_count(ek_try) == elem_slots &&
+ ek_adapter_opt_collect_type(ek_try) == dest, "");
+ ek_opt = ek_try;
+ break;
+ }
+ ek_opt = _adapter_opt_collect_2_ref;
+ break;
+ }
+
+ if (dest == T_OBJECT && OptimizeMethodHandles) {
+ // try to use a fixed length adapter
+ ek_try = EntryKind(_adapter_opt_collect_0_ref + elem_slots);
+ if (ek_try < _adapter_opt_collect_LAST &&
+ ek_adapter_opt_collect_count(ek_try) == elem_slots) {
+ assert(ek_adapter_opt_collect_slot(ek_try) == -1 &&
+ ek_adapter_opt_collect_type(ek_try) == dest, "");
+ ek_opt = ek_try;
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case _adapter_fold_args:
+ {
+ assert(UseRicochetFrames, "else don't come here");
+ int elem_slots = argument_slot_count(
+ java_lang_invoke_MethodHandle::type(
+ java_lang_invoke_AdapterMethodHandle::argument(mh()) ) );
+ // vminfo will be the location to insert the return value
+ vminfo = argslot + elem_slots;
+ ensure_vmlayout_field(target, CHECK);
+
+ switch (dest) {
+ default : if (!is_subword_type(dest)) goto throw_not_impl;
+ // else fall through:
+ case T_INT : ek_opt = _adapter_opt_fold_int; break;
+ case T_LONG : ek_opt = _adapter_opt_fold_long; break;
+ case T_FLOAT : ek_opt = _adapter_opt_fold_float; break;
+ case T_DOUBLE : ek_opt = _adapter_opt_fold_double; break;
+ case T_OBJECT : ek_opt = _adapter_opt_fold_ref; break;
+ case T_VOID : ek_opt = _adapter_opt_fold_void; break;
+ }
+ assert(ek_adapter_opt_collect_slot(ek_opt) == -1 &&
+ ek_adapter_opt_collect_count(ek_opt) == -1 &&
+ (ek_adapter_opt_collect_type(ek_opt) == dest ||
+ ek_adapter_opt_collect_type(ek_opt) == T_INT && is_subword_type(dest)),
+ "");
+
+ if (dest == T_OBJECT && elem_slots == 0 && OptimizeMethodHandles) {
+ // if there are no args, just pretend it's a collect
+ ek_opt = _adapter_opt_collect_0_ref;
+ break;
+ }
+
+ if (dest == T_OBJECT && OptimizeMethodHandles) {
+ // try to use a fixed length adapter
+ ek_try = EntryKind(_adapter_opt_fold_1_ref - 1 + elem_slots);
+ if (ek_try < _adapter_opt_fold_LAST &&
+ ek_adapter_opt_collect_count(ek_try) == elem_slots) {
+ assert(ek_adapter_opt_collect_slot(ek_try) == -1 &&
+ ek_adapter_opt_collect_type(ek_try) == dest, "");
+ ek_opt = ek_try;
+ break;
+ }
+ }
+
+ break;
+ }
default:
// should have failed much earlier; must be a missing case here
@@ -2166,11 +2522,20 @@
// and fall through:
throw_not_impl:
- // FIXME: these adapters are NYI
- err = "adapter not yet implemented in the JVM";
+ if (err == NULL)
+ err = "unknown adapter type";
break;
}
+ if (err != NULL && (vminfo & CONV_VMINFO_MASK) != vminfo) {
+ // should not happen, since vminfo is used to encode arg/slot indexes < 255
+ err = "vminfo overflow";
+ }
+
+ if (err != NULL && !have_entry(ek_opt)) {
+ err = "adapter stub for this kind of method handle is missing";
+ }
+
if (err != NULL) {
throw_InternalError_for_bad_conversion(conversion, err, THREAD);
return;
@@ -2190,6 +2555,26 @@
// Java code can publish it in global data structures.
}
+void MethodHandles::ensure_vmlayout_field(Handle target, TRAPS) {
+ Handle mtype(THREAD, java_lang_invoke_MethodHandle::type(target()));
+ Handle mtform(THREAD, java_lang_invoke_MethodType::form(mtype()));
+ if (mtform.is_null()) { THROW(vmSymbols::java_lang_InternalError()); }
+ if (java_lang_invoke_MethodTypeForm::vmlayout_offset_in_bytes() > 0) {
+ if (java_lang_invoke_MethodTypeForm::vmlayout(mtform()) == NULL) {
+ // fill it in
+ Handle erased_mtype(THREAD, java_lang_invoke_MethodTypeForm::erasedType(mtform()));
+ TempNewSymbol erased_signature
+ = java_lang_invoke_MethodType::as_signature(erased_mtype(), /*intern:*/true, CHECK);
+ methodOop cookie
+ = SystemDictionary::find_method_handle_invoke(vmSymbols::invokeExact_name(),
+ erased_signature,
+ SystemDictionaryHandles::Object_klass(),
+ THREAD);
+ java_lang_invoke_MethodTypeForm::init_vmlayout(mtform(), cookie);
+ }
+ }
+}
+
//
// Here are the native methods on sun.invoke.MethodHandleImpl.
// They are the private interface between this JVM and the HotSpot-specific
@@ -2360,8 +2745,10 @@
#ifndef PRODUCT
#define EACH_NAMED_CON(template) \
- template(MethodHandles,GC_JVM_PUSH_LIMIT) \
- template(MethodHandles,GC_JVM_STACK_MOVE_UNIT) \
+ /* hold back this one until JDK stabilizes */ \
+ /* template(MethodHandles,GC_JVM_PUSH_LIMIT) */ \
+ /* hold back this one until JDK stabilizes */ \
+ /* template(MethodHandles,GC_JVM_STACK_MOVE_UNIT) */ \
template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \
template(MethodHandles,ETF_DIRECT_HANDLE) \
template(MethodHandles,ETF_METHOD_NAME) \
@@ -2385,9 +2772,8 @@
template(java_lang_invoke_AdapterMethodHandle,OP_DROP_ARGS) \
template(java_lang_invoke_AdapterMethodHandle,OP_COLLECT_ARGS) \
template(java_lang_invoke_AdapterMethodHandle,OP_SPREAD_ARGS) \
- template(java_lang_invoke_AdapterMethodHandle,OP_FLYBY) \
- template(java_lang_invoke_AdapterMethodHandle,OP_RICOCHET) \
- template(java_lang_invoke_AdapterMethodHandle,CONV_OP_LIMIT) \
+ /* hold back this one until JDK stabilizes */ \
+ /*template(java_lang_invoke_AdapterMethodHandle,CONV_OP_LIMIT)*/ \
template(java_lang_invoke_AdapterMethodHandle,CONV_OP_MASK) \
template(java_lang_invoke_AdapterMethodHandle,CONV_VMINFO_MASK) \
template(java_lang_invoke_AdapterMethodHandle,CONV_VMINFO_SHIFT) \