hotspot/src/share/vm/prims/methodHandleWalk.cpp
changeset 4567 7fc02fbe5c7a
parent 4562 5d93cb2d2090
child 4571 80b553bddc26
--- a/hotspot/src/share/vm/prims/methodHandleWalk.cpp	Tue Jan 05 13:05:58 2010 +0100
+++ b/hotspot/src/share/vm/prims/methodHandleWalk.cpp	Tue Jan 05 15:21:25 2010 +0100
@@ -29,6 +29,10 @@
 #include "incls/_precompiled.incl"
 #include "incls/_methodHandleWalk.cpp.incl"
 
+
+// -----------------------------------------------------------------------------
+// MethodHandleChain
+
 void MethodHandleChain::set_method_handle(Handle mh, TRAPS) {
   if (!java_dyn_MethodHandle::is_instance(mh()))  lose("bad method handle", CHECK);
 
@@ -58,7 +62,8 @@
     if (!is_bound() || java_dyn_MethodHandle::is_instance(target)) {
       _arg_type = compute_bound_arg_type(target, NULL, _arg_slot, CHECK);
     } else if (target != NULL && target->is_method()) {
-      _arg_type = compute_bound_arg_type(NULL, (methodOop)target, _arg_slot, CHECK);
+      methodOop m = (methodOop) target;
+      _arg_type = compute_bound_arg_type(NULL, m, _arg_slot, CHECK);
       set_last_method(mh(), CHECK);
     } else {
       _is_bound = false;  // lose!
@@ -72,6 +77,7 @@
   }
 }
 
+
 void MethodHandleChain::set_last_method(oop target, TRAPS) {
   _is_last = true;
   klassOop receiver_limit_oop = NULL;
@@ -88,6 +94,7 @@
     _last_invoke = Bytecodes::_invokevirtual;
 }
 
+
 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.
@@ -126,7 +133,9 @@
   return arg_type;
 }
 
+
 void MethodHandleChain::lose(const char* msg, TRAPS) {
+  assert(false, "lose");
   _lose_message = msg;
   if (!THREAD->is_Java_thread() || ((JavaThread*)THREAD)->thread_state() != _thread_in_vm) {
     // throw a preallocated exception
@@ -135,6 +144,10 @@
   THROW_MSG(vmSymbols::java_lang_InternalError(), msg);
 }
 
+
+// -----------------------------------------------------------------------------
+// MethodHandleWalker
+
 Bytecodes::Code MethodHandleWalker::conversion_code(BasicType src, BasicType dest) {
   if (is_subword_type(src)) {
     src = T_INT;          // all subword src types act like int
@@ -170,9 +183,15 @@
   return Bytecodes::_illegal;
 }
 
+
+// -----------------------------------------------------------------------------
+// MethodHandleWalker::walk
+//
 MethodHandleWalker::ArgToken
 MethodHandleWalker::walk(TRAPS) {
-  walk_incoming_state(CHECK_NULL);
+  ArgToken empty = ArgToken();  // Empty return value.
+
+  walk_incoming_state(CHECK_(empty));
 
   for (;;) {
     set_method_handle(chain().method_handle_oop());
@@ -185,26 +204,77 @@
       SlotState* arg_state = slot_state(arg_slot);
       if (arg_state == NULL
           && conv_op > sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW) {
-        lose("bad argument index", CHECK_NULL);
+        lose("bad argument index", CHECK_(empty));
       }
 
       // perform the adapter action
       switch (chain().adapter_conversion_op()) {
       case sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY:
-      case sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW:
         // No changes to arguments; pass the bits through.
-        // The only difference between the two ops is that the "only" version
-        // is fully compatible with the verifier, while the "raw" version
-        // performs a few extra bitwise conversions (like long <-> double).
         break;
 
+      case sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW: {
+        // To keep the verifier happy, emit bitwise ("raw") conversions as needed.
+        // See MethodHandles::same_basic_type_for_arguments for allowed conversions.
+        Handle incoming_mtype(THREAD, chain().method_type_oop());
+        oop outgoing_mh_oop = chain().vmtarget_oop();
+        if (!java_dyn_MethodHandle::is_instance(outgoing_mh_oop))
+          lose("outgoing target not a MethodHandle", CHECK_(empty));
+        Handle outgoing_mtype(THREAD, java_dyn_MethodHandle::type(outgoing_mh_oop));
+        outgoing_mh_oop = NULL;  // GC safety
+
+        int nptypes = java_dyn_MethodType::ptype_count(outgoing_mtype());
+        if (nptypes != java_dyn_MethodType::ptype_count(incoming_mtype()))
+          lose("incoming and outgoing parameter count do not agree", CHECK_(empty));
+
+        for (int i = 0, slot = _outgoing.length() - 1; slot >= 0; slot--) {
+          SlotState* arg_state = slot_state(slot);
+          if (arg_state->_type == T_VOID)  continue;
+          ArgToken arg = _outgoing.at(slot)._arg;
+
+          klassOop  in_klass  = NULL;
+          klassOop  out_klass = NULL;
+          BasicType inpbt  = java_lang_Class::as_BasicType(java_dyn_MethodType::ptype(incoming_mtype(), i), &in_klass);
+          BasicType outpbt = java_lang_Class::as_BasicType(java_dyn_MethodType::ptype(outgoing_mtype(), i), &out_klass);
+          assert(inpbt == arg.basic_type(), "sanity");
+
+          if (inpbt != outpbt) {
+            vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(inpbt, outpbt);
+            if (iid == vmIntrinsics::_none) {
+              lose("no raw conversion method", CHECK_(empty));
+            }
+            ArgToken arglist[2];
+            arglist[0] = arg;         // outgoing 'this'
+            arglist[1] = ArgToken();  // sentinel
+            arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty));
+            change_argument(inpbt, slot, outpbt, arg);
+          }
+
+          i++;  // We need to skip void slots at the top of the loop.
+        }
+
+        BasicType inrbt  = java_lang_Class::as_BasicType(java_dyn_MethodType::rtype(incoming_mtype()));
+        BasicType outrbt = java_lang_Class::as_BasicType(java_dyn_MethodType::rtype(outgoing_mtype()));
+        if (inrbt != outrbt) {
+          if (inrbt == T_INT && outrbt == T_VOID) {
+            // See comments in MethodHandles::same_basic_type_for_arguments.
+          } else {
+            assert(false, "IMPLEMENT ME");
+            lose("no raw conversion method", CHECK_(empty));
+          }
+        }
+        break;
+      }
+
       case sun_dyn_AdapterMethodHandle::OP_CHECK_CAST: {
         // checkcast the Nth outgoing argument in place
         klassOop dest_klass = NULL;
         BasicType dest = java_lang_Class::as_BasicType(chain().adapter_arg_oop(), &dest_klass);
         assert(dest == T_OBJECT, "");
         assert(dest == arg_state->_type, "");
-        arg_state->_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg_state->_arg, CHECK_NULL);
+        ArgToken arg = arg_state->_arg;
+        ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty));
+        assert(arg.index() == new_arg.index(), "should be the same index");
         debug_only(dest_klass = (klassOop)badOop);
         break;
       }
@@ -218,17 +288,17 @@
         if (bc == Bytecodes::_nop) {
           break;
         } else if (bc != Bytecodes::_illegal) {
-          arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL);
+          arg = make_conversion(dest, NULL, bc, arg, CHECK_(empty));
         } else if (is_subword_type(dest)) {
           bc = conversion_code(src, T_INT);
           if (bc != Bytecodes::_illegal) {
-            arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL);
+            arg = make_conversion(dest, NULL, bc, arg, CHECK_(empty));
             bc = conversion_code(T_INT, dest);
-            arg = make_conversion(dest, NULL, bc, arg, CHECK_NULL);
+            arg = make_conversion(dest, NULL, bc, arg, CHECK_(empty));
           }
         }
         if (bc == Bytecodes::_illegal) {
-          lose("bad primitive conversion", CHECK_NULL);
+          lose("bad primitive conversion", CHECK_(empty));
         }
         change_argument(src, arg_slot, dest, arg);
         break;
@@ -239,15 +309,15 @@
         BasicType dest = chain().adapter_conversion_dest_type();
         ArgToken arg = arg_state->_arg;
         arg = make_conversion(T_OBJECT, SystemDictionary::box_klass(dest),
-                              Bytecodes::_checkcast, arg, CHECK_NULL);
+                              Bytecodes::_checkcast, arg, CHECK_(empty));
         vmIntrinsics::ID unboxer = vmIntrinsics::for_unboxing(dest);
         if (unboxer == vmIntrinsics::_none) {
-          lose("no unboxing method", CHECK_NULL);
+          lose("no unboxing method", CHECK_(empty));
         }
         ArgToken arglist[2];
-        arglist[0] = arg;       // outgoing 'this'
-        arglist[1] = NULL;      // sentinel
-        arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_NULL);
+        arglist[0] = arg;         // outgoing 'this'
+        arglist[1] = ArgToken();  // sentinel
+        arg = make_invoke(NULL, unboxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty));
         change_argument(T_OBJECT, arg_slot, dest, arg);
         break;
       }
@@ -258,12 +328,13 @@
         ArgToken arg = arg_state->_arg;
         vmIntrinsics::ID boxer = vmIntrinsics::for_boxing(src);
         if (boxer == vmIntrinsics::_none) {
-          lose("no boxing method", CHECK_NULL);
+          lose("no boxing method", CHECK_(empty));
         }
         ArgToken arglist[2];
-        arglist[0] = arg;       // outgoing value
-        arglist[1] = NULL;      // sentinel
-        arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_NULL);
+        arglist[0] = arg;         // outgoing value
+        arglist[1] = ArgToken();  // sentinel
+        assert(false, "I think the argument count must be 1 instead of 0");
+        arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 0, &arglist[0], CHECK_(empty));
         change_argument(src, arg_slot, T_OBJECT, arg);
         break;
       }
@@ -271,7 +342,7 @@
       case sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS: {
         int dest_arg_slot = chain().adapter_conversion_vminfo();
         if (!slot_has_argument(dest_arg_slot)) {
-          lose("bad swap index", CHECK_NULL);
+          lose("bad swap index", CHECK_(empty));
         }
         // a simple swap between two arguments
         SlotState* dest_arg_state = slot_state(dest_arg_slot);
@@ -284,7 +355,7 @@
       case sun_dyn_AdapterMethodHandle::OP_ROT_ARGS: {
         int dest_arg_slot = chain().adapter_conversion_vminfo();
         if (!slot_has_argument(dest_arg_slot) || arg_slot == dest_arg_slot) {
-          lose("bad rotate index", CHECK_NULL);
+          lose("bad rotate index", CHECK_(empty));
         }
         SlotState* dest_arg_state = slot_state(dest_arg_slot);
         // Rotate the source argument (plus following N slots) into the
@@ -310,7 +381,7 @@
       case sun_dyn_AdapterMethodHandle::OP_DUP_ARGS: {
         int dup_slots = chain().adapter_conversion_stack_pushes();
         if (dup_slots <= 0) {
-          lose("bad dup count", CHECK_NULL);
+          lose("bad dup count", CHECK_(empty));
         }
         for (int i = 0; i < dup_slots; i++) {
           SlotState* dup = slot_state(arg_slot + 2*i);
@@ -324,7 +395,7 @@
       case sun_dyn_AdapterMethodHandle::OP_DROP_ARGS: {
         int drop_slots = -chain().adapter_conversion_stack_pushes();
         if (drop_slots <= 0) {
-          lose("bad drop count", CHECK_NULL);
+          lose("bad drop count", CHECK_(empty));
         }
         for (int i = 0; i < drop_slots; i++) {
           SlotState* drop = slot_state(arg_slot);
@@ -336,7 +407,7 @@
       }
 
       case sun_dyn_AdapterMethodHandle::OP_COLLECT_ARGS: { //NYI, may GC
-        lose("unimplemented", CHECK_NULL);
+        lose("unimplemented", CHECK_(empty));
         break;
       }
 
@@ -358,8 +429,8 @@
         // Fetch the argument, which we will cast to the required array type.
         assert(arg_state->_type == T_OBJECT, "");
         ArgToken array_arg = arg_state->_arg;
-        array_arg = make_conversion(T_OBJECT, array_klass(), Bytecodes::_checkcast, array_arg, CHECK_NULL);
-        change_argument(T_OBJECT, arg_slot, T_VOID, NULL);
+        array_arg = make_conversion(T_OBJECT, array_klass(), Bytecodes::_checkcast, array_arg, CHECK_(empty));
+        change_argument(T_OBJECT, arg_slot, T_VOID, ArgToken(tt_void));
 
         // Check the required length.
         int spread_slots = 1 + chain().adapter_conversion_stack_pushes();
@@ -369,29 +440,29 @@
           spread_length = spread_slots / 2;
         }
         if (spread_slots < 0) {
-          lose("bad spread length", CHECK_NULL);
+          lose("bad spread length", CHECK_(empty));
         }
 
         jvalue   length_jvalue;  length_jvalue.i = spread_length;
-        ArgToken length_arg = make_prim_constant(T_INT, &length_jvalue, CHECK_NULL);
+        ArgToken length_arg = make_prim_constant(T_INT, &length_jvalue, CHECK_(empty));
         // Call a built-in method known to the JVM to validate the length.
         ArgToken arglist[3];
-        arglist[0] = array_arg;  // value to check
-        arglist[1] = length_arg; // length to check
-        arglist[2] = NULL;       // sentinel
+        arglist[0] = array_arg;   // value to check
+        arglist[1] = length_arg;  // length to check
+        arglist[2] = ArgToken();  // sentinel
         make_invoke(NULL, vmIntrinsics::_checkSpreadArgument,
-                    Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_NULL);
+                    Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_(empty));
 
         // Spread out the array elements.
         Bytecodes::Code aload_op = Bytecodes::_aaload;
         if (element_type != T_OBJECT) {
-          lose("primitive array NYI", CHECK_NULL);
+          lose("primitive array NYI", CHECK_(empty));
         }
         int ap = arg_slot;
         for (int i = 0; i < spread_length; i++) {
           jvalue   offset_jvalue;  offset_jvalue.i = i;
-          ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_NULL);
-          ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_NULL);
+          ArgToken offset_arg = make_prim_constant(T_INT, &offset_jvalue, CHECK_(empty));
+          ArgToken element_arg = make_fetch(element_type, element_klass(), aload_op, array_arg, offset_arg, CHECK_(empty));
           change_argument(T_VOID, ap, element_type, element_arg);
           ap += type2size[element_type];
         }
@@ -400,11 +471,11 @@
 
       case sun_dyn_AdapterMethodHandle::OP_FLYBY: //NYI, runs Java code
       case sun_dyn_AdapterMethodHandle::OP_RICOCHET: //NYI, runs Java code
-        lose("unimplemented", CHECK_NULL);
+        lose("unimplemented", CHECK_(empty));
         break;
 
       default:
-        lose("bad adapter conversion", CHECK_NULL);
+        lose("bad adapter conversion", CHECK_(empty));
         break;
       }
     }
@@ -414,16 +485,16 @@
       BasicType arg_type  = chain().bound_arg_type();
       jint      arg_slot  = chain().bound_arg_slot();
       oop       arg_oop   = chain().bound_arg_oop();
-      ArgToken  arg       = NULL;
+      ArgToken  arg;
       if (arg_type == T_OBJECT) {
-        arg = make_oop_constant(arg_oop, CHECK_NULL);
+        arg = make_oop_constant(arg_oop, CHECK_(empty));
       } else {
         jvalue arg_value;
         BasicType bt = java_lang_boxing_object::get_value(arg_oop, &arg_value);
         if (bt == arg_type) {
-          arg = make_prim_constant(arg_type, &arg_value, CHECK_NULL);
+          arg = make_prim_constant(arg_type, &arg_value, CHECK_(empty));
         } else {
-          lose("bad bound value", CHECK_NULL);
+          lose("bad bound value", CHECK_(empty));
         }
       }
       debug_only(arg_oop = badOop);
@@ -432,7 +503,7 @@
 
     // this test must come after the body of the loop
     if (!chain().is_last()) {
-      chain().next(CHECK_NULL);
+      chain().next(CHECK_(empty));
     } else {
       break;
     }
@@ -448,31 +519,36 @@
     arglist[ap++] = _outgoing.at(i)._arg;
   }
   assert(ap == _outgoing_argc, "");
-  arglist[ap] = NULL; // add a sentinel, for the sake of asserts
+  arglist[ap] = ArgToken();  // add a sentinel, for the sake of asserts
   return make_invoke(chain().last_method_oop(),
                      vmIntrinsics::_none,
                      chain().last_invoke_code(), true,
                      ap, arglist, THREAD);
 }
 
+
+// -----------------------------------------------------------------------------
+// MethodHandleWalker::walk_incoming_state
+//
 void MethodHandleWalker::walk_incoming_state(TRAPS) {
   Handle mtype(THREAD, chain().method_type_oop());
   int nptypes = java_dyn_MethodType::ptype_count(mtype());
   _outgoing_argc = nptypes;
   int argp = nptypes - 1;
   if (argp >= 0) {
-    _outgoing.at_grow(argp, make_state(T_VOID, NULL)); // presize
+    _outgoing.at_grow(argp, make_state(T_VOID, ArgToken(tt_void))); // presize
   }
   for (int i = 0; i < nptypes; i++) {
     klassOop  arg_type_klass = NULL;
     BasicType arg_type = java_lang_Class::as_BasicType(
                 java_dyn_MethodType::ptype(mtype(), i), &arg_type_klass);
-    ArgToken  arg = make_parameter(arg_type, arg_type_klass, i, CHECK);
-    debug_only(arg_type_klass = (klassOop)NULL);
+    int index = new_local_index(arg_type);
+    ArgToken arg = make_parameter(arg_type, arg_type_klass, index, CHECK);
+    debug_only(arg_type_klass = (klassOop) NULL);
     _outgoing.at_put(argp, make_state(arg_type, arg));
     if (type2size[arg_type] == 2) {
       // add the extra slot, so we can model the JVM stack
-      _outgoing.insert_before(argp+1, make_state(T_VOID, NULL));
+      _outgoing.insert_before(argp+1, make_state(T_VOID, ArgToken(tt_void)));
     }
     --argp;
   }
@@ -484,17 +560,21 @@
   // ignore ret; client can catch it if needed
 }
 
-// this is messy because some kinds of arguments are paired with
-// companion slots containing an empty value
+
+// -----------------------------------------------------------------------------
+// MethodHandleWalker::change_argument
+//
+// This is messy because some kinds of arguments are paired with
+// companion slots containing an empty value.
 void MethodHandleWalker::change_argument(BasicType old_type, int slot, BasicType new_type,
-                                         MethodHandleWalker::ArgToken new_arg) {
+                                         const ArgToken& new_arg) {
   int old_size = type2size[old_type];
   int new_size = type2size[new_type];
   if (old_size == new_size) {
     // simple case first
     _outgoing.at_put(slot, make_state(new_type, new_arg));
   } else if (old_size > new_size) {
-    for (int i = old_size-1; i >= new_size; i++) {
+    for (int i = old_size - 1; i >= new_size; i--) {
       assert((i != 0) == (_outgoing.at(slot + i)._type == T_VOID), "");
       _outgoing.remove_at(slot + i);
     }
@@ -504,7 +584,7 @@
       _outgoing_argc -= 1;      // deleted a real argument
   } else {
     for (int i = old_size; i < new_size; i++) {
-      _outgoing.insert_before(slot+i, make_state(T_VOID, NULL));
+      _outgoing.insert_before(slot + i, make_state(T_VOID, ArgToken(tt_void)));
     }
     _outgoing.at_put(slot, make_state(new_type, new_arg));
     if (old_size == 0)
@@ -526,72 +606,485 @@
 #endif
 
 
-void MethodHandleCompiler::compile(TRAPS) {
+// -----------------------------------------------------------------------------
+// MethodHandleCompiler
+
+MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, bool is_invokedynamic, TRAPS)
+  : MethodHandleWalker(root, is_invokedynamic, THREAD),
+    _callee(callee),
+    _thread(THREAD),
+    _bytecode(THREAD, 50),
+    _constants(THREAD, 10),
+    _cur_stack(0),
+    _max_stack(0),
+    _rtype(T_ILLEGAL)
+{
+
+  // Element zero is always the null constant.
+  (void) _constants.append(NULL);
+
+  // Set name and signature index.
+  _name_index      = cpool_symbol_put(_callee->name());
+  _signature_index = cpool_symbol_put(_callee->signature());
+
+  // Get return type klass.
+  Handle first_mtype(THREAD, chain().method_type_oop());
+  // _rklass is NULL for primitives.
+  _rtype = java_lang_Class::as_BasicType(java_dyn_MethodType::rtype(first_mtype()), &_rklass);
+
+  int params = _callee->size_of_parameters();  // Incoming arguments plus receiver.
+  _num_params = for_invokedynamic() ? params - 1 : params;  // XXX Check if callee is static?
+}
+
+
+// -----------------------------------------------------------------------------
+// MethodHandleCompiler::compile
+//
+// Compile this MethodHandle into a bytecode adapter and return a
+// methodOop.
+methodHandle MethodHandleCompiler::compile(TRAPS) {
   assert(_thread == THREAD, "must be same thread");
+  methodHandle nullHandle;
+  (void) walk(CHECK_(nullHandle));
+  return get_method_oop(CHECK_(nullHandle));
+}
+
+
+void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
+  Bytecodes::check(op);  // Are we legal?
+
+  switch (op) {
+  // b
+  case Bytecodes::_aconst_null:
+  case Bytecodes::_iconst_m1:
+  case Bytecodes::_iconst_0:
+  case Bytecodes::_iconst_1:
+  case Bytecodes::_iconst_2:
+  case Bytecodes::_iconst_3:
+  case Bytecodes::_iconst_4:
+  case Bytecodes::_iconst_5:
+  case Bytecodes::_lconst_0:
+  case Bytecodes::_lconst_1:
+  case Bytecodes::_fconst_0:
+  case Bytecodes::_fconst_1:
+  case Bytecodes::_fconst_2:
+  case Bytecodes::_dconst_0:
+  case Bytecodes::_dconst_1:
+  case Bytecodes::_iload_0:
+  case Bytecodes::_iload_1:
+  case Bytecodes::_iload_2:
+  case Bytecodes::_iload_3:
+  case Bytecodes::_lload_0:
+  case Bytecodes::_lload_1:
+  case Bytecodes::_lload_2:
+  case Bytecodes::_lload_3:
+  case Bytecodes::_fload_0:
+  case Bytecodes::_fload_1:
+  case Bytecodes::_fload_2:
+  case Bytecodes::_fload_3:
+  case Bytecodes::_dload_0:
+  case Bytecodes::_dload_1:
+  case Bytecodes::_dload_2:
+  case Bytecodes::_dload_3:
+  case Bytecodes::_aload_0:
+  case Bytecodes::_aload_1:
+  case Bytecodes::_aload_2:
+  case Bytecodes::_aload_3:
+  case Bytecodes::_istore_0:
+  case Bytecodes::_istore_1:
+  case Bytecodes::_istore_2:
+  case Bytecodes::_istore_3:
+  case Bytecodes::_lstore_0:
+  case Bytecodes::_lstore_1:
+  case Bytecodes::_lstore_2:
+  case Bytecodes::_lstore_3:
+  case Bytecodes::_fstore_0:
+  case Bytecodes::_fstore_1:
+  case Bytecodes::_fstore_2:
+  case Bytecodes::_fstore_3:
+  case Bytecodes::_dstore_0:
+  case Bytecodes::_dstore_1:
+  case Bytecodes::_dstore_2:
+  case Bytecodes::_dstore_3:
+  case Bytecodes::_astore_0:
+  case Bytecodes::_astore_1:
+  case Bytecodes::_astore_2:
+  case Bytecodes::_astore_3:
+  case Bytecodes::_i2l:
+  case Bytecodes::_i2f:
+  case Bytecodes::_i2d:
+  case Bytecodes::_i2b:
+  case Bytecodes::_i2c:
+  case Bytecodes::_i2s:
+  case Bytecodes::_l2i:
+  case Bytecodes::_l2f:
+  case Bytecodes::_l2d:
+  case Bytecodes::_f2i:
+  case Bytecodes::_f2l:
+  case Bytecodes::_f2d:
+  case Bytecodes::_d2i:
+  case Bytecodes::_d2l:
+  case Bytecodes::_d2f:
+  case Bytecodes::_ireturn:
+  case Bytecodes::_lreturn:
+  case Bytecodes::_freturn:
+  case Bytecodes::_dreturn:
+  case Bytecodes::_areturn:
+  case Bytecodes::_return:
+    assert(strcmp(Bytecodes::format(op), "b") == 0, "wrong bytecode format");
+    _bytecode.push(op);
+    break;
 
-  _constant_oops.append(Handle());  // element zero is always the null constant
-  _constant_prims.append(NULL);
-  {
-    symbolOop sig
-      = java_dyn_MethodType::as_signature(chain().method_type_oop(), true, CHECK);
-    _signature_index = find_oop_constant(sig);
-    assert(signature() == sig, "");
+  // bi
+  case Bytecodes::_ldc:
+  case Bytecodes::_iload:
+  case Bytecodes::_lload:
+  case Bytecodes::_fload:
+  case Bytecodes::_dload:
+  case Bytecodes::_aload:
+  case Bytecodes::_istore:
+  case Bytecodes::_lstore:
+  case Bytecodes::_fstore:
+  case Bytecodes::_dstore:
+  case Bytecodes::_astore:
+    assert(strcmp(Bytecodes::format(op), "bi") == 0, "wrong bytecode format");
+    assert((char) index == index, "index does not fit in 8-bit");
+    _bytecode.push(op);
+    _bytecode.push(index);
+    break;
+
+  // bii
+  case Bytecodes::_ldc2_w:
+  case Bytecodes::_checkcast:
+    assert(strcmp(Bytecodes::format(op), "bii") == 0, "wrong bytecode format");
+    assert((short) index == index, "index does not fit in 16-bit");
+    _bytecode.push(op);
+    _bytecode.push(index >> 8);
+    _bytecode.push(index);
+    break;
+
+  // bjj
+  case Bytecodes::_invokestatic:
+  case Bytecodes::_invokespecial:
+  case Bytecodes::_invokevirtual:
+    assert(strcmp(Bytecodes::format(op), "bjj") == 0, "wrong bytecode format");
+    assert((short) index == index, "index does not fit in 16-bit");
+    _bytecode.push(op);
+    _bytecode.push(index >> 8);
+    _bytecode.push(index);
+    break;
+
+  default:
+    ShouldNotReachHere();
+  }
+}
+
+
+void MethodHandleCompiler::emit_load(BasicType bt, int index) {
+  if (index <= 3) {
+    switch (bt) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
+    case T_INT:    emit_bc(Bytecodes::cast(Bytecodes::_iload_0 + index)); break;
+    case T_LONG:   emit_bc(Bytecodes::cast(Bytecodes::_lload_0 + index)); break;
+    case T_FLOAT:  emit_bc(Bytecodes::cast(Bytecodes::_fload_0 + index)); break;
+    case T_DOUBLE: emit_bc(Bytecodes::cast(Bytecodes::_dload_0 + index)); break;
+    case T_OBJECT: emit_bc(Bytecodes::cast(Bytecodes::_aload_0 + index)); break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  else {
+    switch (bt) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
+    case T_INT:    emit_bc(Bytecodes::_iload, index); break;
+    case T_LONG:   emit_bc(Bytecodes::_lload, index); break;
+    case T_FLOAT:  emit_bc(Bytecodes::_fload, index); break;
+    case T_DOUBLE: emit_bc(Bytecodes::_dload, index); break;
+    case T_OBJECT: emit_bc(Bytecodes::_aload, index); break;
+    default:
+      ShouldNotReachHere();
+    }
   }
+  stack_push(bt);
+}
 
-  walk(CHECK);
+void MethodHandleCompiler::emit_store(BasicType bt, int index) {
+  if (index <= 3) {
+    switch (bt) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
+    case T_INT:    emit_bc(Bytecodes::cast(Bytecodes::_istore_0 + index)); break;
+    case T_LONG:   emit_bc(Bytecodes::cast(Bytecodes::_lstore_0 + index)); break;
+    case T_FLOAT:  emit_bc(Bytecodes::cast(Bytecodes::_fstore_0 + index)); break;
+    case T_DOUBLE: emit_bc(Bytecodes::cast(Bytecodes::_dstore_0 + index)); break;
+    case T_OBJECT: emit_bc(Bytecodes::cast(Bytecodes::_astore_0 + index)); break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  else {
+    switch (bt) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
+    case T_INT:    emit_bc(Bytecodes::_istore, index); break;
+    case T_LONG:   emit_bc(Bytecodes::_lstore, index); break;
+    case T_FLOAT:  emit_bc(Bytecodes::_fstore, index); break;
+    case T_DOUBLE: emit_bc(Bytecodes::_dstore, index); break;
+    case T_OBJECT: emit_bc(Bytecodes::_astore, index); break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+  stack_pop(bt);
 }
 
+
+void MethodHandleCompiler::emit_load_constant(ArgToken arg) {
+  BasicType bt = arg.basic_type();
+  switch (bt) {
+  case T_INT: {
+    jint value = arg.get_jint();
+    if (-1 <= value && value <= 5)
+      emit_bc(Bytecodes::cast(Bytecodes::_iconst_0 + value));
+    else
+      emit_bc(Bytecodes::_ldc, cpool_int_put(value));
+    break;
+  }
+  case T_LONG: {
+    jlong value = arg.get_jlong();
+    if (0 <= value && value <= 1)
+      emit_bc(Bytecodes::cast(Bytecodes::_lconst_0 + (int) value));
+    else
+      emit_bc(Bytecodes::_ldc2_w, cpool_long_put(value));
+    break;
+  }
+  case T_FLOAT: {
+    jfloat value  = arg.get_jfloat();
+    if (value == 0.0 || value == 1.0 || value == 2.0)
+      emit_bc(Bytecodes::cast(Bytecodes::_fconst_0 + (int) value));
+    else
+      emit_bc(Bytecodes::_ldc, cpool_float_put(value));
+    break;
+  }
+  case T_DOUBLE: {
+    jdouble value = arg.get_jdouble();
+    if (value == 0.0 || value == 1.0)
+      emit_bc(Bytecodes::cast(Bytecodes::_dconst_0 + (int) value));
+    else
+      emit_bc(Bytecodes::_ldc2_w, cpool_double_put(value));
+    break;
+  }
+  case T_OBJECT: {
+    Handle value = arg.object();
+    if (value.is_null())
+      emit_bc(Bytecodes::_aconst_null);
+    else
+      emit_bc(Bytecodes::_ldc, cpool_object_put(value));
+    break;
+  }
+  default:
+    ShouldNotReachHere();
+  }
+  stack_push(bt);
+}
+
+
 MethodHandleWalker::ArgToken
 MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Code op,
-                                      MethodHandleWalker::ArgToken src, TRAPS) {
-  Unimplemented();
-  return NULL;
+                                      const ArgToken& src, TRAPS) {
+
+  BasicType srctype = src.basic_type();
+  int index = src.index();
+
+  switch (op) {
+  case Bytecodes::_i2l:
+  case Bytecodes::_i2f:
+  case Bytecodes::_i2d:
+  case Bytecodes::_i2b:
+  case Bytecodes::_i2c:
+  case Bytecodes::_i2s:
+
+  case Bytecodes::_l2i:
+  case Bytecodes::_l2f:
+  case Bytecodes::_l2d:
+
+  case Bytecodes::_f2i:
+  case Bytecodes::_f2l:
+  case Bytecodes::_f2d:
+
+  case Bytecodes::_d2i:
+  case Bytecodes::_d2l:
+  case Bytecodes::_d2f:
+    emit_load(srctype, index);
+    stack_pop(srctype);  // pop the src type
+    emit_bc(op);
+    stack_push(type);    // push the dest value
+    if (srctype != type)
+      index = new_local_index(type);
+    emit_store(type, index);
+    break;
+
+  case Bytecodes::_checkcast:
+    emit_load(srctype, index);
+    emit_bc(op, cpool_klass_put(tk));
+    emit_store(srctype, index);
+    break;
+
+  default:
+    ShouldNotReachHere();
+  }
+
+  return make_parameter(type, tk, index, THREAD);
 }
 
+
+// -----------------------------------------------------------------------------
+// MethodHandleCompiler
+//
+
+static jvalue zero_jvalue;
+
+// Emit bytecodes for the given invoke instruction.
 MethodHandleWalker::ArgToken
 MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
                                   Bytecodes::Code op, bool tailcall,
                                   int argc, MethodHandleWalker::ArgToken* argv,
                                   TRAPS) {
-  // If tailcall, we have walked all the way to a direct method handle.
-  // Otherwise, make a recursive call to some helper routine.
-#ifdef ASSERT
+  if (m == NULL) {
+    // Get the intrinsic methodOop.
+    m = vmIntrinsics::method_for(iid);
+  }
+
+  klassOop  klass     = m->method_holder();
+  symbolOop name      = m->name();
+  symbolOop signature = m->signature();
+
+  // This generated adapter method should be in the same class as the
+  // DMH target method (for accessability reasons).
+  if (tailcall) {
+    _target_klass = klass;
+  }
+
+  // instanceKlass* ik = instanceKlass::cast(klass);
+  // tty->print_cr("MethodHandleCompiler::make_invoke: %s %s.%s%s", Bytecodes::name(op), ik->external_name(), name->as_C_string(), signature->as_C_string());
+
+  // Inline the method.
+  InvocationCounter* ic = m->invocation_counter();
+  ic->set_carry();
+
+  for (int i = 0; i < argc; i++) {
+    ArgToken arg = argv[i];
+    TokenType tt = arg.token_type();
+    BasicType bt = arg.basic_type();
+
+    switch (tt) {
+    case tt_parameter:
+    case tt_temporary:
+      emit_load(bt, arg.index());
+      break;
+    case tt_constant:
+      emit_load_constant(arg);
+      break;
+    case tt_illegal:
+      // Sentinel.
+      assert(i == (argc - 1), "sentinel must be last entry");
+      break;
+    case tt_void:
+    default:
+      ShouldNotReachHere();
+    }
+  }
+
+  // Populate constant pool.
+  int name_index          = cpool_symbol_put(name);
+  int signature_index     = cpool_symbol_put(signature);
+  int name_and_type_index = cpool_name_and_type_put(name_index, signature_index);
+  int klass_index         = cpool_klass_put(klass);
+  int methodref_index     = cpool_methodref_put(klass_index, name_and_type_index);
+
+  // Generate invoke.
   switch (op) {
-  case Bytecodes::_invokevirtual:
+  case Bytecodes::_invokestatic:
   case Bytecodes::_invokespecial:
-  case Bytecodes::_invokestatic:
+  case Bytecodes::_invokevirtual:
+    emit_bc(op, methodref_index);
+    break;
   case Bytecodes::_invokeinterface:
+    Unimplemented();
     break;
   default:
     ShouldNotReachHere();
   }
-#endif //ASSERT
-  _bytes.put((char) op);
 
-  Unimplemented();
-  return NULL;
+  // If tailcall, we have walked all the way to a direct method handle.
+  // Otherwise, make a recursive call to some helper routine.
+  BasicType rbt = m->result_type();
+  ArgToken ret;
+  if (tailcall) {
+    if (rbt != _rtype) {
+      if (rbt == T_VOID) {
+        // push a zero of the right sort
+        ArgToken zero;
+        if (_rtype == T_OBJECT) {
+          zero = make_oop_constant(NULL, CHECK_(zero));
+        } else {
+          zero = make_prim_constant(_rtype, &zero_jvalue, CHECK_(zero));
+        }
+        emit_load_constant(zero);
+      } else if (_rtype == T_VOID) {
+        // We'll emit a _return with something on the stack.
+        // It's OK to ignore what's on the stack.
+      } else {
+        tty->print_cr("*** rbt=%d != rtype=%d", rbt, _rtype);
+        assert(false, "IMPLEMENT ME");
+      }
+    }
+    switch (_rtype) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
+    case T_INT:    emit_bc(Bytecodes::_ireturn); break;
+    case T_LONG:   emit_bc(Bytecodes::_lreturn); break;
+    case T_FLOAT:  emit_bc(Bytecodes::_freturn); break;
+    case T_DOUBLE: emit_bc(Bytecodes::_dreturn); break;
+    case T_VOID:   emit_bc(Bytecodes::_return);  break;
+    case T_OBJECT:
+      if (_rklass.not_null() && _rklass() != SystemDictionary::object_klass())
+        emit_bc(Bytecodes::_checkcast, cpool_klass_put(_rklass()));
+      emit_bc(Bytecodes::_areturn);
+      break;
+    default: ShouldNotReachHere();
+    }
+    ret = ArgToken();  // Dummy return value.
+  }
+  else {
+    stack_push(rbt);  // The return value is already pushed onto the stack.
+    int index = new_local_index(rbt);
+    switch (rbt) {
+    case T_BOOLEAN: case T_BYTE: case T_CHAR:  case T_SHORT:
+    case T_INT:     case T_LONG: case T_FLOAT: case T_DOUBLE:
+    case T_OBJECT:
+      emit_store(rbt, index);
+      ret = ArgToken(tt_temporary, rbt, index);
+      break;
+    case T_VOID:
+      ret = ArgToken(tt_void);
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+  }
+
+  return ret;
 }
 
 MethodHandleWalker::ArgToken
 MethodHandleCompiler::make_fetch(BasicType type, klassOop tk, Bytecodes::Code op,
-                                 MethodHandleWalker::ArgToken base,
-                                 MethodHandleWalker::ArgToken offset,
+                                 const MethodHandleWalker::ArgToken& base,
+                                 const MethodHandleWalker::ArgToken& offset,
                                  TRAPS) {
   Unimplemented();
-  return NULL;
+  return ArgToken();
 }
 
-int MethodHandleCompiler::find_oop_constant(oop con) {
-  if (con == NULL)  return 0;
-  for (int i = 1, imax = _constant_oops.length(); i < imax; i++) {
-    if (_constant_oops.at(i) == con)
-      return i;
-  }
-  _constant_prims.append(NULL);
-  return _constant_oops.append(con);
-}
 
-int MethodHandleCompiler::find_prim_constant(BasicType bt, jvalue* con) {
+int MethodHandleCompiler::cpool_primitive_put(BasicType bt, jvalue* con) {
   jvalue con_copy;
   assert(bt < T_OBJECT, "");
   if (type2aelembytes(bt) < jintSize) {
@@ -607,28 +1100,125 @@
     }
     bt = T_INT;
   }
-  for (int i = 1, imax = _constant_prims.length(); i < imax; i++) {
-    PrimCon* pcon = _constant_prims.at(i);
-    if (pcon != NULL && pcon->_type == bt) {
-      bool match = false;
-      switch (type2size[bt]) {
-      case 1:  if (pcon->_value.i == con->i)  match = true;  break;
-      case 2:  if (pcon->_value.j == con->j)  match = true;  break;
-      }
-      if (match)
-        return i;
+
+//   for (int i = 1, imax = _constants.length(); i < imax; i++) {
+//     ConstantValue* con = _constants.at(i);
+//     if (con != NULL && con->is_primitive() && con->_type == bt) {
+//       bool match = false;
+//       switch (type2size[bt]) {
+//       case 1:  if (pcon->_value.i == con->i)  match = true;  break;
+//       case 2:  if (pcon->_value.j == con->j)  match = true;  break;
+//       }
+//       if (match)
+//         return i;
+//     }
+//   }
+  ConstantValue* cv = new ConstantValue(bt, *con);
+  int index = _constants.append(cv);
+
+  // long and double entries take 2 slots, we add another empty entry.
+  if (type2size[bt] == 2)
+    (void) _constants.append(NULL);
+
+  return index;
+}
+
+
+constantPoolHandle MethodHandleCompiler::get_constant_pool(TRAPS) const {
+  constantPoolHandle nullHandle;
+  bool is_conc_safe = true;
+  constantPoolOop cpool_oop = oopFactory::new_constantPool(_constants.length(), is_conc_safe, CHECK_(nullHandle));
+  constantPoolHandle cpool(THREAD, cpool_oop);
+
+  // Fill the real constant pool skipping the zero element.
+  for (int i = 1; i < _constants.length(); i++) {
+    ConstantValue* cv = _constants.at(i);
+    switch (cv->tag()) {
+    case JVM_CONSTANT_Utf8:        cpool->symbol_at_put(       i, cv->symbol_oop()                     ); break;
+    case JVM_CONSTANT_Integer:     cpool->int_at_put(          i, cv->get_jint()                       ); break;
+    case JVM_CONSTANT_Float:       cpool->float_at_put(        i, cv->get_jfloat()                     ); break;
+    case JVM_CONSTANT_Long:        cpool->long_at_put(         i, cv->get_jlong()                      ); break;
+    case JVM_CONSTANT_Double:      cpool->double_at_put(       i, cv->get_jdouble()                    ); break;
+    case JVM_CONSTANT_Class:       cpool->klass_at_put(        i, cv->klass_oop()                      ); break;
+    case JVM_CONSTANT_Methodref:   cpool->method_at_put(       i, cv->first_index(), cv->second_index()); break;
+    case JVM_CONSTANT_NameAndType: cpool->name_and_type_at_put(i, cv->first_index(), cv->second_index()); break;
+    case JVM_CONSTANT_Object:      cpool->object_at_put(       i, cv->object_oop()                     ); break;
+    default: ShouldNotReachHere();
+    }
+
+    switch (cv->tag()) {
+    case JVM_CONSTANT_Long:
+    case JVM_CONSTANT_Double:
+      i++;  // Skip empty entry.
+      assert(_constants.at(i) == NULL, "empty entry");
+      break;
     }
   }
-  PrimCon* pcon = new PrimCon();
-  pcon->_type = bt;
-  pcon->_value = (*con);
-  _constant_oops.append(Handle());
-  return _constant_prims.append(pcon);
+
+  // Set the constant pool holder to the target method's class.
+  cpool->set_pool_holder(_target_klass());
+
+  return cpool;
+}
+
+
+methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const {
+  methodHandle nullHandle;
+  // Create a method that holds the generated bytecode.  invokedynamic
+  // has no receiver, normal MH calls do.
+  int flags_bits;
+  if (for_invokedynamic())
+    flags_bits = (/*JVM_MH_INVOKE_BITS |*/ JVM_ACC_PUBLIC | JVM_ACC_FINAL | JVM_ACC_STATIC);
+  else
+    flags_bits = (/*JVM_MH_INVOKE_BITS |*/ JVM_ACC_PUBLIC | JVM_ACC_FINAL);
+
+  bool is_conc_safe = true;
+  methodOop m_oop = oopFactory::new_method(bytecode_length(),
+                                           accessFlags_from(flags_bits),
+                                           0, 0, 0, is_conc_safe, CHECK_(nullHandle));
+  methodHandle m(THREAD, m_oop);
+  m_oop = NULL;  // oop not GC safe
+
+  constantPoolHandle cpool = get_constant_pool(CHECK_(nullHandle));
+  m->set_constants(cpool());
+
+  m->set_name_index(_name_index);
+  m->set_signature_index(_signature_index);
+
+  m->set_code((address) bytecode());
+
+  m->set_max_stack(_max_stack);
+  m->set_max_locals(max_locals());
+  m->set_size_of_parameters(_num_params);
+
+  typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
+  m->set_exception_table(exception_handlers());
+
+  // Set the carry bit of the invocation counter to force inlining of
+  // the adapter.
+  InvocationCounter* ic = m->invocation_counter();
+  ic->set_carry();
+
+  // Rewrite the method and set up the constant pool cache.
+  objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(nullHandle));
+  objArrayHandle methods(THREAD, m_array);
+  methods->obj_at_put(0, m());
+  Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(nullHandle));  // Use fake class.
+
+#ifndef PRODUCT
+  if (TraceMethodHandles) {
+    m->print();
+    m->print_codes();
+  }
+#endif //PRODUCT
+
+  return m;
 }
 
 
 #ifndef PRODUCT
 
+#if 0
 // MH printer for debugging.
 
 class MethodHandlePrinter : public MethodHandleWalker {
@@ -791,11 +1381,12 @@
     out->print("\n");
   }
 };
+#endif // 0
 
 extern "C"
 void print_method_handle(oop mh) {
   if (java_dyn_MethodHandle::is_instance(mh)) {
-    MethodHandlePrinter::print(mh);
+    //MethodHandlePrinter::print(mh);
   } else {
     tty->print("*** not a method handle: ");
     mh->print();