1 /* 2 * Copyright 2008-2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 // Low-level parser for method handle chains. 26 class MethodHandleChain : StackObj { 27 public: 28 typedef MethodHandles::EntryKind EntryKind; 29 30 private: 31 Handle _root; // original target 32 Handle _method_handle; // current target 33 bool _is_last; // final guy in chain 34 bool _is_bound; // has a bound argument 35 BasicType _arg_type; // if is_bound, the bound argument type 36 int _arg_slot; // if is_bound or is_adapter, affected argument slot 37 jint _conversion; // conversion field of AMH or -1 38 methodHandle _last_method; // if is_last, which method we target 39 Bytecodes::Code _last_invoke; // if is_last, type of invoke 40 const char* _lose_message; // saved argument to lose() 41 42 void set_method_handle(Handle target, TRAPS); 43 void set_last_method(oop target, TRAPS); 44 static BasicType compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS); 45 46 oop MethodHandle_type_oop() { return java_dyn_MethodHandle::type(method_handle_oop()); } 47 oop MethodHandle_vmtarget_oop() { return java_dyn_MethodHandle::vmtarget(method_handle_oop()); } 48 int MethodHandle_vmslots() { return java_dyn_MethodHandle::vmslots(method_handle_oop()); } 49 int DirectMethodHandle_vmindex() { return sun_dyn_DirectMethodHandle::vmindex(method_handle_oop()); } 50 oop BoundMethodHandle_argument_oop() { return sun_dyn_BoundMethodHandle::argument(method_handle_oop()); } 51 int BoundMethodHandle_vmargslot() { return sun_dyn_BoundMethodHandle::vmargslot(method_handle_oop()); } 52 int AdapterMethodHandle_conversion() { return sun_dyn_AdapterMethodHandle::conversion(method_handle_oop()); } 53 54 public: 55 MethodHandleChain(Handle root, TRAPS) 56 : _root(root) 57 { set_method_handle(root, THREAD); } 58 59 bool is_adapter() { return _conversion != -1; } 60 bool is_bound() { return _is_bound; } 61 bool is_last() { return _is_last; } 62 63 void next(TRAPS) { 64 assert(!is_last(), ""); 65 set_method_handle(MethodHandle_vmtarget_oop(), THREAD); 66 } 67 68 Handle method_handle() { return _method_handle; } 69 oop method_handle_oop() { return _method_handle(); } 70 oop method_type_oop() { return MethodHandle_type_oop(); } 71 72 jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } 73 int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); } 74 BasicType adapter_conversion_src_type() 75 { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); } 76 BasicType adapter_conversion_dest_type() 77 { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); } 78 int adapter_conversion_stack_move() 79 { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); } 80 int adapter_conversion_stack_pushes() 81 { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); } 82 int adapter_conversion_vminfo() 83 { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); } 84 int adapter_arg_slot() { assert(is_adapter(), ""); return _arg_slot; } 85 oop adapter_arg_oop() { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); } 86 87 BasicType bound_arg_type() { assert(is_bound(), ""); return _arg_type; } 88 int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } 89 oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } 90 91 methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } 92 Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } 93 94 void lose(const char* msg, TRAPS); 95 const char* lose_message() { return _lose_message; } 96 }; 97 98 99 // Structure walker for method handles. 100 // Does abstract interpretation on top of low-level parsing. 101 // You supply the tokens shuffled by the abstract interpretation. 102 class MethodHandleWalker : StackObj { 103 public: 104 struct _ArgToken { }; // dummy struct 105 typedef _ArgToken* ArgToken; 106 107 // Abstract interpretation state: 108 struct SlotState { 109 BasicType _type; 110 ArgToken _arg; 111 }; 112 static SlotState make_state(BasicType type, ArgToken arg) { 113 SlotState ss; 114 ss._type = type; ss._arg = arg; 115 return ss; 116 } 117 118 private: 119 MethodHandleChain _chain; 120 121 GrowableArray<SlotState> _outgoing; // current outgoing parameter slots 122 int _outgoing_argc; // # non-empty outgoing slots 123 124 // Replace a value of type old_type at slot (and maybe slot+1) with the new value. 125 // If old_type != T_VOID, remove the old argument at that point. 126 // If new_type != T_VOID, insert the new argument at that point. 127 // Insert or delete a second empty slot as needed. 128 void change_argument(BasicType old_type, int slot, BasicType new_type, ArgToken new_arg); 129 130 SlotState* slot_state(int slot) { 131 if (slot < 0 || slot >= _outgoing.length()) 132 return NULL; 133 return _outgoing.adr_at(slot); 134 } 135 BasicType slot_type(int slot) { 136 SlotState* ss = slot_state(slot); 137 if (ss == NULL) 138 return T_ILLEGAL; 139 return ss->_type; 140 } 141 bool slot_has_argument(int slot) { 142 return slot_type(slot) < T_VOID; 143 } 144 145 #ifdef ASSERT 146 int argument_count_slow(); 147 #endif 148 149 // Return a bytecode for converting src to dest, if one exists. 150 Bytecodes::Code conversion_code(BasicType src, BasicType dest); 151 152 void walk_incoming_state(TRAPS); 153 154 public: 155 MethodHandleWalker(Handle root, TRAPS) 156 : _chain(root, THREAD), 157 _outgoing(THREAD, 10), 158 _outgoing_argc(0) 159 { } 160 161 MethodHandleChain& chain() { return _chain; } 162 163 // plug-in abstract interpretation steps: 164 virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0; 165 virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0; 166 virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0; 167 virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS ) = 0; 168 virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS ) = 0; 169 virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0; 170 171 // For make_invoke, the methodOop can be NULL if the intrinsic ID 172 // is something other than vmIntrinsics::_none. 173 174 // and in case anyone cares to related the previous actions to the chain: 175 virtual void set_method_handle(oop mh) { } 176 177 void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); } 178 const char* lose_message() { return chain().lose_message(); } 179 180 ArgToken walk(TRAPS); 181 }; 182 183 184 // An abstract interpreter for method handle chains. 185 // Produces an account of the semantics of a chain, in terms of a static IR. 186 // The IR happens to be JVM bytecodes. 187 class MethodHandleCompiler : public MethodHandleWalker { 188 private: 189 Thread* _thread; 190 191 struct PrimCon { 192 BasicType _type; 193 jvalue _value; 194 }; 195 196 // Accumulated compiler state: 197 stringStream _bytes; 198 GrowableArray<Handle> _constant_oops; 199 GrowableArray<PrimCon*> _constant_prims; 200 int _max_stack; 201 int _num_params; 202 int _max_locals; 203 int _name_index; 204 int _signature_index; 205 206 // Stack values: 207 enum TokenType { 208 tt_void, 209 tt_parameter, 210 tt_temporary, 211 tt_constant 212 }; 213 214 ArgToken make_stack_value(TokenType tt, BasicType type, int id) { 215 return ArgToken( ((intptr_t)id << 8) | ((intptr_t)type << 4) | (intptr_t)tt ); 216 } 217 218 public: 219 virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { 220 return make_stack_value(tt_parameter, type, argnum); 221 } 222 virtual ArgToken make_oop_constant(oop con, TRAPS) { 223 return make_stack_value(tt_constant, T_OBJECT, find_oop_constant(con)); 224 } 225 virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { 226 return make_stack_value(tt_constant, type, find_prim_constant(type, con)); 227 } 228 virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS); 229 virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS); 230 virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); 231 232 int find_oop_constant(oop con); 233 int find_prim_constant(BasicType type, jvalue* con); 234 235 public: 236 MethodHandleCompiler(Handle root, TRAPS) 237 : MethodHandleWalker(root, THREAD), 238 _thread(THREAD), 239 _bytes(50), 240 _constant_oops(THREAD, 10), 241 _constant_prims(THREAD, 10), 242 _max_stack(0), _max_locals(0), 243 _name_index(0), _signature_index(0) 244 { } 245 const char* bytes() { return _bytes.as_string(); } 246 int constant_length() { return _constant_oops.length(); } 247 int max_stack() { return _max_stack; } 248 int max_locals() { return _max_locals; } 249 int name_index() { return _name_index; } 250 int signature_index() { return _signature_index; } 251 symbolHandle name() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_name_index)()); } 252 symbolHandle signature() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_signature_index)()); } 253 254 bool constant_is_oop_at(int i) { 255 return (_constant_prims.at(i) == NULL); 256 } 257 Handle constant_oop_at(int i) { 258 assert(constant_is_oop_at(i), ""); 259 return _constant_oops.at(i); 260 } 261 PrimCon* constant_prim_at(int i) { 262 assert(!constant_is_oop_at(i), ""); 263 return _constant_prims.at(i); 264 } 265 266 // Compile the given MH chain into bytecode. 267 void compile(TRAPS); 268 };