src/share/vm/prims/methodHandleWalk.hpp

Wed, 02 Feb 2011 14:38:01 -0500

author
kamg
date
Wed, 02 Feb 2011 14:38:01 -0500
changeset 2511
bf8517f4e4d0
parent 2497
3582bf76420e
child 2639
8033953d67ff
permissions
-rw-r--r--

6766644: Redefinition of compiled method fails with assertion "Can not load classes with the Compiler thread"
Summary: Defer posting events from the compiler thread: use service thread
Reviewed-by: coleenp, dholmes, never, dcubed

     1 /*
     2  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #ifndef SHARE_VM_PRIMS_METHODHANDLEWALK_HPP
    26 #define SHARE_VM_PRIMS_METHODHANDLEWALK_HPP
    28 #include "prims/methodHandles.hpp"
    30 // Low-level parser for method handle chains.
    31 class MethodHandleChain : StackObj {
    32 public:
    33   typedef MethodHandles::EntryKind EntryKind;
    35 private:
    36   Handle        _root;          // original target
    37   Handle        _method_handle; // current target
    38   bool          _is_last;       // final guy in chain
    39   bool          _is_bound;      // has a bound argument
    40   BasicType     _arg_type;      // if is_bound, the bound argument type
    41   int           _arg_slot;      // if is_bound or is_adapter, affected argument slot
    42   jint          _conversion;    // conversion field of AMH or -1
    43   methodHandle  _last_method;   // if is_last, which method we target
    44   Bytecodes::Code _last_invoke; // if is_last, type of invoke
    45   const char*   _lose_message;  // saved argument to lose()
    47   void set_method_handle(Handle target, TRAPS);
    48   void set_last_method(oop target, TRAPS);
    49   static BasicType compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS);
    51   oop MethodHandle_type_oop()     { return java_dyn_MethodHandle::type(method_handle_oop()); }
    52   oop MethodHandle_vmtarget_oop() { return java_dyn_MethodHandle::vmtarget(method_handle_oop()); }
    53   int MethodHandle_vmslots()      { return java_dyn_MethodHandle::vmslots(method_handle_oop()); }
    54   int DirectMethodHandle_vmindex()     { return sun_dyn_DirectMethodHandle::vmindex(method_handle_oop()); }
    55   oop BoundMethodHandle_argument_oop() { return sun_dyn_BoundMethodHandle::argument(method_handle_oop()); }
    56   int BoundMethodHandle_vmargslot()    { return sun_dyn_BoundMethodHandle::vmargslot(method_handle_oop()); }
    57   int AdapterMethodHandle_conversion() { return sun_dyn_AdapterMethodHandle::conversion(method_handle_oop()); }
    59 public:
    60   MethodHandleChain(Handle root, TRAPS)
    61     : _root(root)
    62   { set_method_handle(root, THREAD); }
    64   bool is_adapter()             { return _conversion != -1; }
    65   bool is_bound()               { return _is_bound; }
    66   bool is_last()                { return _is_last; }
    68   void next(TRAPS) {
    69     assert(!is_last(), "");
    70     set_method_handle(MethodHandle_vmtarget_oop(), THREAD);
    71   }
    73   Handle method_handle()        { return _method_handle; }
    74   oop    method_handle_oop()    { return _method_handle(); }
    75   oop    method_type_oop()      { return MethodHandle_type_oop(); }
    76   oop    vmtarget_oop()         { return MethodHandle_vmtarget_oop(); }
    78   jint adapter_conversion()     { assert(is_adapter(), ""); return _conversion; }
    79   int  adapter_conversion_op()  { return MethodHandles::adapter_conversion_op(adapter_conversion()); }
    80   BasicType adapter_conversion_src_type()
    81                                 { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); }
    82   BasicType adapter_conversion_dest_type()
    83                                 { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); }
    84   int  adapter_conversion_stack_move()
    85                                 { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); }
    86   int  adapter_conversion_stack_pushes()
    87                                 { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); }
    88   int  adapter_conversion_vminfo()
    89                                 { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); }
    90   int adapter_arg_slot()        { assert(is_adapter(), ""); return _arg_slot; }
    91   oop adapter_arg_oop()         { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); }
    93   BasicType bound_arg_type()    { assert(is_bound(), ""); return _arg_type; }
    94   int       bound_arg_slot()    { assert(is_bound(), ""); return _arg_slot; }
    95   oop       bound_arg_oop()     { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); }
    97   methodOop last_method_oop()   { assert(is_last(), ""); return _last_method(); }
    98   Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; }
   100   void lose(const char* msg, TRAPS);
   101   const char* lose_message()    { return _lose_message; }
   102 };
   105 // Structure walker for method handles.
   106 // Does abstract interpretation on top of low-level parsing.
   107 // You supply the tokens shuffled by the abstract interpretation.
   108 class MethodHandleWalker : StackObj {
   109 public:
   110   // Stack values:
   111   enum TokenType {
   112     tt_void,
   113     tt_parameter,
   114     tt_temporary,
   115     tt_constant,
   116     tt_illegal
   117   };
   119   // Argument token:
   120   class ArgToken {
   121   private:
   122     TokenType _tt;
   123     BasicType _bt;
   124     jvalue    _value;
   125     Handle    _handle;
   127   public:
   128     ArgToken(TokenType tt = tt_illegal) : _tt(tt) {}
   129     ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {}
   131     ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) {
   132       _value.i = index;
   133     }
   135     ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) {
   136       _handle = value;
   137     }
   139     TokenType token_type()  const { return _tt; }
   140     BasicType basic_type()  const { return _bt; }
   141     int       index()       const { return _value.i; }
   142     Handle    object()      const { return _handle; }
   144     jint      get_jint()    const { return _value.i; }
   145     jlong     get_jlong()   const { return _value.j; }
   146     jfloat    get_jfloat()  const { return _value.f; }
   147     jdouble   get_jdouble() const { return _value.d; }
   148   };
   150   // Abstract interpretation state:
   151   struct SlotState {
   152     BasicType _type;
   153     ArgToken  _arg;
   154     SlotState() : _type(), _arg() {}
   155   };
   156   static SlotState make_state(BasicType type, ArgToken arg) {
   157     SlotState ss;
   158     ss._type = type; ss._arg = arg;
   159     return ss;
   160   }
   162 private:
   163   MethodHandleChain _chain;
   164   bool              _for_invokedynamic;
   165   int               _local_index;
   167   GrowableArray<SlotState> _outgoing;       // current outgoing parameter slots
   168   int                      _outgoing_argc;  // # non-empty outgoing slots
   170   // Replace a value of type old_type at slot (and maybe slot+1) with the new value.
   171   // If old_type != T_VOID, remove the old argument at that point.
   172   // If new_type != T_VOID, insert the new argument at that point.
   173   // Insert or delete a second empty slot as needed.
   174   void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg);
   176   SlotState* slot_state(int slot) {
   177     if (slot < 0 || slot >= _outgoing.length())
   178       return NULL;
   179     return _outgoing.adr_at(slot);
   180   }
   181   BasicType slot_type(int slot) {
   182     SlotState* ss = slot_state(slot);
   183     if (ss == NULL)
   184       return T_ILLEGAL;
   185     return ss->_type;
   186   }
   187   bool slot_has_argument(int slot) {
   188     return slot_type(slot) < T_VOID;
   189   }
   191 #ifdef ASSERT
   192   int argument_count_slow();
   193 #endif
   195   // Return a bytecode for converting src to dest, if one exists.
   196   Bytecodes::Code conversion_code(BasicType src, BasicType dest);
   198   void walk_incoming_state(TRAPS);
   200 public:
   201   MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS)
   202     : _chain(root, THREAD),
   203       _for_invokedynamic(for_invokedynamic),
   204       _outgoing(THREAD, 10),
   205       _outgoing_argc(0)
   206   {
   207     _local_index = for_invokedynamic ? 0 : 1;
   208   }
   210   MethodHandleChain& chain() { return _chain; }
   212   bool for_invokedynamic() const { return _for_invokedynamic; }
   214   int new_local_index(BasicType bt) {
   215     //int index = _for_invokedynamic ? _local_index : _local_index - 1;
   216     int index = _local_index;
   217     _local_index += type2size[bt];
   218     return index;
   219   }
   221   int max_locals() const { return _local_index; }
   223   // plug-in abstract interpretation steps:
   224   virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0;
   225   virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0;
   226   virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0;
   227   virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS ) = 0;
   228   virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS ) = 0;
   229   virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0;
   231   // For make_invoke, the methodOop can be NULL if the intrinsic ID
   232   // is something other than vmIntrinsics::_none.
   234   // and in case anyone cares to related the previous actions to the chain:
   235   virtual void set_method_handle(oop mh) { }
   237   void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); }
   238   const char* lose_message()        { return chain().lose_message(); }
   240   ArgToken walk(TRAPS);
   241 };
   244 // An abstract interpreter for method handle chains.
   245 // Produces an account of the semantics of a chain, in terms of a static IR.
   246 // The IR happens to be JVM bytecodes.
   247 class MethodHandleCompiler : public MethodHandleWalker {
   248 private:
   249   methodHandle _callee;
   250   KlassHandle  _rklass;        // Return type for casting.
   251   BasicType    _rtype;
   252   KlassHandle  _target_klass;
   253   Thread*      _thread;
   255   // Fake constant pool entry.
   256   class ConstantValue {
   257   private:
   258     int       _tag;   // Constant pool tag type.
   259     JavaValue _value;
   260     Handle    _handle;
   261     Symbol*   _sym;
   263   public:
   264     // Constructor for oop types.
   265     ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) {
   266       assert(tag == JVM_CONSTANT_Class  ||
   267              tag == JVM_CONSTANT_String ||
   268              tag == JVM_CONSTANT_Object, "must be oop type");
   269     }
   271     ConstantValue(int tag, Symbol* con) : _tag(tag), _sym(con) {
   272       assert(tag == JVM_CONSTANT_Utf8, "must be symbol type");
   273     }
   275     // Constructor for oop reference types.
   276     ConstantValue(int tag, int index) : _tag(tag) {
   277       assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
   278       _value.set_jint(index);
   279     }
   280     ConstantValue(int tag, int first_index, int second_index) : _tag(tag) {
   281       assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
   282       _value.set_jint(first_index << 16 | second_index);
   283     }
   285     // Constructor for primitive types.
   286     ConstantValue(BasicType bt, jvalue con) {
   287       _value.set_type(bt);
   288       switch (bt) {
   289       case T_INT:    _tag = JVM_CONSTANT_Integer; _value.set_jint(   con.i); break;
   290       case T_LONG:   _tag = JVM_CONSTANT_Long;    _value.set_jlong(  con.j); break;
   291       case T_FLOAT:  _tag = JVM_CONSTANT_Float;   _value.set_jfloat( con.f); break;
   292       case T_DOUBLE: _tag = JVM_CONSTANT_Double;  _value.set_jdouble(con.d); break;
   293       default: ShouldNotReachHere();
   294       }
   295     }
   297     int       tag()          const { return _tag; }
   298     Symbol*   symbol()       const { return _sym; }
   299     klassOop  klass_oop()    const { return (klassOop)  _handle(); }
   300     oop       object_oop()   const { return _handle(); }
   301     int       index()        const { return _value.get_jint(); }
   302     int       first_index()  const { return _value.get_jint() >> 16; }
   303     int       second_index() const { return _value.get_jint() & 0x0000FFFF; }
   305     bool      is_primitive() const { return is_java_primitive(_value.get_type()); }
   306     jint      get_jint()     const { return _value.get_jint();    }
   307     jlong     get_jlong()    const { return _value.get_jlong();   }
   308     jfloat    get_jfloat()   const { return _value.get_jfloat();  }
   309     jdouble   get_jdouble()  const { return _value.get_jdouble(); }
   310   };
   312   // Fake constant pool.
   313   GrowableArray<ConstantValue*> _constants;
   315   // Accumulated compiler state:
   316   GrowableArray<unsigned char> _bytecode;
   318   int _cur_stack;
   319   int _max_stack;
   320   int _num_params;
   321   int _name_index;
   322   int _signature_index;
   324   void stack_push(BasicType bt) {
   325     _cur_stack += type2size[bt];
   326     if (_cur_stack > _max_stack) _max_stack = _cur_stack;
   327   }
   328   void stack_pop(BasicType bt) {
   329     _cur_stack -= type2size[bt];
   330     assert(_cur_stack >= 0, "sanity");
   331   }
   333   unsigned char* bytecode()        const { return _bytecode.adr_at(0); }
   334   int            bytecode_length() const { return _bytecode.length(); }
   336   // Fake constant pool.
   337   int cpool_oop_put(int tag, Handle con) {
   338     if (con.is_null())  return 0;
   339     ConstantValue* cv = new ConstantValue(tag, con);
   340     return _constants.append(cv);
   341   }
   343   int cpool_symbol_put(int tag, Symbol* con) {
   344     if (con == NULL)  return 0;
   345     ConstantValue* cv = new ConstantValue(tag, con);
   346     return _constants.append(cv);
   347   }
   349   int cpool_oop_reference_put(int tag, int first_index, int second_index) {
   350     if (first_index == 0 && second_index == 0)  return 0;
   351     assert(first_index != 0 && second_index != 0, "no zero indexes");
   352     ConstantValue* cv = new ConstantValue(tag, first_index, second_index);
   353     return _constants.append(cv);
   354   }
   356   int cpool_primitive_put(BasicType type, jvalue* con);
   358   int cpool_int_put(jint value) {
   359     jvalue con; con.i = value;
   360     return cpool_primitive_put(T_INT, &con);
   361   }
   362   int cpool_long_put(jlong value) {
   363     jvalue con; con.j = value;
   364     return cpool_primitive_put(T_LONG, &con);
   365   }
   366   int cpool_float_put(jfloat value) {
   367     jvalue con; con.f = value;
   368     return cpool_primitive_put(T_FLOAT, &con);
   369   }
   370   int cpool_double_put(jdouble value) {
   371     jvalue con; con.d = value;
   372     return cpool_primitive_put(T_DOUBLE, &con);
   373   }
   375   int cpool_object_put(Handle obj) {
   376     return cpool_oop_put(JVM_CONSTANT_Object, obj);
   377   }
   378   int cpool_symbol_put(Symbol* sym) {
   379     return cpool_symbol_put(JVM_CONSTANT_Utf8, sym);
   380   }
   381   int cpool_klass_put(klassOop klass) {
   382     return cpool_oop_put(JVM_CONSTANT_Class, klass);
   383   }
   384   int cpool_methodref_put(int class_index, int name_and_type_index) {
   385     return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index);
   386   }
   387   int cpool_name_and_type_put(int name_index, int signature_index) {
   388     return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
   389   }
   391   void emit_bc(Bytecodes::Code op, int index = 0);
   392   void emit_load(BasicType bt, int index);
   393   void emit_store(BasicType bt, int index);
   394   void emit_load_constant(ArgToken arg);
   396   virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) {
   397     return ArgToken(tt_parameter, type, argnum);
   398   }
   399   virtual ArgToken make_oop_constant(oop con, TRAPS) {
   400     Handle h(THREAD, con);
   401     return ArgToken(tt_constant, T_OBJECT, h);
   402   }
   403   virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) {
   404     return ArgToken(tt_constant, type, *con);
   405   }
   407   virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
   408   virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS);
   409   virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);
   411   // Get a real constant pool.
   412   constantPoolHandle get_constant_pool(TRAPS) const;
   414   // Get a real methodOop.
   415   methodHandle get_method_oop(TRAPS) const;
   417 public:
   418   MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS);
   420   // Compile the given MH chain into bytecode.
   421   methodHandle compile(TRAPS);
   423   // Tests if the given class is a MH adapter holder.
   424   static bool klass_is_method_handle_adapter_holder(klassOop klass) {
   425     return (klass == SystemDictionary::MethodHandle_klass());
   426   }
   427 };
   429 #endif // SHARE_VM_PRIMS_METHODHANDLEWALK_HPP

mercurial