Wed, 14 Mar 2012 20:06:48 -0700
7123170: JCK vm/jvmti/ResourceExhausted/resexh001/resexh00101/ tests fails since 7u4 b02
Summary: The JVMTI ResourceExhausted events must be generated in all places where OOME is thrown
Reviewed-by: acorn, coleenp, dcubed, dholmes, dsamersoff, jwilhelm, tonyp
Contributed-by: serguei.spitsyn@oracle.com
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 | |
never@3105 | 77 | Handle root() { return _root; } |
twisti@1568 | 78 | Handle method_handle() { return _method_handle; } |
twisti@1568 | 79 | oop method_handle_oop() { return _method_handle(); } |
twisti@1568 | 80 | oop method_type_oop() { return MethodHandle_type_oop(); } |
twisti@1573 | 81 | oop vmtarget_oop() { return MethodHandle_vmtarget_oop(); } |
twisti@1568 | 82 | |
twisti@1568 | 83 | jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } |
twisti@1568 | 84 | int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); } |
twisti@1568 | 85 | BasicType adapter_conversion_src_type() |
twisti@1568 | 86 | { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); } |
twisti@1568 | 87 | BasicType adapter_conversion_dest_type() |
twisti@1568 | 88 | { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); } |
twisti@1568 | 89 | int adapter_conversion_stack_move() |
twisti@1568 | 90 | { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); } |
twisti@1568 | 91 | int adapter_conversion_stack_pushes() |
twisti@1568 | 92 | { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); } |
twisti@1568 | 93 | int adapter_conversion_vminfo() |
twisti@1568 | 94 | { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); } |
twisti@1568 | 95 | int adapter_arg_slot() { assert(is_adapter(), ""); return _arg_slot; } |
twisti@1568 | 96 | oop adapter_arg_oop() { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 97 | |
twisti@1568 | 98 | BasicType bound_arg_type() { assert(is_bound(), ""); return _arg_type; } |
twisti@1568 | 99 | int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } |
twisti@1568 | 100 | oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 101 | |
jrose@2982 | 102 | methodHandle last_method() { assert(is_last(), ""); return _last_method; } |
twisti@1568 | 103 | methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } |
twisti@1568 | 104 | Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } |
twisti@1568 | 105 | |
twisti@1568 | 106 | void lose(const char* msg, TRAPS); |
twisti@1568 | 107 | const char* lose_message() { return _lose_message; } |
never@2937 | 108 | |
never@2937 | 109 | #ifdef ASSERT |
never@2937 | 110 | // Print a symbolic description of a method handle chain, including |
never@2937 | 111 | // the signature for each method. The signatures are printed in |
never@2937 | 112 | // slot order to make it easier to understand. |
never@2937 | 113 | void print(); |
never@2950 | 114 | static void print(oopDesc* mh); |
never@2937 | 115 | #endif |
twisti@1568 | 116 | }; |
twisti@1568 | 117 | |
twisti@1568 | 118 | |
twisti@1568 | 119 | // Structure walker for method handles. |
twisti@1568 | 120 | // Does abstract interpretation on top of low-level parsing. |
twisti@1568 | 121 | // You supply the tokens shuffled by the abstract interpretation. |
twisti@1568 | 122 | class MethodHandleWalker : StackObj { |
twisti@1568 | 123 | public: |
twisti@1573 | 124 | // Stack values: |
twisti@1573 | 125 | enum TokenType { |
twisti@1573 | 126 | tt_void, |
twisti@1573 | 127 | tt_parameter, |
twisti@1573 | 128 | tt_temporary, |
twisti@1573 | 129 | tt_constant, |
twisti@2903 | 130 | tt_symbolic, |
twisti@1573 | 131 | tt_illegal |
twisti@1573 | 132 | }; |
twisti@1573 | 133 | |
twisti@1573 | 134 | // Argument token: |
twisti@1573 | 135 | class ArgToken { |
twisti@1573 | 136 | private: |
twisti@1573 | 137 | TokenType _tt; |
twisti@1573 | 138 | BasicType _bt; |
twisti@1573 | 139 | jvalue _value; |
twisti@1573 | 140 | Handle _handle; |
twisti@1573 | 141 | |
twisti@1573 | 142 | public: |
never@2937 | 143 | ArgToken(TokenType tt = tt_illegal) : _tt(tt), _bt(tt == tt_void ? T_VOID : T_ILLEGAL) { |
never@2920 | 144 | assert(tt == tt_illegal || tt == tt_void, "invalid token type"); |
never@2920 | 145 | } |
twisti@1573 | 146 | |
twisti@1573 | 147 | ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) { |
never@2920 | 148 | assert(_tt == tt_parameter || _tt == tt_temporary, "must have index"); |
twisti@1573 | 149 | _value.i = index; |
twisti@1573 | 150 | } |
twisti@1573 | 151 | |
never@2937 | 152 | ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) { assert(_bt != T_OBJECT, "wrong constructor"); } |
never@2937 | 153 | ArgToken(Handle handle) : _tt(tt_constant), _bt(T_OBJECT), _handle(handle) {} |
never@2920 | 154 | |
never@2920 | 155 | |
never@2937 | 156 | ArgToken(const char* str, BasicType type) : _tt(tt_symbolic), _bt(type) { |
never@2920 | 157 | _value.j = (intptr_t)str; |
twisti@1573 | 158 | } |
twisti@1573 | 159 | |
twisti@1573 | 160 | TokenType token_type() const { return _tt; } |
twisti@1573 | 161 | BasicType basic_type() const { return _bt; } |
never@2920 | 162 | bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; } |
never@2920 | 163 | int index() const { assert(has_index(), "must have index");; return _value.i; } |
never@2937 | 164 | Handle object() const { assert(_bt == T_OBJECT, "wrong accessor"); assert(_tt == tt_constant, "value type"); return _handle; } |
never@2937 | 165 | const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)(intptr_t)_value.j; } |
twisti@1573 | 166 | |
never@2937 | 167 | 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 | 168 | jlong get_jlong() const { assert(_bt == T_LONG, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.j; } |
never@2937 | 169 | jfloat get_jfloat() const { assert(_bt == T_FLOAT, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.f; } |
never@2937 | 170 | jdouble get_jdouble() const { assert(_bt == T_DOUBLE, "wrong accessor"); assert(_tt == tt_constant, "value types"); return _value.d; } |
twisti@1573 | 171 | }; |
twisti@1568 | 172 | |
twisti@1568 | 173 | private: |
twisti@1568 | 174 | MethodHandleChain _chain; |
twisti@1573 | 175 | bool _for_invokedynamic; |
twisti@1573 | 176 | int _local_index; |
twisti@1568 | 177 | |
twisti@2903 | 178 | // This array is kept in an unusual order, indexed by low-level "slot number". |
twisti@2903 | 179 | // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array. |
twisti@2903 | 180 | // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1). |
twisti@2903 | 181 | // 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 | 182 | GrowableArray<ArgToken> _outgoing; // current outgoing parameter slots |
twisti@1568 | 183 | int _outgoing_argc; // # non-empty outgoing slots |
twisti@1568 | 184 | |
jrose@2982 | 185 | vmIntrinsics::ID _return_conv; // Return conversion required by raw retypes. |
jrose@2982 | 186 | |
twisti@1568 | 187 | // Replace a value of type old_type at slot (and maybe slot+1) with the new value. |
twisti@1568 | 188 | // If old_type != T_VOID, remove the old argument at that point. |
twisti@1568 | 189 | // If new_type != T_VOID, insert the new argument at that point. |
twisti@1568 | 190 | // Insert or delete a second empty slot as needed. |
never@2937 | 191 | void change_argument(BasicType old_type, int slot, const ArgToken& new_arg); |
never@2937 | 192 | void change_argument(BasicType old_type, int slot, BasicType type, const ArgToken& new_arg) { |
never@2937 | 193 | assert(type == new_arg.basic_type(), "must agree"); |
never@2937 | 194 | change_argument(old_type, slot, new_arg); |
never@2937 | 195 | } |
twisti@1568 | 196 | |
twisti@2903 | 197 | // Raw retype conversions for OP_RAW_RETYPE. |
twisti@2903 | 198 | void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS); |
twisti@2903 | 199 | void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); } |
twisti@2903 | 200 | void retype_raw_return_type( BasicType src, BasicType dst, TRAPS) { retype_raw_conversion(src, dst, true, -1, CHECK); } |
twisti@2903 | 201 | |
never@2937 | 202 | BasicType arg_type(int slot) { |
never@2937 | 203 | return _outgoing.at(slot).basic_type(); |
twisti@1568 | 204 | } |
never@2937 | 205 | bool has_argument(int slot) { |
never@2937 | 206 | return arg_type(slot) < T_VOID; |
twisti@1568 | 207 | } |
twisti@1568 | 208 | |
twisti@1568 | 209 | #ifdef ASSERT |
twisti@1568 | 210 | int argument_count_slow(); |
twisti@1568 | 211 | #endif |
twisti@1568 | 212 | |
twisti@1568 | 213 | // Return a bytecode for converting src to dest, if one exists. |
twisti@1568 | 214 | Bytecodes::Code conversion_code(BasicType src, BasicType dest); |
twisti@1568 | 215 | |
twisti@1568 | 216 | void walk_incoming_state(TRAPS); |
twisti@1568 | 217 | |
never@2937 | 218 | void verify_args_and_signature(TRAPS) NOT_DEBUG_RETURN; |
never@2937 | 219 | |
twisti@1568 | 220 | public: |
twisti@1573 | 221 | MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS) |
twisti@1568 | 222 | : _chain(root, THREAD), |
twisti@1573 | 223 | _for_invokedynamic(for_invokedynamic), |
twisti@1568 | 224 | _outgoing(THREAD, 10), |
jrose@2982 | 225 | _outgoing_argc(0), |
jrose@2982 | 226 | _return_conv(vmIntrinsics::_none) |
twisti@1573 | 227 | { |
twisti@1573 | 228 | _local_index = for_invokedynamic ? 0 : 1; |
twisti@1573 | 229 | } |
twisti@1568 | 230 | |
twisti@1568 | 231 | MethodHandleChain& chain() { return _chain; } |
twisti@1568 | 232 | |
twisti@1573 | 233 | bool for_invokedynamic() const { return _for_invokedynamic; } |
twisti@1573 | 234 | |
jrose@2982 | 235 | vmIntrinsics::ID return_conv() const { return _return_conv; } |
jrose@2982 | 236 | void set_return_conv(vmIntrinsics::ID c) { _return_conv = c; } |
jrose@2982 | 237 | static vmIntrinsics::ID zero_return_conv() { return vmIntrinsics::_min; } |
jrose@2982 | 238 | |
twisti@1573 | 239 | int new_local_index(BasicType bt) { |
twisti@1573 | 240 | //int index = _for_invokedynamic ? _local_index : _local_index - 1; |
twisti@1573 | 241 | int index = _local_index; |
twisti@1573 | 242 | _local_index += type2size[bt]; |
twisti@1573 | 243 | return index; |
twisti@1573 | 244 | } |
twisti@1573 | 245 | |
twisti@1573 | 246 | int max_locals() const { return _local_index; } |
twisti@1573 | 247 | |
twisti@1568 | 248 | // plug-in abstract interpretation steps: |
twisti@2903 | 249 | virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) = 0; |
twisti@2903 | 250 | virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) = 0; |
twisti@2903 | 251 | virtual ArgToken make_oop_constant(oop con, TRAPS) = 0; |
twisti@2903 | 252 | virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0; |
twisti@2903 | 253 | virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0; |
jrose@2982 | 254 | virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0; |
twisti@1568 | 255 | |
jrose@2982 | 256 | // For make_invoke, the methodHandle can be NULL if the intrinsic ID |
twisti@1568 | 257 | // is something other than vmIntrinsics::_none. |
twisti@1568 | 258 | |
twisti@1568 | 259 | // and in case anyone cares to related the previous actions to the chain: |
twisti@1568 | 260 | virtual void set_method_handle(oop mh) { } |
twisti@1568 | 261 | |
twisti@1568 | 262 | void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); } |
twisti@1568 | 263 | const char* lose_message() { return chain().lose_message(); } |
twisti@1568 | 264 | |
twisti@1568 | 265 | ArgToken walk(TRAPS); |
twisti@1568 | 266 | }; |
twisti@1568 | 267 | |
twisti@1568 | 268 | |
twisti@1568 | 269 | // An abstract interpreter for method handle chains. |
twisti@1568 | 270 | // Produces an account of the semantics of a chain, in terms of a static IR. |
twisti@1568 | 271 | // The IR happens to be JVM bytecodes. |
twisti@1568 | 272 | class MethodHandleCompiler : public MethodHandleWalker { |
twisti@1568 | 273 | private: |
twisti@2898 | 274 | int _invoke_count; // count the original call site has been executed |
twisti@1573 | 275 | KlassHandle _rklass; // Return type for casting. |
twisti@1573 | 276 | BasicType _rtype; |
twisti@1573 | 277 | KlassHandle _target_klass; |
twisti@1573 | 278 | Thread* _thread; |
twisti@1568 | 279 | |
never@3105 | 280 | int _selectAlternative_bci; // These are used for capturing profiles from GWTs |
never@3105 | 281 | int _taken_count; |
never@3105 | 282 | int _not_taken_count; |
never@3105 | 283 | |
twisti@2903 | 284 | // Values used by the compiler. |
twisti@2903 | 285 | static jvalue zero_jvalue; |
twisti@2903 | 286 | static jvalue one_jvalue; |
twisti@2903 | 287 | |
twisti@1573 | 288 | // Fake constant pool entry. |
never@2950 | 289 | class ConstantValue : public ResourceObj { |
twisti@1573 | 290 | private: |
twisti@1573 | 291 | int _tag; // Constant pool tag type. |
twisti@1573 | 292 | JavaValue _value; |
twisti@1573 | 293 | Handle _handle; |
coleenp@2497 | 294 | Symbol* _sym; |
jrose@2982 | 295 | methodHandle _method; // pre-linkage |
twisti@1573 | 296 | |
twisti@1573 | 297 | public: |
twisti@1573 | 298 | // Constructor for oop types. |
twisti@1573 | 299 | ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) { |
coleenp@2497 | 300 | assert(tag == JVM_CONSTANT_Class || |
twisti@1573 | 301 | tag == JVM_CONSTANT_String || |
twisti@1573 | 302 | tag == JVM_CONSTANT_Object, "must be oop type"); |
twisti@1573 | 303 | } |
twisti@1573 | 304 | |
coleenp@2497 | 305 | ConstantValue(int tag, Symbol* con) : _tag(tag), _sym(con) { |
coleenp@2497 | 306 | assert(tag == JVM_CONSTANT_Utf8, "must be symbol type"); |
coleenp@2497 | 307 | } |
coleenp@2497 | 308 | |
twisti@1573 | 309 | // Constructor for oop reference types. |
twisti@1573 | 310 | ConstantValue(int tag, int index) : _tag(tag) { |
twisti@1573 | 311 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 312 | _value.set_jint(index); |
twisti@1573 | 313 | } |
twisti@1573 | 314 | ConstantValue(int tag, int first_index, int second_index) : _tag(tag) { |
twisti@1573 | 315 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 316 | _value.set_jint(first_index << 16 | second_index); |
twisti@1573 | 317 | } |
twisti@1573 | 318 | |
twisti@1573 | 319 | // Constructor for primitive types. |
twisti@1573 | 320 | ConstantValue(BasicType bt, jvalue con) { |
twisti@1573 | 321 | _value.set_type(bt); |
twisti@1573 | 322 | switch (bt) { |
twisti@1573 | 323 | case T_INT: _tag = JVM_CONSTANT_Integer; _value.set_jint( con.i); break; |
twisti@1573 | 324 | case T_LONG: _tag = JVM_CONSTANT_Long; _value.set_jlong( con.j); break; |
twisti@1573 | 325 | case T_FLOAT: _tag = JVM_CONSTANT_Float; _value.set_jfloat( con.f); break; |
twisti@1573 | 326 | case T_DOUBLE: _tag = JVM_CONSTANT_Double; _value.set_jdouble(con.d); break; |
twisti@1573 | 327 | default: ShouldNotReachHere(); |
twisti@1573 | 328 | } |
twisti@1573 | 329 | } |
twisti@1573 | 330 | |
twisti@1573 | 331 | int tag() const { return _tag; } |
coleenp@2497 | 332 | Symbol* symbol() const { return _sym; } |
twisti@1573 | 333 | klassOop klass_oop() const { return (klassOop) _handle(); } |
twisti@1573 | 334 | oop object_oop() const { return _handle(); } |
twisti@1573 | 335 | int index() const { return _value.get_jint(); } |
twisti@1573 | 336 | int first_index() const { return _value.get_jint() >> 16; } |
twisti@1573 | 337 | int second_index() const { return _value.get_jint() & 0x0000FFFF; } |
twisti@1573 | 338 | |
twisti@1573 | 339 | bool is_primitive() const { return is_java_primitive(_value.get_type()); } |
twisti@1573 | 340 | jint get_jint() const { return _value.get_jint(); } |
twisti@1573 | 341 | jlong get_jlong() const { return _value.get_jlong(); } |
twisti@1573 | 342 | jfloat get_jfloat() const { return _value.get_jfloat(); } |
twisti@1573 | 343 | jdouble get_jdouble() const { return _value.get_jdouble(); } |
jrose@2982 | 344 | |
jrose@2982 | 345 | void set_linkage(methodHandle method) { |
jrose@2982 | 346 | assert(_method.is_null(), ""); |
jrose@2982 | 347 | _method = method; |
jrose@2982 | 348 | } |
jrose@2982 | 349 | bool has_linkage() const { return _method.not_null(); } |
jrose@2982 | 350 | methodHandle linkage() const { return _method; } |
twisti@1568 | 351 | }; |
twisti@1568 | 352 | |
twisti@1573 | 353 | // Fake constant pool. |
twisti@1573 | 354 | GrowableArray<ConstantValue*> _constants; |
twisti@1573 | 355 | |
jrose@2982 | 356 | // Non-BCP classes that appear in associated MethodTypes (require special handling). |
jrose@2982 | 357 | GrowableArray<KlassHandle> _non_bcp_klasses; |
jrose@2982 | 358 | |
twisti@1568 | 359 | // Accumulated compiler state: |
twisti@1573 | 360 | GrowableArray<unsigned char> _bytecode; |
twisti@1573 | 361 | |
twisti@1573 | 362 | int _cur_stack; |
twisti@1568 | 363 | int _max_stack; |
twisti@1568 | 364 | int _num_params; |
twisti@1568 | 365 | int _name_index; |
twisti@1568 | 366 | int _signature_index; |
twisti@1568 | 367 | |
twisti@1573 | 368 | void stack_push(BasicType bt) { |
twisti@1573 | 369 | _cur_stack += type2size[bt]; |
twisti@1573 | 370 | if (_cur_stack > _max_stack) _max_stack = _cur_stack; |
twisti@1573 | 371 | } |
twisti@1573 | 372 | void stack_pop(BasicType bt) { |
twisti@1573 | 373 | _cur_stack -= type2size[bt]; |
twisti@1573 | 374 | assert(_cur_stack >= 0, "sanity"); |
twisti@1568 | 375 | } |
twisti@1568 | 376 | |
twisti@1573 | 377 | unsigned char* bytecode() const { return _bytecode.adr_at(0); } |
twisti@1573 | 378 | int bytecode_length() const { return _bytecode.length(); } |
never@3105 | 379 | int cur_bci() const { return _bytecode.length(); } |
twisti@1573 | 380 | |
twisti@1573 | 381 | // Fake constant pool. |
twisti@1573 | 382 | int cpool_oop_put(int tag, Handle con) { |
twisti@1573 | 383 | if (con.is_null()) return 0; |
twisti@1573 | 384 | ConstantValue* cv = new ConstantValue(tag, con); |
twisti@1573 | 385 | return _constants.append(cv); |
twisti@1573 | 386 | } |
twisti@1573 | 387 | |
coleenp@2497 | 388 | int cpool_symbol_put(int tag, Symbol* con) { |
coleenp@2497 | 389 | if (con == NULL) return 0; |
coleenp@2497 | 390 | ConstantValue* cv = new ConstantValue(tag, con); |
jrose@2760 | 391 | con->increment_refcount(); |
coleenp@2497 | 392 | return _constants.append(cv); |
coleenp@2497 | 393 | } |
coleenp@2497 | 394 | |
jrose@2982 | 395 | int cpool_oop_reference_put(int tag, int first_index, int second_index, methodHandle method) { |
twisti@1573 | 396 | if (first_index == 0 && second_index == 0) return 0; |
twisti@1573 | 397 | assert(first_index != 0 && second_index != 0, "no zero indexes"); |
twisti@1573 | 398 | ConstantValue* cv = new ConstantValue(tag, first_index, second_index); |
jrose@2982 | 399 | if (method.not_null()) cv->set_linkage(method); |
twisti@1573 | 400 | return _constants.append(cv); |
twisti@1573 | 401 | } |
twisti@1573 | 402 | |
twisti@1573 | 403 | int cpool_primitive_put(BasicType type, jvalue* con); |
twisti@1573 | 404 | |
jrose@2982 | 405 | bool check_non_bcp_klasses(Handle method_type, TRAPS); |
jrose@2982 | 406 | bool check_non_bcp_klass(klassOop klass, TRAPS); |
jrose@2982 | 407 | void record_non_bcp_klasses(); |
jrose@2982 | 408 | |
twisti@1573 | 409 | int cpool_int_put(jint value) { |
twisti@1573 | 410 | jvalue con; con.i = value; |
twisti@1573 | 411 | return cpool_primitive_put(T_INT, &con); |
twisti@1573 | 412 | } |
twisti@1573 | 413 | int cpool_long_put(jlong value) { |
twisti@1573 | 414 | jvalue con; con.j = value; |
twisti@1573 | 415 | return cpool_primitive_put(T_LONG, &con); |
twisti@1573 | 416 | } |
twisti@1573 | 417 | int cpool_float_put(jfloat value) { |
twisti@1573 | 418 | jvalue con; con.f = value; |
twisti@1573 | 419 | return cpool_primitive_put(T_FLOAT, &con); |
twisti@1573 | 420 | } |
twisti@1573 | 421 | int cpool_double_put(jdouble value) { |
twisti@1573 | 422 | jvalue con; con.d = value; |
twisti@1573 | 423 | return cpool_primitive_put(T_DOUBLE, &con); |
twisti@1573 | 424 | } |
twisti@1573 | 425 | |
twisti@1573 | 426 | int cpool_object_put(Handle obj) { |
twisti@1573 | 427 | return cpool_oop_put(JVM_CONSTANT_Object, obj); |
twisti@1573 | 428 | } |
coleenp@2497 | 429 | int cpool_symbol_put(Symbol* sym) { |
coleenp@2497 | 430 | return cpool_symbol_put(JVM_CONSTANT_Utf8, sym); |
twisti@1573 | 431 | } |
twisti@1573 | 432 | int cpool_klass_put(klassOop klass) { |
twisti@1573 | 433 | return cpool_oop_put(JVM_CONSTANT_Class, klass); |
twisti@1573 | 434 | } |
jrose@2982 | 435 | int cpool_methodref_put(Bytecodes::Code op, int class_index, int name_and_type_index, methodHandle method) { |
jrose@2982 | 436 | int tag = (op == Bytecodes::_invokeinterface ? JVM_CONSTANT_InterfaceMethodref : JVM_CONSTANT_Methodref); |
jrose@2982 | 437 | return cpool_oop_reference_put(tag, class_index, name_and_type_index, method); |
twisti@1573 | 438 | } |
twisti@1573 | 439 | int cpool_name_and_type_put(int name_index, int signature_index) { |
jrose@2982 | 440 | return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index, methodHandle()); |
twisti@1573 | 441 | } |
twisti@1573 | 442 | |
never@2920 | 443 | void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); |
never@3105 | 444 | void update_branch_dest(int src, int dst); |
never@3105 | 445 | void emit_load(ArgToken arg); |
twisti@1573 | 446 | void emit_load(BasicType bt, int index); |
twisti@1573 | 447 | void emit_store(BasicType bt, int index); |
twisti@1573 | 448 | void emit_load_constant(ArgToken arg); |
twisti@1573 | 449 | |
twisti@1568 | 450 | virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { |
twisti@1573 | 451 | return ArgToken(tt_parameter, type, argnum); |
twisti@1568 | 452 | } |
twisti@1568 | 453 | virtual ArgToken make_oop_constant(oop con, TRAPS) { |
twisti@1573 | 454 | Handle h(THREAD, con); |
never@2937 | 455 | return ArgToken(h); |
twisti@1568 | 456 | } |
twisti@1568 | 457 | virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { |
never@2920 | 458 | return ArgToken(type, *con); |
twisti@1568 | 459 | } |
twisti@1573 | 460 | |
twisti@1573 | 461 | virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); |
twisti@1573 | 462 | virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS); |
jrose@2982 | 463 | virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); |
twisti@1568 | 464 | |
never@3105 | 465 | // Check for profiling information on a GWT and return true if it's found |
never@3105 | 466 | bool fetch_counts(ArgToken a1, ArgToken a2); |
never@3105 | 467 | |
twisti@1573 | 468 | // Get a real constant pool. |
twisti@1573 | 469 | constantPoolHandle get_constant_pool(TRAPS) const; |
twisti@1573 | 470 | |
twisti@1573 | 471 | // Get a real methodOop. |
never@3105 | 472 | methodHandle get_method_oop(TRAPS); |
twisti@1568 | 473 | |
twisti@1568 | 474 | public: |
never@2920 | 475 | MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS); |
twisti@1568 | 476 | |
twisti@1568 | 477 | // Compile the given MH chain into bytecode. |
twisti@1573 | 478 | methodHandle compile(TRAPS); |
twisti@1587 | 479 | |
twisti@1587 | 480 | // Tests if the given class is a MH adapter holder. |
twisti@1587 | 481 | static bool klass_is_method_handle_adapter_holder(klassOop klass) { |
twisti@2343 | 482 | return (klass == SystemDictionary::MethodHandle_klass()); |
twisti@1587 | 483 | } |
twisti@1568 | 484 | }; |
stefank@2314 | 485 | |
stefank@2314 | 486 | #endif // SHARE_VM_PRIMS_METHODHANDLEWALK_HPP |