| File: | jdk/src/hotspot/share/asm/register.hpp |
| Warning: | line 70, column 7 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | ||||
| 2 | * Copyright (c) 1997, 2021, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||||
| 20 | * or visit www.oracle.com if you need additional information or have any | ||||
| 21 | * questions. | ||||
| 22 | * | ||||
| 23 | */ | ||||
| 24 | |||||
| 25 | #include "precompiled.hpp" | ||||
| 26 | #include "jvm.h" | ||||
| 27 | #include "asm/macroAssembler.hpp" | ||||
| 28 | #include "classfile/vmClasses.hpp" | ||||
| 29 | #include "compiler/disassembler.hpp" | ||||
| 30 | #include "classfile/javaClasses.inline.hpp" | ||||
| 31 | #include "interpreter/interpreter.hpp" | ||||
| 32 | #include "interpreter/interpreterRuntime.hpp" | ||||
| 33 | #include "logging/log.hpp" | ||||
| 34 | #include "logging/logStream.hpp" | ||||
| 35 | #include "memory/allocation.inline.hpp" | ||||
| 36 | #include "memory/resourceArea.hpp" | ||||
| 37 | #include "prims/jvmtiExport.hpp" | ||||
| 38 | #include "prims/methodHandles.hpp" | ||||
| 39 | #include "runtime/flags/flagSetting.hpp" | ||||
| 40 | #include "runtime/frame.inline.hpp" | ||||
| 41 | #include "runtime/stubRoutines.hpp" | ||||
| 42 | #include "utilities/formatBuffer.hpp" | ||||
| 43 | #include "utilities/preserveException.hpp" | ||||
| 44 | |||||
| 45 | #define __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 45, _masm)-> Disassembler::hook<MacroAssembler>(__FILE__"/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp", __LINE__45, _masm)-> | ||||
| 46 | |||||
| 47 | #ifdef PRODUCT | ||||
| 48 | #define BLOCK_COMMENT(str)Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 48, _masm)-> block_comment(str) /* nothing */ | ||||
| 49 | #define STOP(error)block_comment(error); Disassembler::hook<MacroAssembler> ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 49, _masm)-> stop(error) stop(error) | ||||
| 50 | #else | ||||
| 51 | #define BLOCK_COMMENT(str)Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 51, _masm)-> block_comment(str) __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 51, _masm)-> block_comment(str) | ||||
| 52 | #define STOP(error)block_comment(error); Disassembler::hook<MacroAssembler> ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 52, _masm)-> stop(error) block_comment(error); __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 52, _masm)-> stop(error) | ||||
| 53 | #endif | ||||
| 54 | |||||
| 55 | #define BIND(label)bind(label); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 55, _masm)-> block_comment("label" ":") bind(label); BLOCK_COMMENT(#label ":")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 55, _masm)-> block_comment(#label ":") | ||||
| 56 | |||||
| 57 | void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) { | ||||
| 58 | if (VerifyMethodHandles) | ||||
| 59 | verify_klass(_masm, klass_reg, VM_CLASS_ID(java_lang_Class)vmClassID::java_lang_Class_knum, | ||||
| 60 | "MH argument is a Class"); | ||||
| 61 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 61, _masm)-> movptr(klass_reg, Address(klass_reg, java_lang_Class::klass_offset())); | ||||
| 62 | } | ||||
| 63 | |||||
| 64 | #ifdef ASSERT1 | ||||
| 65 | static int check_nonzero(const char* xname, int x) { | ||||
| 66 | assert(x != 0, "%s should be nonzero", xname)do { if (!(x != 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 66, "assert(" "x != 0" ") failed", "%s should be nonzero", xname ); ::breakpoint(); } } while (0); | ||||
| 67 | return x; | ||||
| 68 | } | ||||
| 69 | #define NONZERO(x)check_nonzero("x", x) check_nonzero(#x, x) | ||||
| 70 | #else //ASSERT | ||||
| 71 | #define NONZERO(x)check_nonzero("x", x) (x) | ||||
| 72 | #endif //ASSERT | ||||
| 73 | |||||
| 74 | #ifdef ASSERT1 | ||||
| 75 | void MethodHandles::verify_klass(MacroAssembler* _masm, | ||||
| 76 | Register obj, vmClassID klass_id, | ||||
| 77 | const char* error_message) { | ||||
| 78 | InstanceKlass** klass_addr = vmClasses::klass_addr_at(klass_id); | ||||
| 79 | Klass* klass = vmClasses::klass_at(klass_id); | ||||
| 80 | Register temp = rdi; | ||||
| 81 | Register temp2 = noreg; | ||||
| 82 | LP64_ONLY(temp2 = rscratch1)temp2 = rscratch1; // used by MacroAssembler::cmpptr and load_klass | ||||
| 83 | Label L_ok, L_bad; | ||||
| 84 | BLOCK_COMMENT("verify_klass {")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 84, _masm)-> block_comment("verify_klass {"); | ||||
| 85 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 85, _masm)-> verify_oop(obj)_verify_oop_checked(obj, "broken oop " "obj", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 85); | ||||
| 86 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 86, _masm)-> testptr(obj, obj); | ||||
| 87 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 87, _masm)-> jcc(Assembler::zero, L_bad); | ||||
| 88 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 88, _masm)-> push(temp); if (temp2 != noreg) __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 88, _masm)-> push(temp2); | ||||
| 89 | #define UNPUSH{ if (temp2 != noreg) Disassembler::hook<MacroAssembler> ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 89, _masm)-> pop(temp2); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 89, _masm)-> pop(temp); } { if (temp2 != noreg) __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 89, _masm)-> pop(temp2); __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 89, _masm)-> pop(temp); } | ||||
| 90 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 90, _masm)-> load_klass(temp, obj, temp2); | ||||
| 91 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 91, _masm)-> cmpptr(temp, ExternalAddress((address) klass_addr)); | ||||
| 92 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 92, _masm)-> jcc(Assembler::equal, L_ok); | ||||
| 93 | intptr_t super_check_offset = klass->super_check_offset(); | ||||
| 94 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 94, _masm)-> movptr(temp, Address(temp, super_check_offset)); | ||||
| 95 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 95, _masm)-> cmpptr(temp, ExternalAddress((address) klass_addr)); | ||||
| 96 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 96, _masm)-> jcc(Assembler::equal, L_ok); | ||||
| 97 | UNPUSH{ if (temp2 != noreg) Disassembler::hook<MacroAssembler> ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 97, _masm)-> pop(temp2); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 97, _masm)-> pop(temp); }; | ||||
| 98 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 98, _masm)-> bind(L_bad); | ||||
| 99 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 99, _masm)-> STOP(error_message)block_comment(error_message); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 99, _masm)-> stop(error_message); | ||||
| 100 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 100, _masm)-> BIND(L_ok)bind(L_ok); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 100, _masm)-> block_comment("L_ok" ":"); | ||||
| 101 | UNPUSH{ if (temp2 != noreg) Disassembler::hook<MacroAssembler> ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 101, _masm)-> pop(temp2); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 101, _masm)-> pop(temp); }; | ||||
| 102 | BLOCK_COMMENT("} verify_klass")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 102, _masm)-> block_comment("} verify_klass"); | ||||
| 103 | } | ||||
| 104 | |||||
| 105 | void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { | ||||
| 106 | Label L; | ||||
| 107 | BLOCK_COMMENT("verify_ref_kind {")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 107, _masm)-> block_comment("verify_ref_kind {"); | ||||
| 108 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 108, _masm)-> movl(temp, Address(member_reg, NONZERO(java_lang_invoke_MemberName::flags_offset())check_nonzero("java_lang_invoke_MemberName::flags_offset()", java_lang_invoke_MemberName ::flags_offset()))); | ||||
| 109 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 109, _masm)-> shrl(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT); | ||||
| 110 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 110, _masm)-> andl(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK); | ||||
| 111 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 111, _masm)-> cmpl(temp, ref_kind); | ||||
| 112 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 112, _masm)-> jcc(Assembler::equal, L); | ||||
| 113 | { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal)(char*) (AllocateHeap((100) * sizeof(char), mtInternal)); | ||||
| 114 | jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); | ||||
| 115 | if (ref_kind == JVM_REF_invokeVirtual || | ||||
| 116 | ref_kind == JVM_REF_invokeSpecial) | ||||
| 117 | // could do this for all ref_kinds, but would explode assembly code size | ||||
| 118 | trace_method_handle(_masm, buf); | ||||
| 119 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 119, _masm)-> STOP(buf)block_comment(buf); Disassembler::hook<MacroAssembler>( "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 119, _masm)-> stop(buf); | ||||
| 120 | } | ||||
| 121 | BLOCK_COMMENT("} verify_ref_kind")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 121, _masm)-> block_comment("} verify_ref_kind"); | ||||
| 122 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 122, _masm)-> bind(L); | ||||
| 123 | } | ||||
| 124 | |||||
| 125 | #endif //ASSERT | ||||
| 126 | |||||
| 127 | void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, | ||||
| 128 | bool for_compiler_entry) { | ||||
| 129 | assert(method == rbx, "interpreter calling convention")do { if (!(method == rbx)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 129, "assert(" "method == rbx" ") failed", "interpreter calling convention" ); ::breakpoint(); } } while (0); | ||||
| 130 | |||||
| 131 | Label L_no_such_method; | ||||
| 132 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 132, _masm)-> testptr(rbx, rbx); | ||||
| 133 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 133, _masm)-> jcc(Assembler::zero, L_no_such_method); | ||||
| 134 | |||||
| 135 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 135, _masm)-> verify_method_ptr(method)_verify_method_ptr(method, "broken method " "method", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 135); | ||||
| 136 | |||||
| 137 | if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { | ||||
| 138 | Label run_compiled_code; | ||||
| 139 | // JVMTI events, such as single-stepping, are implemented partly by avoiding running | ||||
| 140 | // compiled code in threads for which the event is enabled. Check here for | ||||
| 141 | // interp_only_mode if these events CAN be enabled. | ||||
| 142 | #ifdef _LP641 | ||||
| 143 | Register rthread = r15_thread; | ||||
| 144 | #else | ||||
| 145 | Register rthread = temp; | ||||
| 146 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 146, _masm)-> get_thread(rthread); | ||||
| 147 | #endif | ||||
| 148 | // interp_only is an int, on little endian it is sufficient to test the byte only | ||||
| 149 | // Is a cmpl faster? | ||||
| 150 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 150, _masm)-> cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0); | ||||
| 151 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 151, _masm)-> jccb(Assembler::zero, run_compiled_code)jccb_0(Assembler::zero, run_compiled_code, "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 151); | ||||
| 152 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 152, _masm)-> jmp(Address(method, Method::interpreter_entry_offset())); | ||||
| 153 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 153, _masm)-> BIND(run_compiled_code)bind(run_compiled_code); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 153, _masm)-> block_comment("run_compiled_code" ":"); | ||||
| 154 | } | ||||
| 155 | |||||
| 156 | const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : | ||||
| 157 | Method::from_interpreted_offset(); | ||||
| 158 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 158, _masm)-> jmp(Address(method, entry_offset)); | ||||
| 159 | |||||
| 160 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 160, _masm)-> bind(L_no_such_method); | ||||
| 161 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 161, _masm)-> jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); | ||||
| 162 | } | ||||
| 163 | |||||
| 164 | void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, | ||||
| 165 | Register recv, Register method_temp, | ||||
| 166 | Register temp2, | ||||
| 167 | bool for_compiler_entry) { | ||||
| 168 | BLOCK_COMMENT("jump_to_lambda_form {")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 168, _masm)-> block_comment("jump_to_lambda_form {"); | ||||
| 169 | // This is the initial entry point of a lazy method handle. | ||||
| 170 | // After type checking, it picks up the invoker from the LambdaForm. | ||||
| 171 | assert_different_registers(recv, method_temp, temp2); | ||||
| 172 | assert(recv != noreg, "required register")do { if (!(recv != noreg)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 172, "assert(" "recv != noreg" ") failed", "required register" ); ::breakpoint(); } } while (0); | ||||
| 173 | assert(method_temp == rbx, "required register for loading method")do { if (!(method_temp == rbx)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 173, "assert(" "method_temp == rbx" ") failed", "required register for loading method" ); ::breakpoint(); } } while (0); | ||||
| 174 | |||||
| 175 | // Load the invoker, as MH -> MH.form -> LF.vmentry | ||||
| 176 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 176, _masm)-> verify_oop(recv)_verify_oop_checked(recv, "broken oop " "recv", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 176); | ||||
| 177 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 177, _masm)-> load_heap_oop(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset())check_nonzero("java_lang_invoke_MethodHandle::form_offset()", java_lang_invoke_MethodHandle::form_offset())), temp2); | ||||
| 178 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 178, _masm)-> verify_oop(method_temp)_verify_oop_checked(method_temp, "broken oop " "method_temp", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 178); | ||||
| 179 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 179, _masm)-> load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset())check_nonzero("java_lang_invoke_LambdaForm::vmentry_offset()" , java_lang_invoke_LambdaForm::vmentry_offset())), temp2); | ||||
| 180 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 180, _masm)-> verify_oop(method_temp)_verify_oop_checked(method_temp, "broken oop " "method_temp", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 180); | ||||
| 181 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 181, _masm)-> load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset())check_nonzero("java_lang_invoke_MemberName::method_offset()", java_lang_invoke_MemberName::method_offset())), temp2); | ||||
| 182 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 182, _masm)-> verify_oop(method_temp)_verify_oop_checked(method_temp, "broken oop " "method_temp", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 182); | ||||
| 183 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 183, _masm)-> access_load_at(T_ADDRESS, IN_HEAP, method_temp, | ||||
| 184 | Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset())check_nonzero("java_lang_invoke_ResolvedMethodName::vmtarget_offset()" , java_lang_invoke_ResolvedMethodName::vmtarget_offset())), | ||||
| 185 | noreg, noreg); | ||||
| 186 | |||||
| 187 | if (VerifyMethodHandles && !for_compiler_entry) { | ||||
| 188 | // make sure recv is already on stack | ||||
| 189 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 189, _masm)-> movptr(temp2, Address(method_temp, Method::const_offset())); | ||||
| 190 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 190, _masm)-> load_sized_value(temp2, | ||||
| 191 | Address(temp2, ConstMethod::size_of_parameters_offset()), | ||||
| 192 | sizeof(u2), /*is_signed*/ false); | ||||
| 193 | // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); | ||||
| 194 | Label L; | ||||
| 195 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 195, _masm)-> cmpoop(recv, __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 195, _masm)-> argument_address(temp2, -1)); | ||||
| 196 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 196, _masm)-> jcc(Assembler::equal, L); | ||||
| 197 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 197, _masm)-> movptr(rax, __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 197, _masm)-> argument_address(temp2, -1)); | ||||
| 198 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 198, _masm)-> STOP("receiver not on stack")block_comment("receiver not on stack"); Disassembler::hook< MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 198, _masm)-> stop("receiver not on stack"); | ||||
| 199 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 199, _masm)-> BIND(L)bind(L); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 199, _masm)-> block_comment("L" ":"); | ||||
| 200 | } | ||||
| 201 | |||||
| 202 | jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); | ||||
| 203 | BLOCK_COMMENT("} jump_to_lambda_form")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 203, _masm)-> block_comment("} jump_to_lambda_form"); | ||||
| 204 | } | ||||
| 205 | |||||
| 206 | |||||
| 207 | // Code generation | ||||
| 208 | address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm, | ||||
| 209 | vmIntrinsics::ID iid) { | ||||
| 210 | const bool not_for_compiler_entry = false; // this is the interpreter entry | ||||
| 211 | assert(is_signature_polymorphic(iid), "expected invoke iid")do { if (!(is_signature_polymorphic(iid))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 211, "assert(" "is_signature_polymorphic(iid)" ") failed", "expected invoke iid" ); ::breakpoint(); } } while (0); | ||||
| |||||
| 212 | if (iid == vmIntrinsics::_invokeGeneric || | ||||
| 213 | iid
| ||||
| 214 | // Perhaps surprisingly, the symbolic references visible to Java are not directly used. | ||||
| 215 | // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. | ||||
| 216 | // They all allow an appendix argument. | ||||
| 217 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 217, _masm)-> hlt(); // empty stubs make SG sick | ||||
| 218 | return NULL__null; | ||||
| 219 | } | ||||
| 220 | |||||
| 221 | // No need in interpreter entry for linkToNative for now. | ||||
| 222 | // Interpreter calls compiled entry through i2c. | ||||
| 223 | if (iid == vmIntrinsics::_linkToNative) { | ||||
| 224 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 224, _masm)-> hlt(); | ||||
| 225 | return NULL__null; | ||||
| 226 | } | ||||
| 227 | |||||
| 228 | // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted) | ||||
| 229 | // rbx: Method* | ||||
| 230 | // rdx: argument locator (parameter slot count, added to rsp) | ||||
| 231 | // rcx: used as temp to hold mh or receiver | ||||
| 232 | // rax, rdi: garbage temps, blown away | ||||
| 233 | Register rdx_argp = rdx; // argument list ptr, live on error paths | ||||
| 234 | Register rax_temp = rax; | ||||
| 235 | Register rcx_mh = rcx; // MH receiver; dies quickly and is recycled | ||||
| 236 | Register rbx_method = rbx; // eventual target of this invocation | ||||
| 237 | |||||
| 238 | // here's where control starts out: | ||||
| 239 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 239, _masm)-> align(CodeEntryAlignment); | ||||
| 240 | address entry_point = __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 240, _masm)-> pc(); | ||||
| 241 | |||||
| 242 | if (VerifyMethodHandles) { | ||||
| 243 | assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2")do { if (!(Method::intrinsic_id_size_in_bytes() == 2)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 243, "assert(" "Method::intrinsic_id_size_in_bytes() == 2" ") failed" , "assuming Method::_intrinsic_id is u2"); ::breakpoint(); } } while (0); | ||||
| 244 | |||||
| 245 | Label L; | ||||
| 246 | BLOCK_COMMENT("verify_intrinsic_id {")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 246, _masm)-> block_comment("verify_intrinsic_id {"); | ||||
| 247 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 247, _masm)-> cmpw(Address(rbx_method, Method::intrinsic_id_offset_in_bytes()), (int) iid); | ||||
| 248 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 248, _masm)-> jcc(Assembler::equal, L); | ||||
| 249 | if (iid == vmIntrinsics::_linkToVirtual || | ||||
| 250 | iid == vmIntrinsics::_linkToSpecial) { | ||||
| 251 | // could do this for all kinds, but would explode assembly code size | ||||
| 252 | trace_method_handle(_masm, "bad Method*::intrinsic_id"); | ||||
| 253 | } | ||||
| 254 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 254, _masm)-> STOP("bad Method*::intrinsic_id")block_comment("bad Method*::intrinsic_id"); Disassembler::hook <MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 254, _masm)-> stop("bad Method*::intrinsic_id"); | ||||
| 255 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 255, _masm)-> bind(L); | ||||
| 256 | BLOCK_COMMENT("} verify_intrinsic_id")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 256, _masm)-> block_comment("} verify_intrinsic_id"); | ||||
| 257 | } | ||||
| 258 | |||||
| 259 | // First task: Find out how big the argument list is. | ||||
| 260 | Address rdx_first_arg_addr; | ||||
| 261 | int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid); | ||||
| 262 | assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic")do { if (!(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 262, "assert(" "ref_kind != 0 || iid == vmIntrinsics::_invokeBasic" ") failed", "must be _invokeBasic or a linkTo intrinsic"); :: breakpoint(); } } while (0); | ||||
| 263 | if (ref_kind
| ||||
| 264 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 264, _masm)-> movptr(rdx_argp, Address(rbx_method, Method::const_offset())); | ||||
| 265 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 265, _masm)-> load_sized_value(rdx_argp, | ||||
| 266 | Address(rdx_argp, ConstMethod::size_of_parameters_offset()), | ||||
| 267 | sizeof(u2), /*is_signed*/ false); | ||||
| 268 | // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); | ||||
| 269 | rdx_first_arg_addr = __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 269, _masm)-> argument_address(rdx_argp, -1); | ||||
| 270 | } else { | ||||
| 271 | DEBUG_ONLY(rdx_argp = noreg)rdx_argp = noreg; | ||||
| 272 | } | ||||
| 273 | |||||
| 274 | if (!is_signature_polymorphic_static(iid)) { | ||||
| 275 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 275, _masm)-> movptr(rcx_mh, rdx_first_arg_addr); | ||||
| 276 | DEBUG_ONLY(rdx_argp = noreg)rdx_argp = noreg; | ||||
| 277 | } | ||||
| 278 | |||||
| 279 | // rdx_first_arg_addr is live! | ||||
| 280 | |||||
| 281 | trace_method_handle_interpreter_entry(_masm, iid); | ||||
| 282 | |||||
| 283 | if (iid
| ||||
| 284 | generate_method_handle_dispatch(_masm, iid, rcx_mh, noreg, not_for_compiler_entry); | ||||
| 285 | |||||
| 286 | } else { | ||||
| 287 | // Adjust argument list by popping the trailing MemberName argument. | ||||
| 288 | Register rcx_recv = noreg; | ||||
| 289 | if (MethodHandles::ref_kind_has_receiver(ref_kind)) { | ||||
| 290 | // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack. | ||||
| 291 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 291, _masm)-> movptr(rcx_recv = rcx, rdx_first_arg_addr); | ||||
| 292 | } | ||||
| 293 | DEBUG_ONLY(rdx_argp = noreg)rdx_argp = noreg; | ||||
| 294 | Register rbx_member = rbx_method; // MemberName ptr; incoming method ptr is dead now | ||||
| 295 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 295, _masm)-> pop(rax_temp); // return address | ||||
| 296 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 296, _masm)-> pop(rbx_member); // extract last argument | ||||
| 297 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 297, _masm)-> push(rax_temp); // re-push return address | ||||
| 298 | generate_method_handle_dispatch(_masm, iid, rcx_recv, rbx_member, not_for_compiler_entry); | ||||
| 299 | } | ||||
| 300 | |||||
| 301 | return entry_point; | ||||
| 302 | } | ||||
| 303 | |||||
| 304 | void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, | ||||
| 305 | vmIntrinsics::ID iid, | ||||
| 306 | Register receiver_reg, | ||||
| 307 | Register member_reg, | ||||
| 308 | bool for_compiler_entry) { | ||||
| 309 | assert(is_signature_polymorphic(iid), "expected invoke iid")do { if (!(is_signature_polymorphic(iid))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 309, "assert(" "is_signature_polymorphic(iid)" ") failed", "expected invoke iid" ); ::breakpoint(); } } while (0); | ||||
| 310 | Register rbx_method = rbx; // eventual target of this invocation | ||||
| 311 | // temps used in this code are not used in *either* compiled or interpreted calling sequences | ||||
| 312 | #ifdef _LP641 | ||||
| 313 | Register temp1 = rscratch1; | ||||
| 314 | Register temp2 = rscratch2; | ||||
| 315 | Register temp3 = rax; | ||||
| 316 | if (for_compiler_entry
| ||||
| 317 | assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment")do { if (!(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 317, "assert(" "receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0)" ") failed", "only valid assignment"); ::breakpoint(); } } while (0); | ||||
| 318 | assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); | ||||
| 319 | assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); | ||||
| 320 | assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5); | ||||
| 321 | } | ||||
| 322 | #else | ||||
| 323 | Register temp1 = (for_compiler_entry ? rsi : rdx); | ||||
| 324 | Register temp2 = rdi; | ||||
| 325 | Register temp3 = rax; | ||||
| 326 | if (for_compiler_entry) { | ||||
| 327 | assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : rcx), "only valid assignment")do { if (!(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : rcx))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 327, "assert(" "receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : rcx)" ") failed", "only valid assignment"); ::breakpoint(); } } while (0); | ||||
| 328 | assert_different_registers(temp1, rcx, rdx); | ||||
| 329 | assert_different_registers(temp2, rcx, rdx); | ||||
| 330 | assert_different_registers(temp3, rcx, rdx); | ||||
| 331 | } | ||||
| 332 | #endif | ||||
| 333 | else { | ||||
| 334 | assert_different_registers(temp1, temp2, temp3, saved_last_sp_register()); // don't trash lastSP | ||||
| 335 | } | ||||
| 336 | assert_different_registers(temp1, temp2, temp3, receiver_reg); | ||||
| 337 | assert_different_registers(temp1, temp2, temp3, member_reg); | ||||
| 338 | |||||
| 339 | if (iid == vmIntrinsics::_invokeBasic || iid == vmIntrinsics::_linkToNative) { | ||||
| 340 | if (iid == vmIntrinsics::_linkToNative) { | ||||
| 341 | assert(for_compiler_entry, "only compiler entry is supported")do { if (!(for_compiler_entry)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 341, "assert(" "for_compiler_entry" ") failed", "only compiler entry is supported" ); ::breakpoint(); } } while (0); | ||||
| 342 | } | ||||
| 343 | // indirect through MH.form.vmentry.vmtarget | ||||
| 344 | jump_to_lambda_form(_masm, receiver_reg, rbx_method, temp1, for_compiler_entry); | ||||
| 345 | |||||
| 346 | } else { | ||||
| 347 | // The method is a member invoker used by direct method handles. | ||||
| 348 | if (VerifyMethodHandles) { | ||||
| 349 | // make sure the trailing argument really is a MemberName (caller responsibility) | ||||
| 350 | verify_klass(_masm, member_reg, VM_CLASS_ID(java_lang_invoke_MemberName)vmClassID::java_lang_invoke_MemberName_knum, | ||||
| 351 | "MemberName required for invokeVirtual etc."); | ||||
| 352 | } | ||||
| 353 | |||||
| 354 | Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset())check_nonzero("java_lang_invoke_MemberName::clazz_offset()", java_lang_invoke_MemberName ::clazz_offset())); | ||||
| 355 | Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset())check_nonzero("java_lang_invoke_MemberName::vmindex_offset()" , java_lang_invoke_MemberName::vmindex_offset())); | ||||
| 356 | Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset())check_nonzero("java_lang_invoke_MemberName::method_offset()", java_lang_invoke_MemberName::method_offset())); | ||||
| 357 | Address vmtarget_method( rbx_method, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset())check_nonzero("java_lang_invoke_ResolvedMethodName::vmtarget_offset()" , java_lang_invoke_ResolvedMethodName::vmtarget_offset())); | ||||
| 358 | |||||
| 359 | Register temp1_recv_klass = temp1; | ||||
| 360 | if (iid != vmIntrinsics::_linkToStatic) { | ||||
| 361 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 361, _masm)-> verify_oop(receiver_reg)_verify_oop_checked(receiver_reg, "broken oop " "receiver_reg" , "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 361); | ||||
| 362 | if (iid == vmIntrinsics::_linkToSpecial) { | ||||
| 363 | // Don't actually load the klass; just null-check the receiver. | ||||
| 364 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 364, _masm)-> null_check(receiver_reg); | ||||
| 365 | } else { | ||||
| 366 | // load receiver klass itself | ||||
| 367 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 367, _masm)-> null_check(receiver_reg, oopDesc::klass_offset_in_bytes()); | ||||
| 368 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 368, _masm)-> load_klass(temp1_recv_klass, receiver_reg, temp2); | ||||
| 369 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 369, _masm)-> verify_klass_ptr(temp1_recv_klass)_verify_klass_ptr(temp1_recv_klass, "broken klass " "temp1_recv_klass" , "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 369); | ||||
| 370 | } | ||||
| 371 | BLOCK_COMMENT("check_receiver {")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 371, _masm)-> block_comment("check_receiver {"); | ||||
| 372 | // The receiver for the MemberName must be in receiver_reg. | ||||
| 373 | // Check the receiver against the MemberName.clazz | ||||
| 374 | if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) { | ||||
| 375 | // Did not load it above... | ||||
| 376 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 376, _masm)-> load_klass(temp1_recv_klass, receiver_reg, temp2); | ||||
| 377 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 377, _masm)-> verify_klass_ptr(temp1_recv_klass)_verify_klass_ptr(temp1_recv_klass, "broken klass " "temp1_recv_klass" , "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 377); | ||||
| 378 | } | ||||
| 379 | if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { | ||||
| 380 | Label L_ok; | ||||
| 381 | Register temp2_defc = temp2; | ||||
| 382 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 382, _masm)-> load_heap_oop(temp2_defc, member_clazz, temp3); | ||||
| 383 | load_klass_from_Class(_masm, temp2_defc); | ||||
| 384 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 384, _masm)-> verify_klass_ptr(temp2_defc)_verify_klass_ptr(temp2_defc, "broken klass " "temp2_defc", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 384); | ||||
| 385 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 385, _masm)-> check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, L_ok); | ||||
| 386 | // If we get here, the type check failed! | ||||
| 387 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 387, _masm)-> STOP("receiver class disagrees with MemberName.clazz")block_comment("receiver class disagrees with MemberName.clazz" ); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 387, _masm)-> stop("receiver class disagrees with MemberName.clazz" ); | ||||
| 388 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 388, _masm)-> bind(L_ok); | ||||
| 389 | } | ||||
| 390 | BLOCK_COMMENT("} check_receiver")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 390, _masm)-> block_comment("} check_receiver"); | ||||
| 391 | } | ||||
| 392 | if (iid == vmIntrinsics::_linkToSpecial || | ||||
| 393 | iid == vmIntrinsics::_linkToStatic) { | ||||
| 394 | DEBUG_ONLY(temp1_recv_klass = noreg)temp1_recv_klass = noreg; // these guys didn't load the recv_klass | ||||
| 395 | } | ||||
| 396 | |||||
| 397 | // Live registers at this point: | ||||
| 398 | // member_reg - MemberName that was the trailing argument | ||||
| 399 | // temp1_recv_klass - klass of stacked receiver, if needed | ||||
| 400 | // rsi/r13 - interpreter linkage (if interpreted) | ||||
| 401 | // rcx, rdx, rsi, rdi, r8 - compiler arguments (if compiled) | ||||
| 402 | |||||
| 403 | Label L_incompatible_class_change_error; | ||||
| 404 | switch (iid) { | ||||
| 405 | case vmIntrinsics::_linkToSpecial: | ||||
| 406 | if (VerifyMethodHandles) { | ||||
| 407 | verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); | ||||
| 408 | } | ||||
| 409 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 409, _masm)-> load_heap_oop(rbx_method, member_vmtarget); | ||||
| 410 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 410, _masm)-> access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); | ||||
| 411 | break; | ||||
| 412 | |||||
| 413 | case vmIntrinsics::_linkToStatic: | ||||
| 414 | if (VerifyMethodHandles) { | ||||
| 415 | verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); | ||||
| 416 | } | ||||
| 417 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 417, _masm)-> load_heap_oop(rbx_method, member_vmtarget); | ||||
| 418 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 418, _masm)-> access_load_at(T_ADDRESS, IN_HEAP, rbx_method, vmtarget_method, noreg, noreg); | ||||
| 419 | break; | ||||
| 420 | |||||
| 421 | case vmIntrinsics::_linkToVirtual: | ||||
| 422 | { | ||||
| 423 | // same as TemplateTable::invokevirtual, | ||||
| 424 | // minus the CP setup and profiling: | ||||
| 425 | |||||
| 426 | if (VerifyMethodHandles) { | ||||
| 427 | verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3); | ||||
| 428 | } | ||||
| 429 | |||||
| 430 | // pick out the vtable index from the MemberName, and then we can discard it: | ||||
| 431 | Register temp2_index = temp2; | ||||
| 432 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 432, _masm)-> access_load_at(T_ADDRESS, IN_HEAP, temp2_index, member_vmindex, noreg, noreg); | ||||
| 433 | |||||
| 434 | if (VerifyMethodHandles) { | ||||
| 435 | Label L_index_ok; | ||||
| 436 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 436, _masm)-> cmpl(temp2_index, 0); | ||||
| 437 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 437, _masm)-> jcc(Assembler::greaterEqual, L_index_ok); | ||||
| 438 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 438, _masm)-> STOP("no virtual index")block_comment("no virtual index"); Disassembler::hook<MacroAssembler >("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 438, _masm)-> stop("no virtual index"); | ||||
| 439 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 439, _masm)-> BIND(L_index_ok)bind(L_index_ok); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 439, _masm)-> block_comment("L_index_ok" ":"); | ||||
| 440 | } | ||||
| 441 | |||||
| 442 | // Note: The verifier invariants allow us to ignore MemberName.clazz and vmtarget | ||||
| 443 | // at this point. And VerifyMethodHandles has already checked clazz, if needed. | ||||
| 444 | |||||
| 445 | // get target Method* & entry point | ||||
| 446 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 446, _masm)-> lookup_virtual_method(temp1_recv_klass, temp2_index, rbx_method); | ||||
| 447 | break; | ||||
| 448 | } | ||||
| 449 | |||||
| 450 | case vmIntrinsics::_linkToInterface: | ||||
| 451 | { | ||||
| 452 | // same as TemplateTable::invokeinterface | ||||
| 453 | // (minus the CP setup and profiling, with different argument motion) | ||||
| 454 | if (VerifyMethodHandles) { | ||||
| 455 | verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3); | ||||
| 456 | } | ||||
| 457 | |||||
| 458 | Register temp3_intf = temp3; | ||||
| 459 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 459, _masm)-> load_heap_oop(temp3_intf, member_clazz); | ||||
| 460 | load_klass_from_Class(_masm, temp3_intf); | ||||
| 461 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 461, _masm)-> verify_klass_ptr(temp3_intf)_verify_klass_ptr(temp3_intf, "broken klass " "temp3_intf", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 461); | ||||
| 462 | |||||
| 463 | Register rbx_index = rbx_method; | ||||
| 464 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 464, _masm)-> access_load_at(T_ADDRESS, IN_HEAP, rbx_index, member_vmindex, noreg, noreg); | ||||
| 465 | if (VerifyMethodHandles) { | ||||
| 466 | Label L; | ||||
| 467 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 467, _masm)-> cmpl(rbx_index, 0); | ||||
| 468 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 468, _masm)-> jcc(Assembler::greaterEqual, L); | ||||
| 469 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 469, _masm)-> STOP("invalid vtable index for MH.invokeInterface")block_comment("invalid vtable index for MH.invokeInterface"); Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 469, _masm)-> stop("invalid vtable index for MH.invokeInterface" ); | ||||
| 470 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 470, _masm)-> bind(L); | ||||
| 471 | } | ||||
| 472 | |||||
| 473 | // given intf, index, and recv klass, dispatch to the implementation method | ||||
| 474 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 474, _masm)-> lookup_interface_method(temp1_recv_klass, temp3_intf, | ||||
| 475 | // note: next two args must be the same: | ||||
| 476 | rbx_index, rbx_method, | ||||
| 477 | temp2, | ||||
| 478 | L_incompatible_class_change_error); | ||||
| 479 | break; | ||||
| 480 | } | ||||
| 481 | |||||
| 482 | default: | ||||
| 483 | fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 483, "unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid ), vmIntrinsics::name_at(iid)); ::breakpoint(); } while (0); | ||||
| 484 | break; | ||||
| 485 | } | ||||
| 486 | |||||
| 487 | // Live at this point: | ||||
| 488 | // rbx_method | ||||
| 489 | // rsi/r13 (if interpreted) | ||||
| 490 | |||||
| 491 | // After figuring out which concrete method to call, jump into it. | ||||
| 492 | // Note that this works in the interpreter with no data motion. | ||||
| 493 | // But the compiled version will require that rcx_recv be shifted out. | ||||
| 494 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 494, _masm)-> verify_method_ptr(rbx_method)_verify_method_ptr(rbx_method, "broken method " "rbx_method", "/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 494); | ||||
| 495 | jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry); | ||||
| 496 | |||||
| 497 | if (iid == vmIntrinsics::_linkToInterface) { | ||||
| 498 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 498, _masm)-> bind(L_incompatible_class_change_error); | ||||
| 499 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 499, _masm)-> jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); | ||||
| 500 | } | ||||
| 501 | } | ||||
| 502 | } | ||||
| 503 | |||||
| 504 | #ifndef PRODUCT | ||||
| 505 | void trace_method_handle_stub(const char* adaptername, | ||||
| 506 | oopDesc* mh, | ||||
| 507 | intptr_t* saved_regs, | ||||
| 508 | intptr_t* entry_sp) { | ||||
| 509 | // called as a leaf from native code: do not block the JVM! | ||||
| 510 | bool has_mh = (strstr(adaptername, "/static") == NULL__null && | ||||
| 511 | strstr(adaptername, "linkTo") == NULL__null); // static linkers don't have MH | ||||
| 512 | const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx"; | ||||
| 513 | log_info(methodhandles)(!(LogImpl<(LogTag::_methodhandles), (LogTag::__NO_TAG), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Info))) ? (void)0 : LogImpl <(LogTag::_methodhandles), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Info>("MH %s %s=" PTR_FORMAT"0x%016" "l" "x" " sp=" PTR_FORMAT"0x%016" "l" "x", adaptername, mh_reg_name, p2i(mh), p2i(entry_sp)); | ||||
| 514 | |||||
| 515 | LogTarget(Trace, methodhandles)LogTargetImpl<LogLevel::Trace, (LogTag::_methodhandles), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||
| 516 | if (lt.is_enabled()) { | ||||
| 517 | ResourceMark rm; | ||||
| 518 | LogStream ls(lt); | ||||
| 519 | ls.print_cr("Registers:"); | ||||
| 520 | const int saved_regs_count = RegisterImpl::number_of_registers; | ||||
| 521 | for (int i = 0; i < saved_regs_count; i++) { | ||||
| 522 | Register r = as_Register(i); | ||||
| 523 | // The registers are stored in reverse order on the stack (by pusha). | ||||
| 524 | #ifdef AMD641 | ||||
| 525 | assert(RegisterImpl::number_of_registers == 16, "sanity")do { if (!(RegisterImpl::number_of_registers == 16)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 525, "assert(" "RegisterImpl::number_of_registers == 16" ") failed" , "sanity"); ::breakpoint(); } } while (0); | ||||
| 526 | if (r == rsp) { | ||||
| 527 | // rsp is actually not stored by pusha(), compute the old rsp from saved_regs (rsp after pusha): saved_regs + 16 = old rsp | ||||
| 528 | ls.print("%3s=" PTR_FORMAT"0x%016" "l" "x", r->name(), (intptr_t)(&saved_regs[16])); | ||||
| 529 | } else { | ||||
| 530 | ls.print("%3s=" PTR_FORMAT"0x%016" "l" "x", r->name(), saved_regs[((saved_regs_count - 1) - i)]); | ||||
| 531 | } | ||||
| 532 | #else | ||||
| 533 | ls.print("%3s=" PTR_FORMAT"0x%016" "l" "x", r->name(), saved_regs[((saved_regs_count - 1) - i)]); | ||||
| 534 | #endif | ||||
| 535 | if ((i + 1) % 4 == 0) { | ||||
| 536 | ls.cr(); | ||||
| 537 | } else { | ||||
| 538 | ls.print(", "); | ||||
| 539 | } | ||||
| 540 | } | ||||
| 541 | ls.cr(); | ||||
| 542 | |||||
| 543 | // Note: We want to allow trace_method_handle from any call site. | ||||
| 544 | // While trace_method_handle creates a frame, it may be entered | ||||
| 545 | // without a PC on the stack top (e.g. not just after a call). | ||||
| 546 | // Walking that frame could lead to failures due to that invalid PC. | ||||
| 547 | // => carefully detect that frame when doing the stack walking | ||||
| 548 | |||||
| 549 | { | ||||
| 550 | // dumping last frame with frame::describe | ||||
| 551 | |||||
| 552 | JavaThread* p = JavaThread::active(); | ||||
| 553 | |||||
| 554 | // may not be needed by safer and unexpensive here | ||||
| 555 | PreserveExceptionMark pem(Thread::current()); | ||||
| 556 | FrameValues values; | ||||
| 557 | |||||
| 558 | frame cur_frame = os::current_frame(); | ||||
| 559 | |||||
| 560 | if (cur_frame.fp() != 0) { // not walkable | ||||
| 561 | |||||
| 562 | // Robust search of trace_calling_frame (independent of inlining). | ||||
| 563 | // Assumes saved_regs comes from a pusha in the trace_calling_frame. | ||||
| 564 | // | ||||
| 565 | // We have to start the search from cur_frame, because trace_calling_frame may be it. | ||||
| 566 | // It is guaranteed that trace_calling_frame is different from the top frame. | ||||
| 567 | // But os::current_frame() does NOT return the top frame: it returns the next frame under it (caller's frame). | ||||
| 568 | // (Due to inlining and tail call optimizations, caller's frame doesn't necessarily correspond to the immediate | ||||
| 569 | // caller in the source code.) | ||||
| 570 | assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?")do { if (!(cur_frame.sp() < saved_regs)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 570, "assert(" "cur_frame.sp() < saved_regs" ") failed", "registers not saved on stack ?"); ::breakpoint(); } } while (0); | ||||
| 571 | frame trace_calling_frame = cur_frame; | ||||
| 572 | while (trace_calling_frame.fp() < saved_regs) { | ||||
| 573 | assert(trace_calling_frame.cb() == NULL, "not a C frame")do { if (!(trace_calling_frame.cb() == __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 573, "assert(" "trace_calling_frame.cb() == __null" ") failed" , "not a C frame"); ::breakpoint(); } } while (0); | ||||
| 574 | trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame); | ||||
| 575 | } | ||||
| 576 | assert(trace_calling_frame.sp() < saved_regs, "wrong frame")do { if (!(trace_calling_frame.sp() < saved_regs)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 576, "assert(" "trace_calling_frame.sp() < saved_regs" ") failed" , "wrong frame"); ::breakpoint(); } } while (0); | ||||
| 577 | |||||
| 578 | // safely create a frame and call frame::describe | ||||
| 579 | intptr_t *dump_sp = trace_calling_frame.sender_sp(); | ||||
| 580 | intptr_t *dump_fp = trace_calling_frame.link(); | ||||
| 581 | |||||
| 582 | if (has_mh) { | ||||
| 583 | // The previous definition of walkable may have to be refined | ||||
| 584 | // if new call sites cause the next frame constructor to start | ||||
| 585 | // failing. Alternatively, frame constructors could be | ||||
| 586 | // modified to support the current or future non walkable | ||||
| 587 | // frames (but this is more intrusive and is not considered as | ||||
| 588 | // part of this RFE, which will instead use a simpler output). | ||||
| 589 | frame dump_frame = frame(dump_sp, dump_fp); | ||||
| 590 | dump_frame.describe(values, 1); | ||||
| 591 | } else { | ||||
| 592 | // Stack may not be walkable (invalid PC above FP): | ||||
| 593 | // Add descriptions without building a Java frame to avoid issues | ||||
| 594 | values.describe(-1, dump_fp, "fp for #1 <not parsed, cannot trust pc>"); | ||||
| 595 | values.describe(-1, dump_sp, "sp for #1"); | ||||
| 596 | } | ||||
| 597 | } | ||||
| 598 | values.describe(-1, entry_sp, "raw top of stack"); | ||||
| 599 | |||||
| 600 | ls.print_cr("Stack layout:"); | ||||
| 601 | values.print_on(p, &ls); | ||||
| 602 | } | ||||
| 603 | if (has_mh && oopDesc::is_oop(mh)) { | ||||
| 604 | mh->print_on(&ls); | ||||
| 605 | if (java_lang_invoke_MethodHandle::is_instance(mh)) { | ||||
| 606 | java_lang_invoke_MethodHandle::form(mh)->print_on(&ls); | ||||
| 607 | } | ||||
| 608 | } | ||||
| 609 | } | ||||
| 610 | } | ||||
| 611 | |||||
| 612 | // The stub wraps the arguments in a struct on the stack to avoid | ||||
| 613 | // dealing with the different calling conventions for passing 6 | ||||
| 614 | // arguments. | ||||
| 615 | struct MethodHandleStubArguments { | ||||
| 616 | const char* adaptername; | ||||
| 617 | oopDesc* mh; | ||||
| 618 | intptr_t* saved_regs; | ||||
| 619 | intptr_t* entry_sp; | ||||
| 620 | }; | ||||
| 621 | void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) { | ||||
| 622 | trace_method_handle_stub(args->adaptername, | ||||
| 623 | args->mh, | ||||
| 624 | args->saved_regs, | ||||
| 625 | args->entry_sp); | ||||
| 626 | } | ||||
| 627 | |||||
| 628 | void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { | ||||
| 629 | if (!log_is_enabled(Info, methodhandles)(LogImpl<(LogTag::_methodhandles), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag:: __NO_TAG)>::is_level(LogLevel::Info))) return; | ||||
| 630 | BLOCK_COMMENT(err_msg("trace_method_handle %s {", adaptername))Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 630, _masm)-> block_comment(err_msg("trace_method_handle %s {" , adaptername)); | ||||
| 631 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 631, _masm)-> enter(); | ||||
| 632 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 632, _masm)-> andptr(rsp, -16); // align stack if needed for FPU state | ||||
| 633 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 633, _masm)-> pusha(); | ||||
| 634 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 634, _masm)-> mov(rbx, rsp); // for retreiving saved_regs | ||||
| 635 | // Note: saved_regs must be in the entered frame for the | ||||
| 636 | // robust stack walking implemented in trace_method_handle_stub. | ||||
| 637 | |||||
| 638 | // save FP result, valid at some call sites (adapter_opt_return_float, ...) | ||||
| 639 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 639, _masm)-> decrement(rsp, 2 * wordSize); | ||||
| 640 | #ifdef _LP641 | ||||
| 641 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 641, _masm)-> movdbl(Address(rsp, 0), xmm0); | ||||
| 642 | #else | ||||
| 643 | if (UseSSE >= 2) { | ||||
| 644 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 644, _masm)-> movdbl(Address(rsp, 0), xmm0); | ||||
| 645 | } else if (UseSSE == 1) { | ||||
| 646 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 646, _masm)-> movflt(Address(rsp, 0), xmm0); | ||||
| 647 | } else { | ||||
| 648 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 648, _masm)-> fst_d(Address(rsp, 0)); | ||||
| 649 | } | ||||
| 650 | #endif // LP64 | ||||
| 651 | |||||
| 652 | // Incoming state: | ||||
| 653 | // rcx: method handle | ||||
| 654 | // | ||||
| 655 | // To avoid calling convention issues, build a record on the stack | ||||
| 656 | // and pass the pointer to that instead. | ||||
| 657 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 657, _masm)-> push(rbp); // entry_sp (with extra align space) | ||||
| 658 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 658, _masm)-> push(rbx); // pusha saved_regs | ||||
| 659 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 659, _masm)-> push(rcx); // mh | ||||
| 660 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 660, _masm)-> push(rcx); // slot for adaptername | ||||
| 661 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 661, _masm)-> movptr(Address(rsp, 0), (intptr_t) adaptername); | ||||
| 662 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 662, _masm)-> super_call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub_wrapper)((address)((address_word)(trace_method_handle_stub_wrapper))), rsp); | ||||
| 663 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 663, _masm)-> increment(rsp, sizeof(MethodHandleStubArguments)); | ||||
| 664 | |||||
| 665 | #ifdef _LP641 | ||||
| 666 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 666, _masm)-> movdbl(xmm0, Address(rsp, 0)); | ||||
| 667 | #else | ||||
| 668 | if (UseSSE >= 2) { | ||||
| 669 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 669, _masm)-> movdbl(xmm0, Address(rsp, 0)); | ||||
| 670 | } else if (UseSSE == 1) { | ||||
| 671 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 671, _masm)-> movflt(xmm0, Address(rsp, 0)); | ||||
| 672 | } else { | ||||
| 673 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 673, _masm)-> fld_d(Address(rsp, 0)); | ||||
| 674 | } | ||||
| 675 | #endif // LP64 | ||||
| 676 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 676, _masm)-> increment(rsp, 2 * wordSize); | ||||
| 677 | |||||
| 678 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 678, _masm)-> popa(); | ||||
| 679 | __Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 679, _masm)-> leave(); | ||||
| 680 | BLOCK_COMMENT("} trace_method_handle")Disassembler::hook<MacroAssembler>("/home/daniel/Projects/java/jdk/src/hotspot/cpu/x86/methodHandles_x86.cpp" , 680, _masm)-> block_comment("} trace_method_handle"); | ||||
| 681 | } | ||||
| 682 | #endif //PRODUCT |
| 1 | /* | |||
| 2 | * Copyright (c) 2000, 2021, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #ifndef SHARE_ASM_REGISTER_HPP | |||
| 26 | #define SHARE_ASM_REGISTER_HPP | |||
| 27 | ||||
| 28 | #include "utilities/debug.hpp" | |||
| 29 | #include "utilities/globalDefinitions.hpp" | |||
| 30 | #include "utilities/macros.hpp" | |||
| 31 | ||||
| 32 | // Use AbstractRegister as shortcut | |||
| 33 | class AbstractRegisterImpl; | |||
| 34 | typedef AbstractRegisterImpl* AbstractRegister; | |||
| 35 | ||||
| 36 | ||||
| 37 | // The super class for platform specific registers. Instead of using value objects, | |||
| 38 | // registers are implemented as pointers. Subclassing is used so all registers can | |||
| 39 | // use the debugging suport below. No virtual functions are used for efficiency. | |||
| 40 | // They are canonicalized; i.e., registers are equal if their pointers are equal, | |||
| 41 | // and vice versa. A concrete implementation may just map the register onto 'this'. | |||
| 42 | ||||
| 43 | class AbstractRegisterImpl { | |||
| 44 | protected: | |||
| 45 | int value() const { return (int)(intx)this; } | |||
| 46 | }; | |||
| 47 | ||||
| 48 | #define AS_REGISTER(type,name)((type)name_typeEnumValue) ((type)name##_##type##EnumValue) | |||
| 49 | ||||
| 50 | #define CONSTANT_REGISTER_DECLARATION(type, name, value)const type name = ((type)value); enum { name_typeEnumValue = ( value) } \ | |||
| 51 | const type name = ((type)value); \ | |||
| 52 | enum { name##_##type##EnumValue = (value) } | |||
| 53 | ||||
| 54 | #define REGISTER_DECLARATION(type, name, value)const type name = ((type)value) \ | |||
| 55 | const type name = ((type)value) | |||
| 56 | ||||
| 57 | #define REGISTER_DEFINITION(type, name) | |||
| 58 | ||||
| 59 | #include CPU_HEADER(register)"register_x86.hpp" | |||
| 60 | ||||
| 61 | // Debugging support | |||
| 62 | ||||
| 63 | template<typename R, typename... Rx> | |||
| 64 | inline void assert_different_registers(R first_register, Rx... more_registers) { | |||
| 65 | #ifdef ASSERT1 | |||
| 66 | const R regs[] = { first_register, more_registers... }; | |||
| 67 | // Verify there are no equal entries. | |||
| 68 | for (size_t i = 0; i < ARRAY_SIZE(regs)sizeof(array_size_impl(regs)) - 1; ++i) { | |||
| 69 | for (size_t j = i + 1; j < ARRAY_SIZE(regs)sizeof(array_size_impl(regs)); ++j) { | |||
| 70 | assert(regs[i] != regs[j], "Multiple uses of register: %s", regs[i]->name())do { if (!(regs[i] != regs[j])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/asm/register.hpp" , 70, "assert(" "regs[i] != regs[j]" ") failed", "Multiple uses of register: %s" , regs[i]->name()); ::breakpoint(); } } while (0); | |||
| ||||
| 71 | } | |||
| 72 | } | |||
| 73 | #endif | |||
| 74 | } | |||
| 75 | ||||
| 76 | #endif // SHARE_ASM_REGISTER_HPP |