1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/prims/methodHandleWalk.hpp Mon Jan 04 15:52:40 2010 +0100 1.3 @@ -0,0 +1,269 @@ 1.4 +/* 1.5 + * Copyright 2008-2010 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +// Low-level parser for method handle chains. 1.29 +class MethodHandleChain : StackObj { 1.30 +public: 1.31 + typedef MethodHandles::EntryKind EntryKind; 1.32 + 1.33 +private: 1.34 + Handle _root; // original target 1.35 + Handle _method_handle; // current target 1.36 + bool _is_last; // final guy in chain 1.37 + bool _is_bound; // has a bound argument 1.38 + BasicType _arg_type; // if is_bound, the bound argument type 1.39 + int _arg_slot; // if is_bound or is_adapter, affected argument slot 1.40 + jint _conversion; // conversion field of AMH or -1 1.41 + methodHandle _last_method; // if is_last, which method we target 1.42 + Bytecodes::Code _last_invoke; // if is_last, type of invoke 1.43 + const char* _lose_message; // saved argument to lose() 1.44 + 1.45 + void set_method_handle(Handle target, TRAPS); 1.46 + void set_last_method(oop target, TRAPS); 1.47 + static BasicType compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS); 1.48 + 1.49 + oop MethodHandle_type_oop() { return java_dyn_MethodHandle::type(method_handle_oop()); } 1.50 + oop MethodHandle_vmtarget_oop() { return java_dyn_MethodHandle::vmtarget(method_handle_oop()); } 1.51 + int MethodHandle_vmslots() { return java_dyn_MethodHandle::vmslots(method_handle_oop()); } 1.52 + int DirectMethodHandle_vmindex() { return sun_dyn_DirectMethodHandle::vmindex(method_handle_oop()); } 1.53 + oop BoundMethodHandle_argument_oop() { return sun_dyn_BoundMethodHandle::argument(method_handle_oop()); } 1.54 + int BoundMethodHandle_vmargslot() { return sun_dyn_BoundMethodHandle::vmargslot(method_handle_oop()); } 1.55 + int AdapterMethodHandle_conversion() { return sun_dyn_AdapterMethodHandle::conversion(method_handle_oop()); } 1.56 + 1.57 +public: 1.58 + MethodHandleChain(Handle root, TRAPS) 1.59 + : _root(root) 1.60 + { set_method_handle(root, THREAD); } 1.61 + 1.62 + bool is_adapter() { return _conversion != -1; } 1.63 + bool is_bound() { return _is_bound; } 1.64 + bool is_last() { return _is_last; } 1.65 + 1.66 + void next(TRAPS) { 1.67 + assert(!is_last(), ""); 1.68 + set_method_handle(MethodHandle_vmtarget_oop(), THREAD); 1.69 + } 1.70 + 1.71 + Handle method_handle() { return _method_handle; } 1.72 + oop method_handle_oop() { return _method_handle(); } 1.73 + oop method_type_oop() { return MethodHandle_type_oop(); } 1.74 + 1.75 + jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } 1.76 + int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); } 1.77 + BasicType adapter_conversion_src_type() 1.78 + { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); } 1.79 + BasicType adapter_conversion_dest_type() 1.80 + { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); } 1.81 + int adapter_conversion_stack_move() 1.82 + { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); } 1.83 + int adapter_conversion_stack_pushes() 1.84 + { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); } 1.85 + int adapter_conversion_vminfo() 1.86 + { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); } 1.87 + int adapter_arg_slot() { assert(is_adapter(), ""); return _arg_slot; } 1.88 + oop adapter_arg_oop() { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); } 1.89 + 1.90 + BasicType bound_arg_type() { assert(is_bound(), ""); return _arg_type; } 1.91 + int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } 1.92 + oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } 1.93 + 1.94 + methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } 1.95 + Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } 1.96 + 1.97 + void lose(const char* msg, TRAPS); 1.98 + const char* lose_message() { return _lose_message; } 1.99 +}; 1.100 + 1.101 + 1.102 +// Structure walker for method handles. 1.103 +// Does abstract interpretation on top of low-level parsing. 1.104 +// You supply the tokens shuffled by the abstract interpretation. 1.105 +class MethodHandleWalker : StackObj { 1.106 +public: 1.107 + struct _ArgToken { }; // dummy struct 1.108 + typedef _ArgToken* ArgToken; 1.109 + 1.110 + // Abstract interpretation state: 1.111 + struct SlotState { 1.112 + BasicType _type; 1.113 + ArgToken _arg; 1.114 + SlotState() : _type(), _arg() {} 1.115 + }; 1.116 + static SlotState make_state(BasicType type, ArgToken arg) { 1.117 + SlotState ss; 1.118 + ss._type = type; ss._arg = arg; 1.119 + return ss; 1.120 + } 1.121 + 1.122 +private: 1.123 + MethodHandleChain _chain; 1.124 + 1.125 + GrowableArray<SlotState> _outgoing; // current outgoing parameter slots 1.126 + int _outgoing_argc; // # non-empty outgoing slots 1.127 + 1.128 + // Replace a value of type old_type at slot (and maybe slot+1) with the new value. 1.129 + // If old_type != T_VOID, remove the old argument at that point. 1.130 + // If new_type != T_VOID, insert the new argument at that point. 1.131 + // Insert or delete a second empty slot as needed. 1.132 + void change_argument(BasicType old_type, int slot, BasicType new_type, ArgToken new_arg); 1.133 + 1.134 + SlotState* slot_state(int slot) { 1.135 + if (slot < 0 || slot >= _outgoing.length()) 1.136 + return NULL; 1.137 + return _outgoing.adr_at(slot); 1.138 + } 1.139 + BasicType slot_type(int slot) { 1.140 + SlotState* ss = slot_state(slot); 1.141 + if (ss == NULL) 1.142 + return T_ILLEGAL; 1.143 + return ss->_type; 1.144 + } 1.145 + bool slot_has_argument(int slot) { 1.146 + return slot_type(slot) < T_VOID; 1.147 + } 1.148 + 1.149 +#ifdef ASSERT 1.150 + int argument_count_slow(); 1.151 +#endif 1.152 + 1.153 + // Return a bytecode for converting src to dest, if one exists. 1.154 + Bytecodes::Code conversion_code(BasicType src, BasicType dest); 1.155 + 1.156 + void walk_incoming_state(TRAPS); 1.157 + 1.158 +public: 1.159 + MethodHandleWalker(Handle root, TRAPS) 1.160 + : _chain(root, THREAD), 1.161 + _outgoing(THREAD, 10), 1.162 + _outgoing_argc(0) 1.163 + { } 1.164 + 1.165 + MethodHandleChain& chain() { return _chain; } 1.166 + 1.167 + // plug-in abstract interpretation steps: 1.168 + virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0; 1.169 + virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0; 1.170 + virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0; 1.171 + virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS ) = 0; 1.172 + virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS ) = 0; 1.173 + virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0; 1.174 + 1.175 + // For make_invoke, the methodOop can be NULL if the intrinsic ID 1.176 + // is something other than vmIntrinsics::_none. 1.177 + 1.178 + // and in case anyone cares to related the previous actions to the chain: 1.179 + virtual void set_method_handle(oop mh) { } 1.180 + 1.181 + void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); } 1.182 + const char* lose_message() { return chain().lose_message(); } 1.183 + 1.184 + ArgToken walk(TRAPS); 1.185 +}; 1.186 + 1.187 + 1.188 +// An abstract interpreter for method handle chains. 1.189 +// Produces an account of the semantics of a chain, in terms of a static IR. 1.190 +// The IR happens to be JVM bytecodes. 1.191 +class MethodHandleCompiler : public MethodHandleWalker { 1.192 +private: 1.193 + Thread* _thread; 1.194 + 1.195 + struct PrimCon { 1.196 + BasicType _type; 1.197 + jvalue _value; 1.198 + }; 1.199 + 1.200 + // Accumulated compiler state: 1.201 + stringStream _bytes; 1.202 + GrowableArray<Handle> _constant_oops; 1.203 + GrowableArray<PrimCon*> _constant_prims; 1.204 + int _max_stack; 1.205 + int _num_params; 1.206 + int _max_locals; 1.207 + int _name_index; 1.208 + int _signature_index; 1.209 + 1.210 + // Stack values: 1.211 + enum TokenType { 1.212 + tt_void, 1.213 + tt_parameter, 1.214 + tt_temporary, 1.215 + tt_constant 1.216 + }; 1.217 + 1.218 + ArgToken make_stack_value(TokenType tt, BasicType type, int id) { 1.219 + return ArgToken( ((intptr_t)id << 8) | ((intptr_t)type << 4) | (intptr_t)tt ); 1.220 + } 1.221 + 1.222 +public: 1.223 + virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { 1.224 + return make_stack_value(tt_parameter, type, argnum); 1.225 + } 1.226 + virtual ArgToken make_oop_constant(oop con, TRAPS) { 1.227 + return make_stack_value(tt_constant, T_OBJECT, find_oop_constant(con)); 1.228 + } 1.229 + virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { 1.230 + return make_stack_value(tt_constant, type, find_prim_constant(type, con)); 1.231 + } 1.232 + virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS); 1.233 + virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS); 1.234 + virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); 1.235 + 1.236 + int find_oop_constant(oop con); 1.237 + int find_prim_constant(BasicType type, jvalue* con); 1.238 + 1.239 +public: 1.240 + MethodHandleCompiler(Handle root, TRAPS) 1.241 + : MethodHandleWalker(root, THREAD), 1.242 + _thread(THREAD), 1.243 + _bytes(50), 1.244 + _constant_oops(THREAD, 10), 1.245 + _constant_prims(THREAD, 10), 1.246 + _max_stack(0), _max_locals(0), 1.247 + _name_index(0), _signature_index(0) 1.248 + { } 1.249 + const char* bytes() { return _bytes.as_string(); } 1.250 + int constant_length() { return _constant_oops.length(); } 1.251 + int max_stack() { return _max_stack; } 1.252 + int max_locals() { return _max_locals; } 1.253 + int name_index() { return _name_index; } 1.254 + int signature_index() { return _signature_index; } 1.255 + symbolHandle name() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_name_index)()); } 1.256 + symbolHandle signature() { return symbolHandle(_thread, (symbolOop)constant_oop_at(_signature_index)()); } 1.257 + 1.258 + bool constant_is_oop_at(int i) { 1.259 + return (_constant_prims.at(i) == NULL); 1.260 + } 1.261 + Handle constant_oop_at(int i) { 1.262 + assert(constant_is_oop_at(i), ""); 1.263 + return _constant_oops.at(i); 1.264 + } 1.265 + PrimCon* constant_prim_at(int i) { 1.266 + assert(!constant_is_oop_at(i), ""); 1.267 + return _constant_prims.at(i); 1.268 + } 1.269 + 1.270 + // Compile the given MH chain into bytecode. 1.271 + void compile(TRAPS); 1.272 +};