methodHandleWalk.hpp 18.2 KB
Newer Older
1
/*
2
 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
19 20 21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
22 23 24
 *
 */

25 26 27 28 29
#ifndef SHARE_VM_PRIMS_METHODHANDLEWALK_HPP
#define SHARE_VM_PRIMS_METHODHANDLEWALK_HPP

#include "prims/methodHandles.hpp"

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
// Low-level parser for method handle chains.
class MethodHandleChain : StackObj {
public:
  typedef MethodHandles::EntryKind EntryKind;

private:
  Handle        _root;          // original target
  Handle        _method_handle; // current target
  bool          _is_last;       // final guy in chain
  bool          _is_bound;      // has a bound argument
  BasicType     _arg_type;      // if is_bound, the bound argument type
  int           _arg_slot;      // if is_bound or is_adapter, affected argument slot
  jint          _conversion;    // conversion field of AMH or -1
  methodHandle  _last_method;   // if is_last, which method we target
  Bytecodes::Code _last_invoke; // if is_last, type of invoke
  const char*   _lose_message;  // saved argument to lose()

  void set_method_handle(Handle target, TRAPS);
  void set_last_method(oop target, TRAPS);
  static BasicType compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS);

51 52 53 54 55 56 57
  oop MethodHandle_type_oop()          { return java_lang_invoke_MethodHandle::type(method_handle_oop()); }
  oop MethodHandle_vmtarget_oop()      { return java_lang_invoke_MethodHandle::vmtarget(method_handle_oop()); }
  int MethodHandle_vmslots()           { return java_lang_invoke_MethodHandle::vmslots(method_handle_oop()); }
  int DirectMethodHandle_vmindex()     { return java_lang_invoke_DirectMethodHandle::vmindex(method_handle_oop()); }
  oop BoundMethodHandle_argument_oop() { return java_lang_invoke_BoundMethodHandle::argument(method_handle_oop()); }
  int BoundMethodHandle_vmargslot()    { return java_lang_invoke_BoundMethodHandle::vmargslot(method_handle_oop()); }
  int AdapterMethodHandle_conversion() { return java_lang_invoke_AdapterMethodHandle::conversion(method_handle_oop()); }
58

59 60 61 62
#ifdef ASSERT
  void print_impl(TRAPS);
#endif

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
public:
  MethodHandleChain(Handle root, TRAPS)
    : _root(root)
  { set_method_handle(root, THREAD); }

  bool is_adapter()             { return _conversion != -1; }
  bool is_bound()               { return _is_bound; }
  bool is_last()                { return _is_last; }

  void next(TRAPS) {
    assert(!is_last(), "");
    set_method_handle(MethodHandle_vmtarget_oop(), THREAD);
  }

  Handle method_handle()        { return _method_handle; }
  oop    method_handle_oop()    { return _method_handle(); }
  oop    method_type_oop()      { return MethodHandle_type_oop(); }
80
  oop    vmtarget_oop()         { return MethodHandle_vmtarget_oop(); }
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

  jint adapter_conversion()     { assert(is_adapter(), ""); return _conversion; }
  int  adapter_conversion_op()  { return MethodHandles::adapter_conversion_op(adapter_conversion()); }
  BasicType adapter_conversion_src_type()
                                { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); }
  BasicType adapter_conversion_dest_type()
                                { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); }
  int  adapter_conversion_stack_move()
                                { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); }
  int  adapter_conversion_stack_pushes()
                                { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); }
  int  adapter_conversion_vminfo()
                                { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); }
  int adapter_arg_slot()        { assert(is_adapter(), ""); return _arg_slot; }
  oop adapter_arg_oop()         { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); }

  BasicType bound_arg_type()    { assert(is_bound(), ""); return _arg_type; }
  int       bound_arg_slot()    { assert(is_bound(), ""); return _arg_slot; }
  oop       bound_arg_oop()     { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); }

  methodOop last_method_oop()   { assert(is_last(), ""); return _last_method(); }
  Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; }

  void lose(const char* msg, TRAPS);
  const char* lose_message()    { return _lose_message; }
106 107 108 109 110 111 112

#ifdef ASSERT
  // Print a symbolic description of a method handle chain, including
  // the signature for each method.  The signatures are printed in
  // slot order to make it easier to understand.
  void print();
  static void print(Handle mh);
113
  static void print(oopDesc* mh);
114
#endif
115 116 117 118 119 120 121 122
};


// Structure walker for method handles.
// Does abstract interpretation on top of low-level parsing.
// You supply the tokens shuffled by the abstract interpretation.
class MethodHandleWalker : StackObj {
public:
123 124 125 126 127 128
  // Stack values:
  enum TokenType {
    tt_void,
    tt_parameter,
    tt_temporary,
    tt_constant,
129
    tt_symbolic,
130 131 132 133 134 135 136 137 138 139 140 141
    tt_illegal
  };

  // Argument token:
  class ArgToken {
  private:
    TokenType _tt;
    BasicType _bt;
    jvalue    _value;
    Handle    _handle;

  public:
142
    ArgToken(TokenType tt = tt_illegal) : _tt(tt), _bt(tt == tt_void ? T_VOID : T_ILLEGAL) {
143 144
      assert(tt == tt_illegal || tt == tt_void, "invalid token type");
    }
145 146

    ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) {
147
      assert(_tt == tt_parameter || _tt == tt_temporary, "must have index");
148 149 150
      _value.i = index;
    }

151 152
    ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) { assert(_bt != T_OBJECT, "wrong constructor"); }
    ArgToken(Handle handle) : _tt(tt_constant), _bt(T_OBJECT), _handle(handle) {}
153 154


155
    ArgToken(const char* str, BasicType type) : _tt(tt_symbolic), _bt(type) {
156
      _value.j = (intptr_t)str;
157 158 159 160
    }

    TokenType token_type()  const { return _tt; }
    BasicType basic_type()  const { return _bt; }
161 162
    bool      has_index()   const { return _tt == tt_parameter || _tt == tt_temporary; }
    int       index()       const { assert(has_index(), "must have index");; return _value.i; }
163 164
    Handle    object()      const { assert(_bt == T_OBJECT, "wrong accessor"); assert(_tt == tt_constant, "value type"); return _handle; }
    const char* str()       const { assert(_tt == tt_symbolic, "string type"); return (const char*)(intptr_t)_value.j; }
165

166 167 168 169
    jint      get_jint()    const { assert(_bt == T_INT || is_subword_type(_bt), "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.i; }
    jlong     get_jlong()   const { assert(_bt == T_LONG, "wrong accessor");   assert(_tt == tt_constant, "value types"); return _value.j; }
    jfloat    get_jfloat()  const { assert(_bt == T_FLOAT, "wrong accessor");  assert(_tt == tt_constant, "value types"); return _value.f; }
    jdouble   get_jdouble() const { assert(_bt == T_DOUBLE, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.d; }
170
  };
171 172 173

private:
  MethodHandleChain _chain;
174 175
  bool              _for_invokedynamic;
  int               _local_index;
176

177 178 179 180
  // This array is kept in an unusual order, indexed by low-level "slot number".
  // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array.
  // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1).
  // If a value at _outgoing.at(n) is T_LONG or T_DOUBLE, the value at _outgoing.at(n+1) is T_VOID.
181
  GrowableArray<ArgToken>  _outgoing;       // current outgoing parameter slots
182 183 184 185 186 187
  int                      _outgoing_argc;  // # non-empty outgoing slots

  // Replace a value of type old_type at slot (and maybe slot+1) with the new value.
  // If old_type != T_VOID, remove the old argument at that point.
  // If new_type != T_VOID, insert the new argument at that point.
  // Insert or delete a second empty slot as needed.
188 189 190 191 192
  void change_argument(BasicType old_type, int slot, const ArgToken& new_arg);
  void change_argument(BasicType old_type, int slot, BasicType type, const ArgToken& new_arg) {
    assert(type == new_arg.basic_type(), "must agree");
    change_argument(old_type, slot, new_arg);
  }
193

194 195 196 197 198
  // Raw retype conversions for OP_RAW_RETYPE.
  void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS);
  void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); }
  void retype_raw_return_type(  BasicType src, BasicType dst,           TRAPS) { retype_raw_conversion(src, dst, true,  -1,   CHECK); }

199 200
  BasicType arg_type(int slot) {
    return _outgoing.at(slot).basic_type();
201
  }
202 203
  bool has_argument(int slot) {
    return arg_type(slot) < T_VOID;
204 205 206 207 208 209 210 211 212 213 214
  }

#ifdef ASSERT
  int argument_count_slow();
#endif

  // Return a bytecode for converting src to dest, if one exists.
  Bytecodes::Code conversion_code(BasicType src, BasicType dest);

  void walk_incoming_state(TRAPS);

215 216
  void verify_args_and_signature(TRAPS) NOT_DEBUG_RETURN;

217
public:
218
  MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS)
219
    : _chain(root, THREAD),
220
      _for_invokedynamic(for_invokedynamic),
221 222
      _outgoing(THREAD, 10),
      _outgoing_argc(0)
223 224 225
  {
    _local_index = for_invokedynamic ? 0 : 1;
  }
226 227 228

  MethodHandleChain& chain() { return _chain; }

229 230 231 232 233 234 235 236 237 238 239
  bool for_invokedynamic() const { return _for_invokedynamic; }

  int new_local_index(BasicType bt) {
    //int index = _for_invokedynamic ? _local_index : _local_index - 1;
    int index = _local_index;
    _local_index += type2size[bt];
    return index;
  }

  int max_locals() const { return _local_index; }

240
  // plug-in abstract interpretation steps:
241 242 243 244 245 246
  virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) = 0;
  virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) = 0;
  virtual ArgToken make_oop_constant(oop con, TRAPS) = 0;
  virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0;
  virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0;
  virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0;
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

  // For make_invoke, the methodOop can be NULL if the intrinsic ID
  // is something other than vmIntrinsics::_none.

  // and in case anyone cares to related the previous actions to the chain:
  virtual void set_method_handle(oop mh) { }

  void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); }
  const char* lose_message()        { return chain().lose_message(); }

  ArgToken walk(TRAPS);
};


// An abstract interpreter for method handle chains.
// Produces an account of the semantics of a chain, in terms of a static IR.
// The IR happens to be JVM bytecodes.
class MethodHandleCompiler : public MethodHandleWalker {
private:
266
  int          _invoke_count;  // count the original call site has been executed
267 268 269 270 271
  KlassHandle  _rklass;        // Return type for casting.
  BasicType    _rtype;
  KlassHandle  _target_klass;
  Thread*      _thread;

272 273 274 275
  // Values used by the compiler.
  static jvalue zero_jvalue;
  static jvalue one_jvalue;

276
  // Fake constant pool entry.
277
  class ConstantValue : public ResourceObj {
278 279 280 281
  private:
    int       _tag;   // Constant pool tag type.
    JavaValue _value;
    Handle    _handle;
282
    Symbol*   _sym;
283 284 285 286

  public:
    // Constructor for oop types.
    ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) {
287
      assert(tag == JVM_CONSTANT_Class  ||
288 289 290 291
             tag == JVM_CONSTANT_String ||
             tag == JVM_CONSTANT_Object, "must be oop type");
    }

292 293 294 295
    ConstantValue(int tag, Symbol* con) : _tag(tag), _sym(con) {
      assert(tag == JVM_CONSTANT_Utf8, "must be symbol type");
    }

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
    // Constructor for oop reference types.
    ConstantValue(int tag, int index) : _tag(tag) {
      assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
      _value.set_jint(index);
    }
    ConstantValue(int tag, int first_index, int second_index) : _tag(tag) {
      assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type");
      _value.set_jint(first_index << 16 | second_index);
    }

    // Constructor for primitive types.
    ConstantValue(BasicType bt, jvalue con) {
      _value.set_type(bt);
      switch (bt) {
      case T_INT:    _tag = JVM_CONSTANT_Integer; _value.set_jint(   con.i); break;
      case T_LONG:   _tag = JVM_CONSTANT_Long;    _value.set_jlong(  con.j); break;
      case T_FLOAT:  _tag = JVM_CONSTANT_Float;   _value.set_jfloat( con.f); break;
      case T_DOUBLE: _tag = JVM_CONSTANT_Double;  _value.set_jdouble(con.d); break;
      default: ShouldNotReachHere();
      }
    }

    int       tag()          const { return _tag; }
319
    Symbol*   symbol()       const { return _sym; }
320 321 322 323 324 325 326 327 328 329 330
    klassOop  klass_oop()    const { return (klassOop)  _handle(); }
    oop       object_oop()   const { return _handle(); }
    int       index()        const { return _value.get_jint(); }
    int       first_index()  const { return _value.get_jint() >> 16; }
    int       second_index() const { return _value.get_jint() & 0x0000FFFF; }

    bool      is_primitive() const { return is_java_primitive(_value.get_type()); }
    jint      get_jint()     const { return _value.get_jint();    }
    jlong     get_jlong()    const { return _value.get_jlong();   }
    jfloat    get_jfloat()   const { return _value.get_jfloat();  }
    jdouble   get_jdouble()  const { return _value.get_jdouble(); }
331 332
  };

333 334 335
  // Fake constant pool.
  GrowableArray<ConstantValue*> _constants;

336
  // Accumulated compiler state:
337 338 339
  GrowableArray<unsigned char> _bytecode;

  int _cur_stack;
340 341 342 343 344
  int _max_stack;
  int _num_params;
  int _name_index;
  int _signature_index;

345 346 347 348 349 350 351 352 353 354 355
  void stack_push(BasicType bt) {
    _cur_stack += type2size[bt];
    if (_cur_stack > _max_stack) _max_stack = _cur_stack;
  }
  void stack_pop(BasicType bt) {
    _cur_stack -= type2size[bt];
    assert(_cur_stack >= 0, "sanity");
  }

  unsigned char* bytecode()        const { return _bytecode.adr_at(0); }
  int            bytecode_length() const { return _bytecode.length(); }
356

357 358 359 360 361
  // Fake constant pool.
  int cpool_oop_put(int tag, Handle con) {
    if (con.is_null())  return 0;
    ConstantValue* cv = new ConstantValue(tag, con);
    return _constants.append(cv);
362 363
  }

364 365 366
  int cpool_symbol_put(int tag, Symbol* con) {
    if (con == NULL)  return 0;
    ConstantValue* cv = new ConstantValue(tag, con);
367
    con->increment_refcount();
368 369 370
    return _constants.append(cv);
  }

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
  int cpool_oop_reference_put(int tag, int first_index, int second_index) {
    if (first_index == 0 && second_index == 0)  return 0;
    assert(first_index != 0 && second_index != 0, "no zero indexes");
    ConstantValue* cv = new ConstantValue(tag, first_index, second_index);
    return _constants.append(cv);
  }

  int cpool_primitive_put(BasicType type, jvalue* con);

  int cpool_int_put(jint value) {
    jvalue con; con.i = value;
    return cpool_primitive_put(T_INT, &con);
  }
  int cpool_long_put(jlong value) {
    jvalue con; con.j = value;
    return cpool_primitive_put(T_LONG, &con);
  }
  int cpool_float_put(jfloat value) {
    jvalue con; con.f = value;
    return cpool_primitive_put(T_FLOAT, &con);
  }
  int cpool_double_put(jdouble value) {
    jvalue con; con.d = value;
    return cpool_primitive_put(T_DOUBLE, &con);
  }

  int cpool_object_put(Handle obj) {
    return cpool_oop_put(JVM_CONSTANT_Object, obj);
  }
400 401
  int cpool_symbol_put(Symbol* sym) {
    return cpool_symbol_put(JVM_CONSTANT_Utf8, sym);
402 403 404 405 406 407 408 409 410 411 412
  }
  int cpool_klass_put(klassOop klass) {
    return cpool_oop_put(JVM_CONSTANT_Class, klass);
  }
  int cpool_methodref_put(int class_index, int name_and_type_index) {
    return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index);
  }
  int cpool_name_and_type_put(int name_index, int signature_index) {
    return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
  }

413
  void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1);
414 415 416 417
  void emit_load(BasicType bt, int index);
  void emit_store(BasicType bt, int index);
  void emit_load_constant(ArgToken arg);

418
  virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) {
419
    return ArgToken(tt_parameter, type, argnum);
420 421
  }
  virtual ArgToken make_oop_constant(oop con, TRAPS) {
422
    Handle h(THREAD, con);
423
    return ArgToken(h);
424 425
  }
  virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) {
426
    return ArgToken(type, *con);
427
  }
428 429 430

  virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
  virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS);
431 432
  virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS);

433 434 435 436 437
  // Get a real constant pool.
  constantPoolHandle get_constant_pool(TRAPS) const;

  // Get a real methodOop.
  methodHandle get_method_oop(TRAPS) const;
438 439

public:
440
  MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS);
441 442

  // Compile the given MH chain into bytecode.
443
  methodHandle compile(TRAPS);
444 445 446

  // Tests if the given class is a MH adapter holder.
  static bool klass_is_method_handle_adapter_holder(klassOop klass) {
447
    return (klass == SystemDictionary::MethodHandle_klass());
448
  }
449
};
450 451

#endif // SHARE_VM_PRIMS_METHODHANDLEWALK_HPP