Fri, 07 Jan 2011 10:42:32 -0500
7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
Summary: Track allocated bytes in Thread's, update on TLAB retirement and direct allocation in Eden and tenured, add JNI methods for ThreadMXBean.
Reviewed-by: coleenp, kvn, dholmes, ysr
twisti@1568 | 1 | /* |
trims@1907 | 2 | * Copyright (c) 2008, 2010, 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 | |
twisti@1568 | 51 | oop MethodHandle_type_oop() { return java_dyn_MethodHandle::type(method_handle_oop()); } |
twisti@1568 | 52 | oop MethodHandle_vmtarget_oop() { return java_dyn_MethodHandle::vmtarget(method_handle_oop()); } |
twisti@1568 | 53 | int MethodHandle_vmslots() { return java_dyn_MethodHandle::vmslots(method_handle_oop()); } |
twisti@1568 | 54 | int DirectMethodHandle_vmindex() { return sun_dyn_DirectMethodHandle::vmindex(method_handle_oop()); } |
twisti@1568 | 55 | oop BoundMethodHandle_argument_oop() { return sun_dyn_BoundMethodHandle::argument(method_handle_oop()); } |
twisti@1568 | 56 | int BoundMethodHandle_vmargslot() { return sun_dyn_BoundMethodHandle::vmargslot(method_handle_oop()); } |
twisti@1568 | 57 | int AdapterMethodHandle_conversion() { return sun_dyn_AdapterMethodHandle::conversion(method_handle_oop()); } |
twisti@1568 | 58 | |
twisti@1568 | 59 | public: |
twisti@1568 | 60 | MethodHandleChain(Handle root, TRAPS) |
twisti@1568 | 61 | : _root(root) |
twisti@1568 | 62 | { set_method_handle(root, THREAD); } |
twisti@1568 | 63 | |
twisti@1568 | 64 | bool is_adapter() { return _conversion != -1; } |
twisti@1568 | 65 | bool is_bound() { return _is_bound; } |
twisti@1568 | 66 | bool is_last() { return _is_last; } |
twisti@1568 | 67 | |
twisti@1568 | 68 | void next(TRAPS) { |
twisti@1568 | 69 | assert(!is_last(), ""); |
twisti@1568 | 70 | set_method_handle(MethodHandle_vmtarget_oop(), THREAD); |
twisti@1568 | 71 | } |
twisti@1568 | 72 | |
twisti@1568 | 73 | Handle method_handle() { return _method_handle; } |
twisti@1568 | 74 | oop method_handle_oop() { return _method_handle(); } |
twisti@1568 | 75 | oop method_type_oop() { return MethodHandle_type_oop(); } |
twisti@1573 | 76 | oop vmtarget_oop() { return MethodHandle_vmtarget_oop(); } |
twisti@1568 | 77 | |
twisti@1568 | 78 | jint adapter_conversion() { assert(is_adapter(), ""); return _conversion; } |
twisti@1568 | 79 | int adapter_conversion_op() { return MethodHandles::adapter_conversion_op(adapter_conversion()); } |
twisti@1568 | 80 | BasicType adapter_conversion_src_type() |
twisti@1568 | 81 | { return MethodHandles::adapter_conversion_src_type(adapter_conversion()); } |
twisti@1568 | 82 | BasicType adapter_conversion_dest_type() |
twisti@1568 | 83 | { return MethodHandles::adapter_conversion_dest_type(adapter_conversion()); } |
twisti@1568 | 84 | int adapter_conversion_stack_move() |
twisti@1568 | 85 | { return MethodHandles::adapter_conversion_stack_move(adapter_conversion()); } |
twisti@1568 | 86 | int adapter_conversion_stack_pushes() |
twisti@1568 | 87 | { return adapter_conversion_stack_move() / MethodHandles::stack_move_unit(); } |
twisti@1568 | 88 | int adapter_conversion_vminfo() |
twisti@1568 | 89 | { return MethodHandles::adapter_conversion_vminfo(adapter_conversion()); } |
twisti@1568 | 90 | int adapter_arg_slot() { assert(is_adapter(), ""); return _arg_slot; } |
twisti@1568 | 91 | oop adapter_arg_oop() { assert(is_adapter(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 92 | |
twisti@1568 | 93 | BasicType bound_arg_type() { assert(is_bound(), ""); return _arg_type; } |
twisti@1568 | 94 | int bound_arg_slot() { assert(is_bound(), ""); return _arg_slot; } |
twisti@1568 | 95 | oop bound_arg_oop() { assert(is_bound(), ""); return BoundMethodHandle_argument_oop(); } |
twisti@1568 | 96 | |
twisti@1568 | 97 | methodOop last_method_oop() { assert(is_last(), ""); return _last_method(); } |
twisti@1568 | 98 | Bytecodes::Code last_invoke_code() { assert(is_last(), ""); return _last_invoke; } |
twisti@1568 | 99 | |
twisti@1568 | 100 | void lose(const char* msg, TRAPS); |
twisti@1568 | 101 | const char* lose_message() { return _lose_message; } |
twisti@1568 | 102 | }; |
twisti@1568 | 103 | |
twisti@1568 | 104 | |
twisti@1568 | 105 | // Structure walker for method handles. |
twisti@1568 | 106 | // Does abstract interpretation on top of low-level parsing. |
twisti@1568 | 107 | // You supply the tokens shuffled by the abstract interpretation. |
twisti@1568 | 108 | class MethodHandleWalker : StackObj { |
twisti@1568 | 109 | public: |
twisti@1573 | 110 | // Stack values: |
twisti@1573 | 111 | enum TokenType { |
twisti@1573 | 112 | tt_void, |
twisti@1573 | 113 | tt_parameter, |
twisti@1573 | 114 | tt_temporary, |
twisti@1573 | 115 | tt_constant, |
twisti@1573 | 116 | tt_illegal |
twisti@1573 | 117 | }; |
twisti@1573 | 118 | |
twisti@1573 | 119 | // Argument token: |
twisti@1573 | 120 | class ArgToken { |
twisti@1573 | 121 | private: |
twisti@1573 | 122 | TokenType _tt; |
twisti@1573 | 123 | BasicType _bt; |
twisti@1573 | 124 | jvalue _value; |
twisti@1573 | 125 | Handle _handle; |
twisti@1573 | 126 | |
twisti@1573 | 127 | public: |
twisti@1573 | 128 | ArgToken(TokenType tt = tt_illegal) : _tt(tt) {} |
twisti@1573 | 129 | ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {} |
twisti@1573 | 130 | |
twisti@1573 | 131 | ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) { |
twisti@1573 | 132 | _value.i = index; |
twisti@1573 | 133 | } |
twisti@1573 | 134 | |
twisti@1573 | 135 | ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) { |
twisti@1573 | 136 | _handle = value; |
twisti@1573 | 137 | } |
twisti@1573 | 138 | |
twisti@1573 | 139 | TokenType token_type() const { return _tt; } |
twisti@1573 | 140 | BasicType basic_type() const { return _bt; } |
twisti@1573 | 141 | int index() const { return _value.i; } |
twisti@1573 | 142 | Handle object() const { return _handle; } |
twisti@1573 | 143 | |
twisti@1573 | 144 | jint get_jint() const { return _value.i; } |
twisti@1573 | 145 | jlong get_jlong() const { return _value.j; } |
twisti@1573 | 146 | jfloat get_jfloat() const { return _value.f; } |
twisti@1573 | 147 | jdouble get_jdouble() const { return _value.d; } |
twisti@1573 | 148 | }; |
twisti@1568 | 149 | |
twisti@1568 | 150 | // Abstract interpretation state: |
twisti@1568 | 151 | struct SlotState { |
twisti@1568 | 152 | BasicType _type; |
twisti@1568 | 153 | ArgToken _arg; |
twisti@1568 | 154 | SlotState() : _type(), _arg() {} |
twisti@1568 | 155 | }; |
twisti@1568 | 156 | static SlotState make_state(BasicType type, ArgToken arg) { |
twisti@1568 | 157 | SlotState ss; |
twisti@1568 | 158 | ss._type = type; ss._arg = arg; |
twisti@1568 | 159 | return ss; |
twisti@1568 | 160 | } |
twisti@1568 | 161 | |
twisti@1568 | 162 | private: |
twisti@1568 | 163 | MethodHandleChain _chain; |
twisti@1573 | 164 | bool _for_invokedynamic; |
twisti@1573 | 165 | int _local_index; |
twisti@1568 | 166 | |
twisti@1573 | 167 | GrowableArray<SlotState> _outgoing; // current outgoing parameter slots |
twisti@1568 | 168 | int _outgoing_argc; // # non-empty outgoing slots |
twisti@1568 | 169 | |
twisti@1568 | 170 | // Replace a value of type old_type at slot (and maybe slot+1) with the new value. |
twisti@1568 | 171 | // If old_type != T_VOID, remove the old argument at that point. |
twisti@1568 | 172 | // If new_type != T_VOID, insert the new argument at that point. |
twisti@1568 | 173 | // Insert or delete a second empty slot as needed. |
twisti@1573 | 174 | void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg); |
twisti@1568 | 175 | |
twisti@1568 | 176 | SlotState* slot_state(int slot) { |
twisti@1568 | 177 | if (slot < 0 || slot >= _outgoing.length()) |
twisti@1568 | 178 | return NULL; |
twisti@1568 | 179 | return _outgoing.adr_at(slot); |
twisti@1568 | 180 | } |
twisti@1568 | 181 | BasicType slot_type(int slot) { |
twisti@1568 | 182 | SlotState* ss = slot_state(slot); |
twisti@1568 | 183 | if (ss == NULL) |
twisti@1568 | 184 | return T_ILLEGAL; |
twisti@1568 | 185 | return ss->_type; |
twisti@1568 | 186 | } |
twisti@1568 | 187 | bool slot_has_argument(int slot) { |
twisti@1568 | 188 | return slot_type(slot) < T_VOID; |
twisti@1568 | 189 | } |
twisti@1568 | 190 | |
twisti@1568 | 191 | #ifdef ASSERT |
twisti@1568 | 192 | int argument_count_slow(); |
twisti@1568 | 193 | #endif |
twisti@1568 | 194 | |
twisti@1568 | 195 | // Return a bytecode for converting src to dest, if one exists. |
twisti@1568 | 196 | Bytecodes::Code conversion_code(BasicType src, BasicType dest); |
twisti@1568 | 197 | |
twisti@1568 | 198 | void walk_incoming_state(TRAPS); |
twisti@1568 | 199 | |
twisti@1568 | 200 | public: |
twisti@1573 | 201 | MethodHandleWalker(Handle root, bool for_invokedynamic, TRAPS) |
twisti@1568 | 202 | : _chain(root, THREAD), |
twisti@1573 | 203 | _for_invokedynamic(for_invokedynamic), |
twisti@1568 | 204 | _outgoing(THREAD, 10), |
twisti@1568 | 205 | _outgoing_argc(0) |
twisti@1573 | 206 | { |
twisti@1573 | 207 | _local_index = for_invokedynamic ? 0 : 1; |
twisti@1573 | 208 | } |
twisti@1568 | 209 | |
twisti@1568 | 210 | MethodHandleChain& chain() { return _chain; } |
twisti@1568 | 211 | |
twisti@1573 | 212 | bool for_invokedynamic() const { return _for_invokedynamic; } |
twisti@1573 | 213 | |
twisti@1573 | 214 | int new_local_index(BasicType bt) { |
twisti@1573 | 215 | //int index = _for_invokedynamic ? _local_index : _local_index - 1; |
twisti@1573 | 216 | int index = _local_index; |
twisti@1573 | 217 | _local_index += type2size[bt]; |
twisti@1573 | 218 | return index; |
twisti@1573 | 219 | } |
twisti@1573 | 220 | |
twisti@1573 | 221 | int max_locals() const { return _local_index; } |
twisti@1573 | 222 | |
twisti@1568 | 223 | // plug-in abstract interpretation steps: |
twisti@1568 | 224 | virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0; |
twisti@1568 | 225 | virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0; |
twisti@1568 | 226 | virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0; |
twisti@1573 | 227 | virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS ) = 0; |
twisti@1573 | 228 | virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS ) = 0; |
twisti@1568 | 229 | virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0; |
twisti@1568 | 230 | |
twisti@1568 | 231 | // For make_invoke, the methodOop can be NULL if the intrinsic ID |
twisti@1568 | 232 | // is something other than vmIntrinsics::_none. |
twisti@1568 | 233 | |
twisti@1568 | 234 | // and in case anyone cares to related the previous actions to the chain: |
twisti@1568 | 235 | virtual void set_method_handle(oop mh) { } |
twisti@1568 | 236 | |
twisti@1568 | 237 | void lose(const char* msg, TRAPS) { chain().lose(msg, THREAD); } |
twisti@1568 | 238 | const char* lose_message() { return chain().lose_message(); } |
twisti@1568 | 239 | |
twisti@1568 | 240 | ArgToken walk(TRAPS); |
twisti@1568 | 241 | }; |
twisti@1568 | 242 | |
twisti@1568 | 243 | |
twisti@1568 | 244 | // An abstract interpreter for method handle chains. |
twisti@1568 | 245 | // Produces an account of the semantics of a chain, in terms of a static IR. |
twisti@1568 | 246 | // The IR happens to be JVM bytecodes. |
twisti@1568 | 247 | class MethodHandleCompiler : public MethodHandleWalker { |
twisti@1568 | 248 | private: |
twisti@1573 | 249 | methodHandle _callee; |
twisti@1573 | 250 | KlassHandle _rklass; // Return type for casting. |
twisti@1573 | 251 | BasicType _rtype; |
twisti@1573 | 252 | KlassHandle _target_klass; |
twisti@1573 | 253 | Thread* _thread; |
twisti@1568 | 254 | |
twisti@1573 | 255 | // Fake constant pool entry. |
twisti@1573 | 256 | class ConstantValue { |
twisti@1573 | 257 | private: |
twisti@1573 | 258 | int _tag; // Constant pool tag type. |
twisti@1573 | 259 | JavaValue _value; |
twisti@1573 | 260 | Handle _handle; |
twisti@1573 | 261 | |
twisti@1573 | 262 | public: |
twisti@1573 | 263 | // Constructor for oop types. |
twisti@1573 | 264 | ConstantValue(int tag, Handle con) : _tag(tag), _handle(con) { |
twisti@1573 | 265 | assert(tag == JVM_CONSTANT_Utf8 || |
twisti@1573 | 266 | tag == JVM_CONSTANT_Class || |
twisti@1573 | 267 | tag == JVM_CONSTANT_String || |
twisti@1573 | 268 | tag == JVM_CONSTANT_Object, "must be oop type"); |
twisti@1573 | 269 | } |
twisti@1573 | 270 | |
twisti@1573 | 271 | // Constructor for oop reference types. |
twisti@1573 | 272 | ConstantValue(int tag, int index) : _tag(tag) { |
twisti@1573 | 273 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 274 | _value.set_jint(index); |
twisti@1573 | 275 | } |
twisti@1573 | 276 | ConstantValue(int tag, int first_index, int second_index) : _tag(tag) { |
twisti@1573 | 277 | assert(JVM_CONSTANT_Fieldref <= tag && tag <= JVM_CONSTANT_NameAndType, "must be ref type"); |
twisti@1573 | 278 | _value.set_jint(first_index << 16 | second_index); |
twisti@1573 | 279 | } |
twisti@1573 | 280 | |
twisti@1573 | 281 | // Constructor for primitive types. |
twisti@1573 | 282 | ConstantValue(BasicType bt, jvalue con) { |
twisti@1573 | 283 | _value.set_type(bt); |
twisti@1573 | 284 | switch (bt) { |
twisti@1573 | 285 | case T_INT: _tag = JVM_CONSTANT_Integer; _value.set_jint( con.i); break; |
twisti@1573 | 286 | case T_LONG: _tag = JVM_CONSTANT_Long; _value.set_jlong( con.j); break; |
twisti@1573 | 287 | case T_FLOAT: _tag = JVM_CONSTANT_Float; _value.set_jfloat( con.f); break; |
twisti@1573 | 288 | case T_DOUBLE: _tag = JVM_CONSTANT_Double; _value.set_jdouble(con.d); break; |
twisti@1573 | 289 | default: ShouldNotReachHere(); |
twisti@1573 | 290 | } |
twisti@1573 | 291 | } |
twisti@1573 | 292 | |
twisti@1573 | 293 | int tag() const { return _tag; } |
twisti@1573 | 294 | symbolOop symbol_oop() const { return (symbolOop) _handle(); } |
twisti@1573 | 295 | klassOop klass_oop() const { return (klassOop) _handle(); } |
twisti@1573 | 296 | oop object_oop() const { return _handle(); } |
twisti@1573 | 297 | int index() const { return _value.get_jint(); } |
twisti@1573 | 298 | int first_index() const { return _value.get_jint() >> 16; } |
twisti@1573 | 299 | int second_index() const { return _value.get_jint() & 0x0000FFFF; } |
twisti@1573 | 300 | |
twisti@1573 | 301 | bool is_primitive() const { return is_java_primitive(_value.get_type()); } |
twisti@1573 | 302 | jint get_jint() const { return _value.get_jint(); } |
twisti@1573 | 303 | jlong get_jlong() const { return _value.get_jlong(); } |
twisti@1573 | 304 | jfloat get_jfloat() const { return _value.get_jfloat(); } |
twisti@1573 | 305 | jdouble get_jdouble() const { return _value.get_jdouble(); } |
twisti@1568 | 306 | }; |
twisti@1568 | 307 | |
twisti@1573 | 308 | // Fake constant pool. |
twisti@1573 | 309 | GrowableArray<ConstantValue*> _constants; |
twisti@1573 | 310 | |
twisti@1568 | 311 | // Accumulated compiler state: |
twisti@1573 | 312 | GrowableArray<unsigned char> _bytecode; |
twisti@1573 | 313 | |
twisti@1573 | 314 | int _cur_stack; |
twisti@1568 | 315 | int _max_stack; |
twisti@1568 | 316 | int _num_params; |
twisti@1568 | 317 | int _name_index; |
twisti@1568 | 318 | int _signature_index; |
twisti@1568 | 319 | |
twisti@1573 | 320 | void stack_push(BasicType bt) { |
twisti@1573 | 321 | _cur_stack += type2size[bt]; |
twisti@1573 | 322 | if (_cur_stack > _max_stack) _max_stack = _cur_stack; |
twisti@1573 | 323 | } |
twisti@1573 | 324 | void stack_pop(BasicType bt) { |
twisti@1573 | 325 | _cur_stack -= type2size[bt]; |
twisti@1573 | 326 | assert(_cur_stack >= 0, "sanity"); |
twisti@1568 | 327 | } |
twisti@1568 | 328 | |
twisti@1573 | 329 | unsigned char* bytecode() const { return _bytecode.adr_at(0); } |
twisti@1573 | 330 | int bytecode_length() const { return _bytecode.length(); } |
twisti@1573 | 331 | |
twisti@1573 | 332 | // Fake constant pool. |
twisti@1573 | 333 | int cpool_oop_put(int tag, Handle con) { |
twisti@1573 | 334 | if (con.is_null()) return 0; |
twisti@1573 | 335 | ConstantValue* cv = new ConstantValue(tag, con); |
twisti@1573 | 336 | return _constants.append(cv); |
twisti@1573 | 337 | } |
twisti@1573 | 338 | |
twisti@1573 | 339 | int cpool_oop_reference_put(int tag, int first_index, int second_index) { |
twisti@1573 | 340 | if (first_index == 0 && second_index == 0) return 0; |
twisti@1573 | 341 | assert(first_index != 0 && second_index != 0, "no zero indexes"); |
twisti@1573 | 342 | ConstantValue* cv = new ConstantValue(tag, first_index, second_index); |
twisti@1573 | 343 | return _constants.append(cv); |
twisti@1573 | 344 | } |
twisti@1573 | 345 | |
twisti@1573 | 346 | int cpool_primitive_put(BasicType type, jvalue* con); |
twisti@1573 | 347 | |
twisti@1573 | 348 | int cpool_int_put(jint value) { |
twisti@1573 | 349 | jvalue con; con.i = value; |
twisti@1573 | 350 | return cpool_primitive_put(T_INT, &con); |
twisti@1573 | 351 | } |
twisti@1573 | 352 | int cpool_long_put(jlong value) { |
twisti@1573 | 353 | jvalue con; con.j = value; |
twisti@1573 | 354 | return cpool_primitive_put(T_LONG, &con); |
twisti@1573 | 355 | } |
twisti@1573 | 356 | int cpool_float_put(jfloat value) { |
twisti@1573 | 357 | jvalue con; con.f = value; |
twisti@1573 | 358 | return cpool_primitive_put(T_FLOAT, &con); |
twisti@1573 | 359 | } |
twisti@1573 | 360 | int cpool_double_put(jdouble value) { |
twisti@1573 | 361 | jvalue con; con.d = value; |
twisti@1573 | 362 | return cpool_primitive_put(T_DOUBLE, &con); |
twisti@1573 | 363 | } |
twisti@1573 | 364 | |
twisti@1573 | 365 | int cpool_object_put(Handle obj) { |
twisti@1573 | 366 | return cpool_oop_put(JVM_CONSTANT_Object, obj); |
twisti@1573 | 367 | } |
twisti@1573 | 368 | int cpool_symbol_put(symbolOop sym) { |
twisti@1573 | 369 | return cpool_oop_put(JVM_CONSTANT_Utf8, sym); |
twisti@1573 | 370 | } |
twisti@1573 | 371 | int cpool_klass_put(klassOop klass) { |
twisti@1573 | 372 | return cpool_oop_put(JVM_CONSTANT_Class, klass); |
twisti@1573 | 373 | } |
twisti@1573 | 374 | int cpool_methodref_put(int class_index, int name_and_type_index) { |
twisti@1573 | 375 | return cpool_oop_reference_put(JVM_CONSTANT_Methodref, class_index, name_and_type_index); |
twisti@1573 | 376 | } |
twisti@1573 | 377 | int cpool_name_and_type_put(int name_index, int signature_index) { |
twisti@1573 | 378 | return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index); |
twisti@1573 | 379 | } |
twisti@1573 | 380 | |
twisti@1573 | 381 | void emit_bc(Bytecodes::Code op, int index = 0); |
twisti@1573 | 382 | void emit_load(BasicType bt, int index); |
twisti@1573 | 383 | void emit_store(BasicType bt, int index); |
twisti@1573 | 384 | void emit_load_constant(ArgToken arg); |
twisti@1573 | 385 | |
twisti@1568 | 386 | virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { |
twisti@1573 | 387 | return ArgToken(tt_parameter, type, argnum); |
twisti@1568 | 388 | } |
twisti@1568 | 389 | virtual ArgToken make_oop_constant(oop con, TRAPS) { |
twisti@1573 | 390 | Handle h(THREAD, con); |
twisti@1573 | 391 | return ArgToken(tt_constant, T_OBJECT, h); |
twisti@1568 | 392 | } |
twisti@1568 | 393 | virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) { |
twisti@1573 | 394 | return ArgToken(tt_constant, type, *con); |
twisti@1568 | 395 | } |
twisti@1573 | 396 | |
twisti@1573 | 397 | virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS); |
twisti@1573 | 398 | virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS); |
twisti@1568 | 399 | virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); |
twisti@1568 | 400 | |
twisti@1573 | 401 | // Get a real constant pool. |
twisti@1573 | 402 | constantPoolHandle get_constant_pool(TRAPS) const; |
twisti@1573 | 403 | |
twisti@1573 | 404 | // Get a real methodOop. |
twisti@1573 | 405 | methodHandle get_method_oop(TRAPS) const; |
twisti@1568 | 406 | |
twisti@1568 | 407 | public: |
twisti@1573 | 408 | MethodHandleCompiler(Handle root, methodHandle call_method, bool for_invokedynamic, TRAPS); |
twisti@1568 | 409 | |
twisti@1568 | 410 | // Compile the given MH chain into bytecode. |
twisti@1573 | 411 | methodHandle compile(TRAPS); |
twisti@1587 | 412 | |
twisti@1587 | 413 | // Tests if the given class is a MH adapter holder. |
twisti@1587 | 414 | static bool klass_is_method_handle_adapter_holder(klassOop klass) { |
twisti@2343 | 415 | return (klass == SystemDictionary::MethodHandle_klass()); |
twisti@1587 | 416 | } |
twisti@1568 | 417 | }; |
stefank@2314 | 418 | |
stefank@2314 | 419 | #endif // SHARE_VM_PRIMS_METHODHANDLEWALK_HPP |