Fri, 03 Jun 2011 22:31:43 -0700
7045514: SPARC assembly code for JSR 292 ricochet frames
Reviewed-by: kvn, jrose
twisti@1568 | 1 | /* |
jrose@2639 | 2 | * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. |
twisti@1568 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
twisti@1568 | 4 | * |
twisti@1568 | 5 | * This code is free software; you can redistribute it and/or modify it |
twisti@1568 | 6 | * under the terms of the GNU General Public License version 2 only, as |
twisti@1568 | 7 | * published by the Free Software Foundation. |
twisti@1568 | 8 | * |
twisti@1568 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
twisti@1568 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
twisti@1568 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
twisti@1568 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
twisti@1568 | 13 | * accompanied this code). |
twisti@1568 | 14 | * |
twisti@1568 | 15 | * You should have received a copy of the GNU General Public License version |
twisti@1568 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
twisti@1568 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
twisti@1568 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
twisti@1568 | 22 | * |
twisti@1568 | 23 | */ |
twisti@1568 | 24 | |
stefank@2314 | 25 | #ifndef SHARE_VM_PRIMS_METHODHANDLEWALK_HPP |
stefank@2314 | 26 | #define SHARE_VM_PRIMS_METHODHANDLEWALK_HPP |
stefank@2314 | 27 | |
stefank@2314 | 28 | #include "prims/methodHandles.hpp" |
stefank@2314 | 29 | |
twisti@1568 | 30 | // Low-level parser for method handle chains. |
twisti@1568 | 31 | class MethodHandleChain : StackObj { |
twisti@1568 | 32 | public: |
twisti@1568 | 33 | typedef MethodHandles::EntryKind EntryKind; |
twisti@1568 | 34 | |
twisti@1568 | 35 | private: |
twisti@1568 | 36 | Handle _root; // original target |
twisti@1568 | 37 | Handle _method_handle; // current target |
twisti@1568 | 38 | bool _is_last; // final guy in chain |
twisti@1568 | 39 | bool _is_bound; // has a bound argument |
twisti@1568 | 40 | BasicType _arg_type; // if is_bound, the bound argument type |
twisti@1568 | 41 | int _arg_slot; // if is_bound or is_adapter, affected argument slot |
twisti@1568 | 42 | jint _conversion; // conversion field of AMH or -1 |
twisti@1568 | 43 | methodHandle _last_method; // if is_last, which method we target |
twisti@1568 | 44 | Bytecodes::Code _last_invoke; // if is_last, type of invoke |
twisti@1568 | 45 | const char* _lose_message; // saved argument to lose() |
twisti@1568 | 46 | |
twisti@1568 | 47 | void set_method_handle(Handle target, TRAPS); |
twisti@1568 | 48 | void set_last_method(oop target, TRAPS); |
twisti@1568 | 49 | static BasicType compute_bound_arg_type(oop target, methodOop m, int arg_slot, TRAPS); |
twisti@1568 | 50 | |
jrose@2639 | 51 | oop MethodHandle_type_oop() { return java_lang_invoke_MethodHandle::type(method_handle_oop()); } |
jrose@2639 | 52 | oop MethodHandle_vmtarget_oop() { return java_lang_invoke_MethodHandle::vmtarget(method_handle_oop()); } |
jrose@2639 | 53 | int MethodHandle_vmslots() { return java_lang_invoke_MethodHandle::vmslots(method_handle_oop()); } |
jrose@2639 | 54 | int DirectMethodHandle_vmindex() { return java_lang_invoke_DirectMethodHandle::vmindex(method_handle_oop()); } |
jrose@2639 | 55 | oop BoundMethodHandle_argument_oop() { return java_lang_invoke_BoundMethodHandle::argument(method_handle_oop()); } |
jrose@2639 | 56 | int BoundMethodHandle_vmargslot() { return java_lang_invoke_BoundMethodHandle::vmargslot(method_handle_oop()); } |
jrose@2639 | 57 | int AdapterMethodHandle_conversion() { return java_lang_invoke_AdapterMethodHandle::conversion(method_handle_oop()); } |
twisti@1568 | 58 | |
never@2937 | 59 | #ifdef ASSERT |
never@2937 | 60 | void print_impl(TRAPS); |
never@2937 | 61 | #endif |
never@2937 | 62 | |
twisti@1568 | 63 | public: |
twisti@1568 | 64 | MethodHandleChain(Handle root, TRAPS) |
twisti@1568 | 65 | : _root(root) |
twisti@1568 | 66 | { set_method_handle(root, THREAD); } |
twisti@1568 | 67 | |
twisti@1568 | 68 | bool is_adapter() { return _conversion != -1; } |
twisti@1568 | 69 | bool is_bound() { return _is_bound; } |
twisti@1568 | 70 | bool is_last() { return _is_last; } |
twisti@1568 | 71 | |
twisti@1568 | 72 | void next(TRAPS) { |
twisti@1568 | 73 | assert(!is_last(), ""); |
twisti@1568 | 74 | set_method_handle(MethodHandle_vmtarget_oop(), THREAD); |
twisti@1568 | 75 | } |
twisti@1568 | 76 | |
twisti@1568 | 77 | Handle method_handle() { return _method_handle; } |
twisti@1568 | 78 | oop method_handle_oop() { return _method_handle(); } |
twisti@1568 | 79 | oop method_type_oop() { return MethodHandle_type_oop(); } |
twisti@1573 | 80 | oop vmtarget_oop() { return MethodHandle_vmtarget_oop(); } |
twisti@1568 | 81 | |
twisti@1568 | 82 | jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } |
twisti@1568 | 83 | int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); } |
twisti@1568 | 84 | BasicType adapter_conversion_src_type() |
twisti@1568 | 85 | { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); } |
twisti@1568 | 86 | BasicType adapter_conversion_dest_type() |
twisti@1568 | 87 | { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); } |
twisti@1568 | 88 | int adapter_conversion_stack_move() |
twisti@1568 | 89 | { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); } |
twisti@1568 | 90 | int adapter_conversion_stack_pushes() |
twisti@1568 | 91 | { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); } |
twisti@1568 | 92 | int adapter_conversion_vminfo() |
twisti@1568 | 93 | { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); } |
twisti@1568 | 94 | int adapter_arg_slot() { assert(is_adapter(), ""); return _arg_slot; } |
twisti@1568 | 95 | oop adapter_arg_oop() { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 96 | |
twisti@1568 | 97 | BasicType bound_arg_type() { assert(is_bound(), ""); return _arg_type; } |
twisti@1568 | 98 | int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } |
twisti@1568 | 99 | oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 100 | |
twisti@1568 | 101 | methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } |
twisti@1568 | 102 | Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } |
twisti@1568 | 103 | |
twisti@1568 | 104 | void lose(const char* msg, TRAPS); |
twisti@1568 | 105 | const char* lose_message() { return _lose_message; } |
never@2937 | 106 | |
never@2937 | 107 | #ifdef ASSERT |
never@2937 | 108 | // Print a symbolic description of a method handle chain, including |
never@2937 | 109 | // the signature for each method. The signatures are printed in |
never@2937 | 110 | // slot order to make it easier to understand. |
never@2937 | 111 | void print(); |
never@2937 | 112 | static void print(Handle mh); |
never@2950 | 113 | static void print(oopDesc* mh); |
never@2937 | 114 | #endif |
twisti@1568 | 115 | }; |
twisti@1568 | 116 | |
twisti@1568 | 117 | |
twisti@1568 | 118 | // Structure walker for method handles. |
twisti@1568 | 119 | // Does abstract interpretation on top of low-level parsing. |
twisti@1568 | 120 | // You supply the tokens shuffled by the abstract interpretation. |
twisti@1568 | 121 | class MethodHandleWalker : StackObj { |
twisti@1568 | 122 | public: |
twisti@1573 | 123 | // Stack values: |
twisti@1573 | 124 | enum TokenType { |
twisti@1573 | 125 | tt_void, |
twisti@1573 | 126 | tt_parameter, |
twisti@1573 | 127 | tt_temporary, |
twisti@1573 | 128 | tt_constant, |
twisti@2903 | 129 | tt_symbolic, |
twisti@1573 | 130 | tt_illegal |
twisti@1573 | 131 | }; |
twisti@1573 | 132 | |
twisti@1573 | 133 | // Argument token: |
twisti@1573 | 134 | class ArgToken { |
twisti@1573 | 135 | private: |
twisti@1573 | 136 | TokenType _tt; |
twisti@1573 | 137 | BasicType _bt; |
twisti@1573 | 138 | jvalue _value; |
twisti@1573 | 139 | Handle _handle; |
twisti@1573 | 140 | |
twisti@1573 | 141 | public: |
never@2937 | 142 | ArgToken(TokenType tt = tt_illegal) : _tt(tt), _bt(tt == tt_void ? T_VOID : T_ILLEGAL) { |
never@2920 | 143 | assert(tt == tt_illegal || tt == tt_void, "invalid token type"); |
never@2920 | 144 | } |
twisti@1573 | 145 | |
twisti@1573 | 146 | ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) { |
never@2920 | 147 | assert(_tt == tt_parameter || _tt == tt_temporary, "must have index"); |
twisti@1573 | 148 | _value.i = index; |
twisti@1573 | 149 | } |
twisti@1573 | 150 | |
never@2937 | 151 | ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) { assert(_bt != T_OBJECT, "wrong constructor"); } |
never@2937 | 152 | ArgToken(Handle handle) : _tt(tt_constant), _bt(T_OBJECT), _handle(handle) {} |
never@2920 | 153 | |
never@2920 | 154 | |
never@2937 | 155 | ArgToken(const char* str, BasicType type) : _tt(tt_symbolic), _bt(type) { |
never@2920 | 156 | _value.j = (intptr_t)str; |
twisti@1573 | 157 | } |
twisti@1573 | 158 | |
twisti@1573 | 159 | TokenType token_type() const { return _tt; } |
twisti@1573 | 160 | BasicType basic_type() const { return _bt; } |
never@2920 | 161 | bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; } |
never@2920 | 162 | int index() const { assert(has_index(), "must have index");; return _value.i; } |
never@2937 | 163 | Handle object() const { assert(_bt == T_OBJECT, "wrong accessor"); assert(_tt == tt_constant, "value type"); return _handle; } |
never@2937 | 164 | const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)(intptr_t)_value.j; } |
twisti@1573 | 165 | |
never@2937 | 166 | jint get_jint() const { assert(_bt == T_INT || is_subword_type(_bt), "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.i; } |
never@2937 | 167 | jlong get_jlong() const { assert(_bt == T_LONG, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.j; } |
never@2937 | 168 | jfloat get_jfloat() const { assert(_bt == T_FLOAT, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.f; } |
never@2937 | 169 | jdouble get_jdouble() const { assert(_bt == T_DOUBLE, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.d; } |
twisti@1573 | 170 | }; |
twisti@1568 | 171 | |
twisti@1568 | 172 | private: |
twisti@1568 | 173 | MethodHandleChain _chain; |
twisti@1573 | 174 | bool _for_invokedynamic; |
twisti@1573 | 175 | int _local_index; |
twisti@1568 | 176 | |
twisti@2903 | 177 | // This array is kept in an unusual order, indexed by low-level "slot number". |
twisti@2903 | 178 | // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array. |
twisti@2903 | 179 | // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1). |
twisti@2903 | 180 | // If a value at _outgoing.at(n) is T_LONG or T_DOUBLE, the value at _outgoing.at(n+1) is T_VOID. |
never@2937 | 181 | GrowableArray<ArgToken> _outgoing; // current outgoing parameter slots |
twisti@1568 | 182 | int _outgoing_argc; // # non-empty outgoing slots |
twisti@1568 | 183 | |
twisti@1568 | 184 | // Replace a value of type old_type at slot (and maybe slot+1) with the new value. |
twisti@1568 | 185 | // If old_type != T_VOID, remove the old argument at that point. |
twisti@1568 | 186 | // If new_type != T_VOID, insert the new argument at that point. |
twisti@1568 | 187 | // Insert or delete a second empty slot as needed. |
never@2937 | 188 | void change_argument(BasicType old_type, int slot, const ArgToken& new_arg); |
never@2937 | 189 | void change_argument(BasicType old_type, int slot, BasicType type, const ArgToken& new_arg) { |
never@2937 | 190 | assert(type == new_arg.basic_type(), "must agree"); |
never@2937 | 191 | change_argument(old_type, slot, new_arg); |
never@2937 | 192 | } |
twisti@1568 | 193 | |
twisti@2903 | 194 | // Raw retype conversions for OP_RAW_RETYPE. |
twisti@2903 | 195 | void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS); |
twisti@2903 | 196 | void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); } |
twisti@2903 | 197 | void retype_raw_return_type( BasicType src, BasicType dst, TRAPS) { retype_raw_conversion(src, dst, true, -1, CHECK); } |
twisti@2903 | 198 | |
never@2937 | 199 | BasicType arg_type(int slot) { |
never@2937 | 200 | return _outgoing.at(slot).basic_type(); |
twisti@1568 | 201 | } |
never@2937 | 202 | bool has_argument(int slot) { |
never@2937 | 203 | return arg_type(slot) < T_VOID; |
twisti@1568 | 204 | } |
twisti@1568 | 205 | |
twisti@1568 | 206 | #ifdef ASSERT |
twisti@1568 | 207 | int argument_count_slow(); |
twisti@1568 | 208 | #endif |
twisti@1568 | 209 | |
twisti@1568 | 210 | // Return a bytecode for converting src to dest, if one exists. |
twisti@1568 | 211 | Bytecodes::Code conversion_code(BasicType src, BasicType dest); |
twisti@1568 | 212 | |
twisti@1568 | 213 | void walk_incoming_state(TRAPS); |
twisti@1568 | 214 | |
never@2937 | 215 | void verify_args_and_signature(TRAPS) NOT_DEBUG_RETURN; |
never@2937 | 216 | |
twisti@1568 | 217 | public: |
twisti@1573 | 218 | MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS) |
twisti@1568 | 219 | : _chain(root, THREAD), |
twisti@1573 | 220 | _for_invokedynamic(for_invokedynamic), |
twisti@1568 | 221 | _outgoing(THREAD, 10), |
twisti@1568 | 222 | _outgoing_argc(0) |
twisti@1573 | 223 | { |
twisti@1573 | 224 | _local_index = for_invokedynamic ? 0 : 1; |
twisti@1573 | 225 | } |
twisti@1568 | 226 | |
twisti@1568 | 227 | MethodHandleChain& chain() { return _chain; } |
twisti@1568 | 228 | |
twisti@1573 | 229 | bool for_invokedynamic() const { return _for_invokedynamic; } |
twisti@1573 | 230 | |
twisti@1573 | 231 | int new_local_index(BasicType bt) { |
twisti@1573 | 232 | //int index = _for_invokedynamic ? _local_index : _local_index - 1; |
twisti@1573 | 233 | int index = _local_index; |
twisti@1573 | 234 | _local_index += type2size[bt]; |
twisti@1573 | 235 | return index; |
twisti@1573 | 236 | } |
twisti@1573 | 237 | |
twisti@1573 | 238 | int max_locals() const { return _local_index; } |
twisti@1573 | 239 | |
twisti@1568 | 240 | // plug-in abstract interpretation steps: |
twisti@2903 | 241 | virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) = 0; |
twisti@2903 | 242 | virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) = 0; |
twisti@2903 | 243 | virtual ArgToken make_oop_constant(oop con, TRAPS) = 0; |
twisti@2903 | 244 | virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0; |
twisti@2903 | 245 | virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0; |
twisti@2903 | 246 | virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0; |
twisti@1568 | 247 | |
twisti@1568 | 248 | // For make_invoke, the methodOop can be NULL if the intrinsic ID |
twisti@1568 | 249 | // is something other than vmIntrinsics::_none. |
twisti@1568 | 250 | |
twisti@1568 | 251 | // and in case anyone cares to related the previous actions to the chain: |
twisti@1568 | 252 | virtual void set_method_handle(oop mh) { } |
twisti@1568 | 253 | |
twisti@1568 | 254 | void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); } |
twisti@1568 | 255 | const char* lose_message() { return chain().lose_message(); } |
twisti@1568 | 256 | |
twisti@1568 | 257 | ArgToken walk(TRAPS); |
twisti@1568 | 258 | }; |
twisti@1568 | 259 | |
twisti@1568 | 260 | |
twisti@1568 | 261 | // An abstract interpreter for method handle chains. |
twisti@1568 | 262 | // Produces an account of the semantics of a chain, in terms of a static IR. |
twisti@1568 | 263 | // The IR happens to be JVM bytecodes. |
twisti@1568 | 264 | class MethodHandleCompiler : public MethodHandleWalker { |
twisti@1568 | 265 | private: |
twisti@2898 | 266 | int _invoke_count; // count the original call site has been executed |
twisti@1573 | 267 | KlassHandle _rklass; // Return type for casting. |
twisti@1573 | 268 | BasicType _rtype; |
twisti@1573 | 269 | KlassHandle _target_klass; |
twisti@1573 | 270 | Thread* _thread; |
twisti@1568 | 271 | |
twisti@2903 | 272 | // Values used by the compiler. |
twisti@2903 | 273 | static jvalue zero_jvalue; |
twisti@2903 | 274 | static jvalue one_jvalue; |
twisti@2903 | 275 | |
twisti@1573 | 276 | // Fake constant pool entry. |
never@2950 | 277 | class ConstantValue : public ResourceObj { |
twisti@1573 | 278 | private: |
twisti@1573 | 279 | int _tag; // Constant pool tag type. |
twisti@1573 | 280 | JavaValue _value; |
twisti@1573 | 281 | Handle _handle; |
coleenp@2497 | 282 | Symbol* _sym; |
twisti@1573 | 283 | |
twisti@1573 | 284 | public: |
twisti@1573 | 285 | // Constructor for oop types. |
twisti@1573 | 286 | ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) { |
coleenp@2497 | 287 | assert(tag == JVM_CONSTANT_Class || |
twisti@1573 | 288 | tag == JVM_CONSTANT_String || |
twisti@1573 | 289 | tag == JVM_CONSTANT_Object, "must be oop type"); |
twisti@1573 | 290 | } |
twisti@1573 | 291 | |
coleenp@2497 | 292 | ConstantValue(int tag, Symbol* con) : _tag(tag), _sym(con) { |
coleenp@2497 | 293 | assert(tag == JVM_CONSTANT_Utf8, "must be symbol type"); |
coleenp@2497 | 294 | } |
coleenp@2497 | 295 | |
twisti@1573 | 296 | // Constructor for oop reference types. |
twisti@1573 | 297 | ConstantValue(int tag, int index) : _tag(tag) { |
twisti@1573 | 298 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 299 | _value.set_jint(index); |
twisti@1573 | 300 | } |
twisti@1573 | 301 | ConstantValue(int tag, int first_index, int second_index) : _tag(tag) { |
twisti@1573 | 302 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 303 | _value.set_jint(first_index << 16 | second_index); |
twisti@1573 | 304 | } |
twisti@1573 | 305 | |
twisti@1573 | 306 | // Constructor for primitive types. |
twisti@1573 | 307 | ConstantValue(BasicType bt, jvalue con) { |
twisti@1573 | 308 | _value.set_type(bt); |
twisti@1573 | 309 | switch (bt) { |
twisti@1573 | 310 | case T_INT: _tag = JVM_CONSTANT_Integer; _value.set_jint( con.i); break; |
twisti@1573 | 311 | case T_LONG: _tag = JVM_CONSTANT_Long; _value.set_jlong( con.j); break; |
twisti@1573 | 312 | case T_FLOAT: _tag = JVM_CONSTANT_Float; _value.set_jfloat( con.f); break; |
twisti@1573 | 313 | case T_DOUBLE: _tag = JVM_CONSTANT_Double; _value.set_jdouble(con.d); break; |
twisti@1573 | 314 | default: ShouldNotReachHere(); |
twisti@1573 | 315 | } |
twisti@1573 | 316 | } |
twisti@1573 | 317 | |
twisti@1573 | 318 | int tag() const { return _tag; } |
coleenp@2497 | 319 | Symbol* symbol() const { return _sym; } |
twisti@1573 | 320 | klassOop klass_oop() const { return (klassOop) _handle(); } |
twisti@1573 | 321 | oop object_oop() const { return _handle(); } |
twisti@1573 | 322 | int index() const { return _value.get_jint(); } |
twisti@1573 | 323 | int first_index() const { return _value.get_jint() >> 16; } |
twisti@1573 | 324 | int second_index() const { return _value.get_jint() & 0x0000FFFF; } |
twisti@1573 | 325 | |
twisti@1573 | 326 | bool is_primitive() const { return is_java_primitive(_value.get_type()); } |
twisti@1573 | 327 | jint get_jint() const { return _value.get_jint(); } |
twisti@1573 | 328 | jlong get_jlong() const { return _value.get_jlong(); } |
twisti@1573 | 329 | jfloat get_jfloat() const { return _value.get_jfloat(); } |
twisti@1573 | 330 | jdouble get_jdouble() const { return _value.get_jdouble(); } |
twisti@1568 | 331 | }; |
twisti@1568 | 332 | |
twisti@1573 | 333 | // Fake constant pool. |
twisti@1573 | 334 | GrowableArray<ConstantValue*> _constants; |
twisti@1573 | 335 | |
twisti@1568 | 336 | // Accumulated compiler state: |
twisti@1573 | 337 | GrowableArray<unsigned char> _bytecode; |
twisti@1573 | 338 | |
twisti@1573 | 339 | int _cur_stack; |
twisti@1568 | 340 | int _max_stack; |
twisti@1568 | 341 | int _num_params; |
twisti@1568 | 342 | int _name_index; |
twisti@1568 | 343 | int _signature_index; |
twisti@1568 | 344 | |
twisti@1573 | 345 | void stack_push(BasicType bt) { |
twisti@1573 | 346 | _cur_stack += type2size[bt]; |
twisti@1573 | 347 | if (_cur_stack > _max_stack) _max_stack = _cur_stack; |
twisti@1573 | 348 | } |
twisti@1573 | 349 | void stack_pop(BasicType bt) { |
twisti@1573 | 350 | _cur_stack -= type2size[bt]; |
twisti@1573 | 351 | assert(_cur_stack >= 0, "sanity"); |
twisti@1568 | 352 | } |
twisti@1568 | 353 | |
twisti@1573 | 354 | unsigned char* bytecode() const { return _bytecode.adr_at(0); } |
twisti@1573 | 355 | int bytecode_length() const { return _bytecode.length(); } |
twisti@1573 | 356 | |
twisti@1573 | 357 | // Fake constant pool. |
twisti@1573 | 358 | int cpool_oop_put(int tag, Handle con) { |
twisti@1573 | 359 | if (con.is_null()) return 0; |
twisti@1573 | 360 | ConstantValue* cv = new ConstantValue(tag, con); |
twisti@1573 | 361 | return _constants.append(cv); |
twisti@1573 | 362 | } |
twisti@1573 | 363 | |
coleenp@2497 | 364 | int cpool_symbol_put(int tag, Symbol* con) { |
coleenp@2497 | 365 | if (con == NULL) return 0; |
coleenp@2497 | 366 | ConstantValue* cv = new ConstantValue(tag, con); |
jrose@2760 | 367 | con->increment_refcount(); |
coleenp@2497 | 368 | return _constants.append(cv); |
coleenp@2497 | 369 | } |
coleenp@2497 | 370 | |
twisti@1573 | 371 | int cpool_oop_reference_put(int tag, int first_index, int second_index) { |
twisti@1573 | 372 | if (first_index == 0 && second_index == 0) return 0; |
twisti@1573 | 373 | assert(first_index != 0 && second_index != 0, "no zero indexes"); |
twisti@1573 | 374 | ConstantValue* cv = new ConstantValue(tag, first_index, second_index); |
twisti@1573 | 375 | return _constants.append(cv); |
twisti@1573 | 376 | } |
twisti@1573 | 377 | |
twisti@1573 | 378 | int cpool_primitive_put(BasicType type, jvalue* con); |
twisti@1573 | 379 | |
twisti@1573 | 380 | int cpool_int_put(jint value) { |
twisti@1573 | 381 | jvalue con; con.i = value; |
twisti@1573 | 382 | return cpool_primitive_put(T_INT, &con); |
twisti@1573 | 383 | } |
twisti@1573 | 384 | int cpool_long_put(jlong value) { |
twisti@1573 | 385 | jvalue con; con.j = value; |
twisti@1573 | 386 | return cpool_primitive_put(T_LONG, &con); |
twisti@1573 | 387 | } |
twisti@1573 | 388 | int cpool_float_put(jfloat value) { |
twisti@1573 | 389 | jvalue con; con.f = value; |
twisti@1573 | 390 | return cpool_primitive_put(T_FLOAT, &con); |
twisti@1573 | 391 | } |
twisti@1573 | 392 | int cpool_double_put(jdouble value) { |
twisti@1573 | 393 | jvalue con; con.d = value; |
twisti@1573 | 394 | return cpool_primitive_put(T_DOUBLE, &con); |
twisti@1573 | 395 | } |
twisti@1573 | 396 | |
twisti@1573 | 397 | int cpool_object_put(Handle obj) { |
twisti@1573 | 398 | return cpool_oop_put(JVM_CONSTANT_Object, obj); |
twisti@1573 | 399 | } |
coleenp@2497 | 400 | int cpool_symbol_put(Symbol* sym) { |
coleenp@2497 | 401 | return cpool_symbol_put(JVM_CONSTANT_Utf8, sym); |
twisti@1573 | 402 | } |
twisti@1573 | 403 | int cpool_klass_put(klassOop klass) { |
twisti@1573 | 404 | return cpool_oop_put(JVM_CONSTANT_Class, klass); |
twisti@1573 | 405 | } |
twisti@1573 | 406 | int cpool_methodref_put(int class_index, int name_and_type_index) { |
twisti@1573 | 407 | return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index); |
twisti@1573 | 408 | } |
twisti@1573 | 409 | int cpool_name_and_type_put(int name_index, int signature_index) { |
twisti@1573 | 410 | return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index); |
twisti@1573 | 411 | } |
twisti@1573 | 412 | |
never@2920 | 413 | void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); |
twisti@1573 | 414 | void emit_load(BasicType bt, int index); |
twisti@1573 | 415 | void emit_store(BasicType bt, int index); |
twisti@1573 | 416 | void emit_load_constant(ArgToken arg); |
twisti@1573 | 417 | |
twisti@1568 | 418 | virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { |
twisti@1573 | 419 | return ArgToken(tt_parameter, type, argnum); |
twisti@1568 | 420 | } |
twisti@1568 | 421 | virtual ArgToken make_oop_constant(oop con, TRAPS) { |
twisti@1573 | 422 | Handle h(THREAD, con); |
never@2937 | 423 | return ArgToken(h); |
twisti@1568 | 424 | } |
twisti@1568 | 425 | virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { |
never@2920 | 426 | return ArgToken(type, *con); |
twisti@1568 | 427 | } |
twisti@1573 | 428 | |
twisti@1573 | 429 | virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); |
twisti@1573 | 430 | virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS); |
twisti@1568 | 431 | virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); |
twisti@1568 | 432 | |
twisti@1573 | 433 | // Get a real constant pool. |
twisti@1573 | 434 | constantPoolHandle get_constant_pool(TRAPS) const; |
twisti@1573 | 435 | |
twisti@1573 | 436 | // Get a real methodOop. |
twisti@1573 | 437 | methodHandle get_method_oop(TRAPS) const; |
twisti@1568 | 438 | |
twisti@1568 | 439 | public: |
never@2920 | 440 | MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS); |
twisti@1568 | 441 | |
twisti@1568 | 442 | // Compile the given MH chain into bytecode. |
twisti@1573 | 443 | methodHandle compile(TRAPS); |
twisti@1587 | 444 | |
twisti@1587 | 445 | // Tests if the given class is a MH adapter holder. |
twisti@1587 | 446 | static bool klass_is_method_handle_adapter_holder(klassOop klass) { |
twisti@2343 | 447 | return (klass == SystemDictionary::MethodHandle_klass()); |
twisti@1587 | 448 | } |
twisti@1568 | 449 | }; |
stefank@2314 | 450 | |
stefank@2314 | 451 | #endif // SHARE_VM_PRIMS_METHODHANDLEWALK_HPP |