# HG changeset patch # User kvn # Date 1556739089 25200 # Node ID ad45b3802d4e8796d66b4e2915d433ccf6c7b696 # Parent 0bda2308eded44a507e4324ce0a5ab8b4ccd996c 8220623: [JVMCI] Update JVMCI to support JVMCI based Compiler compiled into shared library Reviewed-by: dnsimon, never, stefank, rehn, neliasso, dholmes, kbarrett, coleenp diff -r 0bda2308eded -r ad45b3802d4e make/autoconf/hotspot.m4 --- a/make/autoconf/hotspot.m4 Wed May 01 12:41:26 2019 -0400 +++ b/make/autoconf/hotspot.m4 Wed May 01 12:31:29 2019 -0700 @@ -392,9 +392,8 @@ JVM_FEATURES_jvmci="" INCLUDE_JVMCI="false" else - # Only enable jvmci on x86_64, sparcv9 and aarch64 + # Only enable jvmci on x86_64 and aarch64 if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \ - test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \ test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then AC_MSG_RESULT([yes]) JVM_FEATURES_jvmci="jvmci" diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/.mx.jvmci/suite.py --- a/src/hotspot/.mx.jvmci/suite.py Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/.mx.jvmci/suite.py Wed May 01 12:31:29 2019 -0700 @@ -56,6 +56,9 @@ "jdk.vm.ci.common" : { "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], + "dependencies" : [ + "jdk.vm.ci.services", + ], "checkstyle" : "jdk.vm.ci.services", "javaCompliance" : "9+", "workingSets" : "API,JVMCI", @@ -258,9 +261,11 @@ "subDir" : "../../test/hotspot/jtreg/compiler/jvmci", "dependencies" : [ "jdk.vm.ci.runtime.test", + "jdk.vm.ci.hotspot.test", ], "distDependencies" : [ "JVMCI_API", + "JVMCI_HOTSPOT", ], "exclude" : ["mx:JUNIT"], }, diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp --- a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "runtime/sharedRuntime.hpp" #include "vmreg_aarch64.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS) { if (inst->is_call() || inst->is_jump() || inst->is_blr()) { return pc_offset + NativeCall::instruction_size; } else if (inst->is_general_jump()) { @@ -43,12 +43,12 @@ } } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; #ifdef ASSERT { NativeInstruction *insn = nativeInstruction_at(pc); - if (HotSpotObjectConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) { // Mov narrow constant: movz n << 16, movk assert(Instruction_aarch64::extract(insn->encoding(), 31, 21) == 0b11010010101 && nativeInstruction_at(pc+4)->is_movk(), "wrong insn in patch"); @@ -59,7 +59,7 @@ } } #endif // ASSERT - Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant)); + Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK); jobject value = JNIHandles::make_local(obj()); MacroAssembler::patch_oop(pc, (address)obj()); int oop_index = _oop_recorder->find_index(value); @@ -67,21 +67,21 @@ _instructions->relocate(pc, rspec); } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; - if (HotSpotMetaspaceConstantImpl::compressed(constant)) { - narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, CHECK); + if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) { + narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); MacroAssembler::patch_narrow_klass(pc, narrowOop); TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); } else { NativeMovConstReg* move = nativeMovConstReg_at(pc); - void* reference = record_metadata_reference(_instructions, pc, constant, CHECK); + void* reference = record_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); move->set_data((intptr_t) reference); TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference)); } } -void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; NativeInstruction* inst = nativeInstruction_at(pc); if (inst->is_adr_aligned() || inst->is_ldr_literal() @@ -94,7 +94,7 @@ } } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS) { address pc = (address) inst; if (inst->is_call()) { NativeCall* call = nativeCall_at(pc); @@ -118,12 +118,12 @@ TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); } -void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, Handle hotspot_method, jint pc_offset, TRAPS) { +void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &cbuf, JVMCIObject hotspot_method, jint pc_offset, JVMCI_TRAPS) { #ifdef ASSERT Method* method = NULL; // we need to check, this might also be an unresolved method - if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - method = getMethodFromHotSpotMethod(hotspot_method()); + if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(hotspot_method)) { + method = JVMCIENV->asMethod(hotspot_method); } #endif switch (_next_call_type) { @@ -157,7 +157,7 @@ } } -void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS) { switch (mark) { case POLL_NEAR: JVMCI_ERROR("unimplemented"); @@ -178,7 +178,7 @@ } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) { if (jvmci_reg < RegisterImpl::number_of_registers) { return as_Register(jvmci_reg)->as_VMReg(); } else { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp --- a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ #include "utilities/align.hpp" #include "vmreg_sparc.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS) { if (inst->is_call() || inst->is_jump()) { return pc_offset + NativeCall::instruction_size; } else if (inst->is_call_reg()) { @@ -44,11 +44,11 @@ } } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; - Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant)); + Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK); jobject value = JNIHandles::make_local(obj()); - if (HotSpotObjectConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) { int oop_index = _oop_recorder->find_index(value); RelocationHolder rspec = oop_Relocation::spec(oop_index); _instructions->relocate(pc, rspec, 1); @@ -64,22 +64,22 @@ } } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; - if (HotSpotMetaspaceConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) { NativeMovConstReg32* move = nativeMovConstReg32_at(pc); - narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, CHECK); + narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); move->set_data((intptr_t)narrowOop); TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); } else { NativeMovConstReg* move = nativeMovConstReg_at(pc); - void* reference = record_metadata_reference(_instructions, pc, constant, CHECK); + void* reference = record_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); move->set_data((intptr_t)reference); TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference)); } } -void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; NativeInstruction* inst = nativeInstruction_at(pc); NativeInstruction* inst1 = nativeInstruction_at(pc + 4); @@ -100,7 +100,7 @@ } } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS) { address pc = (address) inst; if (inst->is_call()) { NativeCall* call = nativeCall_at(pc); @@ -116,12 +116,12 @@ TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); } -void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, Handle hotspot_method, jint pc_offset, TRAPS) { +void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_method, jint pc_offset, JVMCI_TRAPS) { #ifdef ASSERT Method* method = NULL; // we need to check, this might also be an unresolved method - if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - method = getMethodFromHotSpotMethod(hotspot_method()); + if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(hotspot_method)) { + method = JVMCIENV->asMethod(hotspot_method); } #endif switch (_next_call_type) { @@ -155,7 +155,7 @@ } } -void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS) { switch (mark) { case POLL_NEAR: JVMCI_ERROR("unimplemented"); @@ -176,7 +176,7 @@ } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) { // JVMCI Registers are numbered as follows: // 0..31: Thirty-two General Purpose registers (CPU Registers) // 32..63: Thirty-two single precision float registers diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp --- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ #include "code/vmreg.hpp" #include "vmreg_x86.inline.hpp" -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) { +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS) { if (inst->is_call() || inst->is_jump()) { assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); return (pc_offset + NativeCall::instruction_size); @@ -54,7 +54,7 @@ return (offset); } else if (inst->is_call_reg()) { // the inlined vtable stub contains a "call register" instruction - assert(method.not_null(), "only valid for virtual calls"); + assert(method.is_non_null(), "only valid for virtual calls"); return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset()); } else if (inst->is_cond_jump()) { address pc = (address) (inst); @@ -64,11 +64,12 @@ } } -void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; - Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant)); + Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK); + Thread* THREAD = Thread::current(); jobject value = JNIHandles::make_local(obj()); - if (HotSpotObjectConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) { #ifdef _LP64 address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); int oop_index = _oop_recorder->find_index(value); @@ -85,24 +86,24 @@ } } -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) { +void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; - if (HotSpotMetaspaceConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) { #ifdef _LP64 address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); - *((narrowKlass*) operand) = record_narrow_metadata_reference(_instructions, operand, constant, CHECK); + *((narrowKlass*) operand) = record_narrow_metadata_reference(_instructions, operand, constant, JVMCI_CHECK); TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); #else JVMCI_ERROR("compressed Klass* on 32bit"); #endif } else { address operand = Assembler::locate_operand(pc, Assembler::imm_operand); - *((void**) operand) = record_metadata_reference(_instructions, operand, constant, CHECK); + *((void**) operand) = record_metadata_reference(_instructions, operand, constant, JVMCI_CHECK); TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); } } -void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS) { address pc = _instructions->start() + pc_offset; address operand = Assembler::locate_operand(pc, Assembler::disp32_operand); @@ -117,7 +118,7 @@ TRACE_jvmci_3("relocating at " PTR_FORMAT "/" PTR_FORMAT " with destination at " PTR_FORMAT " (%d)", p2i(pc), p2i(operand), p2i(dest), data_offset); } -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) { +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS) { address pc = (address) inst; if (inst->is_call()) { // NOTE: for call without a mov, the offset must fit a 32-bit immediate @@ -145,12 +146,12 @@ TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); } -void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, Handle hotspot_method, jint pc_offset, TRAPS) { +void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_method, jint pc_offset, JVMCI_TRAPS) { #ifdef ASSERT Method* method = NULL; // we need to check, this might also be an unresolved method - if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - method = getMethodFromHotSpotMethod(hotspot_method()); + if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(hotspot_method)) { + method = JVMCIENV->asMethod(hotspot_method); } #endif switch (_next_call_type) { @@ -199,7 +200,7 @@ } -void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) { +void CodeInstaller::pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS) { switch (mark) { case POLL_NEAR: { relocate_poll_near(pc); @@ -229,7 +230,7 @@ } // convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) { +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) { if (jvmci_reg < RegisterImpl::number_of_registers) { return as_Register(jvmci_reg)->as_VMReg(); } else { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/aot/aotCompiledMethod.cpp --- a/src/hotspot/share/aot/aotCompiledMethod.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/aot/aotCompiledMethod.cpp Wed May 01 12:31:29 2019 -0700 @@ -32,8 +32,6 @@ #include "compiler/compilerOracle.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/collectedHeap.hpp" -#include "jvmci/compilerRuntime.hpp" -#include "jvmci/jvmciRuntime.hpp" #include "oops/method.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/aot/aotLoader.cpp --- a/src/hotspot/share/aot/aotLoader.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/aot/aotLoader.cpp Wed May 01 12:31:29 2019 -0700 @@ -26,8 +26,8 @@ #include "aot/aotCodeHeap.hpp" #include "aot/aotLoader.inline.hpp" -#include "jvmci/jvmciRuntime.hpp" #include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "runtime/handles.inline.hpp" #include "runtime/os.inline.hpp" diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/javaClasses.cpp Wed May 01 12:31:29 2019 -0700 @@ -2607,6 +2607,45 @@ } } +#if INCLUDE_JVMCI +void java_lang_StackTraceElement::decode(Handle mirror, methodHandle method, int bci, Symbol*& methodname, Symbol*& filename, int& line_number) { + int method_id = method->orig_method_idnum(); + int cpref = method->name_index(); + decode(mirror, method_id, method->constants()->version(), bci, cpref, methodname, filename, line_number); +} + +void java_lang_StackTraceElement::decode(Handle mirror, int method_id, int version, int bci, int cpref, Symbol*& methodname, Symbol*& filename, int& line_number) { + // Fill in class name + InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); + Method* method = holder->method_with_orig_idnum(method_id, version); + + // The method can be NULL if the requested class version is gone + Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); + + // Fill in method name + methodname = sym; + + if (!version_matches(method, version)) { + // If the method was redefined, accurate line number information isn't available + filename = NULL; + line_number = -1; + } else { + // Fill in source file name and line number. + // Use a specific ik version as a holder since the mirror might + // refer to a version that is now obsolete and no longer accessible + // via the previous versions list. + holder = holder->get_klass_version(version); + assert(holder != NULL, "sanity check"); + Symbol* source = holder->source_file_name(); + if (ShowHiddenFrames && source == NULL) { + source = vmSymbols::unknown_class_name(); + } + filename = source; + line_number = Backtrace::get_line_number(method, bci); + } +} +#endif // INCLUDE_JVMCI + Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) { HandleMark hm(THREAD); Handle mname(THREAD, stackFrame->obj_field(_memberName_offset)); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/javaClasses.hpp --- a/src/hotspot/share/classfile/javaClasses.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/javaClasses.hpp Wed May 01 12:31:29 2019 -0700 @@ -1368,6 +1368,11 @@ static void compute_offsets(); static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; +#if INCLUDE_JVMCI + static void decode(Handle mirror, int method, int version, int bci, int cpref, Symbol*& methodName, Symbol*& fileName, int& lineNumber); + static void decode(Handle mirror, methodHandle method, int bci, Symbol*& methodName, Symbol*& fileName, int& lineNumber); +#endif + // Debugging friend class JavaClasses; }; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/metadataOnStackMark.cpp --- a/src/hotspot/share/classfile/metadataOnStackMark.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/metadataOnStackMark.cpp Wed May 01 12:31:29 2019 -0700 @@ -33,7 +33,7 @@ #include "services/threadService.hpp" #include "utilities/chunkedList.hpp" #if INCLUDE_JVMCI -#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmci.hpp" #endif MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; @@ -73,7 +73,7 @@ JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack); #if INCLUDE_JVMCI - JVMCIRuntime::metadata_do(Metadata::mark_on_stack); + JVMCI::metadata_do(Metadata::mark_on_stack); #endif } } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/systemDictionary.cpp --- a/src/hotspot/share/classfile/systemDictionary.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/systemDictionary.cpp Wed May 01 12:31:29 2019 -0700 @@ -86,9 +86,6 @@ #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" #endif -#if INCLUDE_JVMCI -#include "jvmci/jvmciRuntime.hpp" -#endif #if INCLUDE_JFR #include "jfr/jfr.hpp" #endif @@ -1922,13 +1919,6 @@ Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid); InstanceKlass** klassp = &_well_known_klasses[id]; - -#if INCLUDE_JVMCI - if (id >= FIRST_JVMCI_WKID) { - assert(EnableJVMCI, "resolve JVMCI classes only when EnableJVMCI is true"); - } -#endif - if ((*klassp) == NULL) { Klass* k = resolve_or_fail(symbol, true, CHECK_0); (*klassp) = InstanceKlass::cast(k); @@ -2017,7 +2007,7 @@ WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass); resolve_wk_klasses_until(jsr292_group_start, scan, CHECK); resolve_wk_klasses_through(jsr292_group_end, scan, CHECK); - WKID last = NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID); + WKID last = WKID_LIMIT; resolve_wk_klasses_until(last, scan, CHECK); _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/systemDictionary.hpp --- a/src/hotspot/share/classfile/systemDictionary.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/systemDictionary.hpp Wed May 01 12:31:29 2019 -0700 @@ -26,7 +26,6 @@ #define SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP #include "classfile/classLoaderData.hpp" -#include "jvmci/systemDictionary_jvmci.hpp" #include "oops/objArrayOop.hpp" #include "oops/symbol.hpp" #include "runtime/java.hpp" @@ -215,9 +214,6 @@ do_klass(Integer_klass, java_lang_Integer ) \ do_klass(Long_klass, java_lang_Long ) \ \ - /* JVMCI classes. These are loaded on-demand. */ \ - JVMCI_WK_KLASSES_DO(do_klass) \ - \ /*end*/ @@ -236,11 +232,6 @@ WKID_LIMIT, -#if INCLUDE_JVMCI - FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(JVMCI_klass), - LAST_JVMCI_WKID = WK_KLASS_ENUM_NAME(Value_klass), -#endif - FIRST_WKID = NO_WKID + 1 }; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/classfile/vmSymbols.hpp --- a/src/hotspot/share/classfile/vmSymbols.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/classfile/vmSymbols.hpp Wed May 01 12:31:29 2019 -0700 @@ -358,8 +358,7 @@ template(destroyed_name, "destroyed") \ template(nthreads_name, "nthreads") \ template(ngroups_name, "ngroups") \ - template(shutdown_method_name, "shutdown") \ - template(bootstrapFinished_method_name, "bootstrapFinished") \ + template(shutdown_name, "shutdown") \ template(finalize_method_name, "finalize") \ template(reference_lock_name, "lock") \ template(reference_discovered_name, "discovered") \ diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/code/nmethod.cpp --- a/src/hotspot/share/code/nmethod.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/code/nmethod.cpp Wed May 01 12:31:29 2019 -0700 @@ -64,7 +64,7 @@ #include "utilities/resourceHash.hpp" #include "utilities/xmlstream.hpp" #if INCLUDE_JVMCI -#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" #endif #ifdef DTRACE_ENABLED @@ -112,6 +112,10 @@ int dependencies_size; int handler_table_size; int nul_chk_table_size; +#if INCLUDE_JVMCI + int speculations_size; + int jvmci_data_size; +#endif int oops_size; int metadata_size; @@ -129,6 +133,10 @@ dependencies_size += nm->dependencies_size(); handler_table_size += nm->handler_table_size(); nul_chk_table_size += nm->nul_chk_table_size(); +#if INCLUDE_JVMCI + speculations_size += nm->speculations_size(); + jvmci_data_size += nm->jvmci_data_size(); +#endif } void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; @@ -146,6 +154,10 @@ if (dependencies_size != 0) tty->print_cr(" dependencies = %d", dependencies_size); if (handler_table_size != 0) tty->print_cr(" handler table = %d", handler_table_size); if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %d", nul_chk_table_size); +#if INCLUDE_JVMCI + if (speculations_size != 0) tty->print_cr(" speculations = %d", speculations_size); + if (jvmci_data_size != 0) tty->print_cr(" JVMCI data = %d", jvmci_data_size); +#endif } }; @@ -426,11 +438,6 @@ #if INCLUDE_RTM_OPT _rtm_state = NoRTM; #endif -#if INCLUDE_JVMCI - _jvmci_installed_code = NULL; - _speculation_log = NULL; - _jvmci_installed_code_triggers_invalidation = false; -#endif } nmethod* nmethod::new_native_nmethod(const methodHandle& method, @@ -483,8 +490,11 @@ AbstractCompiler* compiler, int comp_level #if INCLUDE_JVMCI - , jweak installed_code, - jweak speculationLog + , char* speculations, + int speculations_len, + int nmethod_mirror_index, + const char* nmethod_mirror_name, + FailedSpeculation** failed_speculations #endif ) { @@ -493,12 +503,19 @@ // create nmethod nmethod* nm = NULL; { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); +#if INCLUDE_JVMCI + int jvmci_data_size = !compiler->is_jvmci() ? 0 : JVMCINMethodData::compute_size(nmethod_mirror_name); +#endif int nmethod_size = CodeBlob::allocation_size(code_buffer, sizeof(nmethod)) + adjust_pcs_size(debug_info->pcs_size()) + align_up((int)dependencies->size_in_bytes(), oopSize) + align_up(handler_table->size_in_bytes() , oopSize) + align_up(nul_chk_table->size_in_bytes() , oopSize) +#if INCLUDE_JVMCI + + align_up(speculations_len , oopSize) + + align_up(jvmci_data_size , oopSize) +#endif + align_up(debug_info->data_size() , oopSize); nm = new (nmethod_size, comp_level) @@ -510,12 +527,19 @@ compiler, comp_level #if INCLUDE_JVMCI - , installed_code, - speculationLog + , speculations, + speculations_len, + jvmci_data_size #endif ); if (nm != NULL) { +#if INCLUDE_JVMCI + if (compiler->is_jvmci()) { + // Initialize the JVMCINMethodData object inlined into nm + nm->jvmci_nmethod_data()->initialize(nmethod_mirror_index, nmethod_mirror_name, failed_speculations); + } +#endif // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -591,7 +615,13 @@ _dependencies_offset = _scopes_pcs_offset; _handler_table_offset = _dependencies_offset; _nul_chk_table_offset = _handler_table_offset; +#if INCLUDE_JVMCI + _speculations_offset = _nul_chk_table_offset; + _jvmci_data_offset = _speculations_offset; + _nmethod_end_offset = _jvmci_data_offset; +#else _nmethod_end_offset = _nul_chk_table_offset; +#endif _compile_id = compile_id; _comp_level = CompLevel_none; _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); @@ -667,8 +697,9 @@ AbstractCompiler* compiler, int comp_level #if INCLUDE_JVMCI - , jweak installed_code, - jweak speculation_log + , char* speculations, + int speculations_len, + int jvmci_data_size #endif ) : CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false), @@ -697,15 +728,6 @@ set_ctable_begin(header_begin() + _consts_offset); #if INCLUDE_JVMCI - _jvmci_installed_code = installed_code; - _speculation_log = speculation_log; - oop obj = JNIHandles::resolve(installed_code); - if (obj == NULL || (obj->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(obj))) { - _jvmci_installed_code_triggers_invalidation = false; - } else { - _jvmci_installed_code_triggers_invalidation = true; - } - if (compiler->is_jvmci()) { // JVMCI might not produce any stub sections if (offsets->value(CodeOffsets::Exceptions) != -1) { @@ -735,10 +757,10 @@ _deopt_mh_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { _deopt_mh_handler_begin = NULL; + } #if INCLUDE_JVMCI } #endif - } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); } else { @@ -753,7 +775,13 @@ _dependencies_offset = _scopes_pcs_offset + adjust_pcs_size(debug_info->pcs_size()); _handler_table_offset = _dependencies_offset + align_up((int)dependencies->size_in_bytes (), oopSize); _nul_chk_table_offset = _handler_table_offset + align_up(handler_table->size_in_bytes(), oopSize); +#if INCLUDE_JVMCI + _speculations_offset = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize); + _jvmci_data_offset = _speculations_offset + align_up(speculations_len, oopSize); + _nmethod_end_offset = _jvmci_data_offset + align_up(jvmci_data_size, oopSize); +#else _nmethod_end_offset = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize); +#endif _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = code_begin() + offsets->value(CodeOffsets::OSR_Entry); @@ -779,6 +807,13 @@ handler_table->copy_to(this); nul_chk_table->copy_to(this); +#if INCLUDE_JVMCI + // Copy speculations to nmethod + if (speculations_size() != 0) { + memcpy(speculations_begin(), speculations, speculations_len); + } +#endif + // we use the information of entry points to find out if a method is // static or non static assert(compiler->is_c2() || compiler->is_jvmci() || @@ -798,13 +833,14 @@ log->print(" level='%d'", comp_level()); } #if INCLUDE_JVMCI - char buffer[O_BUFLEN]; - char* jvmci_name = jvmci_installed_code_name(buffer, O_BUFLEN); + if (jvmci_nmethod_data() != NULL) { + const char* jvmci_name = jvmci_nmethod_data()->name(); if (jvmci_name != NULL) { - log->print(" jvmci_installed_code_name='"); + log->print(" jvmci_mirror_name='"); log->text("%s", jvmci_name); log->print("'"); } + } #endif } @@ -1115,13 +1151,6 @@ // Log the unloading. log_state_change(); -#if INCLUDE_JVMCI - // The method can only be unloaded after the pointer to the installed code - // Java wrapper is no longer alive. Here we need to clear out this weak - // reference to the dead object. - maybe_invalidate_installed_code(); -#endif - // The Method* is gone at this point assert(_method == NULL, "Tautology"); @@ -1134,6 +1163,15 @@ // concurrent nmethod unloading. Therefore, there is no need for // acquire on the loader side. OrderAccess::release_store(&_state, (signed char)unloaded); + +#if INCLUDE_JVMCI + // Clear the link between this nmethod and a HotSpotNmethod mirror + JVMCINMethodData* nmethod_data = jvmci_nmethod_data(); + if (nmethod_data != NULL) { + nmethod_data->invalidate_nmethod_mirror(this); + nmethod_data->clear_nmethod_mirror(this); + } +#endif } void nmethod::invalidate_osr_method() { @@ -1265,13 +1303,18 @@ // Log the transition once log_state_change(); - // Invalidate while holding the patching lock - JVMCI_ONLY(maybe_invalidate_installed_code()); - // Remove nmethod from method. unlink_from_method(false /* already owns Patching_lock */); } // leave critical region under Patching_lock +#if INCLUDE_JVMCI + // Invalidate can't occur while holding the Patching lock + JVMCINMethodData* nmethod_data = jvmci_nmethod_data(); + if (nmethod_data != NULL) { + nmethod_data->invalidate_nmethod_mirror(this); + } +#endif + #ifdef ASSERT if (is_osr_method() && method() != NULL) { // Make sure osr nmethod is invalidated, i.e. not on the list @@ -1297,6 +1340,14 @@ flush_dependencies(/*delete_immediately*/true); } +#if INCLUDE_JVMCI + // Now that the nmethod has been unregistered, it's + // safe to clear the HotSpotNmethod mirror oop. + if (nmethod_data != NULL) { + nmethod_data->clear_nmethod_mirror(this); + } +#endif + // Clear ICStubs to prevent back patching stubs of zombie or flushed // nmethods during the next safepoint (see ICStub::finalize), as well // as to free up CompiledICHolder resources. @@ -1324,7 +1375,7 @@ assert(state == not_entrant, "other cases may need to be handled differently"); } - if (TraceCreateZombies) { + if (TraceCreateZombies && state == zombie) { ResourceMark m; tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); } @@ -1362,11 +1413,6 @@ ec = next; } -#if INCLUDE_JVMCI - assert(_jvmci_installed_code == NULL, "should have been nulled out when transitioned to zombie"); - assert(_speculation_log == NULL, "should have been nulled out when transitioned to zombie"); -#endif - Universe::heap()->flush_nmethod(this); CodeBlob::flush(); @@ -1660,17 +1706,6 @@ if (is_unloading()) { make_unloaded(); } else { -#if INCLUDE_JVMCI - if (_jvmci_installed_code != NULL) { - if (JNIHandles::is_global_weak_cleared(_jvmci_installed_code)) { - if (_jvmci_installed_code_triggers_invalidation) { - make_not_entrant(); - } - clear_jvmci_installed_code(); - } - } -#endif - guarantee(unload_nmethod_caches(unloading_occurred), "Should not need transition stubs"); } @@ -2066,7 +2101,7 @@ if (cm->is_aot()) return; // FIXME: Revisit once _lock_count is added to aot_method nmethod* nm = cm->as_nmethod(); Atomic::inc(&nm->_lock_count); - assert(zombie_ok || !nm->is_zombie(), "cannot lock a zombie method"); + assert(zombie_ok || !nm->is_zombie(), "cannot lock a zombie method: %p", nm); } void nmethodLocker::unlock_nmethod(CompiledMethod* cm) { @@ -2275,6 +2310,16 @@ p2i(nul_chk_table_begin()), p2i(nul_chk_table_end()), nul_chk_table_size()); +#if INCLUDE_JVMCI + if (speculations_size () > 0) tty->print_cr(" speculations [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", + p2i(speculations_begin()), + p2i(speculations_end()), + speculations_size()); + if (jvmci_data_size () > 0) tty->print_cr(" JVMCI data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", + p2i(jvmci_data_begin()), + p2i(jvmci_data_end()), + jvmci_data_size()); +#endif } #ifndef PRODUCT @@ -2857,115 +2902,18 @@ #endif // !PRODUCT #if INCLUDE_JVMCI -void nmethod::clear_jvmci_installed_code() { - assert_locked_or_safepoint(Patching_lock); - if (_jvmci_installed_code != NULL) { - JNIHandles::destroy_weak_global(_jvmci_installed_code); - _jvmci_installed_code = NULL; - } -} - -void nmethod::clear_speculation_log() { - assert_locked_or_safepoint(Patching_lock); - if (_speculation_log != NULL) { - JNIHandles::destroy_weak_global(_speculation_log); - _speculation_log = NULL; - } -} - -void nmethod::maybe_invalidate_installed_code() { - if (!is_compiled_by_jvmci()) { - return; - } - - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "should be performed under a lock for consistency"); - oop installed_code = JNIHandles::resolve(_jvmci_installed_code); - if (installed_code != NULL) { - // Update the values in the InstalledCode instance if it still refers to this nmethod - nmethod* nm = (nmethod*)InstalledCode::address(installed_code); - if (nm == this) { - if (!is_alive() || is_unloading()) { - // Break the link between nmethod and InstalledCode such that the nmethod - // can subsequently be flushed safely. The link must be maintained while - // the method could have live activations since invalidateInstalledCode - // might want to invalidate all existing activations. - InstalledCode::set_address(installed_code, 0); - InstalledCode::set_entryPoint(installed_code, 0); - } else if (is_not_entrant()) { - // Remove the entry point so any invocation will fail but keep - // the address link around that so that existing activations can - // be invalidated. - InstalledCode::set_entryPoint(installed_code, 0); - } - } - } - if (!is_alive() || is_unloading()) { - // Clear these out after the nmethod has been unregistered and any - // updates to the InstalledCode instance have been performed. - clear_jvmci_installed_code(); - clear_speculation_log(); +void nmethod::update_speculation(JavaThread* thread) { + jlong speculation = thread->pending_failed_speculation(); + if (speculation != 0) { + guarantee(jvmci_nmethod_data() != NULL, "failed speculation in nmethod without failed speculation list"); + jvmci_nmethod_data()->add_failed_speculation(this, speculation); + thread->set_pending_failed_speculation(0); } } -void nmethod::invalidate_installed_code(Handle installedCode, TRAPS) { - if (installedCode() == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - jlong nativeMethod = InstalledCode::address(installedCode); - nmethod* nm = (nmethod*)nativeMethod; - if (nm == NULL) { - // Nothing to do - return; - } - - nmethodLocker nml(nm); -#ifdef ASSERT - { - MutexLocker pl(Patching_lock, Mutex::_no_safepoint_check_flag); - // This relationship can only be checked safely under a lock - assert(!nm->is_alive() || nm->is_unloading() || nm->jvmci_installed_code() == installedCode(), "sanity check"); - } -#endif - - if (nm->is_alive()) { - // Invalidating the InstalledCode means we want the nmethod - // to be deoptimized. - nm->mark_for_deoptimization(); - VM_Deoptimize op; - VMThread::execute(&op); - } - - // Multiple threads could reach this point so we now need to - // lock and re-check the link to the nmethod so that only one - // thread clears it. - MutexLocker pl(Patching_lock, Mutex::_no_safepoint_check_flag); - if (InstalledCode::address(installedCode) == nativeMethod) { - InstalledCode::set_address(installedCode, 0); - } -} - -oop nmethod::jvmci_installed_code() { - return JNIHandles::resolve(_jvmci_installed_code); -} - -oop nmethod::speculation_log() { - return JNIHandles::resolve(_speculation_log); -} - -char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) const { - if (!this->is_compiled_by_jvmci()) { - return NULL; - } - oop installed_code = JNIHandles::resolve(_jvmci_installed_code); - if (installed_code != NULL) { - oop installed_code_name = NULL; - if (installed_code->is_a(InstalledCode::klass())) { - installed_code_name = InstalledCode::name(installed_code); - } - if (installed_code_name != NULL) { - return java_lang_String::as_utf8_string(installed_code_name, buf, (int)buflen); - } +const char* nmethod::jvmci_name() { + if (jvmci_nmethod_data() != NULL) { + return jvmci_nmethod_data()->name(); } return NULL; } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/code/nmethod.hpp --- a/src/hotspot/share/code/nmethod.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/code/nmethod.hpp Wed May 01 12:31:29 2019 -0700 @@ -51,37 +51,28 @@ // - handler entry point array // [Implicit Null Pointer exception table] // - implicit null table array +// [Speculations] +// - encoded speculations array +// [JVMCINMethodData] +// - meta data for JVMCI compiled nmethod + +#if INCLUDE_JVMCI +class FailedSpeculation; +class JVMCINMethodData; +#endif class nmethod : public CompiledMethod { friend class VMStructs; friend class JVMCIVMStructs; friend class NMethodSweeper; friend class CodeCache; // scavengable oops + friend class JVMCINMethodData; private: // Shared fields for all nmethod's int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method jmethodID _jmethod_id; // Cache of method()->jmethod_id() -#if INCLUDE_JVMCI - // A weak reference to an InstalledCode object associated with - // this nmethod. - jweak _jvmci_installed_code; - - // A weak reference to a SpeculationLog object associated with - // this nmethod. - jweak _speculation_log; - - // Determines whether this nmethod is unloaded when the - // referent in _jvmci_installed_code is cleared. This - // will be false if the referent is initialized to a - // HotSpotNMethod object whose isDefault field is true. - // That is, installed code other than a "default" - // HotSpotNMethod causes nmethod unloading. - // This field is ignored once _jvmci_installed_code is NULL. - bool _jvmci_installed_code_triggers_invalidation; -#endif - // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head @@ -107,6 +98,10 @@ int _dependencies_offset; int _handler_table_offset; int _nul_chk_table_offset; +#if INCLUDE_JVMCI + int _speculations_offset; + int _jvmci_data_offset; +#endif int _nmethod_end_offset; int code_offset() const { return (address) code_begin() - header_begin(); } @@ -207,8 +202,9 @@ AbstractCompiler* compiler, int comp_level #if INCLUDE_JVMCI - , jweak installed_code, - jweak speculation_log + , char* speculations, + int speculations_len, + int jvmci_data_size #endif ); @@ -251,8 +247,11 @@ AbstractCompiler* compiler, int comp_level #if INCLUDE_JVMCI - , jweak installed_code = NULL, - jweak speculation_log = NULL + , char* speculations = NULL, + int speculations_len = 0, + int nmethod_mirror_index = -1, + const char* nmethod_mirror_name = NULL, + FailedSpeculation** failed_speculations = NULL #endif ); @@ -299,12 +298,24 @@ address handler_table_begin () const { return header_begin() + _handler_table_offset ; } address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; } address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; } +#if INCLUDE_JVMCI + address nul_chk_table_end () const { return header_begin() + _speculations_offset ; } + address speculations_begin () const { return header_begin() + _speculations_offset ; } + address speculations_end () const { return header_begin() + _jvmci_data_offset ; } + address jvmci_data_begin () const { return header_begin() + _jvmci_data_offset ; } + address jvmci_data_end () const { return header_begin() + _nmethod_end_offset ; } +#else address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; } +#endif // Sizes int oops_size () const { return (address) oops_end () - (address) oops_begin (); } int metadata_size () const { return (address) metadata_end () - (address) metadata_begin (); } int dependencies_size () const { return dependencies_end () - dependencies_begin (); } +#if INCLUDE_JVMCI + int speculations_size () const { return speculations_end () - speculations_begin (); } + int jvmci_data_size () const { return jvmci_data_end () - jvmci_data_begin (); } +#endif int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; } int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; } @@ -446,39 +457,19 @@ void set_method(Method* method) { _method = method; } #if INCLUDE_JVMCI - // Gets the InstalledCode object associated with this nmethod - // which may be NULL if this nmethod was not compiled by JVMCI - // or the weak reference has been cleared. - oop jvmci_installed_code(); + // Gets the JVMCI name of this nmethod. + const char* jvmci_name(); - // Copies the value of the name field in the InstalledCode - // object (if any) associated with this nmethod into buf. - // Returns the value of buf if it was updated otherwise NULL. - char* jvmci_installed_code_name(char* buf, size_t buflen) const; - - // Updates the state of the InstalledCode (if any) associated with - // this nmethod based on the current value of _state. - void maybe_invalidate_installed_code(); + // Records the pending failed speculation in the + // JVMCI speculation log associated with this nmethod. + void update_speculation(JavaThread* thread); - // Deoptimizes the nmethod (if any) in the address field of a given - // InstalledCode object. The address field is zeroed upon return. - static void invalidate_installed_code(Handle installed_code, TRAPS); - - // Gets the SpeculationLog object associated with this nmethod - // which may be NULL if this nmethod was not compiled by JVMCI - // or the weak reference has been cleared. - oop speculation_log(); - - private: - // Deletes the weak reference (if any) to the InstalledCode object - // associated with this nmethod. - void clear_jvmci_installed_code(); - - // Deletes the weak reference (if any) to the SpeculationLog object - // associated with this nmethod. - void clear_speculation_log(); - - public: + // Gets the data specific to a JVMCI compiled method. + // This returns a non-NULL value iff this nmethod was + // compiled by the JVMCI compiler. + JVMCINMethodData* jvmci_nmethod_data() const { + return jvmci_data_size() == 0 ? NULL : (JVMCINMethodData*) jvmci_data_begin(); + } #endif public: diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/compiler/abstractCompiler.hpp --- a/src/hotspot/share/compiler/abstractCompiler.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/compiler/abstractCompiler.hpp Wed May 01 12:31:29 2019 -0700 @@ -154,9 +154,6 @@ const bool is_jvmci() { return _type == compiler_jvmci; } const CompilerType type() { return _type; } - // Extra tests to identify trivial methods for the tiered compilation policy. - virtual bool is_trivial(Method* method) { return false; } - // Customization virtual void initialize () = 0; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/compiler/compileBroker.cpp --- a/src/hotspot/share/compiler/compileBroker.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/compiler/compileBroker.cpp Wed May 01 12:31:29 2019 -0700 @@ -68,9 +68,8 @@ #include "c1/c1_Compiler.hpp" #endif #if INCLUDE_JVMCI -#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "jvmci/jvmciJavaClasses.hpp" #include "runtime/vframe.hpp" #endif #ifdef COMPILER2 @@ -1064,36 +1063,34 @@ } #if INCLUDE_JVMCI - if (UseJVMCICompiler) { - if (blocking) { - // Don't allow blocking compiles for requests triggered by JVMCI. - if (thread->is_Compiler_thread()) { - blocking = false; - } + if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) { + // Don't allow blocking compiles for requests triggered by JVMCI. + if (thread->is_Compiler_thread()) { + blocking = false; + } - // Don't allow blocking compiles if inside a class initializer or while performing class loading - vframeStream vfst((JavaThread*) thread); - for (; !vfst.at_end(); vfst.next()) { - if (vfst.method()->is_static_initializer() || - (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && - vfst.method()->name() == vmSymbols::loadClass_name())) { - blocking = false; - break; - } + // Don't allow blocking compiles if inside a class initializer or while performing class loading + vframeStream vfst((JavaThread*) thread); + for (; !vfst.at_end(); vfst.next()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { + blocking = false; + break; } + } - // Don't allow blocking compilation requests to JVMCI - // if JVMCI itself is not yet initialized - if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized() && compiler(comp_level)->is_jvmci()) { - blocking = false; - } + // Don't allow blocking compilation requests to JVMCI + // if JVMCI itself is not yet initialized + if (!JVMCI::is_compiler_initialized() && compiler(comp_level)->is_jvmci()) { + blocking = false; + } - // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown - // to avoid deadlock between compiler thread(s) and threads run at shutdown - // such as the DestroyJavaVM thread. - if (JVMCIRuntime::shutdown_called()) { - blocking = false; - } + // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown + // to avoid deadlock between compiler thread(s) and threads run at shutdown + // such as the DestroyJavaVM thread. + if (JVMCI::shutdown_called()) { + blocking = false; } } #endif // INCLUDE_JVMCI @@ -1193,7 +1190,7 @@ } #if INCLUDE_JVMCI - if (comp->is_jvmci() && !JVMCIRuntime::can_initialize_JVMCI()) { + if (comp->is_jvmci() && !JVMCI::can_initialize_JVMCI()) { return NULL; } #endif @@ -2061,20 +2058,24 @@ // Skip redefined methods if (target_handle->is_old()) { - failure_reason = "redefined method"; - retry_message = "not retryable"; - compilable = ciEnv::MethodCompilable_never; + failure_reason = "redefined method"; + retry_message = "not retryable"; + compilable = ciEnv::MethodCompilable_never; } else { - JVMCIEnv env(task, system_dictionary_modification_counter); - methodHandle method(thread, target_handle); - jvmci->compile_method(method, osr_bci, &env); + JVMCICompileState compile_state(task, system_dictionary_modification_counter); + JVMCIEnv env(&compile_state, __FILE__, __LINE__); + methodHandle method(thread, target_handle); + env.runtime()->compile_method(&env, jvmci, method, osr_bci); - failure_reason = env.failure_reason(); - failure_reason_on_C_heap = env.failure_reason_on_C_heap(); - if (!env.retryable()) { - retry_message = "not retryable"; - compilable = ciEnv::MethodCompilable_not_at_tier; - } + failure_reason = compile_state.failure_reason(); + failure_reason_on_C_heap = compile_state.failure_reason_on_C_heap(); + if (!compile_state.retryable()) { + retry_message = "not retryable"; + compilable = ciEnv::MethodCompilable_not_at_tier; + } + if (task->code() == NULL) { + assert(failure_reason != NULL, "must specify failure_reason"); + } } post_compile(thread, task, task->code() != NULL, NULL, compilable, failure_reason); if (event.should_commit()) { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/compiler/compileTask.cpp --- a/src/hotspot/share/compiler/compileTask.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/compiler/compileTask.cpp Wed May 01 12:31:29 2019 -0700 @@ -396,6 +396,7 @@ ResourceMark rm(thread); if (!_is_success) { + assert(_failure_reason != NULL, "missing"); const char* reason = _failure_reason != NULL ? _failure_reason : "unknown"; log->elem("failure reason='%s'", reason); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/compiler/compilerDefinitions.cpp --- a/src/hotspot/share/compiler/compilerDefinitions.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp Wed May 01 12:31:29 2019 -0700 @@ -253,22 +253,6 @@ if (FLAG_IS_DEFAULT(TypeProfileWidth)) { FLAG_SET_DEFAULT(TypeProfileWidth, 8); } - if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { - FLAG_SET_DEFAULT(OnStackReplacePercentage, 933); - } - // JVMCI needs values not less than defaults - if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { - FLAG_SET_DEFAULT(ReservedCodeCacheSize, MAX2(64*M, ReservedCodeCacheSize)); - } - if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { - FLAG_SET_DEFAULT(InitialCodeCacheSize, MAX2(16*M, InitialCodeCacheSize)); - } - if (FLAG_IS_DEFAULT(MetaspaceSize)) { - FLAG_SET_DEFAULT(MetaspaceSize, MIN2(MAX2(12*M, MetaspaceSize), MaxMetaspaceSize)); - } - if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) { - FLAG_SET_DEFAULT(NewSizeThreadIncrease, MAX2(4*K, NewSizeThreadIncrease)); - } if (TieredStopAtLevel != CompLevel_full_optimization) { // Currently JVMCI compiler can only work at the full optimization level warning("forcing TieredStopAtLevel to full optimization because JVMCI is enabled"); @@ -277,7 +261,43 @@ if (FLAG_IS_DEFAULT(TypeProfileLevel)) { FLAG_SET_DEFAULT(TypeProfileLevel, 0); } - } + + if (UseJVMCINativeLibrary) { + // SVM compiled code requires more stack space + if (FLAG_IS_DEFAULT(CompilerThreadStackSize)) { + // Duplicate logic in the implementations of os::create_thread + // so that we can then double the computed stack size. Once + // the stack size requirements of SVM are better understood, + // this logic can be pushed down into os::create_thread. + int stack_size = CompilerThreadStackSize; + if (stack_size == 0) { + stack_size = VMThreadStackSize; + } + if (stack_size != 0) { + FLAG_SET_DEFAULT(CompilerThreadStackSize, stack_size * 2); + } + } + } else { + // Adjust the on stack replacement percentage to avoid early + // OSR compilations while JVMCI itself is warming up + if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { + FLAG_SET_DEFAULT(OnStackReplacePercentage, 933); + } + // JVMCI needs values not less than defaults + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_DEFAULT(ReservedCodeCacheSize, MAX2(64*M, ReservedCodeCacheSize)); + } + if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { + FLAG_SET_DEFAULT(InitialCodeCacheSize, MAX2(16*M, InitialCodeCacheSize)); + } + if (FLAG_IS_DEFAULT(MetaspaceSize)) { + FLAG_SET_DEFAULT(MetaspaceSize, MIN2(MAX2(12*M, MetaspaceSize), MaxMetaspaceSize)); + } + if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) { + FLAG_SET_DEFAULT(NewSizeThreadIncrease, MAX2(4*K, NewSizeThreadIncrease)); + } + } // !UseJVMCINativeLibrary + } // UseJVMCICompiler } #endif // INCLUDE_JVMCI @@ -392,6 +412,8 @@ // Check that JVMCI compiler supports selested GC. // Should be done after GCConfig::initialize() was called. JVMCIGlobals::check_jvmci_supported_gc(); + + // Do JVMCI specific settings set_jvmci_specific_flags(); #endif diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/compiler/disassembler.cpp --- a/src/hotspot/share/compiler/disassembler.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/compiler/disassembler.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -672,8 +672,7 @@ nm->method()->signature()->print_symbol_on(env.output()); #if INCLUDE_JVMCI { - char buffer[O_BUFLEN]; - char* jvmciName = nm->jvmci_installed_code_name(buffer, O_BUFLEN); + const char* jvmciName = nm->jvmci_name(); if (jvmciName != NULL) { env.output()->print(" (%s)", jvmciName); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp --- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Wed May 01 12:31:29 2019 -0700 @@ -82,6 +82,9 @@ #include "services/runtimeService.hpp" #include "utilities/align.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif // statics CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL; @@ -5258,6 +5261,9 @@ // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(purged_class); + + // Clean JVMCI metadata handles. + JVMCI_ONLY(JVMCI::do_unloading(purged_class)); } } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp Wed May 01 12:31:29 2019 -0700 @@ -60,9 +60,8 @@ _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms):"); _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms):"); _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms):"); -#if INCLUDE_AOT - _gc_par_phases[AOTCodeRoots] = new WorkerDataArray(max_gc_threads, "AOT Root Scan (ms):"); -#endif + AOT_ONLY(_gc_par_phases[AOTCodeRoots] = new WorkerDataArray(max_gc_threads, "AOT Root Scan (ms):");) + JVMCI_ONLY(_gc_par_phases[JVMCIRoots] = new WorkerDataArray(max_gc_threads, "JVMCI Root Scan (ms):");) _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms):"); _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms):"); _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms):"); @@ -527,9 +526,8 @@ "SystemDictionaryRoots", "CLDGRoots", "JVMTIRoots", -#if INCLUDE_AOT - "AOTCodeRoots", -#endif + AOT_ONLY("AOTCodeRoots" COMMA) + JVMCI_ONLY("JVMCIRoots" COMMA) "CMRefRoots", "WaitForStrongCLD", "WeakCLDRoots", diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp Wed May 01 12:31:29 2019 -0700 @@ -55,9 +55,8 @@ SystemDictionaryRoots, CLDGRoots, JVMTIRoots, -#if INCLUDE_AOT - AOTCodeRoots, -#endif + AOT_ONLY(AOTCodeRoots COMMA) + JVMCI_ONLY(JVMCIRoots COMMA) CMRefRoots, WaitForStrongCLD, WeakCLDRoots, diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/g1/g1RootProcessor.cpp --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp Wed May 01 12:31:29 2019 -0700 @@ -43,6 +43,9 @@ #include "runtime/mutex.hpp" #include "services/management.hpp" #include "utilities/macros.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif void G1RootProcessor::worker_has_discovered_all_strong_classes() { assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading"); @@ -267,6 +270,15 @@ } #endif +#if INCLUDE_JVMCI + if (EnableJVMCI) { + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JVMCIRoots, worker_i); + if (_process_strong_tasks.try_claim_task(G1RP_PS_JVMCI_oops_do)) { + JVMCI::oops_do(strong_roots); + } + } +#endif + { G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i); if (_process_strong_tasks.try_claim_task(G1RP_PS_SystemDictionary_oops_do)) { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/g1/g1RootProcessor.hpp --- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp Wed May 01 12:31:29 2019 -0700 @@ -63,7 +63,8 @@ G1RP_PS_ClassLoaderDataGraph_oops_do, G1RP_PS_jvmti_oops_do, G1RP_PS_CodeCache_oops_do, - G1RP_PS_aot_oops_do, + AOT_ONLY(G1RP_PS_aot_oops_do COMMA) + JVMCI_ONLY(G1RP_PS_JVMCI_oops_do COMMA) G1RP_PS_filter_satb_buffers, G1RP_PS_refProcessor_oops_do, // Leave this one last. diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/pcTasks.cpp --- a/src/hotspot/share/gc/parallel/pcTasks.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/pcTasks.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,9 @@ #include "runtime/vmThread.hpp" #include "services/management.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif // // ThreadRootsMarkingTask @@ -121,6 +124,12 @@ AOTLoader::oops_do(&mark_and_push_closure); break; +#if INCLUDE_JVMCI + case jvmci: + JVMCI::oops_do(&mark_and_push_closure); + break; +#endif + default: fatal("Unknown root type"); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/pcTasks.hpp --- a/src/hotspot/share/gc/parallel/pcTasks.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/pcTasks.hpp Wed May 01 12:31:29 2019 -0700 @@ -98,6 +98,7 @@ system_dictionary = 7, class_loader_data = 8, code_cache = 9 + JVMCI_ONLY(COMMA jvmci = 10) }; private: RootType _root_type; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/psMarkSweep.cpp --- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp Wed May 01 12:31:29 2019 -0700 @@ -62,6 +62,9 @@ #include "utilities/align.hpp" #include "utilities/events.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif elapsedTimer PSMarkSweep::_accumulated_time; jlong PSMarkSweep::_time_of_last_gc = 0; @@ -524,7 +527,8 @@ ClassLoaderDataGraph::always_strong_cld_do(follow_cld_closure()); // Do not treat nmethods as strong roots for mark/sweep, since we can unload them. //ScavengableNMethods::scavengable_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure())); - AOTLoader::oops_do(mark_and_push_closure()); + AOT_ONLY(AOTLoader::oops_do(mark_and_push_closure());) + JVMCI_ONLY(JVMCI::oops_do(mark_and_push_closure());) } // Flush marking stack. @@ -562,6 +566,9 @@ // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(purged_class); + + // Clean JVMCI metadata handles. + JVMCI_ONLY(JVMCI::do_unloading(purged_class)); } _gc_tracer->report_object_count_after_gc(is_alive_closure()); @@ -615,7 +622,10 @@ CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); - AOTLoader::oops_do(adjust_pointer_closure()); + AOT_ONLY(AOTLoader::oops_do(adjust_pointer_closure());) + + JVMCI_ONLY(JVMCI::oops_do(adjust_pointer_closure());) + ref_processor()->weak_oops_do(adjust_pointer_closure()); PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure()); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/psParallelCompact.cpp --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp Wed May 01 12:31:29 2019 -0700 @@ -77,6 +77,9 @@ #include "utilities/formatBuffer.hpp" #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif #include @@ -2123,6 +2126,7 @@ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache)); + JVMCI_ONLY(q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmci));) if (active_gc_threads > 1) { for (uint j = 0; j < active_gc_threads; j++) { @@ -2176,6 +2180,9 @@ // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(purged_class); + + // Clean JVMCI metadata handles. + JVMCI_ONLY(JVMCI::do_unloading(purged_class)); } _gc_tracer.report_object_count_after_gc(is_alive_closure()); @@ -2207,7 +2214,10 @@ CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_from_blobs); - AOTLoader::oops_do(&oop_closure); + AOT_ONLY(AOTLoader::oops_do(&oop_closure);) + + JVMCI_ONLY(JVMCI::oops_do(&oop_closure);) + ref_processor()->weak_oops_do(&oop_closure); // Roots were visited so references into the young gen in roots // may have been scanned. Process them also. diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/psScavenge.cpp --- a/src/hotspot/share/gc/parallel/psScavenge.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp Wed May 01 12:31:29 2019 -0700 @@ -379,6 +379,7 @@ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); + JVMCI_ONLY(q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmci));) TaskTerminator terminator(active_workers, (TaskQueueSetSuper*) promotion_manager->stack_array_depth()); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/psTasks.cpp --- a/src/hotspot/share/gc/parallel/psTasks.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/psTasks.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,9 @@ #include "runtime/thread.hpp" #include "runtime/vmThread.hpp" #include "services/management.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif // // ScavengeRootsTask @@ -95,7 +98,6 @@ JvmtiExport::oops_do(&roots_closure); break; - case code_cache: { MarkingCodeBlobClosure code_closure(&roots_to_old_closure, CodeBlobToOopClosure::FixRelocations); @@ -104,6 +106,12 @@ } break; +#if INCLUDE_JVMCI + case jvmci: + JVMCI::oops_do(&roots_closure); + break; +#endif + default: fatal("Unknown root type"); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/parallel/psTasks.hpp --- a/src/hotspot/share/gc/parallel/psTasks.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/parallel/psTasks.hpp Wed May 01 12:31:29 2019 -0700 @@ -61,6 +61,7 @@ management = 7, jvmti = 8, code_cache = 9 + JVMCI_ONLY(COMMA jvmci = 10) }; private: RootType _root_type; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/serial/genMarkSweep.cpp --- a/src/hotspot/share/gc/serial/genMarkSweep.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp Wed May 01 12:31:29 2019 -0700 @@ -56,6 +56,9 @@ #include "utilities/copy.hpp" #include "utilities/events.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); @@ -233,6 +236,9 @@ // Prune dead klasses from subklass/sibling/implementor lists. Klass::clean_weak_klass_links(purged_class); + + // Clean JVMCI metadata handles. + JVMCI_ONLY(JVMCI::do_unloading(purged_class)); } gc_tracer()->report_object_count_after_gc(&is_alive); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/shared/genCollectedHeap.cpp --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp Wed May 01 12:31:29 2019 -0700 @@ -69,6 +69,9 @@ #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy, Generation::Name young, @@ -857,10 +860,16 @@ if (_process_strong_tasks->try_claim_task(GCH_PS_jvmti_oops_do)) { JvmtiExport::oops_do(strong_roots); } +#if INCLUDE_AOT if (UseAOT && _process_strong_tasks->try_claim_task(GCH_PS_aot_oops_do)) { AOTLoader::oops_do(strong_roots); } - +#endif +#if INCLUDE_JVMCI + if (EnableJVMCI && _process_strong_tasks->try_claim_task(GCH_PS_jvmci_oops_do)) { + JVMCI::oops_do(strong_roots); + } +#endif if (_process_strong_tasks->try_claim_task(GCH_PS_SystemDictionary_oops_do)) { SystemDictionary::oops_do(strong_roots); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/shared/genCollectedHeap.hpp --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp Wed May 01 12:31:29 2019 -0700 @@ -117,7 +117,8 @@ GCH_PS_ClassLoaderDataGraph_oops_do, GCH_PS_jvmti_oops_do, GCH_PS_CodeCache_oops_do, - GCH_PS_aot_oops_do, + AOT_ONLY(GCH_PS_aot_oops_do COMMA) + JVMCI_ONLY(GCH_PS_jvmci_oops_do COMMA) GCH_PS_younger_gens, // Leave this one last. GCH_PS_NumElements diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/shared/parallelCleaning.cpp --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp Wed May 01 12:31:29 2019 -0700 @@ -30,6 +30,9 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "logging/log.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif StringDedupCleaningTask::StringDedupCleaningTask(BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -158,6 +161,27 @@ } } +#if INCLUDE_JVMCI +JVMCICleaningTask::JVMCICleaningTask() : + _cleaning_claimed(0) { +} + +bool JVMCICleaningTask::claim_cleaning_task() { + if (_cleaning_claimed) { + return false; + } + + return Atomic::cmpxchg(1, &_cleaning_claimed, 0) == 0; +} + +void JVMCICleaningTask::work(bool unloading_occurred) { + // One worker will clean JVMCI metadata handles. + if (unloading_occurred && EnableJVMCI && claim_cleaning_task()) { + JVMCI::do_unloading(unloading_occurred); + } +} +#endif // INCLUDE_JVMCI + ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive, uint num_workers, bool unloading_occurred, @@ -166,11 +190,16 @@ _unloading_occurred(unloading_occurred), _string_dedup_task(is_alive, NULL, resize_dedup_table), _code_cache_task(num_workers, is_alive, unloading_occurred), + JVMCI_ONLY(_jvmci_cleaning_task() COMMA) _klass_cleaning_task() { } // The parallel work done by all worker threads. void ParallelCleaningTask::work(uint worker_id) { + // Clean JVMCI metadata handles. + // Execute this task first because it is serial task. + JVMCI_ONLY(_jvmci_cleaning_task.work(_unloading_occurred);) + // Do first pass of code cache cleaning. _code_cache_task.work(worker_id); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/gc/shared/parallelCleaning.hpp --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp Wed May 01 12:31:29 2019 -0700 @@ -87,6 +87,20 @@ void work(); }; +#if INCLUDE_JVMCI +class JVMCICleaningTask : public StackObj { + volatile int _cleaning_claimed; + +public: + JVMCICleaningTask(); + // Clean JVMCI metadata handles. + void work(bool unloading_occurred); + +private: + bool claim_cleaning_task(); +}; +#endif + // Do cleanup of some weakly held data in the same parallel task. // Assumes a non-moving context. class ParallelCleaningTask : public AbstractGangTask { @@ -94,6 +108,9 @@ bool _unloading_occurred; StringDedupCleaningTask _string_dedup_task; CodeCacheUnloadingTask _code_cache_task; +#if INCLUDE_JVMCI + JVMCICleaningTask _jvmci_cleaning_task; +#endif KlassCleaningTask _klass_cleaning_task; public: diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp --- a/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jfr/leakprofiler/chains/rootSetClosure.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,9 @@ #include "runtime/thread.hpp" #include "services/management.hpp" #include "utilities/align.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif RootSetClosure::RootSetClosure(EdgeQueue* edge_queue) : _edge_queue(edge_queue) { @@ -104,4 +107,5 @@ Management::oops_do(closure); StringTable::oops_do(closure); AOTLoader::oops_do(closure); + JVMCI_ONLY(JVMCI::oops_do(closure);) } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,9 @@ #include "runtime/vframe_hp.hpp" #include "services/management.hpp" #include "utilities/growableArray.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif class ReferenceLocateClosure : public OopClosure { protected: @@ -102,6 +105,7 @@ bool do_management_roots(); bool do_string_table_roots(); bool do_aot_loader_roots(); + JVMCI_ONLY(bool do_jvmci_roots();) bool do_roots(); @@ -188,6 +192,15 @@ return rcl.complete(); } +#if INCLUDE_JVMCI +bool ReferenceToRootClosure::do_jvmci_roots() { + assert(!complete(), "invariant"); + ReferenceLocateClosure rcl(_callback, OldObjectRoot::_jvmci, OldObjectRoot::_type_undetermined, NULL); + JVMCI::oops_do(&rcl); + return rcl.complete(); +} +#endif + bool ReferenceToRootClosure::do_roots() { assert(!complete(), "invariant"); assert(OldObjectRoot::_system_undetermined == _info._system, "invariant"); @@ -238,6 +251,13 @@ return true; } +#if INCLUDE_JVMCI + if (do_jvmci_roots()) { + _complete = true; + return true; + } +#endif + return false; } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp --- a/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jfr/leakprofiler/utilities/rootType.hpp Wed May 01 12:31:29 2019 -0700 @@ -43,6 +43,7 @@ _code_cache, _string_table, _aot, + JVMCI_ONLY(_jvmci COMMA) _number_of_systems }; @@ -81,6 +82,10 @@ return "String Table"; case _aot: return "AOT"; +#if INCLUDE_JVMCI + case _jvmci: + return "JVMCI"; +#endif default: ShouldNotReachHere(); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jniAccessMark.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/jniAccessMark.inline.hpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JVMCI_JNIACCESSMARK_INLINE_HPP +#define SHARE_JVMCI_JNIACCESSMARK_INLINE_HPP + +#include "jvmci/jvmciEnv.hpp" +#include "runtime/interfaceSupport.inline.hpp" + +// Wrapper for a JNI call into the JVMCI shared library. +// This performs a ThreadToNativeFromVM transition so that the VM +// will not be blocked if the call takes a long time (e.g., due +// to a GC in the shared library). +class JNIAccessMark : public StackObj { + private: + ThreadToNativeFromVM ttnfv; + HandleMark hm; + JNIEnv* _env; + public: + inline JNIAccessMark(JVMCIEnv* jvmci_env) : + ttnfv(JavaThread::current()), hm(JavaThread::current()) { + _env = jvmci_env->_env; + } + JNIEnv* env() const { return _env; } + JNIEnv* operator () () const { return _env; } +}; + +#endif // SHARE_JVMCI_JNIACCESSMARK_INLINE_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmci.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/jvmci.cpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/oopStorage.inline.hpp" +#include "jvmci/jvmci.hpp" +#include "jvmci/jvmci_globals.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/metadataHandleBlock.hpp" + +OopStorage* JVMCI::_object_handles = NULL; +MetadataHandleBlock* JVMCI::_metadata_handles = NULL; +JVMCIRuntime* JVMCI::_compiler_runtime = NULL; +JVMCIRuntime* JVMCI::_java_runtime = NULL; + +bool JVMCI::can_initialize_JVMCI() { + // Initializing JVMCI requires the module system to be initialized past phase 3. + // The JVMCI API itself isn't available until phase 2 and ServiceLoader (which + // JVMCI initialization requires) isn't usable until after phase 3. Testing + // whether the system loader is initialized satisfies all these invariants. + if (SystemDictionary::java_system_loader() == NULL) { + return false; + } + assert(Universe::is_module_initialized(), "must be"); + return true; +} + +void JVMCI::initialize_compiler(TRAPS) { + if (JVMCILibDumpJNIConfig) { + JNIJVMCI::initialize_ids(NULL); + ShouldNotReachHere(); + } + + JVMCI::compiler_runtime()->call_getCompiler(CHECK); +} + +void JVMCI::initialize_globals() { + _object_handles = new OopStorage("JVMCI Global Oop Handles", + JVMCIGlobalAlloc_lock, + JVMCIGlobalActive_lock); + _metadata_handles = MetadataHandleBlock::allocate_block(); + if (UseJVMCINativeLibrary) { + // There are two runtimes. + _compiler_runtime = new JVMCIRuntime(); + _java_runtime = new JVMCIRuntime(); + } else { + // There is only a single runtime + _java_runtime = _compiler_runtime = new JVMCIRuntime(); + } +} + +OopStorage* JVMCI::object_handles() { + assert(_object_handles != NULL, "Uninitialized"); + return _object_handles; +} + +jobject JVMCI::make_global(const Handle& obj) { + assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); + assert(oopDesc::is_oop(obj()), "not an oop"); + oop* ptr = object_handles()->allocate(); + jobject res = NULL; + if (ptr != NULL) { + assert(*ptr == NULL, "invariant"); + NativeAccess<>::oop_store(ptr, obj()); + res = reinterpret_cast(ptr); + } else { + vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR, + "Cannot create JVMCI oop handle"); + } + return res; +} + +bool JVMCI::is_global_handle(jobject handle) { + const oop* ptr = reinterpret_cast(handle); + return object_handles()->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY; +} + +jmetadata JVMCI::allocate_handle(const methodHandle& handle) { + assert(_metadata_handles != NULL, "uninitialized"); + MutexLocker ml(JVMCI_lock); + return _metadata_handles->allocate_handle(handle); +} + +jmetadata JVMCI::allocate_handle(const constantPoolHandle& handle) { + assert(_metadata_handles != NULL, "uninitialized"); + MutexLocker ml(JVMCI_lock); + return _metadata_handles->allocate_handle(handle); +} + +void JVMCI::release_handle(jmetadata handle) { + MutexLocker ml(JVMCI_lock); + _metadata_handles->chain_free_list(handle); +} + +void JVMCI::oops_do(OopClosure* f) { + if (_object_handles != NULL) { + _object_handles->oops_do(f); + } +} + +void JVMCI::metadata_do(void f(Metadata*)) { + if (_metadata_handles != NULL) { + _metadata_handles->metadata_do(f); + } +} + +void JVMCI::do_unloading(bool unloading_occurred) { + if (_metadata_handles != NULL && unloading_occurred) { + _metadata_handles->do_unloading(); + } +} + +bool JVMCI::is_compiler_initialized() { + return compiler_runtime()->is_HotSpotJVMCIRuntime_initialized(); +} + +void JVMCI::shutdown() { + if (compiler_runtime() != NULL) { + compiler_runtime()->shutdown(); + } +} + +bool JVMCI::shutdown_called() { + if (compiler_runtime() != NULL) { + return compiler_runtime()->shutdown_called(); + } + return false; +} diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmci.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/jvmci.hpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_JVMCI_JVMCI_HPP +#define SHARE_JVMCI_JVMCI_HPP + +#include "compiler/compilerDefinitions.hpp" +#include "utilities/exceptions.hpp" + +class BoolObjectClosure; +class constantPoolHandle; +class JavaThread; +class JVMCIEnv; +class JVMCIRuntime; +class Metadata; +class MetadataHandleBlock; +class OopClosure; +class OopStorage; + +struct _jmetadata; +typedef struct _jmetadata *jmetadata; + +class JVMCI : public AllStatic { + friend class JVMCIRuntime; + friend class JVMCIEnv; + + private: + // Handles to objects in the HotSpot heap. + static OopStorage* _object_handles; + + static OopStorage* object_handles(); + + // Handles to Metadata objects. + static MetadataHandleBlock* _metadata_handles; + + // Access to the HotSpotJVMCIRuntime used by the CompileBroker. + static JVMCIRuntime* _compiler_runtime; + + // Access to the HotSpotJVMCIRuntime used by Java code running on the + // HotSpot heap. It will be the same as _compiler_runtime if + // UseJVMCINativeLibrary is false + static JVMCIRuntime* _java_runtime; + + public: + enum CodeInstallResult { + ok, + dependencies_failed, + dependencies_invalid, + cache_full, + code_too_large + }; + + static void do_unloading(bool unloading_occurred); + + static void metadata_do(void f(Metadata*)); + + static void oops_do(OopClosure* f); + + static void shutdown(); + + static bool shutdown_called(); + + static bool is_compiler_initialized(); + + /** + * Determines if the VM is sufficiently booted to initialize JVMCI. + */ + static bool can_initialize_JVMCI(); + + static void initialize_globals(); + + static void initialize_compiler(TRAPS); + + static jobject make_global(const Handle& obj); + static bool is_global_handle(jobject handle); + + static jmetadata allocate_handle(const methodHandle& handle); + static jmetadata allocate_handle(const constantPoolHandle& handle); + + static void release_handle(jmetadata handle); + + static JVMCIRuntime* compiler_runtime() { return _compiler_runtime; } + static JVMCIRuntime* java_runtime() { return _java_runtime; } +}; + +#endif // SHARE_JVMCI_JVMCI_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCodeInstaller.cpp --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp Wed May 01 12:31:29 2019 -0700 @@ -22,28 +22,13 @@ */ #include "precompiled.hpp" -#include "asm/register.hpp" -#include "classfile/vmSymbols.hpp" #include "code/compiledIC.hpp" -#include "code/vmreg.inline.hpp" #include "compiler/compileBroker.hpp" -#include "compiler/disassembler.hpp" -#include "jvmci/jvmciEnv.hpp" -#include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciCodeInstaller.hpp" -#include "jvmci/jvmciJavaClasses.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "memory/allocation.inline.hpp" -#include "oops/arrayOop.inline.hpp" -#include "oops/oop.inline.hpp" -#include "oops/objArrayOop.inline.hpp" -#include "oops/typeArrayOop.inline.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" -#include "runtime/javaCalls.hpp" #include "runtime/jniHandles.inline.hpp" -#include "runtime/safepointMechanism.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" @@ -51,30 +36,25 @@ // Allocate them with new so they are never destroyed (otherwise, a // forced exit could destroy these objects while they are still in // use). -ConstantOopWriteValue* CodeInstaller::_oop_null_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantOopWriteValue(NULL); -ConstantIntValue* CodeInstaller::_int_m1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(-1); -ConstantIntValue* CodeInstaller::_int_0_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue((jint)0); -ConstantIntValue* CodeInstaller::_int_1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(1); -ConstantIntValue* CodeInstaller::_int_2_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(2); -LocationValue* CodeInstaller::_illegal_value = new (ResourceObj::C_HEAP, mtCompiler) LocationValue(Location()); +ConstantOopWriteValue* CodeInstaller::_oop_null_scope_value = new (ResourceObj::C_HEAP, mtJVMCI) ConstantOopWriteValue(NULL); +ConstantIntValue* CodeInstaller::_int_m1_scope_value = new (ResourceObj::C_HEAP, mtJVMCI) ConstantIntValue(-1); +ConstantIntValue* CodeInstaller::_int_0_scope_value = new (ResourceObj::C_HEAP, mtJVMCI) ConstantIntValue((jint)0); +ConstantIntValue* CodeInstaller::_int_1_scope_value = new (ResourceObj::C_HEAP, mtJVMCI) ConstantIntValue(1); +ConstantIntValue* CodeInstaller::_int_2_scope_value = new (ResourceObj::C_HEAP, mtJVMCI) ConstantIntValue(2); +LocationValue* CodeInstaller::_illegal_value = new (ResourceObj::C_HEAP, mtJVMCI) LocationValue(Location()); -Method* getMethodFromHotSpotMethod(oop hotspot_method) { - assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass()), "sanity"); - return CompilerToVM::asMethod(hotspot_method); -} - -VMReg getVMRegFromLocation(Handle location, int total_frame_size, TRAPS) { +VMReg CodeInstaller::getVMRegFromLocation(JVMCIObject location, int total_frame_size, JVMCI_TRAPS) { if (location.is_null()) { - THROW_NULL(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW_NULL(NullPointerException); } - Handle reg(THREAD, code_Location::reg(location)); - jint offset = code_Location::offset(location); + JVMCIObject reg = jvmci_env()->get_code_Location_reg(location); + jint offset = jvmci_env()->get_code_Location_offset(location); - if (reg.not_null()) { + if (reg.is_non_null()) { // register - jint number = code_Register::number(reg); - VMReg vmReg = CodeInstaller::get_hotspot_reg(number, CHECK_NULL); + jint number = jvmci_env()->get_code_Register_number(reg); + VMReg vmReg = CodeInstaller::get_hotspot_reg(number, JVMCI_CHECK_NULL); if (offset % 4 == 0) { return vmReg->next(offset / 4); } else { @@ -102,71 +82,45 @@ } } -objArrayOop CodeInstaller::sites() { - return (objArrayOop) JNIHandles::resolve(_sites_handle); -} - -arrayOop CodeInstaller::code() { - return (arrayOop) JNIHandles::resolve(_code_handle); -} - -arrayOop CodeInstaller::data_section() { - return (arrayOop) JNIHandles::resolve(_data_section_handle); -} - -objArrayOop CodeInstaller::data_section_patches() { - return (objArrayOop) JNIHandles::resolve(_data_section_patches_handle); -} - -#ifndef PRODUCT -objArrayOop CodeInstaller::comments() { - return (objArrayOop) JNIHandles::resolve(_comments_handle); -} -#endif - -oop CodeInstaller::word_kind() { - return JNIHandles::resolve(_word_kind_handle); -} - // creates a HotSpot oop map out of the byte arrays provided by DebugInfo -OopMap* CodeInstaller::create_oop_map(Handle debug_info, TRAPS) { - Handle reference_map(THREAD, DebugInfo::referenceMap(debug_info)); +OopMap* CodeInstaller::create_oop_map(JVMCIObject debug_info, JVMCI_TRAPS) { + JVMCIObject reference_map = jvmci_env()->get_DebugInfo_referenceMap(debug_info); if (reference_map.is_null()) { - THROW_NULL(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW_NULL(NullPointerException); } - if (!reference_map->is_a(HotSpotReferenceMap::klass())) { - JVMCI_ERROR_NULL("unknown reference map: %s", reference_map->klass()->signature_name()); + if (!jvmci_env()->isa_HotSpotReferenceMap(reference_map)) { + JVMCI_ERROR_NULL("unknown reference map: %s", jvmci_env()->klass_name(reference_map)); } - if (!_has_wide_vector && SharedRuntime::is_wide_vector(HotSpotReferenceMap::maxRegisterSize(reference_map))) { + if (!_has_wide_vector && SharedRuntime::is_wide_vector(jvmci_env()->get_HotSpotReferenceMap_maxRegisterSize(reference_map))) { if (SharedRuntime::polling_page_vectors_safepoint_handler_blob() == NULL) { JVMCI_ERROR_NULL("JVMCI is producing code using vectors larger than the runtime supports"); } _has_wide_vector = true; } OopMap* map = new OopMap(_total_frame_size, _parameter_count); - objArrayHandle objects(THREAD, HotSpotReferenceMap::objects(reference_map)); - objArrayHandle derivedBase(THREAD, HotSpotReferenceMap::derivedBase(reference_map)); - typeArrayHandle sizeInBytes(THREAD, HotSpotReferenceMap::sizeInBytes(reference_map)); + JVMCIObjectArray objects = jvmci_env()->get_HotSpotReferenceMap_objects(reference_map); + JVMCIObjectArray derivedBase = jvmci_env()->get_HotSpotReferenceMap_derivedBase(reference_map); + JVMCIPrimitiveArray sizeInBytes = jvmci_env()->get_HotSpotReferenceMap_sizeInBytes(reference_map); if (objects.is_null() || derivedBase.is_null() || sizeInBytes.is_null()) { - THROW_NULL(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW_NULL(NullPointerException); } - if (objects->length() != derivedBase->length() || objects->length() != sizeInBytes->length()) { - JVMCI_ERROR_NULL("arrays in reference map have different sizes: %d %d %d", objects->length(), derivedBase->length(), sizeInBytes->length()); + if (JVMCIENV->get_length(objects) != JVMCIENV->get_length(derivedBase) || JVMCIENV->get_length(objects) != JVMCIENV->get_length(sizeInBytes)) { + JVMCI_ERROR_NULL("arrays in reference map have different sizes: %d %d %d", JVMCIENV->get_length(objects), JVMCIENV->get_length(derivedBase), JVMCIENV->get_length(sizeInBytes)); } - for (int i = 0; i < objects->length(); i++) { - Handle location(THREAD, objects->obj_at(i)); - Handle baseLocation(THREAD, derivedBase->obj_at(i)); - int bytes = sizeInBytes->int_at(i); + for (int i = 0; i < JVMCIENV->get_length(objects); i++) { + JVMCIObject location = JVMCIENV->get_object_at(objects, i); + JVMCIObject baseLocation = JVMCIENV->get_object_at(derivedBase, i); + jint bytes = JVMCIENV->get_int_at(sizeInBytes, i); - VMReg vmReg = getVMRegFromLocation(location, _total_frame_size, CHECK_NULL); - if (baseLocation.not_null()) { + VMReg vmReg = getVMRegFromLocation(location, _total_frame_size, JVMCI_CHECK_NULL); + if (baseLocation.is_non_null()) { // derived oop #ifdef _LP64 if (bytes == 8) { #else if (bytes == 4) { #endif - VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size, CHECK_NULL); + VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size, JVMCI_CHECK_NULL); map->set_derived_oop(vmReg, baseReg); } else { JVMCI_ERROR_NULL("invalid derived oop size in ReferenceMap: %d", bytes); @@ -187,16 +141,16 @@ } } - Handle callee_save_info(THREAD, (oop) DebugInfo::calleeSaveInfo(debug_info)); - if (callee_save_info.not_null()) { - objArrayHandle registers(THREAD, RegisterSaveLayout::registers(callee_save_info)); - typeArrayHandle slots(THREAD, RegisterSaveLayout::slots(callee_save_info)); - for (jint i = 0; i < slots->length(); i++) { - Handle jvmci_reg (THREAD, registers->obj_at(i)); - jint jvmci_reg_number = code_Register::number(jvmci_reg); - VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number, CHECK_NULL); + JVMCIObject callee_save_info = jvmci_env()->get_DebugInfo_calleeSaveInfo(debug_info); + if (callee_save_info.is_non_null()) { + JVMCIObjectArray registers = jvmci_env()->get_RegisterSaveLayout_registers(callee_save_info); + JVMCIPrimitiveArray slots = jvmci_env()->get_RegisterSaveLayout_slots(callee_save_info); + for (jint i = 0; i < JVMCIENV->get_length(slots); i++) { + JVMCIObject jvmci_reg = JVMCIENV->get_object_at(registers, i); + jint jvmci_reg_number = jvmci_env()->get_code_Register_number(jvmci_reg); + VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number, JVMCI_CHECK_NULL); // HotSpot stack slots are 4 bytes - jint jvmci_slot = slots->int_at(i); + jint jvmci_slot = JVMCIENV->get_int_at(slots, i); jint hotspot_slot = jvmci_slot * VMRegImpl::slots_per_word; VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); @@ -211,7 +165,8 @@ } #if INCLUDE_AOT -AOTOopRecorder::AOTOopRecorder(Arena* arena, bool deduplicate) : OopRecorder(arena, deduplicate) { +AOTOopRecorder::AOTOopRecorder(CodeInstaller* code_inst, Arena* arena, bool deduplicate) : OopRecorder(arena, deduplicate) { + _code_inst = code_inst; _meta_refs = new GrowableArray(); } @@ -225,6 +180,7 @@ int AOTOopRecorder::find_index(Metadata* h) { JavaThread* THREAD = JavaThread::current(); + JVMCIEnv* JVMCIENV = _code_inst->jvmci_env(); int oldCount = metadata_count(); int index = this->OopRecorder::find_index(h); int newCount = metadata_count(); @@ -237,18 +193,18 @@ vmassert(index + 1 == newCount, "must be last"); JVMCIKlassHandle klass(THREAD); - oop result = NULL; + JVMCIObject result; guarantee(h != NULL, "If DebugInformationRecorder::describe_scope passes NULL oldCount == newCount must hold."); if (h->is_klass()) { klass = (Klass*) h; - result = CompilerToVM::get_jvmci_type(klass, CATCH); + result = JVMCIENV->get_jvmci_type(klass, JVMCI_CATCH); } else if (h->is_method()) { Method* method = (Method*) h; methodHandle mh(method); - result = CompilerToVM::get_jvmci_method(method, CATCH); + result = JVMCIENV->get_jvmci_method(method, JVMCI_CATCH); } - jobject ref = JNIHandles::make_local(THREAD, result); + jobject ref = JVMCIENV->get_jobject(result); record_meta_ref(ref, index); return index; @@ -272,43 +228,43 @@ } #endif // INCLUDE_AOT -void* CodeInstaller::record_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS) { +void* CodeInstaller::record_metadata_reference(CodeSection* section, address dest, JVMCIObject constant, JVMCI_TRAPS) { /* * This method needs to return a raw (untyped) pointer, since the value of a pointer to the base * class is in general not equal to the pointer of the subclass. When patching metaspace pointers, * the compiler expects a direct pointer to the subclass (Klass* or Method*), not a pointer to the * base class (Metadata* or MetaspaceObj*). */ - oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); - if (obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { - Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); - assert(!HotSpotMetaspaceConstantImpl::compressed(constant), "unexpected compressed klass pointer %s @ " INTPTR_FORMAT, klass->name()->as_C_string(), p2i(klass)); + JVMCIObject obj = jvmci_env()->get_HotSpotMetaspaceConstantImpl_metaspaceObject(constant); + if (jvmci_env()->isa_HotSpotResolvedObjectTypeImpl(obj)) { + Klass* klass = JVMCIENV->asKlass(obj); + assert(!jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant), "unexpected compressed klass pointer %s @ " INTPTR_FORMAT, klass->name()->as_C_string(), p2i(klass)); int index = _oop_recorder->find_index(klass); section->relocate(dest, metadata_Relocation::spec(index)); TRACE_jvmci_3("metadata[%d of %d] = %s", index, _oop_recorder->metadata_count(), klass->name()->as_C_string()); return klass; - } else if (obj->is_a(HotSpotResolvedJavaMethodImpl::klass())) { - Method* method = (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(obj); - assert(!HotSpotMetaspaceConstantImpl::compressed(constant), "unexpected compressed method pointer %s @ " INTPTR_FORMAT, method->name()->as_C_string(), p2i(method)); + } else if (jvmci_env()->isa_HotSpotResolvedJavaMethodImpl(obj)) { + Method* method = jvmci_env()->asMethod(obj); + assert(!jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant), "unexpected compressed method pointer %s @ " INTPTR_FORMAT, method->name()->as_C_string(), p2i(method)); int index = _oop_recorder->find_index(method); section->relocate(dest, metadata_Relocation::spec(index)); TRACE_jvmci_3("metadata[%d of %d] = %s", index, _oop_recorder->metadata_count(), method->name()->as_C_string()); return method; } else { - JVMCI_ERROR_NULL("unexpected metadata reference for constant of type %s", obj->klass()->signature_name()); + JVMCI_ERROR_NULL("unexpected metadata reference for constant of type %s", jvmci_env()->klass_name(obj)); } } #ifdef _LP64 -narrowKlass CodeInstaller::record_narrow_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS) { - oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); - assert(HotSpotMetaspaceConstantImpl::compressed(constant), "unexpected uncompressed pointer"); +narrowKlass CodeInstaller::record_narrow_metadata_reference(CodeSection* section, address dest, JVMCIObject constant, JVMCI_TRAPS) { + JVMCIObject obj = jvmci_env()->get_HotSpotMetaspaceConstantImpl_metaspaceObject(constant); + assert(jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant), "unexpected uncompressed pointer"); - if (!obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { - JVMCI_ERROR_0("unexpected compressed pointer of type %s", obj->klass()->signature_name()); + if (!jvmci_env()->isa_HotSpotResolvedObjectTypeImpl(obj)) { + JVMCI_ERROR_0("unexpected compressed pointer of type %s", jvmci_env()->klass_name(obj)); } - Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); + Klass* klass = JVMCIENV->asKlass(obj); int index = _oop_recorder->find_index(klass); section->relocate(dest, metadata_Relocation::spec(index)); TRACE_jvmci_3("narrowKlass[%d of %d] = %s", index, _oop_recorder->metadata_count(), klass->name()->as_C_string()); @@ -316,34 +272,34 @@ } #endif -Location::Type CodeInstaller::get_oop_type(Thread* thread, Handle value) { - Handle valueKind(thread, Value::valueKind(value)); - Handle platformKind(thread, ValueKind::platformKind(valueKind)); +Location::Type CodeInstaller::get_oop_type(JVMCIObject value) { + JVMCIObject valueKind = jvmci_env()->get_Value_valueKind(value); + JVMCIObject platformKind = jvmci_env()->get_ValueKind_platformKind(valueKind); - if (platformKind == word_kind()) { + if (jvmci_env()->equals(platformKind, word_kind())) { return Location::oop; } else { return Location::narrowoop; } } -ScopeValue* CodeInstaller::get_scope_value(Handle value, BasicType type, GrowableArray* objects, ScopeValue* &second, TRAPS) { +ScopeValue* CodeInstaller::get_scope_value(JVMCIObject value, BasicType type, GrowableArray* objects, ScopeValue* &second, JVMCI_TRAPS) { second = NULL; if (value.is_null()) { - THROW_NULL(vmSymbols::java_lang_NullPointerException()); - } else if (value == Value::ILLEGAL()) { + JVMCI_THROW_NULL(NullPointerException); + } else if (JVMCIENV->equals(value, jvmci_env()->get_Value_ILLEGAL())) { if (type != T_ILLEGAL) { JVMCI_ERROR_NULL("unexpected illegal value, expected %s", basictype_to_str(type)); } return _illegal_value; - } else if (value->is_a(RegisterValue::klass())) { - Handle reg(THREAD, RegisterValue::reg(value)); - jint number = code_Register::number(reg); - VMReg hotspotRegister = get_hotspot_reg(number, CHECK_NULL); + } else if (jvmci_env()->isa_RegisterValue(value)) { + JVMCIObject reg = jvmci_env()->get_RegisterValue_reg(value); + jint number = jvmci_env()->get_code_Register_number(reg); + VMReg hotspotRegister = get_hotspot_reg(number, JVMCI_CHECK_NULL); if (is_general_purpose_reg(hotspotRegister)) { Location::Type locationType; if (type == T_OBJECT) { - locationType = get_oop_type(THREAD, value); + locationType = get_oop_type(value); } else if (type == T_LONG) { locationType = Location::lng; } else if (type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN) { @@ -372,15 +328,15 @@ } return value; } - } else if (value->is_a(StackSlot::klass())) { - jint offset = StackSlot::offset(value); - if (StackSlot::addFrameSize(value)) { + } else if (jvmci_env()->isa_StackSlot(value)) { + jint offset = jvmci_env()->get_StackSlot_offset(value); + if (jvmci_env()->get_StackSlot_addFrameSize(value)) { offset += _total_frame_size; } Location::Type locationType; if (type == T_OBJECT) { - locationType = get_oop_type(THREAD, value); + locationType = get_oop_type(value); } else if (type == T_LONG) { locationType = Location::lng; } else if (type == T_DOUBLE) { @@ -395,19 +351,18 @@ second = value; } return value; - } else if (value->is_a(JavaConstant::klass())) { - if (value->is_a(PrimitiveConstant::klass())) { - if (value->is_a(RawConstant::klass())) { - jlong prim = PrimitiveConstant::primitive(value); + } else if (jvmci_env()->isa_JavaConstant(value)) { + if (jvmci_env()->isa_PrimitiveConstant(value)) { + if (jvmci_env()->isa_RawConstant(value)) { + jlong prim = jvmci_env()->get_PrimitiveConstant_primitive(value); return new ConstantLongValue(prim); } else { - Handle primitive_constant_kind(THREAD, PrimitiveConstant::kind(value)); - BasicType constantType = JVMCIRuntime::kindToBasicType(primitive_constant_kind, CHECK_NULL); + BasicType constantType = jvmci_env()->kindToBasicType(jvmci_env()->get_PrimitiveConstant_kind(value), JVMCI_CHECK_NULL); if (type != constantType) { JVMCI_ERROR_NULL("primitive constant type doesn't match, expected %s but got %s", basictype_to_str(type), basictype_to_str(constantType)); } if (type == T_INT || type == T_FLOAT) { - jint prim = (jint)PrimitiveConstant::primitive(value); + jint prim = (jint)jvmci_env()->get_PrimitiveConstant_primitive(value); switch (prim) { case -1: return _int_m1_scope_value; case 0: return _int_0_scope_value; @@ -416,33 +371,33 @@ default: return new ConstantIntValue(prim); } } else if (type == T_LONG || type == T_DOUBLE) { - jlong prim = PrimitiveConstant::primitive(value); + jlong prim = jvmci_env()->get_PrimitiveConstant_primitive(value); second = _int_1_scope_value; return new ConstantLongValue(prim); } else { JVMCI_ERROR_NULL("unexpected primitive constant type %s", basictype_to_str(type)); } } - } else if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + } else if (jvmci_env()->isa_NullConstant(value) || jvmci_env()->isa_HotSpotCompressedNullConstant(value)) { if (type == T_OBJECT) { return _oop_null_scope_value; } else { JVMCI_ERROR_NULL("unexpected null constant, expected %s", basictype_to_str(type)); } - } else if (value->is_a(HotSpotObjectConstantImpl::klass())) { + } else if (jvmci_env()->isa_HotSpotObjectConstantImpl(value)) { if (type == T_OBJECT) { - oop obj = HotSpotObjectConstantImpl::object(value); + Handle obj = jvmci_env()->asConstant(value, JVMCI_CHECK_NULL); if (obj == NULL) { JVMCI_ERROR_NULL("null value must be in NullConstant"); } - return new ConstantOopWriteValue(JNIHandles::make_local(obj)); + return new ConstantOopWriteValue(JNIHandles::make_local(obj())); } else { JVMCI_ERROR_NULL("unexpected object constant, expected %s", basictype_to_str(type)); } } - } else if (value->is_a(VirtualObject::klass())) { + } else if (jvmci_env()->isa_VirtualObject(value)) { if (type == T_OBJECT) { - int id = VirtualObject::id(value); + int id = jvmci_env()->get_VirtualObject_id(value); if (0 <= id && id < objects->length()) { ScopeValue* object = objects->at(id); if (object != NULL) { @@ -455,26 +410,22 @@ } } - JVMCI_ERROR_NULL("unexpected value in scope: %s", value->klass()->signature_name()) + JVMCI_ERROR_NULL("unexpected value in scope: %s", jvmci_env()->klass_name(value)) } -void CodeInstaller::record_object_value(ObjectValue* sv, Handle value, GrowableArray* objects, TRAPS) { - // Might want a HandleMark here. - Handle type(THREAD, VirtualObject::type(value)); - int id = VirtualObject::id(value); - oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); - Klass* klass = java_lang_Class::as_Klass(javaMirror); +void CodeInstaller::record_object_value(ObjectValue* sv, JVMCIObject value, GrowableArray* objects, JVMCI_TRAPS) { + JVMCIObject type = jvmci_env()->get_VirtualObject_type(value); + int id = jvmci_env()->get_VirtualObject_id(value); + Klass* klass = JVMCIENV->asKlass(type); bool isLongArray = klass == Universe::longArrayKlassObj(); - objArrayHandle values(THREAD, VirtualObject::values(value)); - objArrayHandle slotKinds(THREAD, VirtualObject::slotKinds(value)); - for (jint i = 0; i < values->length(); i++) { - HandleMark hm(THREAD); + JVMCIObjectArray values = jvmci_env()->get_VirtualObject_values(value); + JVMCIObjectArray slotKinds = jvmci_env()->get_VirtualObject_slotKinds(value); + for (jint i = 0; i < JVMCIENV->get_length(values); i++) { ScopeValue* cur_second = NULL; - Handle object(THREAD, values->obj_at(i)); - Handle slot_kind (THREAD, slotKinds->obj_at(i)); - BasicType type = JVMCIRuntime::kindToBasicType(slot_kind, CHECK); - ScopeValue* value = get_scope_value(object, type, objects, cur_second, CHECK); + JVMCIObject object = JVMCIENV->get_object_at(values, i); + BasicType type = jvmci_env()->kindToBasicType(JVMCIENV->get_object_at(slotKinds, i), JVMCI_CHECK); + ScopeValue* value = get_scope_value(object, type, objects, cur_second, JVMCI_CHECK); if (isLongArray && cur_second == NULL) { // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. @@ -490,68 +441,65 @@ } } -MonitorValue* CodeInstaller::get_monitor_value(Handle value, GrowableArray* objects, TRAPS) { +MonitorValue* CodeInstaller::get_monitor_value(JVMCIObject value, GrowableArray* objects, JVMCI_TRAPS) { if (value.is_null()) { - THROW_NULL(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW_NULL(NullPointerException); } - if (!value->is_a(StackLockValue::klass())) { - JVMCI_ERROR_NULL("Monitors must be of type StackLockValue, got %s", value->klass()->signature_name()); + if (!jvmci_env()->isa_StackLockValue(value)) { + JVMCI_ERROR_NULL("Monitors must be of type StackLockValue, got %s", jvmci_env()->klass_name(value)); } ScopeValue* second = NULL; - Handle stack_lock_owner(THREAD, StackLockValue::owner(value)); - ScopeValue* owner_value = get_scope_value(stack_lock_owner, T_OBJECT, objects, second, CHECK_NULL); + ScopeValue* owner_value = get_scope_value(jvmci_env()->get_StackLockValue_owner(value), T_OBJECT, objects, second, JVMCI_CHECK_NULL); assert(second == NULL, "monitor cannot occupy two stack slots"); - Handle stack_lock_slot(THREAD, StackLockValue::slot(value)); - ScopeValue* lock_data_value = get_scope_value(stack_lock_slot, T_LONG, objects, second, CHECK_NULL); + ScopeValue* lock_data_value = get_scope_value(jvmci_env()->get_StackLockValue_slot(value), T_LONG, objects, second, JVMCI_CHECK_NULL); assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); assert(lock_data_value->is_location(), "invalid monitor location"); Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); bool eliminated = false; - if (StackLockValue::eliminated(value)) { + if (jvmci_env()->get_StackLockValue_eliminated(value)) { eliminated = true; } return new MonitorValue(owner_value, lock_data_loc, eliminated); } -void CodeInstaller::initialize_dependencies(oop compiled_code, OopRecorder* recorder, TRAPS) { +void CodeInstaller::initialize_dependencies(JVMCIObject compiled_code, OopRecorder* oop_recorder, JVMCI_TRAPS) { JavaThread* thread = JavaThread::current(); - assert(THREAD == thread, ""); CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL; - _oop_recorder = recorder; + _oop_recorder = oop_recorder; _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL); - objArrayHandle assumptions(THREAD, HotSpotCompiledCode::assumptions(compiled_code)); - if (!assumptions.is_null()) { - int length = assumptions->length(); + JVMCIObjectArray assumptions = jvmci_env()->get_HotSpotCompiledCode_assumptions(compiled_code); + if (assumptions.is_non_null()) { + int length = JVMCIENV->get_length(assumptions); for (int i = 0; i < length; ++i) { - Handle assumption(THREAD, assumptions->obj_at(i)); - if (!assumption.is_null()) { - if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) { - assumption_NoFinalizableSubclass(THREAD, assumption); - } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) { - assumption_ConcreteSubtype(THREAD, assumption); - } else if (assumption->klass() == Assumptions_LeafType::klass()) { - assumption_LeafType(THREAD, assumption); - } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) { - assumption_ConcreteMethod(THREAD, assumption); - } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { - assumption_CallSiteTargetValue(THREAD, assumption); + JVMCIObject assumption = JVMCIENV->get_object_at(assumptions, i); + if (assumption.is_non_null()) { + if (jvmci_env()->isa_Assumptions_NoFinalizableSubclass(assumption)) { + assumption_NoFinalizableSubclass(assumption); + } else if (jvmci_env()->isa_Assumptions_ConcreteSubtype(assumption)) { + assumption_ConcreteSubtype(assumption); + } else if (jvmci_env()->isa_Assumptions_LeafType(assumption)) { + assumption_LeafType(assumption); + } else if (jvmci_env()->isa_Assumptions_ConcreteMethod(assumption)) { + assumption_ConcreteMethod(assumption); + } else if (jvmci_env()->isa_Assumptions_CallSiteTargetValue(assumption)) { + assumption_CallSiteTargetValue(assumption, JVMCI_CHECK); } else { - JVMCI_ERROR("unexpected Assumption subclass %s", assumption->klass()->signature_name()); + JVMCI_ERROR("unexpected Assumption subclass %s", jvmci_env()->klass_name(assumption)); } } } } if (JvmtiExport::can_hotswap_or_post_breakpoint()) { - objArrayHandle methods(THREAD, HotSpotCompiledCode::methods(compiled_code)); - if (!methods.is_null()) { - int length = methods->length(); + JVMCIObjectArray methods = jvmci_env()->get_HotSpotCompiledCode_methods(compiled_code); + if (methods.is_non_null()) { + int length = JVMCIENV->get_length(methods); for (int i = 0; i < length; ++i) { - Handle method_handle(THREAD, methods->obj_at(i)); - methodHandle method = getMethodFromHotSpotMethod(method_handle()); + JVMCIObject method_handle = JVMCIENV->get_object_at(methods, i); + methodHandle method = jvmci_env()->asMethod(method_handle); _dependencies->assert_evol_method(method()); } } @@ -581,16 +529,16 @@ assert(_buffer == NULL, "can only be used once"); assert(_size == 0, "can only be used once"); if (bytes >= RelocBuffer::stack_size) { - _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtInternal); + _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtJVMCI); } _size = bytes; } -JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS) { +JVMCI::CodeInstallResult CodeInstaller::gather_metadata(JVMCIObject target, JVMCIObject compiled_code, CodeMetadata& metadata, JVMCI_TRAPS) { + assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode"); CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); - jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); - AOTOopRecorder* recorder = new AOTOopRecorder(&_arena, true); - initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder, CHECK_OK); + AOTOopRecorder* recorder = new AOTOopRecorder(this, &_arena, true); + initialize_dependencies(compiled_code, recorder, JVMCI_CHECK_OK); metadata.set_oop_recorder(recorder); @@ -599,9 +547,9 @@ _constants = buffer.consts(); buffer.set_immutable_PIC(_immutable_pic_compilation); - initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, false, CHECK_OK); - if (result != JVMCIEnv::ok) { + initialize_fields(target, compiled_code, JVMCI_CHECK_OK); + JVMCI::CodeInstallResult result = initialize_buffer(buffer, false, JVMCI_CHECK_OK); + if (result != JVMCI::ok) { return result; } @@ -618,16 +566,24 @@ reloc_buffer->ensure_size(buffer.total_relocation_size()); size_t size = (size_t) buffer.copy_relocations_to(reloc_buffer->begin(), (CodeBuffer::csize_t) reloc_buffer->size(), true); reloc_buffer->set_size(size); - return JVMCIEnv::ok; + return JVMCI::ok; } #endif // INCLUDE_AOT // constructor used to create a method -JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS) { +JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, + JVMCIObject target, + JVMCIObject compiled_code, + CodeBlob*& cb, + JVMCIObject installed_code, + FailedSpeculation** failed_speculations, + char* speculations, + int speculations_len, + JVMCI_TRAPS) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer"); - jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); OopRecorder* recorder = new OopRecorder(&_arena, true); - initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder, CHECK_OK); + initialize_dependencies(compiled_code, recorder, JVMCI_CHECK_OK); // Get instructions and constants CodeSections early because we need it. _instructions = buffer.insts(); @@ -636,44 +592,55 @@ buffer.set_immutable_PIC(_immutable_pic_compilation); #endif - initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, true, CHECK_OK); - if (result != JVMCIEnv::ok) { + initialize_fields(target, compiled_code, JVMCI_CHECK_OK); + JVMCI::CodeInstallResult result = initialize_buffer(buffer, true, JVMCI_CHECK_OK); + if (result != JVMCI::ok) { return result; } int stack_slots = _total_frame_size / HeapWordSize; // conversion to words - if (!compiled_code->is_a(HotSpotCompiledNmethod::klass())) { - oop stubName = HotSpotCompiledCode::name(compiled_code_obj); - if (stubName == NULL) { + if (!jvmci_env()->isa_HotSpotCompiledNmethod(compiled_code)) { + JVMCIObject stubName = jvmci_env()->get_HotSpotCompiledCode_name(compiled_code); + if (stubName.is_null()) { JVMCI_ERROR_OK("stub should have a name"); } - char* name = strdup(java_lang_String::as_utf8_string(stubName)); + char* name = strdup(jvmci_env()->as_utf8_string(stubName)); cb = RuntimeStub::new_runtime_stub(name, &buffer, CodeOffsets::frame_never_safe, stack_slots, _debug_recorder->_oopmaps, false); - result = JVMCIEnv::ok; + result = JVMCI::ok; } else { - nmethod* nm = NULL; - methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); - jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); - jint id = HotSpotCompiledNmethod::id(compiled_code); - bool has_unsafe_access = HotSpotCompiledNmethod::hasUnsafeAccess(compiled_code) == JNI_TRUE; - JVMCIEnv* env = (JVMCIEnv*) (address) HotSpotCompiledNmethod::jvmciEnv(compiled_code); + JVMCICompileState* compile_state = (JVMCICompileState*) (address) jvmci_env()->get_HotSpotCompiledNmethod_compileState(compiled_code); + if (compile_state != NULL) { + jvmci_env()->set_compile_state(compile_state); + } + + methodHandle method = jvmci_env()->asMethod(jvmci_env()->get_HotSpotCompiledNmethod_method(compiled_code)); + jint entry_bci = jvmci_env()->get_HotSpotCompiledNmethod_entryBCI(compiled_code); + bool has_unsafe_access = jvmci_env()->get_HotSpotCompiledNmethod_hasUnsafeAccess(compiled_code) == JNI_TRUE; + jint id = jvmci_env()->get_HotSpotCompiledNmethod_id(compiled_code); if (id == -1) { // Make sure a valid compile_id is associated with every compile id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); + jvmci_env()->set_HotSpotCompiledNmethod_id(compiled_code, id); } - result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _orig_pc_offset, &buffer, - stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, - compiler, _debug_recorder, _dependencies, env, id, - has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); + if (!jvmci_env()->isa_HotSpotNmethod(installed_code)) { + JVMCI_THROW_MSG_(IllegalArgumentException, "InstalledCode object must be a HotSpotNmethod when installing a HotSpotCompiledNmethod", JVMCI::ok); + } + + JVMCIObject mirror = installed_code; + nmethod* nm = NULL; + result = runtime()->register_method(jvmci_env(), method, nm, entry_bci, &_offsets, _orig_pc_offset, &buffer, + stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + compiler, _debug_recorder, _dependencies, id, + has_unsafe_access, _has_wide_vector, compiled_code, mirror, + failed_speculations, speculations, speculations_len); cb = nm->as_codeblob_or_null(); - if (nm != NULL && env == NULL) { + if (nm != NULL && compile_state == NULL) { DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption; if (!printnmethods && (PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers)) { @@ -690,10 +657,10 @@ return result; } -void CodeInstaller::initialize_fields(oop target, oop compiled_code, TRAPS) { - if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) { - Handle hotspotJavaMethod(THREAD, HotSpotCompiledNmethod::method(compiled_code)); - methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod()); +void CodeInstaller::initialize_fields(JVMCIObject target, JVMCIObject compiled_code, JVMCI_TRAPS) { + if (jvmci_env()->isa_HotSpotCompiledNmethod(compiled_code)) { + JVMCIObject hotspotJavaMethod = jvmci_env()->get_HotSpotCompiledNmethod_method(compiled_code); + methodHandle method = jvmci_env()->asMethod(hotspotJavaMethod); _parameter_count = method->size_of_parameters(); TRACE_jvmci_2("installing code for %s", method->name_and_sig_as_C_string()); } else { @@ -701,18 +668,18 @@ // Only used in OopMap constructor for non-product builds _parameter_count = 0; } - _sites_handle = JNIHandles::make_local(HotSpotCompiledCode::sites(compiled_code)); + _sites_handle = jvmci_env()->get_HotSpotCompiledCode_sites(compiled_code); - _code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code)); - _code_size = HotSpotCompiledCode::targetCodeSize(compiled_code); - _total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code); + _code_handle = jvmci_env()->get_HotSpotCompiledCode_targetCode(compiled_code); + _code_size = jvmci_env()->get_HotSpotCompiledCode_targetCodeSize(compiled_code); + _total_frame_size = jvmci_env()->get_HotSpotCompiledCode_totalFrameSize(compiled_code); - oop deoptRescueSlot = HotSpotCompiledCode::deoptRescueSlot(compiled_code); - if (deoptRescueSlot == NULL) { + JVMCIObject deoptRescueSlot = jvmci_env()->get_HotSpotCompiledCode_deoptRescueSlot(compiled_code); + if (deoptRescueSlot.is_null()) { _orig_pc_offset = -1; } else { - _orig_pc_offset = StackSlot::offset(deoptRescueSlot); - if (StackSlot::addFrameSize(deoptRescueSlot)) { + _orig_pc_offset = jvmci_env()->get_StackSlot_offset(deoptRescueSlot); + if (jvmci_env()->get_StackSlot_addFrameSize(deoptRescueSlot)) { _orig_pc_offset += _total_frame_size; } if (_orig_pc_offset < 0) { @@ -721,62 +688,61 @@ } // Pre-calculate the constants section size. This is required for PC-relative addressing. - _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code)); - if ((_constants->alignment() % HotSpotCompiledCode::dataSectionAlignment(compiled_code)) != 0) { - JVMCI_ERROR("invalid data section alignment: %d", HotSpotCompiledCode::dataSectionAlignment(compiled_code)); + _data_section_handle = jvmci_env()->get_HotSpotCompiledCode_dataSection(compiled_code); + if ((_constants->alignment() % jvmci_env()->get_HotSpotCompiledCode_dataSectionAlignment(compiled_code)) != 0) { + JVMCI_ERROR("invalid data section alignment: %d", jvmci_env()->get_HotSpotCompiledCode_dataSectionAlignment(compiled_code)); } - _constants_size = data_section()->length(); + _constants_size = JVMCIENV->get_length(data_section()); - _data_section_patches_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSectionPatches(compiled_code)); + _data_section_patches_handle = jvmci_env()->get_HotSpotCompiledCode_dataSectionPatches(compiled_code); #ifndef PRODUCT - _comments_handle = JNIHandles::make_local(HotSpotCompiledCode::comments(compiled_code)); + _comments_handle = jvmci_env()->get_HotSpotCompiledCode_comments(compiled_code); #endif _next_call_type = INVOKE_INVALID; _has_wide_vector = false; - oop arch = TargetDescription::arch(target); - _word_kind_handle = JNIHandles::make_local(Architecture::wordKind(arch)); + JVMCIObject arch = jvmci_env()->get_TargetDescription_arch(target); + _word_kind_handle = jvmci_env()->get_Architecture_wordKind(arch); } -int CodeInstaller::estimate_stubs_size(TRAPS) { +int CodeInstaller::estimate_stubs_size(JVMCI_TRAPS) { // Estimate the number of static and aot call stubs that might be emitted. int static_call_stubs = 0; int aot_call_stubs = 0; int trampoline_stubs = 0; - objArrayOop sites = this->sites(); - for (int i = 0; i < sites->length(); i++) { - oop site = sites->obj_at(i); - if (site != NULL) { - if (site->is_a(site_Mark::klass())) { - oop id_obj = site_Mark::id(site); - if (id_obj != NULL) { - if (!java_lang_boxing_object::is_instance(id_obj, T_INT)) { - JVMCI_ERROR_0("expected Integer id, got %s", id_obj->klass()->signature_name()); + JVMCIObjectArray sites = this->sites(); + for (int i = 0; i < JVMCIENV->get_length(sites); i++) { + JVMCIObject site = JVMCIENV->get_object_at(sites, i); + if (!site.is_null()) { + if (jvmci_env()->isa_site_Mark(site)) { + JVMCIObject id_obj = jvmci_env()->get_site_Mark_id(site); + if (id_obj.is_non_null()) { + if (!jvmci_env()->is_boxing_object(T_INT, id_obj)) { + JVMCI_ERROR_0("expected Integer id, got %s", jvmci_env()->klass_name(id_obj)); } - jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + jint id = jvmci_env()->get_boxed_value(T_INT, id_obj).i; switch (id) { - case INVOKEINTERFACE: - case INVOKEVIRTUAL: - trampoline_stubs++; - break; - case INVOKESTATIC: - case INVOKESPECIAL: - static_call_stubs++; - trampoline_stubs++; - break; - default: - break; + case INVOKEINTERFACE: + case INVOKEVIRTUAL: + trampoline_stubs++; + break; + case INVOKESTATIC: + case INVOKESPECIAL: + static_call_stubs++; + trampoline_stubs++; + break; + default: + break; } } } #if INCLUDE_AOT - if (UseAOT && site->is_a(site_Call::klass())) { - oop target = site_Call::target(site); - InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); - if (!target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { + if (UseAOT && jvmci_env()->isa_site_Call(site)) { + JVMCIObject target = jvmci_env()-> get_site_Call_target(site); + if (!jvmci_env()->isa_HotSpotForeignCallTarget(target)) { // Add far aot trampolines. aot_call_stubs++; } @@ -793,25 +759,25 @@ } // perform data and call relocation on the CodeBuffer -JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS) { +JVMCI::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, JVMCI_TRAPS) { HandleMark hm; - objArrayHandle sites(THREAD, this->sites()); - int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); + JVMCIObjectArray sites = this->sites(); + int locs_buffer_size = JVMCIENV->get_length(sites) * (relocInfo::length_limit + sizeof(relocInfo)); // Allocate enough space in the stub section for the static call // stubs. Stubs have extra relocs but they are managed by the stub // section itself so they don't need to be accounted for in the // locs_buffer above. - int stubs_size = estimate_stubs_size(CHECK_OK); + int stubs_size = estimate_stubs_size(JVMCI_CHECK_OK); int total_size = align_up(_code_size, buffer.insts()->alignment()) + align_up(_constants_size, buffer.consts()->alignment()) + align_up(stubs_size, buffer.stubs()->alignment()); if (check_size && total_size > JVMCINMethodSizeLimit) { - return JVMCIEnv::code_too_large; + return JVMCI::code_too_large; } buffer.initialize(total_size, locs_buffer_size); if (buffer.blob() == NULL) { - return JVMCIEnv::cache_full; + return JVMCI::cache_full; } buffer.initialize_stubs_size(stubs_size); buffer.initialize_consts_size(_constants_size); @@ -823,49 +789,49 @@ // copy the constant data into the newly created CodeBuffer address end_data = _constants->start() + _constants_size; - memcpy(_constants->start(), data_section()->base(T_BYTE), _constants_size); + JVMCIENV->copy_bytes_to(data_section(), (jbyte*) _constants->start(), 0, _constants_size); _constants->set_end(end_data); // copy the code into the newly created CodeBuffer address end_pc = _instructions->start() + _code_size; guarantee(_instructions->allocates2(end_pc), "initialize should have reserved enough space for all the code"); - memcpy(_instructions->start(), code()->base(T_BYTE), _code_size); + JVMCIENV->copy_bytes_to(code(), (jbyte*) _instructions->start(), 0, _code_size); _instructions->set_end(end_pc); - for (int i = 0; i < data_section_patches()->length(); i++) { - HandleMark hm(THREAD); - Handle patch(THREAD, data_section_patches()->obj_at(i)); + for (int i = 0; i < JVMCIENV->get_length(data_section_patches()); i++) { + // HandleMark hm(THREAD); + JVMCIObject patch = JVMCIENV->get_object_at(data_section_patches(), i); if (patch.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + JVMCI_THROW_(NullPointerException, JVMCI::ok); } - Handle reference(THREAD, site_DataPatch::reference(patch)); + JVMCIObject reference = jvmci_env()->get_site_DataPatch_reference(patch); if (reference.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + JVMCI_THROW_(NullPointerException, JVMCI::ok); } - if (!reference->is_a(site_ConstantReference::klass())) { - JVMCI_ERROR_OK("invalid patch in data section: %s", reference->klass()->signature_name()); + if (!jvmci_env()->isa_site_ConstantReference(reference)) { + JVMCI_ERROR_OK("invalid patch in data section: %s", jvmci_env()->klass_name(reference)); } - Handle constant(THREAD, site_ConstantReference::constant(reference)); + JVMCIObject constant = jvmci_env()->get_site_ConstantReference_constant(reference); if (constant.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + JVMCI_THROW_(NullPointerException, JVMCI::ok); } - address dest = _constants->start() + site_Site::pcOffset(patch); - if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { - if (HotSpotMetaspaceConstantImpl::compressed(constant)) { + address dest = _constants->start() + jvmci_env()->get_site_Site_pcOffset(patch); + if (jvmci_env()->isa_HotSpotMetaspaceConstantImpl(constant)) { + if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) { #ifdef _LP64 - *((narrowKlass*) dest) = record_narrow_metadata_reference(_constants, dest, constant, CHECK_OK); + *((narrowKlass*) dest) = record_narrow_metadata_reference(_constants, dest, constant, JVMCI_CHECK_OK); #else JVMCI_ERROR_OK("unexpected compressed Klass* in 32-bit mode"); #endif } else { - *((void**) dest) = record_metadata_reference(_constants, dest, constant, CHECK_OK); + *((void**) dest) = record_metadata_reference(_constants, dest, constant, JVMCI_CHECK_OK); } - } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { - Handle obj(THREAD, HotSpotObjectConstantImpl::object(constant)); + } else if (jvmci_env()->isa_HotSpotObjectConstantImpl(constant)) { + Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK_OK); jobject value = JNIHandles::make_local(obj()); int oop_index = _oop_recorder->find_index(value); - if (HotSpotObjectConstantImpl::compressed(constant)) { + if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) { #ifdef _LP64 _constants->relocate(dest, oop_Relocation::spec(oop_index), relocInfo::narrow_oop_in_const); #else @@ -875,46 +841,48 @@ _constants->relocate(dest, oop_Relocation::spec(oop_index)); } } else { - JVMCI_ERROR_OK("invalid constant in data section: %s", constant->klass()->signature_name()); + JVMCI_ERROR_OK("invalid constant in data section: %s", jvmci_env()->klass_name(constant)); } } jint last_pc_offset = -1; - for (int i = 0; i < sites->length(); i++) { - HandleMark hm(THREAD); - Handle site(THREAD, sites->obj_at(i)); + for (int i = 0; i < JVMCIENV->get_length(sites); i++) { + // HandleMark hm(THREAD); + JVMCIObject site = JVMCIENV->get_object_at(sites, i); if (site.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), JVMCIEnv::ok); + JVMCI_THROW_(NullPointerException, JVMCI::ok); } - jint pc_offset = site_Site::pcOffset(site); + jint pc_offset = jvmci_env()->get_site_Site_pcOffset(site); - if (site->is_a(site_Call::klass())) { + if (jvmci_env()->isa_site_Call(site)) { TRACE_jvmci_4("call at %i", pc_offset); - site_Call(buffer, pc_offset, site, CHECK_OK); - } else if (site->is_a(site_Infopoint::klass())) { + site_Call(buffer, pc_offset, site, JVMCI_CHECK_OK); + } else if (jvmci_env()->isa_site_Infopoint(site)) { // three reasons for infopoints denote actual safepoints - oop reason = site_Infopoint::reason(site); - if (site_InfopointReason::SAFEPOINT() == reason || site_InfopointReason::CALL() == reason || site_InfopointReason::IMPLICIT_EXCEPTION() == reason) { + JVMCIObject reason = jvmci_env()->get_site_Infopoint_reason(site); + if (JVMCIENV->equals(reason, jvmci_env()->get_site_InfopointReason_SAFEPOINT()) || + JVMCIENV->equals(reason, jvmci_env()->get_site_InfopointReason_CALL()) || + JVMCIENV->equals(reason, jvmci_env()->get_site_InfopointReason_IMPLICIT_EXCEPTION())) { TRACE_jvmci_4("safepoint at %i", pc_offset); - site_Safepoint(buffer, pc_offset, site, CHECK_OK); + site_Safepoint(buffer, pc_offset, site, JVMCI_CHECK_OK); if (_orig_pc_offset < 0) { JVMCI_ERROR_OK("method contains safepoint, but has no deopt rescue slot"); } } else { TRACE_jvmci_4("infopoint at %i", pc_offset); - site_Infopoint(buffer, pc_offset, site, CHECK_OK); + site_Infopoint(buffer, pc_offset, site, JVMCI_CHECK_OK); } - } else if (site->is_a(site_DataPatch::klass())) { + } else if (jvmci_env()->isa_site_DataPatch(site)) { TRACE_jvmci_4("datapatch at %i", pc_offset); - site_DataPatch(buffer, pc_offset, site, CHECK_OK); - } else if (site->is_a(site_Mark::klass())) { + site_DataPatch(buffer, pc_offset, site, JVMCI_CHECK_OK); + } else if (jvmci_env()->isa_site_Mark(site)) { TRACE_jvmci_4("mark at %i", pc_offset); - site_Mark(buffer, pc_offset, site, CHECK_OK); - } else if (site->is_a(site_ExceptionHandler::klass())) { + site_Mark(buffer, pc_offset, site, JVMCI_CHECK_OK); + } else if (jvmci_env()->isa_site_ExceptionHandler(site)) { TRACE_jvmci_4("exceptionhandler at %i", pc_offset); site_ExceptionHandler(pc_offset, site); } else { - JVMCI_ERROR_OK("unexpected site subclass: %s", site->klass()->signature_name()); + JVMCI_ERROR_OK("unexpected site subclass: %s", jvmci_env()->klass_name(site)); } last_pc_offset = pc_offset; @@ -926,61 +894,62 @@ } #ifndef PRODUCT - if (comments() != NULL) { - for (int i = 0; i < comments()->length(); i++) { - oop comment = comments()->obj_at(i); - assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); - jint offset = HotSpotCompiledCode_Comment::pcOffset(comment); - char* text = java_lang_String::as_utf8_string(HotSpotCompiledCode_Comment::text(comment)); + if (comments().is_non_null()) { + for (int i = 0; i < JVMCIENV->get_length(comments()); i++) { + JVMCIObject comment = JVMCIENV->get_object_at(comments(), i); + assert(jvmci_env()->isa_HotSpotCompiledCode_Comment(comment), "cce"); + jint offset = jvmci_env()->get_HotSpotCompiledCode_Comment_pcOffset(comment); + const char* text = jvmci_env()->as_utf8_string(jvmci_env()->get_HotSpotCompiledCode_Comment_text(comment)); buffer.block_comment(offset, text); } } #endif - return JVMCIEnv::ok; + return JVMCI::ok; } -void CodeInstaller::assumption_NoFinalizableSubclass(Thread* thread, Handle assumption) { - Handle receiverType_handle (thread, Assumptions_NoFinalizableSubclass::receiverType(assumption())); - Klass* receiverType = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(receiverType_handle)); +void CodeInstaller::assumption_NoFinalizableSubclass(JVMCIObject assumption) { + JVMCIObject receiverType_handle = jvmci_env()->get_Assumptions_NoFinalizableSubclass_receiverType(assumption); + Klass* receiverType = jvmci_env()->asKlass(receiverType_handle); _dependencies->assert_has_no_finalizable_subclasses(receiverType); } -void CodeInstaller::assumption_ConcreteSubtype(Thread* thread, Handle assumption) { - Handle context_handle (thread, Assumptions_ConcreteSubtype::context(assumption())); - Handle subtype_handle (thread, Assumptions_ConcreteSubtype::subtype(assumption())); - Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); - Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(subtype_handle)); +void CodeInstaller::assumption_ConcreteSubtype(JVMCIObject assumption) { + JVMCIObject context_handle = jvmci_env()->get_Assumptions_ConcreteSubtype_context(assumption); + JVMCIObject subtype_handle = jvmci_env()->get_Assumptions_ConcreteSubtype_subtype(assumption); + Klass* context = jvmci_env()->asKlass(context_handle); + Klass* subtype = jvmci_env()->asKlass(subtype_handle); assert(context->is_abstract(), ""); _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype); } -void CodeInstaller::assumption_LeafType(Thread* thread, Handle assumption) { - Handle context_handle (thread, Assumptions_LeafType::context(assumption())); - Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); +void CodeInstaller::assumption_LeafType(JVMCIObject assumption) { + JVMCIObject context_handle = jvmci_env()->get_Assumptions_LeafType_context(assumption); + Klass* context = jvmci_env()->asKlass(context_handle); _dependencies->assert_leaf_type(context); } -void CodeInstaller::assumption_ConcreteMethod(Thread* thread, Handle assumption) { - Handle impl_handle (thread, Assumptions_ConcreteMethod::impl(assumption())); - Handle context_handle (thread, Assumptions_ConcreteMethod::context(assumption())); +void CodeInstaller::assumption_ConcreteMethod(JVMCIObject assumption) { + JVMCIObject impl_handle = jvmci_env()->get_Assumptions_ConcreteMethod_impl(assumption); + JVMCIObject context_handle = jvmci_env()->get_Assumptions_ConcreteMethod_context(assumption); - methodHandle impl = getMethodFromHotSpotMethod(impl_handle()); - Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + methodHandle impl = jvmci_env()->asMethod(impl_handle); + Klass* context = jvmci_env()->asKlass(context_handle); _dependencies->assert_unique_concrete_method(context, impl()); } -void CodeInstaller::assumption_CallSiteTargetValue(Thread* thread, Handle assumption) { - Handle callSite(thread, HotSpotObjectConstantImpl::object(Assumptions_CallSiteTargetValue::callSite(assumption()))); - Handle methodHandle(thread, HotSpotObjectConstantImpl::object(Assumptions_CallSiteTargetValue::methodHandle(assumption()))); - +void CodeInstaller::assumption_CallSiteTargetValue(JVMCIObject assumption, JVMCI_TRAPS) { + JVMCIObject callSiteConstant = jvmci_env()->get_Assumptions_CallSiteTargetValue_callSite(assumption); + Handle callSite = jvmci_env()->asConstant(callSiteConstant, JVMCI_CHECK); + JVMCIObject methodConstant = jvmci_env()->get_Assumptions_CallSiteTargetValue_methodHandle(assumption); + Handle methodHandle = jvmci_env()->asConstant(methodConstant, JVMCI_CHECK); _dependencies->assert_call_site_target_value(callSite(), methodHandle()); } -void CodeInstaller::site_ExceptionHandler(jint pc_offset, Handle exc) { - jint handler_offset = site_ExceptionHandler::handlerPos(exc); +void CodeInstaller::site_ExceptionHandler(jint pc_offset, JVMCIObject exc) { + jint handler_offset = jvmci_env()->get_site_ExceptionHandler_handlerPos(exc); // Subtable header _exception_handler_table.add_entry(HandlerTableEntry(1, pc_offset, 0)); @@ -1005,19 +974,20 @@ return true; } -GrowableArray* CodeInstaller::record_virtual_objects(Handle debug_info, TRAPS) { - objArrayHandle virtualObjects(THREAD, DebugInfo::virtualObjectMapping(debug_info)); +GrowableArray* CodeInstaller::record_virtual_objects(JVMCIObject debug_info, JVMCI_TRAPS) { + JVMCIObjectArray virtualObjects = jvmci_env()->get_DebugInfo_virtualObjectMapping(debug_info); if (virtualObjects.is_null()) { return NULL; } - GrowableArray* objects = new GrowableArray(virtualObjects->length(), virtualObjects->length(), NULL); + GrowableArray* objects = new GrowableArray(JVMCIENV->get_length(virtualObjects), JVMCIENV->get_length(virtualObjects), NULL); // Create the unique ObjectValues - for (int i = 0; i < virtualObjects->length(); i++) { - HandleMark hm(THREAD); - Handle value(THREAD, virtualObjects->obj_at(i)); - int id = VirtualObject::id(value); - Handle type(THREAD, VirtualObject::type(value)); - oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + for (int i = 0; i < JVMCIENV->get_length(virtualObjects); i++) { + // HandleMark hm(THREAD); + JVMCIObject value = JVMCIENV->get_object_at(virtualObjects, i); + int id = jvmci_env()->get_VirtualObject_id(value); + JVMCIObject type = jvmci_env()->get_VirtualObject_type(value); + Klass* klass = jvmci_env()->asKlass(type); + oop javaMirror = klass->java_mirror(); ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror))); if (id < 0 || id >= objects->length()) { JVMCI_ERROR_NULL("virtual object id %d out of bounds", id); @@ -1029,18 +999,18 @@ } // All the values which could be referenced by the VirtualObjects // exist, so now describe all the VirtualObjects themselves. - for (int i = 0; i < virtualObjects->length(); i++) { - HandleMark hm(THREAD); - Handle value(THREAD, virtualObjects->obj_at(i)); - int id = VirtualObject::id(value); - record_object_value(objects->at(id)->as_ObjectValue(), value, objects, CHECK_NULL); + for (int i = 0; i < JVMCIENV->get_length(virtualObjects); i++) { + // HandleMark hm(THREAD); + JVMCIObject value = JVMCIENV->get_object_at(virtualObjects, i); + int id = jvmci_env()->get_VirtualObject_id(value); + record_object_value(objects->at(id)->as_ObjectValue(), value, objects, JVMCI_CHECK_NULL); } _debug_recorder->dump_object_pool(objects); return objects; } -void CodeInstaller::record_scope(jint pc_offset, Handle debug_info, ScopeMode scope_mode, bool return_oop, TRAPS) { - Handle position(THREAD, DebugInfo::bytecodePosition(debug_info)); +void CodeInstaller::record_scope(jint pc_offset, JVMCIObject debug_info, ScopeMode scope_mode, bool return_oop, JVMCI_TRAPS) { + JVMCIObject position = jvmci_env()->get_DebugInfo_bytecodePosition(debug_info); if (position.is_null()) { // Stubs do not record scope info, just oop maps return; @@ -1048,26 +1018,26 @@ GrowableArray* objectMapping; if (scope_mode == CodeInstaller::FullFrame) { - objectMapping = record_virtual_objects(debug_info, CHECK); + objectMapping = record_virtual_objects(debug_info, JVMCI_CHECK); } else { objectMapping = NULL; } - record_scope(pc_offset, position, scope_mode, objectMapping, return_oop, CHECK); + record_scope(pc_offset, position, scope_mode, objectMapping, return_oop, JVMCI_CHECK); } int CodeInstaller::map_jvmci_bci(int bci) { if (bci < 0) { - if (bci == BytecodeFrame::BEFORE_BCI()) { + if (bci == jvmci_env()->get_BytecodeFrame_BEFORE_BCI()) { return BeforeBci; - } else if (bci == BytecodeFrame::AFTER_BCI()) { + } else if (bci == jvmci_env()->get_BytecodeFrame_AFTER_BCI()) { return AfterBci; - } else if (bci == BytecodeFrame::UNWIND_BCI()) { + } else if (bci == jvmci_env()->get_BytecodeFrame_UNWIND_BCI()) { return UnwindBci; - } else if (bci == BytecodeFrame::AFTER_EXCEPTION_BCI()) { + } else if (bci == jvmci_env()->get_BytecodeFrame_AFTER_EXCEPTION_BCI()) { return AfterExceptionBci; - } else if (bci == BytecodeFrame::UNKNOWN_BCI()) { + } else if (bci == jvmci_env()->get_BytecodeFrame_UNKNOWN_BCI()) { return UnknownBci; - } else if (bci == BytecodeFrame::INVALID_FRAMESTATE_BCI()) { + } else if (bci == jvmci_env()->get_BytecodeFrame_INVALID_FRAMESTATE_BCI()) { return InvalidFrameStateBci; } ShouldNotReachHere(); @@ -1075,34 +1045,37 @@ return bci; } -void CodeInstaller::record_scope(jint pc_offset, Handle position, ScopeMode scope_mode, GrowableArray* objects, bool return_oop, TRAPS) { - Handle frame; +void CodeInstaller::record_scope(jint pc_offset, JVMCIObject position, ScopeMode scope_mode, GrowableArray* objects, bool return_oop, JVMCI_TRAPS) { + JVMCIObject frame; if (scope_mode == CodeInstaller::FullFrame) { - if (!position->is_a(BytecodeFrame::klass())) { + if (!jvmci_env()->isa_BytecodeFrame(position)) { JVMCI_ERROR("Full frame expected for debug info at %i", pc_offset); } frame = position; } - Handle caller_frame (THREAD, BytecodePosition::caller(position)); - if (caller_frame.not_null()) { - record_scope(pc_offset, caller_frame, scope_mode, objects, return_oop, CHECK); + JVMCIObject caller_frame = jvmci_env()->get_BytecodePosition_caller(position); + if (caller_frame.is_non_null()) { + record_scope(pc_offset, caller_frame, scope_mode, objects, return_oop, JVMCI_CHECK); } - Handle hotspot_method (THREAD, BytecodePosition::method(position)); - Method* method = getMethodFromHotSpotMethod(hotspot_method()); - jint bci = map_jvmci_bci(BytecodePosition::bci(position)); + JVMCIObject hotspot_method = jvmci_env()->get_BytecodePosition_method(position); + Method* method = jvmci_env()->asMethod(hotspot_method); + jint bci = map_jvmci_bci(jvmci_env()->get_BytecodePosition_bci(position)); + if (bci == jvmci_env()->get_BytecodeFrame_BEFORE_BCI()) { + bci = SynchronizationEntryBCI; + } TRACE_jvmci_2("Recording scope pc_offset=%d bci=%d method=%s", pc_offset, bci, method->name_and_sig_as_C_string()); bool reexecute = false; - if (frame.not_null()) { - if (bci < 0) { + if (frame.is_non_null()) { + if (bci < 0){ reexecute = false; } else { Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci)); reexecute = bytecode_should_reexecute(code); - if (frame.not_null()) { - reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE); + if (frame.is_non_null()) { + reexecute = (jvmci_env()->get_BytecodeFrame_duringCall(frame) == JNI_FALSE); } } } @@ -1112,55 +1085,55 @@ DebugToken* monitors_token = NULL; bool throw_exception = false; - if (frame.not_null()) { - jint local_count = BytecodeFrame::numLocals(frame); - jint expression_count = BytecodeFrame::numStack(frame); - jint monitor_count = BytecodeFrame::numLocks(frame); - objArrayHandle values(THREAD, BytecodeFrame::values(frame)); - objArrayHandle slotKinds(THREAD, BytecodeFrame::slotKinds(frame)); + if (frame.is_non_null()) { + jint local_count = jvmci_env()->get_BytecodeFrame_numLocals(frame); + jint expression_count = jvmci_env()->get_BytecodeFrame_numStack(frame); + jint monitor_count = jvmci_env()->get_BytecodeFrame_numLocks(frame); + JVMCIObjectArray values = jvmci_env()->get_BytecodeFrame_values(frame); + JVMCIObjectArray slotKinds = jvmci_env()->get_BytecodeFrame_slotKinds(frame); if (values.is_null() || slotKinds.is_null()) { - THROW(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW(NullPointerException); } - if (local_count + expression_count + monitor_count != values->length()) { - JVMCI_ERROR("unexpected values length %d in scope (%d locals, %d expressions, %d monitors)", values->length(), local_count, expression_count, monitor_count); + if (local_count + expression_count + monitor_count != JVMCIENV->get_length(values)) { + JVMCI_ERROR("unexpected values length %d in scope (%d locals, %d expressions, %d monitors)", JVMCIENV->get_length(values), local_count, expression_count, monitor_count); } - if (local_count + expression_count != slotKinds->length()) { - JVMCI_ERROR("unexpected slotKinds length %d in scope (%d locals, %d expressions)", slotKinds->length(), local_count, expression_count); + if (local_count + expression_count != JVMCIENV->get_length(slotKinds)) { + JVMCI_ERROR("unexpected slotKinds length %d in scope (%d locals, %d expressions)", JVMCIENV->get_length(slotKinds), local_count, expression_count); } GrowableArray* locals = local_count > 0 ? new GrowableArray (local_count) : NULL; GrowableArray* expressions = expression_count > 0 ? new GrowableArray (expression_count) : NULL; GrowableArray* monitors = monitor_count > 0 ? new GrowableArray (monitor_count) : NULL; - TRACE_jvmci_2("Scope at bci %d with %d values", bci, values->length()); + TRACE_jvmci_2("Scope at bci %d with %d values", bci, JVMCIENV->get_length(values)); TRACE_jvmci_2("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count); - for (jint i = 0; i < values->length(); i++) { - HandleMark hm(THREAD); + for (jint i = 0; i < JVMCIENV->get_length(values); i++) { + // HandleMark hm(THREAD); ScopeValue* second = NULL; - Handle value(THREAD, values->obj_at(i)); + JVMCIObject value = JVMCIENV->get_object_at(values, i); if (i < local_count) { - BasicType type = JVMCIRuntime::kindToBasicType(Handle(THREAD, slotKinds->obj_at(i)), CHECK); - ScopeValue* first = get_scope_value(value, type, objects, second, CHECK); + BasicType type = jvmci_env()->kindToBasicType(JVMCIENV->get_object_at(slotKinds, i), JVMCI_CHECK); + ScopeValue* first = get_scope_value(value, type, objects, second, JVMCI_CHECK); if (second != NULL) { locals->append(second); } locals->append(first); } else if (i < local_count + expression_count) { - BasicType type = JVMCIRuntime::kindToBasicType(Handle(THREAD, slotKinds->obj_at(i)), CHECK); - ScopeValue* first = get_scope_value(value, type, objects, second, CHECK); + BasicType type = jvmci_env()->kindToBasicType(JVMCIENV->get_object_at(slotKinds, i), JVMCI_CHECK); + ScopeValue* first = get_scope_value(value, type, objects, second, JVMCI_CHECK); if (second != NULL) { expressions->append(second); } expressions->append(first); } else { - MonitorValue *monitor = get_monitor_value(value, objects, CHECK); + MonitorValue *monitor = get_monitor_value(value, objects, JVMCI_CHECK); monitors->append(monitor); } if (second != NULL) { i++; - if (i >= values->length() || values->obj_at(i) != Value::ILLEGAL()) { + if (i >= JVMCIENV->get_length(values) || !JVMCIENV->equals(JVMCIENV->get_object_at(values, i), jvmci_env()->get_Value_ILLEGAL())) { JVMCI_ERROR("double-slot value not followed by Value.ILLEGAL"); } } @@ -1170,29 +1143,29 @@ expressions_token = _debug_recorder->create_scope_values(expressions); monitors_token = _debug_recorder->create_monitor_values(monitors); - throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE; + throw_exception = jvmci_env()->get_BytecodeFrame_rethrowException(frame) == JNI_TRUE; } _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, return_oop, locals_token, expressions_token, monitors_token); } -void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { - Handle debug_info (THREAD, site_Infopoint::debugInfo(site)); +void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) { + JVMCIObject debug_info = jvmci_env()->get_site_Infopoint_debugInfo(site); if (debug_info.is_null()) { JVMCI_ERROR("debug info expected at safepoint at %i", pc_offset); } // address instruction = _instructions->start() + pc_offset; // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); - OopMap *map = create_oop_map(debug_info, CHECK); + OopMap *map = create_oop_map(debug_info, JVMCI_CHECK); _debug_recorder->add_safepoint(pc_offset, map); - record_scope(pc_offset, debug_info, CodeInstaller::FullFrame, CHECK); + record_scope(pc_offset, debug_info, CodeInstaller::FullFrame, JVMCI_CHECK); _debug_recorder->end_safepoint(pc_offset); } -void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { - Handle debug_info (THREAD, site_Infopoint::debugInfo(site)); +void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) { + JVMCIObject debug_info = jvmci_env()->get_site_Infopoint_debugInfo(site); if (debug_info.is_null()) { JVMCI_ERROR("debug info expected at infopoint at %i", pc_offset); } @@ -1202,53 +1175,51 @@ // but DebugInformationRecorder doesn't have sufficient public API. _debug_recorder->add_non_safepoint(pc_offset); - record_scope(pc_offset, debug_info, CodeInstaller::BytecodePosition, CHECK); + record_scope(pc_offset, debug_info, CodeInstaller::BytecodePosition, JVMCI_CHECK); _debug_recorder->end_non_safepoint(pc_offset); } -void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { - Handle target(THREAD, site_Call::target(site)); - InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); +void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) { + JVMCIObject target = jvmci_env()->get_site_Call_target(site); + JVMCIObject hotspot_method; // JavaMethod + JVMCIObject foreign_call; - Handle hotspot_method; // JavaMethod - Handle foreign_call; - - if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { + if (jvmci_env()->isa_HotSpotForeignCallTarget(target)) { foreign_call = target; } else { hotspot_method = target; } - Handle debug_info (THREAD, site_Call::debugInfo(site)); + JVMCIObject debug_info = jvmci_env()->get_site_Infopoint_debugInfo(site); - assert(hotspot_method.not_null() ^ foreign_call.not_null(), "Call site needs exactly one type"); + assert(hotspot_method.is_non_null() ^ foreign_call.is_non_null(), "Call site needs exactly one type"); NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); - jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method, CHECK); + jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method, JVMCI_CHECK); - if (debug_info.not_null()) { - OopMap *map = create_oop_map(debug_info, CHECK); + if (debug_info.is_non_null()) { + OopMap *map = create_oop_map(debug_info, JVMCI_CHECK); _debug_recorder->add_safepoint(next_pc_offset, map); - bool return_oop = hotspot_method.not_null() && getMethodFromHotSpotMethod(hotspot_method())->is_returning_oop(); + bool return_oop = hotspot_method.is_non_null() && jvmci_env()->asMethod(hotspot_method)->is_returning_oop(); - record_scope(next_pc_offset, debug_info, CodeInstaller::FullFrame, return_oop, CHECK); + record_scope(next_pc_offset, debug_info, CodeInstaller::FullFrame, return_oop, JVMCI_CHECK); } - if (foreign_call.not_null()) { - jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call); + if (foreign_call.is_non_null()) { + jlong foreign_call_destination = jvmci_env()->get_HotSpotForeignCallTarget_address(foreign_call); if (_immutable_pic_compilation) { // Use fake short distance during PIC compilation. foreign_call_destination = (jlong)(_instructions->start() + pc_offset); } - CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, CHECK); + CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination, JVMCI_CHECK); } else { // method != NULL if (debug_info.is_null()) { JVMCI_ERROR("debug info expected at call at %i", pc_offset); } TRACE_jvmci_3("method call"); - CodeInstaller::pd_relocate_JavaMethod(buffer, hotspot_method, pc_offset, CHECK); + CodeInstaller::pd_relocate_JavaMethod(buffer, hotspot_method, pc_offset, JVMCI_CHECK); if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) { // Need a static call stub for transitions from compiled to interpreted. CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset); @@ -1261,57 +1232,67 @@ _next_call_type = INVOKE_INVALID; - if (debug_info.not_null()) { + if (debug_info.is_non_null()) { _debug_recorder->end_safepoint(next_pc_offset); } } -void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { - Handle reference(THREAD, site_DataPatch::reference(site)); +void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) { + JVMCIObject reference = jvmci_env()->get_site_DataPatch_reference(site); if (reference.is_null()) { - THROW(vmSymbols::java_lang_NullPointerException()); - } else if (reference->is_a(site_ConstantReference::klass())) { - Handle constant(THREAD, site_ConstantReference::constant(reference)); + JVMCI_THROW(NullPointerException); + } else if (jvmci_env()->isa_site_ConstantReference(reference)) { + JVMCIObject constant = jvmci_env()->get_site_ConstantReference_constant(reference); if (constant.is_null()) { - THROW(vmSymbols::java_lang_NullPointerException()); - } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + JVMCI_THROW(NullPointerException); + } else if (jvmci_env()->isa_DirectHotSpotObjectConstantImpl(constant)) { + if (!JVMCIENV->is_hotspot()) { + JVMCIObject string = JVMCIENV->call_HotSpotJVMCIRuntime_callToString(constant, JVMCI_CHECK); + const char* to_string = JVMCIENV->as_utf8_string(string); + JVMCI_THROW_MSG(IllegalArgumentException, err_msg("Direct object constant reached the backend: %s", to_string)); + } if (!_immutable_pic_compilation) { // Do not patch during PIC compilation. - pd_patch_OopConstant(pc_offset, constant, CHECK); + pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK); } - } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + } else if (jvmci_env()->isa_IndirectHotSpotObjectConstantImpl(constant)) { if (!_immutable_pic_compilation) { - pd_patch_MetaspaceConstant(pc_offset, constant, CHECK); + // Do not patch during PIC compilation. + pd_patch_OopConstant(pc_offset, constant, JVMCI_CHECK); + } + } else if (jvmci_env()->isa_HotSpotMetaspaceConstantImpl(constant)) { + if (!_immutable_pic_compilation) { + pd_patch_MetaspaceConstant(pc_offset, constant, JVMCI_CHECK); } #if INCLUDE_AOT - } else if (constant->is_a(HotSpotSentinelConstant::klass())) { + } else if (jvmci_env()->isa_HotSpotSentinelConstant(constant)) { if (!_immutable_pic_compilation) { - JVMCI_ERROR("sentinel constant not supported for normal compiles: %s", constant->klass()->signature_name()); + JVMCI_ERROR("sentinel constant not supported for normal compiles: %s", jvmci_env()->klass_name(constant)); } #endif } else { - JVMCI_ERROR("unknown constant type in data patch: %s", constant->klass()->signature_name()); + JVMCI_ERROR("unknown constant type in data patch: %s", jvmci_env()->klass_name(constant)); } - } else if (reference->is_a(site_DataSectionReference::klass())) { - int data_offset = site_DataSectionReference::offset(reference); + } else if (jvmci_env()->isa_site_DataSectionReference(reference)) { + int data_offset = jvmci_env()->get_site_DataSectionReference_offset(reference); if (0 <= data_offset && data_offset < _constants_size) { - pd_patch_DataSectionReference(pc_offset, data_offset, CHECK); + pd_patch_DataSectionReference(pc_offset, data_offset, JVMCI_CHECK); } else { JVMCI_ERROR("data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size); } } else { - JVMCI_ERROR("unknown data patch type: %s", reference->klass()->signature_name()); + JVMCI_ERROR("unknown data patch type: %s", jvmci_env()->klass_name(reference)); } } -void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS) { - Handle id_obj (THREAD, site_Mark::id(site)); +void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) { + JVMCIObject id_obj = jvmci_env()->get_site_Mark_id(site); - if (id_obj.not_null()) { - if (!java_lang_boxing_object::is_instance(id_obj(), T_INT)) { - JVMCI_ERROR("expected Integer id, got %s", id_obj->klass()->signature_name()); + if (id_obj.is_non_null()) { + if (!jvmci_env()->is_boxing_object(T_INT, id_obj)) { + JVMCI_ERROR("expected Integer id, got %s", jvmci_env()->klass_name(id_obj)); } - jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + jint id = jvmci_env()->get_boxed_value(T_INT, id_obj).i; address pc = _instructions->start() + pc_offset; @@ -1343,7 +1324,7 @@ case POLL_FAR: case POLL_RETURN_NEAR: case POLL_RETURN_FAR: - pd_relocate_poll(pc, id, CHECK); + pd_relocate_poll(pc, id, JVMCI_CHECK); break; case CARD_TABLE_SHIFT: case CARD_TABLE_ADDRESS: diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCodeInstaller.hpp --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp Wed May 01 12:31:29 2019 -0700 @@ -24,9 +24,11 @@ #ifndef SHARE_JVMCI_JVMCICODEINSTALLER_HPP #define SHARE_JVMCI_JVMCICODEINSTALLER_HPP -#include "jvmci/jvmciCompiler.hpp" +#include "code/debugInfoRec.hpp" +#include "code/exceptionHandlerTable.hpp" +#include "code/nativeInst.hpp" +#include "jvmci/jvmci.hpp" #include "jvmci/jvmciEnv.hpp" -#include "code/nativeInst.hpp" #if INCLUDE_AOT class RelocBuffer : public StackObj { @@ -44,9 +46,11 @@ char *_buffer; }; +class CodeInstaller; + class AOTOopRecorder : public OopRecorder { public: - AOTOopRecorder(Arena* arena = NULL, bool deduplicate = false); + AOTOopRecorder(CodeInstaller* code_inst, Arena* arena = NULL, bool deduplicate = false); virtual int find_index(Metadata* h); virtual int find_index(jobject h); @@ -57,7 +61,10 @@ void record_meta_ref(jobject ref, int index); GrowableArray* _meta_refs; + + CodeInstaller* _code_inst; }; +#endif // INCLUDE_AOT class CodeMetadata { public: @@ -71,9 +78,10 @@ u_char* get_scopes_desc() const { return _scopes_desc; } int get_scopes_size() const { return _nr_scopes_desc; } +#if INCLUDE_AOT RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; } - AOTOopRecorder* get_oop_recorder() { return _oop_recorder; } +#endif ExceptionHandlerTable* get_exception_table() { return _exception_table; } @@ -87,9 +95,11 @@ _nr_scopes_desc = size; } +#if INCLUDE_AOT void set_oop_recorder(AOTOopRecorder* recorder) { _oop_recorder = recorder; } +#endif void set_exception_table(ExceptionHandlerTable* table) { _exception_table = table; @@ -103,11 +113,12 @@ u_char* _scopes_desc; int _nr_scopes_desc; +#if INCLUDE_AOT RelocBuffer _reloc_buffer; AOTOopRecorder* _oop_recorder; +#endif ExceptionHandlerTable* _exception_table; }; -#endif // INCLUDE_AOT /* * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. @@ -143,24 +154,26 @@ }; Arena _arena; + JVMCIEnv* _jvmci_env; - jobject _data_section_handle; - jobject _data_section_patches_handle; - jobject _sites_handle; + JVMCIPrimitiveArray _data_section_handle; + JVMCIObjectArray _data_section_patches_handle; + JVMCIObjectArray _sites_handle; +#ifndef PRODUCT + JVMCIObjectArray _comments_handle; +#endif + JVMCIPrimitiveArray _code_handle; + JVMCIObject _word_kind_handle; + CodeOffsets _offsets; - jobject _code_handle; jint _code_size; jint _total_frame_size; jint _orig_pc_offset; jint _parameter_count; jint _constants_size; -#ifndef PRODUCT - jobject _comments_handle; -#endif bool _has_wide_vector; - jobject _word_kind_handle; MarkId _next_call_type; address _invoke_mark_pc; @@ -182,72 +195,84 @@ static ConstantIntValue* _int_2_scope_value; static LocationValue* _illegal_value; - jint pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS); - void pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS); - void pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS); - void pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS); - void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS); - void pd_relocate_JavaMethod(CodeBuffer &cbuf, Handle method, jint pc_offset, TRAPS); - void pd_relocate_poll(address pc, jint mark, TRAPS); + jint pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS); + void pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS); + void pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS); + void pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS); + void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS); + void pd_relocate_JavaMethod(CodeBuffer &cbuf, JVMCIObject method, jint pc_offset, JVMCI_TRAPS); + void pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS); - objArrayOop sites(); - arrayOop code(); - arrayOop data_section(); - objArrayOop data_section_patches(); + JVMCIObjectArray sites() { return _sites_handle; } + JVMCIPrimitiveArray code() { return _code_handle; } + JVMCIPrimitiveArray data_section() { return _data_section_handle; } + JVMCIObjectArray data_section_patches() { return _data_section_patches_handle; } #ifndef PRODUCT - objArrayOop comments(); + JVMCIObjectArray comments() { return _comments_handle; } #endif - - oop word_kind(); + JVMCIObject word_kind() { return _word_kind_handle; } public: - CodeInstaller(bool immutable_pic_compilation) : _arena(mtCompiler), _immutable_pic_compilation(immutable_pic_compilation) {} + CodeInstaller(JVMCIEnv* jvmci_env, bool immutable_pic_compilation) : _arena(mtJVMCI), _jvmci_env(jvmci_env), _immutable_pic_compilation(immutable_pic_compilation) {} #if INCLUDE_AOT - JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle compiled_code, CodeMetadata& metadata, TRAPS); + JVMCI::CodeInstallResult gather_metadata(JVMCIObject target, JVMCIObject compiled_code, CodeMetadata& metadata, JVMCI_TRAPS); #endif - JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log, TRAPS); + JVMCI::CodeInstallResult install(JVMCICompiler* compiler, + JVMCIObject target, + JVMCIObject compiled_code, + CodeBlob*& cb, + JVMCIObject installed_code, + FailedSpeculation** failed_speculations, + char* speculations, + int speculations_len, + JVMCI_TRAPS); + + JVMCIEnv* jvmci_env() { return _jvmci_env; } + JVMCIRuntime* runtime() { return _jvmci_env->runtime(); } static address runtime_call_target_address(oop runtime_call); - static VMReg get_hotspot_reg(jint jvmciRegisterNumber, TRAPS); + static VMReg get_hotspot_reg(jint jvmciRegisterNumber, JVMCI_TRAPS); static bool is_general_purpose_reg(VMReg hotspotRegister); const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } protected: - Location::Type get_oop_type(Thread* thread, Handle value); - ScopeValue* get_scope_value(Handle value, BasicType type, GrowableArray* objects, ScopeValue* &second, TRAPS); - MonitorValue* get_monitor_value(Handle value, GrowableArray* objects, TRAPS); + Location::Type get_oop_type(JVMCIObject value); + ScopeValue* get_scope_value(JVMCIObject value, BasicType type, GrowableArray* objects, ScopeValue* &second, JVMCI_TRAPS); + MonitorValue* get_monitor_value(JVMCIObject value, GrowableArray* objects, JVMCI_TRAPS); - void* record_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS); + void* record_metadata_reference(CodeSection* section, address dest, JVMCIObject constant, JVMCI_TRAPS); #ifdef _LP64 - narrowKlass record_narrow_metadata_reference(CodeSection* section, address dest, Handle constant, TRAPS); + narrowKlass record_narrow_metadata_reference(CodeSection* section, address dest, JVMCIObject constant, JVMCI_TRAPS); #endif // extract the fields of the HotSpotCompiledCode - void initialize_fields(oop target, oop target_method, TRAPS); - void initialize_dependencies(oop target_method, OopRecorder* oop_recorder, TRAPS); + void initialize_fields(JVMCIObject target, JVMCIObject compiled_code, JVMCI_TRAPS); + void initialize_dependencies(JVMCIObject compiled_code, OopRecorder* oop_recorder, JVMCI_TRAPS); - int estimate_stubs_size(TRAPS); + int estimate_stubs_size(JVMCI_TRAPS); // perform data and call relocation on the CodeBuffer - JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS); + JVMCI::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, JVMCI_TRAPS); - void assumption_NoFinalizableSubclass(Thread* thread, Handle assumption); - void assumption_ConcreteSubtype(Thread* thread, Handle assumption); - void assumption_LeafType(Thread* thread, Handle assumption); - void assumption_ConcreteMethod(Thread* thread, Handle assumption); - void assumption_CallSiteTargetValue(Thread* thread, Handle assumption); + void assumption_NoFinalizableSubclass(JVMCIObject assumption); + void assumption_ConcreteSubtype(JVMCIObject assumption); + void assumption_LeafType(JVMCIObject assumption); + void assumption_ConcreteMethod(JVMCIObject assumption); + void assumption_CallSiteTargetValue(JVMCIObject assumption, JVMCI_TRAPS); - void site_Safepoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - void site_Infopoint(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - void site_Call(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - void site_DataPatch(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - void site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, TRAPS); - void site_ExceptionHandler(jint pc_offset, Handle site); + void site_Safepoint(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS); + void site_Infopoint(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS); + void site_Call(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS); + void site_DataPatch(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS); + void site_Mark(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS); + void site_ExceptionHandler(jint pc_offset, JVMCIObject site); - OopMap* create_oop_map(Handle debug_info, TRAPS); + OopMap* create_oop_map(JVMCIObject debug_info, JVMCI_TRAPS); + + VMReg getVMRegFromLocation(JVMCIObject location, int total_frame_size, JVMCI_TRAPS); /** * Specifies the level of detail to record for a scope. @@ -260,23 +285,17 @@ }; int map_jvmci_bci(int bci); - void record_scope(jint pc_offset, Handle debug_info, ScopeMode scope_mode, bool return_oop, TRAPS); - void record_scope(jint pc_offset, Handle debug_info, ScopeMode scope_mode, TRAPS) { - record_scope(pc_offset, debug_info, scope_mode, false /* return_oop */, THREAD); + + void record_scope(jint pc_offset, JVMCIObject debug_info, ScopeMode scope_mode, bool return_oop, JVMCI_TRAPS); + void record_scope(jint pc_offset, JVMCIObject debug_info, ScopeMode scope_mode, JVMCI_TRAPS) { + record_scope(pc_offset, debug_info, scope_mode, false /* return_oop */, JVMCIENV); } - void record_scope(jint pc_offset, Handle position, ScopeMode scope_mode, GrowableArray* objects, bool return_oop, TRAPS); - void record_object_value(ObjectValue* sv, Handle value, GrowableArray* objects, TRAPS); + void record_scope(jint pc_offset, JVMCIObject position, ScopeMode scope_mode, GrowableArray* objects, bool return_oop, JVMCI_TRAPS); + void record_object_value(ObjectValue* sv, JVMCIObject value, GrowableArray* objects, JVMCI_TRAPS); - GrowableArray* record_virtual_objects(Handle debug_info, TRAPS); + GrowableArray* record_virtual_objects(JVMCIObject debug_info, JVMCI_TRAPS); int estimateStubSpace(int static_call_stubs); }; -/** - * Gets the Method metaspace object from a HotSpotResolvedJavaMethodImpl Java object. - */ -Method* getMethodFromHotSpotMethod(oop hotspot_method); - - - #endif // SHARE_JVMCI_JVMCICODEINSTALLER_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCompiler.cpp --- a/src/hotspot/share/jvmci/jvmciCompiler.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp Wed May 01 12:31:29 2019 -0700 @@ -22,19 +22,10 @@ */ #include "precompiled.hpp" -#include "jvm.h" +#include "compiler/compileBroker.hpp" #include "classfile/moduleEntry.hpp" -#include "memory/oopFactory.hpp" -#include "memory/resourceArea.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/handles.hpp" -#include "jvmci/jvmciJavaClasses.hpp" -#include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "runtime/compilationPolicy.hpp" -#include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" JVMCICompiler* JVMCICompiler::_instance = NULL; @@ -104,112 +95,39 @@ tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methods_compiled); } _bootstrapping = false; - JVMCIRuntime::bootstrap_finished(CHECK); + JVMCI::compiler_runtime()->bootstrap_finished(CHECK); } -#define CHECK_EXIT THREAD); \ -if (HAS_PENDING_EXCEPTION) { \ - char buf[256]; \ - jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ - JVMCICompiler::exit_on_pending_exception(PENDING_EXCEPTION, buf); \ - return; \ -} \ -(void)(0 - -void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JVMCIEnv* env) { - JVMCI_EXCEPTION_CONTEXT - - bool is_osr = entry_bci != InvocationEntryBci; - if (_bootstrapping && is_osr) { - // no OSR compilations during bootstrap - the compiler is just too slow at this point, - // and we know that there are no endless loops - env->set_failure(true, "No OSR during boostrap"); - return; +bool JVMCICompiler::force_comp_at_level_simple(Method *method) { + if (UseJVMCINativeLibrary) { + // This mechanism exists to force compilation of a JVMCI compiler by C1 + // to reduces the compilation time spent on the JVMCI compiler itself. In + // +UseJVMCINativeLibrary mode, the JVMCI compiler is AOT compiled. + return false; } - JVMCIRuntime::initialize_well_known_classes(CHECK_EXIT); - - HandleMark hm; - Handle receiver = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK_EXIT); - - JavaValue method_result(T_OBJECT); - JavaCallArguments args; - args.push_long((jlong) (address) method()); - JavaCalls::call_static(&method_result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), - vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, THREAD); - - JavaValue result(T_OBJECT); - if (!HAS_PENDING_EXCEPTION) { - JavaCallArguments args; - args.push_oop(receiver); - args.push_oop(Handle(THREAD, (oop)method_result.get_jobject())); - args.push_int(entry_bci); - args.push_long((jlong) (address) env); - args.push_int(env->task()->compile_id()); - JavaCalls::call_special(&result, receiver->klass(), - vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, THREAD); + if (_bootstrapping) { + // When bootstrapping, the JVMCI compiler can compile its own methods. + return false; } - // An uncaught exception was thrown during compilation. Generally these - // should be handled by the Java code in some useful way but if they leak - // through to here report them instead of dying or silently ignoring them. - if (HAS_PENDING_EXCEPTION) { - Handle exception(THREAD, PENDING_EXCEPTION); - CLEAR_PENDING_EXCEPTION; - - java_lang_Throwable::java_printStackTrace(exception, THREAD); - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - } - - env->set_failure(false, "unexpected exception thrown"); - } else { - oop result_object = (oop) result.get_jobject(); - if (result_object != NULL) { - oop failure_message = HotSpotCompilationRequestResult::failureMessage(result_object); - if (failure_message != NULL) { - // Copy failure reason into resource memory first ... - const char* failure_reason = java_lang_String::as_utf8_string(failure_message); - // ... and then into the C heap. - failure_reason = os::strdup(failure_reason, mtCompiler); - bool retryable = HotSpotCompilationRequestResult::retry(result_object) != 0; - env->set_failure(retryable, failure_reason, true); - } else { - if (env->task()->code() == NULL) { - env->set_failure(true, "no nmethod produced"); - } else { - env->task()->set_num_inlined_bytecodes(HotSpotCompilationRequestResult::inlinedBytecodes(result_object)); - Atomic::inc(&_methods_compiled); + JVMCIRuntime* runtime = JVMCI::compiler_runtime(); + if (runtime != NULL && runtime->is_HotSpotJVMCIRuntime_initialized()) { + JavaThread* thread = JavaThread::current(); + HandleMark hm(thread); + THREAD_JVMCIENV(thread); + JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(JVMCIENV); + objArrayHandle excludeModules(thread, HotSpotJVMCI::HotSpotJVMCIRuntime::excludeFromJVMCICompilation(JVMCIENV, HotSpotJVMCI::resolve(receiver))); + if (excludeModules.not_null()) { + ModuleEntry* moduleEntry = method->method_holder()->module(); + for (int i = 0; i < excludeModules->length(); i++) { + if (oopDesc::equals(excludeModules->obj_at(i), moduleEntry->module())) { + return true; } } - } else { - assert(false, "JVMCICompiler.compileMethod should always return non-null"); } } - if (_bootstrapping) { - _bootstrap_compilation_request_handled = true; - } -} - -void JVMCICompiler::exit_on_pending_exception(oop exception, const char* message) { - JavaThread* THREAD = JavaThread::current(); - CLEAR_PENDING_EXCEPTION; - - static volatile int report_error = 0; - if (!report_error && Atomic::cmpxchg(1, &report_error, 0) == 0) { - // Only report an error once - tty->print_raw_cr(message); - Handle ex(THREAD, exception); - java_lang_Throwable::java_printStackTrace(ex, THREAD); - } else { - // Allow error reporting thread to print the stack trace. Windows - // doesn't allow uninterruptible wait for JavaThreads - const bool interruptible = true; - os::sleep(THREAD, 200, interruptible); - } - - before_exit(THREAD); - vm_exit(-1); + return false; } // Compilation entry point for methods @@ -227,33 +145,3 @@ TRACE_jvmci_1("JVMCICompiler::print_timers"); tty->print_cr(" JVMCI code install time: %6.3f s", _codeInstallTimer.seconds()); } - -bool JVMCICompiler::force_comp_at_level_simple(Method *method) { - JVMCI_EXCEPTION_CONTEXT - - if (_bootstrapping) { - // When bootstrapping, the JVMCI compiler can compile its own methods. - return false; - } - - if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized()) { - // JVMCI cannot participate in compilation scheduling until - // JVMCI is initialized and indicates it wants to participate. - return false; - } - // Support for graal.CompileGraalWithC1Only - HandleMark hm(thread); - jobject runtime = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CATCH); - objArrayHandle excludeFromJVMCICompilation(thread, HotSpotJVMCIRuntime::excludeFromJVMCICompilation(runtime)); - if (excludeFromJVMCICompilation.is_null()) { - return false; - } - ModuleEntry *module = method->method_holder()->module(); - for (int i = 0; i < excludeFromJVMCICompilation->length(); ++i) { - if (module->module() == excludeFromJVMCICompilation->obj_at(i)) { - return true; - } - } - - return false; -} diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCompiler.hpp --- a/src/hotspot/share/jvmci/jvmciCompiler.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCompiler.hpp Wed May 01 12:31:29 2019 -0700 @@ -25,8 +25,6 @@ #define SHARE_JVMCI_JVMCICOMPILER_HPP #include "compiler/abstractCompiler.hpp" -#include "jvmci/jvmciEnv.hpp" -#include "utilities/exceptions.hpp" class JVMCICompiler : public AbstractCompiler { private: @@ -65,7 +63,7 @@ return _instance; } - virtual const char* name() { return "JVMCI"; } + virtual const char* name() { return UseJVMCINativeLibrary ? "JVMCI-native" : "JVMCI"; } virtual bool supports_native() { return true; } virtual bool supports_osr () { return true; } @@ -90,11 +88,13 @@ bool is_bootstrapping() const { return _bootstrapping; } + void set_bootstrap_compilation_request_handled() { + _instance->_bootstrap_compilation_request_handled = true; + } + // Compilation entry point for methods virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive); - void compile_method(const methodHandle& target, int entry_bci, JVMCIEnv* env); - // Print compilation timers and statistics virtual void print_timers(); @@ -104,6 +104,10 @@ */ int methods_compiled() { return _methods_compiled; } + void inc_methods_compiled() { + Atomic::inc(&_methods_compiled); + } + // Print compilation timers and statistics static void print_compilation_timers(); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCompilerToVM.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Wed May 01 12:31:29 2019 -0700 @@ -22,25 +22,25 @@ */ #include "precompiled.hpp" -#include "ci/ciUtilities.inline.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" #include "code/scopeDesc.hpp" -#include "interpreter/linkResolver.hpp" -#include "memory/oopFactory.hpp" -#include "oops/cpCache.inline.hpp" -#include "oops/generateOopMap.hpp" -#include "oops/method.inline.hpp" -#include "oops/objArrayOop.inline.hpp" -#include "oops/typeArrayOop.inline.hpp" #include "compiler/compileBroker.hpp" #include "compiler/disassembler.hpp" +#include "interpreter/linkResolver.hpp" +#include "interpreter/bytecodeStream.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "memory/oopFactory.hpp" +#include "oops/constantPool.inline.hpp" +#include "oops/method.inline.hpp" +#include "oops/typeArrayOop.inline.hpp" +#include "prims/nativeLookup.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/fieldDescriptor.inline.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/frame.inline.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/timerTrace.hpp" @@ -87,38 +87,22 @@ } } -// Entry to native method implementation that transitions current thread to '_thread_in_vm'. -#define C2V_VMENTRY(result_type, name, signature) \ - JNIEXPORT result_type JNICALL c2v_ ## name signature { \ - TRACE_jvmci_1("CompilerToVM::" #name); \ - TRACE_CALL(result_type, jvmci_ ## name signature) \ - JVMCI_VM_ENTRY_MARK; \ - -#define C2V_END } - -oop CompilerToVM::get_jvmci_method(const methodHandle& method, TRAPS) { - if (method() != NULL) { - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_long((jlong) (address) method()); - JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_NULL); +class JVMCITraceMark : public StackObj { + const char* _msg; + public: + JVMCITraceMark(const char* msg) { + _msg = msg; + if (JVMCITraceLevel >= 1) { + tty->print_cr(PTR_FORMAT " JVMCITrace-1: Enter %s", p2i(JavaThread::current()), _msg); + } + } + ~JVMCITraceMark() { + if (JVMCITraceLevel >= 1) { + tty->print_cr(PTR_FORMAT " JVMCITrace-1: Exit %s", p2i(JavaThread::current()), _msg); + } + } +}; - return (oop)result.get_jobject(); - } - return NULL; -} - -oop CompilerToVM::get_jvmci_type(JVMCIKlassHandle& klass, TRAPS) { - if (!klass.is_null()) { - JavaValue result(T_OBJECT); - JavaCallArguments args; - args.push_oop(Handle(THREAD, klass->java_mirror())); - JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedObjectTypeImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::klass_fromMetaspace_signature(), &args, CHECK_NULL); - - return (oop)result.get_jobject(); - } - return NULL; -} Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) { assert(_index < _args->length(), "out of bounds"); @@ -127,22 +111,32 @@ return Handle(Thread::current(), arg); } -jobjectArray readConfiguration0(JNIEnv *env, TRAPS); +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + JVMCITraceMark jtm("CompilerToVM::" #name); \ + TRACE_CALL(result_type, jvmci_ ## name signature) \ + JVMCI_VM_ENTRY_MARK; \ + ResourceMark rm; \ + JNI_JVMCIENV(env); -C2V_VMENTRY(jobjectArray, readConfiguration, (JNIEnv *env)) - jobjectArray config = readConfiguration0(env, CHECK_NULL); - return config; -C2V_END +#define C2V_END } + +jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS); -C2V_VMENTRY(jobject, getFlagValue, (JNIEnv *, jobject c2vm, jobject name_handle)) -#define RETURN_BOXED_LONG(value) oop box; jvalue p; p.j = (jlong) (value); box = java_lang_boxing_object::create(T_LONG, &p, CHECK_NULL); return JNIHandles::make_local(THREAD, box); -#define RETURN_BOXED_DOUBLE(value) oop box; jvalue p; p.d = (jdouble) (value); box = java_lang_boxing_object::create(T_DOUBLE, &p, CHECK_NULL); return JNIHandles::make_local(THREAD, box); - Handle name(THREAD, JNIHandles::resolve(name_handle)); +C2V_VMENTRY(jobjectArray, readConfiguration, (JNIEnv* env)) + jobjectArray config = readConfiguration0(env, JVMCI_CHECK_NULL); + return config; +} + +C2V_VMENTRY(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name_handle)) +#define RETURN_BOXED_LONG(value) jvalue p; p.j = (jlong) (value); JVMCIObject box = JVMCIENV->create_box(T_LONG, &p, JVMCI_CHECK_NULL); return box.as_jobject(); +#define RETURN_BOXED_DOUBLE(value) jvalue p; p.d = (jdouble) (value); JVMCIObject box = JVMCIENV->create_box(T_DOUBLE, &p, JVMCI_CHECK_NULL); return box.as_jobject(); + JVMCIObject name = JVMCIENV->wrap(name_handle); if (name.is_null()) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW_NULL(NullPointerException); } - ResourceMark rm; - const char* cstring = java_lang_String::as_utf8_string(name()); + const char* cstring = JVMCIENV->as_utf8_string(name); JVMFlag* flag = JVMFlag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true); if (flag == NULL) { return c2vm; @@ -150,11 +144,11 @@ if (flag->is_bool()) { jvalue prim; prim.z = flag->get_bool(); - oop box = java_lang_boxing_object::create(T_BOOLEAN, &prim, CHECK_NULL); - return JNIHandles::make_local(THREAD, box); + JVMCIObject box = JVMCIENV->create_box(T_BOOLEAN, &prim, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(box); } else if (flag->is_ccstr()) { - Handle value = java_lang_String::create_from_str(flag->get_ccstr(), CHECK_NULL); - return JNIHandles::make_local(THREAD, value()); + JVMCIObject value = JVMCIENV->create_string(flag->get_ccstr(), JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(value); } else if (flag->is_intx()) { RETURN_BOXED_LONG(flag->get_intx()); } else if (flag->is_int()) { @@ -176,12 +170,25 @@ #undef RETURN_BOXED_DOUBLE C2V_END -C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); - ResourceMark rm; +C2V_VMENTRY(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address)) + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); + } + if (oop_address == 0) { + JVMCI_THROW_MSG_NULL(InternalError, "Handle must be non-zero"); + } + oop obj = *((oopDesc**) oop_address); + if (obj != NULL) { + oopDesc::verify(obj); + } + return JNIHandles::make_local(obj); +C2V_END + +C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); int code_size = method->code_size(); - typeArrayOop reconstituted_code = oopFactory::new_byteArray(code_size, CHECK_NULL); + jbyte* reconstituted_code = NEW_RESOURCE_ARRAY(jbyte, code_size); guarantee(method->method_holder()->is_rewritten(), "Method's holder should be rewritten"); // iterate over all bytecodes and replace non-Java bytecodes @@ -193,9 +200,9 @@ int len = s.instruction_size(); // Restore original byte code. - reconstituted_code->byte_at_put(bci, (jbyte) (s.is_wide()? Bytecodes::_wide : code)); + reconstituted_code[bci] = (jbyte) (s.is_wide()? Bytecodes::_wide : code); if (len > 1) { - memcpy(reconstituted_code->byte_at_addr(bci + 1), s.bcp()+1, len-1); + memcpy(reconstituted_code + (bci + 1), s.bcp()+1, len-1); } if (len > 1) { @@ -211,14 +218,14 @@ case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: case Bytecodes::_invokehandle: { - int cp_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); - Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + int cp_index = Bytes::get_native_u2((address) reconstituted_code + (bci + 1)); + Bytes::put_Java_u2((address) reconstituted_code + (bci + 1), (u2) cp_index); break; } case Bytecodes::_invokedynamic: { - int cp_index = Bytes::get_native_u4((address) reconstituted_code->byte_at_addr(bci + 1)); - Bytes::put_Java_u4((address) reconstituted_code->byte_at_addr(bci + 1), (u4) cp_index); + int cp_index = Bytes::get_native_u4((address) reconstituted_code + (bci + 1)); + Bytes::put_Java_u4((address) reconstituted_code + (bci + 1), (u4) cp_index); break; } @@ -229,18 +236,18 @@ // Not all ldc byte code are rewritten. switch (raw_code) { case Bytecodes::_fast_aldc: { - int cpc_index = reconstituted_code->byte_at(bci + 1) & 0xff; + int cpc_index = reconstituted_code[bci + 1] & 0xff; int cp_index = method->constants()->object_to_cp_index(cpc_index); assert(cp_index < method->constants()->length(), "sanity check"); - reconstituted_code->byte_at_put(bci + 1, (jbyte) cp_index); + reconstituted_code[bci + 1] = (jbyte) cp_index; break; } case Bytecodes::_fast_aldc_w: { - int cpc_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + int cpc_index = Bytes::get_native_u2((address) reconstituted_code + (bci + 1)); int cp_index = method->constants()->object_to_cp_index(cpc_index); assert(cp_index < method->constants()->length(), "sanity check"); - Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + Bytes::put_Java_u2((address) reconstituted_code + (bci + 1), (u2) cp_index); break; } @@ -250,25 +257,29 @@ } } - return (jbyteArray) JNIHandles::make_local(THREAD, reconstituted_code); + JVMCIPrimitiveArray result = JVMCIENV->new_byteArray(code_size, JVMCI_CHECK_NULL); + JVMCIENV->copy_bytes_from(reconstituted_code, result, 0, code_size); + return JVMCIENV->get_jbyteArray(result); C2V_END -C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv *, jobject, jobject jvmci_method)) - ResourceMark rm; - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); return method->exception_table_length(); C2V_END -C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv *, jobject, jobject jvmci_method)) - ResourceMark rm; - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); if (method->exception_table_length() == 0) { return 0L; } return (jlong) (address) method->exception_table_start(); C2V_END -C2V_VMENTRY(jobject, asResolvedJavaMethod, (JNIEnv *, jobject, jobject executable_handle)) +C2V_VMENTRY(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject executable_handle)) + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); + } + oop executable = JNIHandles::resolve(executable_handle); oop mirror = NULL; int slot = 0; @@ -283,89 +294,101 @@ } Klass* holder = java_lang_Class::as_Klass(mirror); methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); - oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv *, jobject, jobject base, jlong offset)) +C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset)) methodHandle method; - oop base_object = JNIHandles::resolve(base); - if (base_object == NULL) { + JVMCIObject base_object = JVMCIENV->wrap(base); + if (base_object.is_null()) { method = *((Method**)(offset)); - } else if (base_object->is_a(SystemDictionary::ResolvedMethodName_klass())) { - method = (Method*) (intptr_t) base_object->long_field(offset); - } else if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { - method = *((Method**)(HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object) + offset)); - } else { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } else if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) { + Handle obj = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL); + if (obj->is_a(SystemDictionary::ResolvedMethodName_klass())) { + method = (Method*) (intptr_t) obj->long_field(offset); + } else { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected type: %s", obj->klass()->external_name())); + } + } else if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(base_object)) { + method = JVMCIENV->asMethod(base_object); + } + if (method.is_null()) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected type: %s", JVMCIENV->klass_name(base_object))); } assert (method.is_null() || method->is_method(), "invalid read"); - oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getConstantPool, (JNIEnv *, jobject, jobject object_handle)) +C2V_VMENTRY(jobject, getConstantPool, (JNIEnv* env, jobject, jobject object_handle)) constantPoolHandle cp; - oop object = JNIHandles::resolve(object_handle); - if (object == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + JVMCIObject object = JVMCIENV->wrap(object_handle); + if (object.is_null()) { + JVMCI_THROW_NULL(NullPointerException); } - if (object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { - cp = CompilerToVM::asMethod(object)->constMethod()->constants(); - } else if (object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { - cp = InstanceKlass::cast(CompilerToVM::asKlass(object))->constants(); + if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(object)) { + cp = JVMCIENV->asMethod(object)->constMethod()->constants(); + } else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(object)) { + cp = InstanceKlass::cast(JVMCIENV->asKlass(object))->constants(); } else { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Unexpected type: %s", object->klass()->external_name())); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + err_msg("Unexpected type: %s", JVMCIENV->klass_name(object))); } assert(!cp.is_null(), "npe"); - JavaValue method_result(T_OBJECT); - JavaCallArguments args; - args.push_long((jlong) (address) cp()); - JavaCalls::call_static(&method_result, SystemDictionary::HotSpotConstantPool_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::constantPool_fromMetaspace_signature(), &args, CHECK_NULL); - return JNIHandles::make_local(THREAD, (oop)method_result.get_jobject()); + + JVMCIObject result = JVMCIENV->get_jvmci_constant_pool(cp, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, getResolvedJavaType, (JNIEnv *, jobject, jobject base, jlong offset, jboolean compressed)) +C2V_VMENTRY(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject base, jlong offset, jboolean compressed)) JVMCIKlassHandle klass(THREAD); - oop base_object = JNIHandles::resolve(base); + JVMCIObject base_object = JVMCIENV->wrap(base); jlong base_address = 0; - if (base_object != NULL && offset == oopDesc::klass_offset_in_bytes()) { - klass = base_object->klass(); + if (base_object.is_non_null() && offset == oopDesc::klass_offset_in_bytes()) { + // klass = JVMCIENV->unhandle(base_object)->klass(); + if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) { + Handle base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL); + klass = base_oop->klass(); + } else { + assert(false, "What types are we actually expecting here?"); + } } else if (!compressed) { - if (base_object != NULL) { - if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { - base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); - } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { - base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); - } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { - base_address = (jlong) CompilerToVM::asKlass(base_object); - } else if (base_object->is_a(SystemDictionary::Class_klass())) { - base_address = (jlong) (address) base_object; - } else { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + if (base_object.is_non_null()) { + if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(base_object)) { + base_address = (intptr_t) JVMCIENV->asMethod(base_object); + } else if (JVMCIENV->isa_HotSpotConstantPool(base_object)) { + base_address = (intptr_t) JVMCIENV->asConstantPool(base_object); + } else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base_object)) { + base_address = (intptr_t) JVMCIENV->asKlass(base_object); + } else if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) { + Handle base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL); + if (base_oop->is_a(SystemDictionary::Class_klass())) { + base_address = (jlong) (address) base_oop(); + } + } + if (base_address == 0) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", JVMCIENV->klass_name(base_object), offset, compressed ? "true" : "false")); } } klass = *((Klass**) (intptr_t) (base_address + offset)); } else { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", - base_object != NULL ? base_object->klass()->external_name() : "null", + base_object.is_non_null() ? JVMCIENV->klass_name(base_object) : "null", offset, compressed ? "true" : "false")); } assert (klass == NULL || klass->is_klass(), "invalid read"); - oop result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); } -C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) - ResourceMark rm; - methodHandle method = CompilerToVM::asMethod(jvmci_method); - Klass* holder = CompilerToVM::asKlass(jvmci_type); +C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); + Klass* holder = JVMCIENV->asKlass(jvmci_type); if (holder->is_interface()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", holder->external_name())); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Interface %s should be handled in Java code", holder->external_name())); } methodHandle ucm; @@ -373,12 +396,12 @@ MutexLocker locker(Compile_lock); ucm = Dependencies::find_unique_concrete_method(holder, method()); } - oop result = CompilerToVM::get_jvmci_method(ucm, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_method(ucm, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, getImplementor, (JNIEnv *, jobject, jobject jvmci_type)) - Klass* klass = CompilerToVM::asKlass(jvmci_type); +C2V_VMENTRY(jobject, getImplementor, (JNIEnv* env, jobject, jobject jvmci_type)) + Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_interface()) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Expected interface type, got %s", klass->external_name())); @@ -390,48 +413,55 @@ MutexLocker locker(Compile_lock); handle = iklass->implementor(); } - oop implementor = CompilerToVM::get_jvmci_type(handle, CHECK_NULL); - return JNIHandles::make_local(THREAD, implementor); + JVMCIObject implementor = JVMCIENV->get_jvmci_type(handle, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(implementor); C2V_END -C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); return method->is_ignored_by_security_stack_walk(); C2V_END -C2V_VMENTRY(jboolean, isCompilable,(JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); constantPoolHandle cp = method->constMethod()->constants(); assert(!cp.is_null(), "npe"); // don't inline method when constant pool contains a CONSTANT_Dynamic return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant(); C2V_END -C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); return !Inline || CompilerOracle::should_not_inline(method) || method->dont_inline(); C2V_END -C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); return CompilerOracle::should_inline(method) || method->force_inline(); C2V_END -C2V_VMENTRY(jobject, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve)) - ResourceMark rm; - Handle name(THREAD, JNIHandles::resolve(jname)); - Symbol* class_name = java_lang_String::as_symbol(name(), CHECK_0); - if (java_lang_String::length(name()) <= 1) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string())); +C2V_VMENTRY(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve)) + JVMCIObject name = JVMCIENV->wrap(jname); + const char* str = JVMCIENV->as_utf8_string(name); + TempNewSymbol class_name = SymbolTable::new_symbol(str, CHECK_NULL); + + if (class_name->utf8_length() <= 1) { + JVMCI_THROW_MSG_0(InternalError, err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string())); } JVMCIKlassHandle resolved_klass(THREAD); - if (JNIHandles::resolve(accessing_class) == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + Klass* accessing_klass = NULL; + Handle class_loader; + Handle protection_domain; + if (accessing_class != NULL) { + accessing_klass = JVMCIENV->asKlass(accessing_class); + class_loader = Handle(THREAD, accessing_klass->class_loader()); + protection_domain = Handle(THREAD, accessing_klass->protection_domain()); + } else { + // Use the System class loader + class_loader = Handle(THREAD, SystemDictionary::java_system_loader()); + JVMCIENV->runtime()->initialize(JVMCIENV); } - Klass* accessing_klass = java_lang_Class::as_Klass(JNIHandles::resolve(accessing_class)); - Handle class_loader(THREAD, accessing_klass->class_loader()); - Handle protection_domain(THREAD, accessing_klass->protection_domain()); if (resolve) { resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0); @@ -464,135 +494,163 @@ } else { resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(t))->array_klass(fd.dimension(), CHECK_0); } + } else { + resolved_klass = SystemDictionary::find(class_name, class_loader, protection_domain, CHECK_0); } } - oop result = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_type(resolved_klass, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); + } + if (mirror == NULL) { + return NULL; + } + JVMCIKlassHandle klass(THREAD); + klass = java_lang_Class::as_Klass(JNIHandles::resolve(mirror)); + if (klass == NULL) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "Primitive classes are unsupported"); + } + JVMCIObject result = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +} + +C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop result = cp->resolve_constant_at(index, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result)); C2V_END -C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result)); C2V_END -C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->name_and_type_ref_index_at(index); C2V_END -C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); - Handle sym = java_lang_String::create_from_symbol(cp->name_ref_at(which), CHECK_NULL); - return JNIHandles::make_local(THREAD, sym()); +C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); + JVMCIObject sym = JVMCIENV->create_string(cp->name_ref_at(which), JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(sym); C2V_END -C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); - Handle sym = java_lang_String::create_from_symbol(cp->signature_ref_at(which), CHECK_NULL); - return JNIHandles::make_local(THREAD, sym()); +C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); + JVMCIObject sym = JVMCIENV->create_string(cp->signature_ref_at(which), JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(sym); C2V_END -C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->klass_ref_index_at(index); C2V_END -C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Klass* klass = cp->klass_at(index, CHECK_NULL); JVMCIKlassHandle resolved_klass(THREAD, klass); if (resolved_klass->is_instance_klass()) { InstanceKlass::cast(resolved_klass())->link_class_or_fail(THREAD); } - oop jvmci_type = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); - return JNIHandles::make_local(THREAD, jvmci_type); + JVMCIObject klassObject = JVMCIENV->get_jvmci_type(resolved_klass, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(klassObject); C2V_END -C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Klass* loading_klass = cp->pool_holder(); bool is_accessible = false; - JVMCIKlassHandle klass(THREAD, JVMCIEnv::get_klass_by_index(cp, index, is_accessible, loading_klass)); + JVMCIKlassHandle klass(THREAD, JVMCIRuntime::get_klass_by_index(cp, index, is_accessible, loading_klass)); Symbol* symbol = NULL; - if (klass == NULL) { - symbol = cp->klass_name_at(index); + if (klass.is_null()) { + constantTag tag = cp->tag_at(index); + if (tag.is_klass()) { + // The klass has been inserted into the constant pool + // very recently. + klass = cp->resolved_klass_at(index); + } else if (tag.is_symbol()) { + symbol = cp->symbol_at(index); + } else { + assert(cp->tag_at(index).is_unresolved_klass(), "wrong tag"); + symbol = cp->klass_name_at(index); + } } - oop result_oop; + JVMCIObject result; if (!klass.is_null()) { - result_oop = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + result = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); } else { - Handle result = java_lang_String::create_from_symbol(symbol, CHECK_NULL); - result_oop = result(); + result = JVMCIENV->create_string(symbol, JVMCI_CHECK_NULL); } - return JNIHandles::make_local(THREAD, result_oop); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); - return JNIHandles::make_local(THREAD, appendix_oop); + return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(appendix_oop)); C2V_END -C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); InstanceKlass* pool_holder = cp->pool_holder(); Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); - methodHandle method = JVMCIEnv::get_method_by_index(cp, index, bc, pool_holder); - oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + methodHandle method = JVMCIRuntime::get_method_by_index(cp, index, bc, pool_holder); + JVMCIObject result = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); return cp->remap_instruction_operand_from_cache(index); C2V_END -C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle)) - ResourceMark rm; - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); fieldDescriptor fd; - LinkInfo link_info(cp, index, (jvmci_method != NULL) ? CompilerToVM::asMethod(jvmci_method) : NULL, CHECK_0); + LinkInfo link_info(cp, index, (jvmci_method != NULL) ? JVMCIENV->asMethod(jvmci_method) : NULL, CHECK_0); LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0); - typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle); - if (info == NULL || info->length() != 3) { + JVMCIPrimitiveArray info = JVMCIENV->wrap(info_handle); + if (info.is_null() || JVMCIENV->get_length(info) != 3) { JVMCI_ERROR_NULL("info must not be null and have a length of 3"); } - info->int_at_put(0, fd.access_flags().as_int()); - info->int_at_put(1, fd.offset()); - info->int_at_put(2, fd.index()); + JVMCIENV->put_int_at(info, 0, fd.access_flags().as_int()); + JVMCIENV->put_int_at(info, 1, fd.offset()); + JVMCIENV->put_int_at(info, 2, fd.index()); JVMCIKlassHandle handle(THREAD, fd.field_holder()); - oop field_holder = CompilerToVM::get_jvmci_type(handle, CHECK_NULL); - return JNIHandles::make_local(THREAD, field_holder); + JVMCIObject field_holder = JVMCIENV->get_jvmci_type(handle, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(field_holder); C2V_END -C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) - ResourceMark rm; - Klass* klass = CompilerToVM::asKlass(jvmci_type); - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method)) + Klass* klass = JVMCIENV->asKlass(jvmci_type); + Method* method = JVMCIENV->asMethod(jvmci_method); if (klass->is_interface()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", klass->external_name())); + JVMCI_THROW_MSG_0(InternalError, err_msg("Interface %s should be handled in Java code", klass->external_name())); } if (!method->method_holder()->is_interface()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Method %s is not held by an interface, this case should be handled in Java code", method->name_and_sig_as_C_string())); + JVMCI_THROW_MSG_0(InternalError, err_msg("Method %s is not held by an interface, this case should be handled in Java code", method->name_and_sig_as_C_string())); + } + if (!klass->is_instance_klass()) { + JVMCI_THROW_MSG_0(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); } if (!InstanceKlass::cast(klass)->is_linked()) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Class %s must be linked", klass->external_name())); + JVMCI_THROW_MSG_0(InternalError, err_msg("Class %s must be linked", klass->external_name())); } return LinkResolver::vtable_index_of_interface_method(klass, method); C2V_END -C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) - Klass* recv_klass = CompilerToVM::asKlass(receiver_jvmci_type); - Klass* caller_klass = CompilerToVM::asKlass(caller_jvmci_type); - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jobject, resolveMethod, (JNIEnv* env, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) + Klass* recv_klass = JVMCIENV->asKlass(receiver_jvmci_type); + Klass* caller_klass = JVMCIENV->asKlass(caller_jvmci_type); + methodHandle method = JVMCIENV->asMethod(jvmci_method); Klass* resolved = method->method_holder(); Symbol* h_name = method->name(); @@ -632,27 +690,27 @@ return NULL; } - oop result = CompilerToVM::get_jvmci_method(m, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_method(m, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jobject jvmci_type)) - Klass* klass = CompilerToVM::asKlass(jvmci_type); +C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type)) + Klass* klass = JVMCIENV->asKlass(jvmci_type); assert(klass != NULL, "method must not be called for primitive types"); return Dependencies::find_finalizable_subclass(klass) != NULL; C2V_END -C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv *, jobject, jobject jvmci_type)) - Klass* klass = CompilerToVM::asKlass(jvmci_type); +C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type)) + Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_instance_klass()) { return NULL; } InstanceKlass* iklass = InstanceKlass::cast(klass); - oop result = CompilerToVM::get_jvmci_method(iklass->class_initializer(), CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_method(iklass->class_initializer(), JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr)) +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr)) address target_addr = (address) addr; if (target_addr != 0x0) { int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); @@ -662,34 +720,47 @@ return -1; C2V_END -C2V_VMENTRY(void, setNotInlinableOrCompilable,(JNIEnv *, jobject, jobject jvmci_method)) - methodHandle method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(void, setNotInlinableOrCompilable,(JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); method->set_not_c1_compilable(); method->set_not_c2_compilable(); method->set_dont_inline(true); C2V_END -C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log)) - ResourceMark rm; +C2V_VMENTRY(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code, + jobject installed_code, jlong failed_speculations_address, jbyteArray speculations_obj)) HandleMark hm; JNIHandleMark jni_hm; - Handle target_handle(THREAD, JNIHandles::resolve(target)); - Handle compiled_code_handle(THREAD, JNIHandles::resolve(compiled_code)); + JVMCIObject target_handle = JVMCIENV->wrap(target); + JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code); CodeBlob* cb = NULL; - Handle installed_code_handle(THREAD, JNIHandles::resolve(installed_code)); - Handle speculation_log_handle(THREAD, JNIHandles::resolve(speculation_log)); + JVMCIObject installed_code_handle = JVMCIENV->wrap(installed_code); + JVMCIPrimitiveArray speculations_handle = JVMCIENV->wrap(speculations_obj); + + int speculations_len = JVMCIENV->get_length(speculations_handle); + char* speculations = NEW_RESOURCE_ARRAY(char, speculations_len); + JVMCIENV->copy_bytes_to(speculations_handle, (jbyte*) speculations, 0, speculations_len); JVMCICompiler* compiler = JVMCICompiler::instance(true, CHECK_JNI_ERR); TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer()); - bool is_immutable_PIC = HotSpotCompiledCode::isImmutablePIC(compiled_code_handle) > 0; - CodeInstaller installer(is_immutable_PIC); - JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle, CHECK_0); + bool is_immutable_PIC = JVMCIENV->get_HotSpotCompiledCode_isImmutablePIC(compiled_code_handle) > 0; + + CodeInstaller installer(JVMCIENV, is_immutable_PIC); + JVMCI::CodeInstallResult result = installer.install(compiler, + target_handle, + compiled_code_handle, + cb, + installed_code_handle, + (FailedSpeculation**)(address) failed_speculations_address, + speculations, + speculations_len, + JVMCI_CHECK_0); if (PrintCodeCacheOnCompilation) { stringStream s; - // Dump code cache into a buffer before locking the tty, + // Dump code cache into a buffer before locking the tty, { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::print_summary(&s, false); @@ -698,130 +769,115 @@ tty->print_raw_cr(s.as_string()); } - if (result != JVMCIEnv::ok) { + if (result != JVMCI::ok) { assert(cb == NULL, "should be"); } else { - if (installed_code_handle.not_null()) { - assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); - nmethod::invalidate_installed_code(installed_code_handle, CHECK_0); - { - // Ensure that all updates to the InstalledCode fields are consistent. - MutexLocker pl(Patching_lock, Mutex::_no_safepoint_check_flag); - InstalledCode::set_address(installed_code_handle, (jlong) cb); - InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); - if (cb->is_nmethod()) { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); - } else { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->code_begin()); - } - if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { - HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); - HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); - HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); - } + if (installed_code_handle.is_non_null()) { + if (cb->is_nmethod()) { + assert(JVMCIENV->isa_HotSpotNmethod(installed_code_handle), "wrong type"); + // Clear the link to an old nmethod first + JVMCIObject nmethod_mirror = installed_code_handle; + JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, JVMCI_CHECK_0); + } else { + assert(JVMCIENV->isa_InstalledCode(installed_code_handle), "wrong type"); } + // Initialize the link to the new code blob + JVMCIENV->initialize_installed_code(installed_code_handle, cb, JVMCI_CHECK_0); } } return result; C2V_END -C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject metadata)) +C2V_VMENTRY(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata)) #if INCLUDE_AOT - ResourceMark rm; HandleMark hm; + assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode"); - Handle target_handle(THREAD, JNIHandles::resolve(target)); - Handle compiled_code_handle(THREAD, JNIHandles::resolve(compiled_code)); - Handle metadata_handle(THREAD, JNIHandles::resolve(metadata)); + JVMCIObject target_handle = JVMCIENV->wrap(target); + JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code); + JVMCIObject metadata_handle = JVMCIENV->wrap(metadata); CodeMetadata code_metadata; - CodeBlob *cb = NULL; - CodeInstaller installer(true /* immutable PIC compilation */); - JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, CHECK_0); - if (result != JVMCIEnv::ok) { + CodeInstaller installer(JVMCIENV, true /* immutable PIC compilation */); + JVMCI::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, JVMCI_CHECK_0); + if (result != JVMCI::ok) { return result; } if (code_metadata.get_nr_pc_desc() > 0) { - typeArrayHandle pcArrayOop = oopFactory::new_byteArray_handle(sizeof(PcDesc) * code_metadata.get_nr_pc_desc(), CHECK_(JVMCIEnv::cache_full)); - memcpy(pcArrayOop->byte_at_addr(0), code_metadata.get_pc_desc(), sizeof(PcDesc) * code_metadata.get_nr_pc_desc()); - HotSpotMetaData::set_pcDescBytes(metadata_handle, pcArrayOop()); + int size = sizeof(PcDesc) * code_metadata.get_nr_pc_desc(); + JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full)); + JVMCIENV->copy_bytes_from((jbyte*) code_metadata.get_pc_desc(), array, 0, size); + HotSpotJVMCI::HotSpotMetaData::set_pcDescBytes(JVMCIENV, metadata_handle, array); } if (code_metadata.get_scopes_size() > 0) { - typeArrayHandle scopesArrayOop = oopFactory::new_byteArray_handle(code_metadata.get_scopes_size(), CHECK_(JVMCIEnv::cache_full)); - memcpy(scopesArrayOop->byte_at_addr(0), code_metadata.get_scopes_desc(), code_metadata.get_scopes_size()); - HotSpotMetaData::set_scopesDescBytes(metadata_handle, scopesArrayOop()); + int size = code_metadata.get_scopes_size(); + JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full)); + JVMCIENV->copy_bytes_from((jbyte*) code_metadata.get_scopes_desc(), array, 0, size); + HotSpotJVMCI::HotSpotMetaData::set_scopesDescBytes(JVMCIENV, metadata_handle, array); } RelocBuffer* reloc_buffer = code_metadata.get_reloc_buffer(); - typeArrayHandle relocArrayOop = oopFactory::new_byteArray_handle((int) reloc_buffer->size(), CHECK_(JVMCIEnv::cache_full)); - if (reloc_buffer->size() > 0) { - memcpy(relocArrayOop->byte_at_addr(0), reloc_buffer->begin(), reloc_buffer->size()); - } - HotSpotMetaData::set_relocBytes(metadata_handle, relocArrayOop()); + int size = (int) reloc_buffer->size(); + JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full)); + JVMCIENV->copy_bytes_from((jbyte*) reloc_buffer->begin(), array, 0, size); + HotSpotJVMCI::HotSpotMetaData::set_relocBytes(JVMCIENV, metadata_handle, array); const OopMapSet* oopMapSet = installer.oopMapSet(); { ResourceMark mark; ImmutableOopMapBuilder builder(oopMapSet); - int oopmap_size = builder.heap_size(); - typeArrayHandle oopMapArrayHandle = oopFactory::new_byteArray_handle(oopmap_size, CHECK_(JVMCIEnv::cache_full)); - builder.generate_into((address) oopMapArrayHandle->byte_at_addr(0)); - HotSpotMetaData::set_oopMaps(metadata_handle, oopMapArrayHandle()); + int size = builder.heap_size(); + JVMCIPrimitiveArray array = JVMCIENV->new_byteArray(size, JVMCI_CHECK_(JVMCI::cache_full)); + builder.generate_into((address) HotSpotJVMCI::resolve(array)->byte_at_addr(0)); + HotSpotJVMCI::HotSpotMetaData::set_oopMaps(JVMCIENV, metadata_handle, array); } AOTOopRecorder* recorder = code_metadata.get_oop_recorder(); int nr_meta_refs = recorder->nr_meta_refs(); - objArrayOop metadataArray = oopFactory::new_objectArray(nr_meta_refs, CHECK_(JVMCIEnv::cache_full)); - objArrayHandle metadataArrayHandle(THREAD, metadataArray); + JVMCIObjectArray metadataArray = JVMCIENV->new_Object_array(nr_meta_refs, JVMCI_CHECK_(JVMCI::cache_full)); for (int i = 0; i < nr_meta_refs; ++i) { jobject element = recorder->meta_element(i); if (element == NULL) { - return JVMCIEnv::cache_full; + return JVMCI::cache_full; } - metadataArrayHandle->obj_at_put(i, JNIHandles::resolve(element)); + JVMCIENV->put_object_at(metadataArray, i, JVMCIENV->wrap(element)); } - HotSpotMetaData::set_metadata(metadata_handle, metadataArrayHandle()); + HotSpotJVMCI::HotSpotMetaData::set_metadata(JVMCIENV, metadata_handle, metadataArray); ExceptionHandlerTable* handler = code_metadata.get_exception_table(); int table_size = handler->size_in_bytes(); - typeArrayHandle exceptionArrayOop = oopFactory::new_byteArray_handle(table_size, CHECK_(JVMCIEnv::cache_full)); - + JVMCIPrimitiveArray exceptionArray = JVMCIENV->new_byteArray(table_size, JVMCI_CHECK_(JVMCI::cache_full)); if (table_size > 0) { - handler->copy_bytes_to((address) exceptionArrayOop->byte_at_addr(0)); + handler->copy_bytes_to((address) HotSpotJVMCI::resolve(exceptionArray)->byte_at_addr(0)); } - HotSpotMetaData::set_exceptionBytes(metadata_handle, exceptionArrayOop()); + HotSpotJVMCI::HotSpotMetaData::set_exceptionBytes(JVMCIENV, metadata_handle, exceptionArray); return result; #else - THROW_MSG_0(vmSymbols::java_lang_InternalError(), "unimplemented"); + JVMCI_THROW_MSG_0(InternalError, "unimplemented"); #endif C2V_END -C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv *jniEnv, jobject)) +C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv* env, jobject)) JVMCICompiler* compiler = JVMCICompiler::instance(true, CHECK); CompilerStatistics* stats = compiler->stats(); stats->_standard.reset(); stats->_osr.reset(); C2V_END -C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jobject installedCode)) - ResourceMark rm; +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv* env, jobject, jobject installedCode)) HandleMark hm; if (installedCode == NULL) { - THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "installedCode is null"); + JVMCI_THROW_MSG_NULL(NullPointerException, "installedCode is null"); } - jlong codeBlob = InstalledCode::address(installedCode); - if (codeBlob == 0L) { - return NULL; - } - - CodeBlob* cb = (CodeBlob*) (address) codeBlob; + JVMCIObject installedCodeObject = JVMCIENV->wrap(installedCode); + CodeBlob* cb = JVMCIENV->asCodeBlob(installedCodeObject); if (cb == NULL) { return NULL; } @@ -846,28 +902,32 @@ return NULL; } - Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); - return JNIHandles::make_local(THREAD, result()); + JVMCIObject result = JVMCIENV->create_string(st.as_string(), JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jobject jvmci_method, int bci)) - ResourceMark rm; +C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv* env, jobject, jobject jvmci_method, int bci)) HandleMark hm; - methodHandle method = CompilerToVM::asMethod(jvmci_method); - oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); - return JNIHandles::make_local(THREAD, element); + methodHandle method = JVMCIENV->asMethod(jvmci_method); + JVMCIObject element = JVMCIENV->new_StackTraceElement(method, bci, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(element); C2V_END -C2V_VMENTRY(jobject, executeInstalledCode, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode)) - ResourceMark rm; +C2V_VMENTRY(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod)) + if (env != JavaThread::current()->jni_environment()) { + // The incoming arguments array would have to contain JavaConstants instead of regular objects + // and the return value would have to be wrapped as a JavaConstant. + JVMCI_THROW_MSG_NULL(InternalError, "Wrapping of arguments is currently unsupported"); + } + HandleMark hm; - jlong nmethodValue = InstalledCode::address(hotspotInstalledCode); - if (nmethodValue == 0L) { - THROW_NULL(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException()); + JVMCIObject nmethod_mirror = JVMCIENV->wrap(hs_nmethod); + nmethod* nm = JVMCIENV->asNmethod(nmethod_mirror); + if (nm == NULL) { + JVMCI_THROW_NULL(InvalidInstalledCodeException); } - nmethod* nm = (nmethod*) (address) nmethodValue; methodHandle mh = nm->method(); Symbol* signature = mh->signature(); JavaCallArguments jca(mh->size_of_parameters()); @@ -880,7 +940,7 @@ if (jap.get_ret_type() == T_VOID) { return NULL; } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { - return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); + return JNIHandles::make_local((oop) result.get_jobject()); } else { jvalue *value = (jvalue *) result.get_value_addr(); // Narrow the value down if required (Important on big endian machines) @@ -900,13 +960,13 @@ default: break; } - oop o = java_lang_boxing_object::create(jap.get_ret_type(), value, CHECK_NULL); - return JNIHandles::make_local(THREAD, o); + JVMCIObject o = JVMCIENV->create_box(jap.get_ret_type(), value, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(o); } C2V_END -C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jobject jvmci_method)) - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv* env, jobject, jobject jvmci_method)) + Method* method = JVMCIENV->asMethod(jvmci_method); if (!method->has_linenumber_table()) { return NULL; } @@ -917,38 +977,36 @@ } CompressedLineNumberReadStream stream(method->compressed_linenumber_table()); - typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL); + JVMCIPrimitiveArray result = JVMCIENV->new_longArray(2 * num_entries, JVMCI_CHECK_NULL); int i = 0; jlong value; while (stream.read_pair()) { value = ((long) stream.bci()); - result->long_at_put(i, value); + JVMCIENV->put_long_at(result, i, value); value = ((long) stream.line()); - result->long_at_put(i + 1, value); + JVMCIENV->put_long_at(result, i + 1, value); i += 2; } - return (jlongArray) JNIHandles::make_local(THREAD, result); + return (jlongArray) JVMCIENV->get_jobject(result); C2V_END -C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jobject jvmci_method)) - ResourceMark rm; - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv* env, jobject, jobject jvmci_method)) + Method* method = JVMCIENV->asMethod(jvmci_method); if (!method->has_localvariable_table()) { return 0; } return (jlong) (address) method->localvariable_table_start(); C2V_END -C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv *, jobject, jobject jvmci_method)) - ResourceMark rm; - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv* env, jobject, jobject jvmci_method)) + Method* method = JVMCIENV->asMethod(jvmci_method); return method->localvariable_table_length(); C2V_END -C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jobject jvmci_method)) - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, jobject jvmci_method)) + Method* method = JVMCIENV->asMethod(jvmci_method); MethodCounters* mcs = method->method_counters(); if (mcs != NULL) { mcs->clear_counters(); @@ -971,52 +1029,56 @@ C2V_END -C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject installed_code)) - Handle installed_code_handle(THREAD, JNIHandles::resolve(installed_code)); - nmethod::invalidate_installed_code(installed_code_handle, CHECK); +C2V_VMENTRY(void, invalidateHotSpotNmethod, (JNIEnv* env, jobject, jobject hs_nmethod)) + JVMCIObject nmethod_mirror = JVMCIENV->wrap(hs_nmethod); + JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, JVMCI_CHECK); C2V_END -C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject)) - typeArrayOop arrayOop = oopFactory::new_longArray(JVMCICounterSize, CHECK_NULL); - JavaThread::collect_counters(arrayOop); - return (jlongArray) JNIHandles::make_local(THREAD, arrayOop); +C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr)) + oop ret = RawAccess<>::oop_load((oop*)(address)addr); + return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(ret)); + C2V_END + +C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv* env, jobject)) + JVMCIPrimitiveArray array = JVMCIENV->new_longArray(JVMCICounterSize, JVMCI_CHECK_NULL); + JavaThread::collect_counters(JVMCIENV, array); + return (jlongArray) JVMCIENV->get_jobject(array); C2V_END -C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci)) +C2V_VMENTRY(int, allocateCompileId, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci)) HandleMark hm; - ResourceMark rm; - if (JNIHandles::resolve(jvmci_method) == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + if (jvmci_method == NULL) { + JVMCI_THROW_0(NullPointerException); } - Method* method = CompilerToVM::asMethod(jvmci_method); + Method* method = JVMCIENV->asMethod(jvmci_method); if (entry_bci >= method->code_size() || entry_bci < -1) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Unexpected bci %d", entry_bci)); + JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Unexpected bci %d", entry_bci)); } return CompileBroker::assign_compile_id_unlocked(THREAD, method, entry_bci); C2V_END -C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data)) - MethodData* mdo = CompilerToVM::asMethodData(metaspace_method_data); +C2V_VMENTRY(jboolean, isMature, (JNIEnv* env, jobject, jlong metaspace_method_data)) + MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data); return mdo != NULL && mdo->is_mature(); C2V_END -C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci, int comp_level)) - Method* method = CompilerToVM::asMethod(jvmci_method); +C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci, int comp_level)) + Method* method = JVMCIENV->asMethod(jvmci_method); return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL; C2V_END -C2V_VMENTRY(jobject, getSymbol, (JNIEnv*, jobject, jlong symbol)) - Handle sym = java_lang_String::create_from_symbol((Symbol*)(address)symbol, CHECK_NULL); - return JNIHandles::make_local(THREAD, sym()); +C2V_VMENTRY(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol)) + JVMCIObject sym = JVMCIENV->create_string((Symbol*)(address)symbol, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(sym); C2V_END -bool matches(jobjectArray methods, Method* method) { +bool matches(jobjectArray methods, Method* method, JVMCIEnv* JVMCIENV) { objArrayOop methods_oop = (objArrayOop) JNIHandles::resolve(methods); for (int i = 0; i < methods_oop->length(); i++) { oop resolved = methods_oop->obj_at(i); - if (resolved->is_a(HotSpotResolvedJavaMethodImpl::klass()) && CompilerToVM::asMethod(resolved) == method) { + if ((resolved->klass() == HotSpotJVMCI::HotSpotResolvedJavaMethodImpl::klass()) && HotSpotJVMCI::asMethod(JVMCIENV, resolved) == method) { return true; } } @@ -1037,18 +1099,21 @@ JavaCalls::call(result, method, args, CHECK); } -C2V_VMENTRY(jobject, iterateFrames, (JNIEnv*, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle)) - ResourceMark rm; +C2V_VMENTRY(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle)) if (!thread->has_last_Java_frame()) { return NULL; } Handle visitor(THREAD, JNIHandles::resolve_non_null(visitor_handle)); - Handle frame_reference = HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL); - HotSpotStackFrameReference::klass()->initialize(CHECK_NULL); + + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "getNextStackFrame is only supported for HotSpot stack walking"); + } + + HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL); + Handle frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL); StackFrameStream fst(thread); - jobjectArray methods = initial_methods; int frame_number = 0; @@ -1062,7 +1127,7 @@ if (vf->is_compiled_frame()) { // compiled method frame compiledVFrame* cvf = compiledVFrame::cast(vf); - if (methods == NULL || matches(methods, cvf->method())) { + if (methods == NULL || matches(methods, cvf->method(), JVMCIENV)) { if (initialSkip > 0) { initialSkip--; } else { @@ -1096,29 +1161,29 @@ array->bool_at_put(i, true); } } - HotSpotStackFrameReference::set_localIsVirtual(frame_reference, array()); + HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), array()); } else { - HotSpotStackFrameReference::set_localIsVirtual(frame_reference, NULL); + HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), NULL); } locals = cvf->locals(); - HotSpotStackFrameReference::set_bci(frame_reference, cvf->bci()); - oop method = CompilerToVM::get_jvmci_method(cvf->method(), CHECK_NULL); - HotSpotStackFrameReference::set_method(frame_reference, method); + HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), cvf->bci()); + JVMCIObject method = JVMCIENV->get_jvmci_method(cvf->method(), JVMCI_CHECK_NULL); + HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), JNIHandles::resolve(method.as_jobject())); } } } else if (vf->is_interpreted_frame()) { // interpreted method frame interpretedVFrame* ivf = interpretedVFrame::cast(vf); - if (methods == NULL || matches(methods, ivf->method())) { + if (methods == NULL || matches(methods, ivf->method(), JVMCIENV)) { if (initialSkip > 0) { initialSkip--; } else { locals = ivf->locals(); - HotSpotStackFrameReference::set_bci(frame_reference, ivf->bci()); - oop method = CompilerToVM::get_jvmci_method(ivf->method(), CHECK_NULL); - HotSpotStackFrameReference::set_method(frame_reference, method); - HotSpotStackFrameReference::set_localIsVirtual(frame_reference, NULL); + HotSpotJVMCI::HotSpotStackFrameReference::set_bci(JVMCIENV, frame_reference(), ivf->bci()); + JVMCIObject method = JVMCIENV->get_jvmci_method(ivf->method(), JVMCI_CHECK_NULL); + HotSpotJVMCI::HotSpotStackFrameReference::set_method(JVMCIENV, frame_reference(), JNIHandles::resolve(method.as_jobject())); + HotSpotJVMCI::HotSpotStackFrameReference::set_localIsVirtual(JVMCIENV, frame_reference(), NULL); } } } @@ -1126,9 +1191,9 @@ // locals != NULL means that we found a matching frame and result is already partially initialized if (locals != NULL) { methods = match_methods; - HotSpotStackFrameReference::set_compilerToVM(frame_reference, JNIHandles::resolve(compilerToVM)); - HotSpotStackFrameReference::set_stackPointer(frame_reference, (jlong) fst.current()->sp()); - HotSpotStackFrameReference::set_frameNumber(frame_reference, frame_number); + HotSpotJVMCI::HotSpotStackFrameReference::set_compilerToVM(JVMCIENV, frame_reference(), JNIHandles::resolve(compilerToVM)); + HotSpotJVMCI::HotSpotStackFrameReference::set_stackPointer(JVMCIENV, frame_reference(), (jlong) fst.current()->sp()); + HotSpotJVMCI::HotSpotStackFrameReference::set_frameNumber(JVMCIENV, frame_reference(), frame_number); // initialize the locals array objArrayOop array_oop = oopFactory::new_objectArray(locals->size(), CHECK_NULL); @@ -1139,20 +1204,20 @@ array->obj_at_put(i, locals->at(i)->get_obj()()); } } - HotSpotStackFrameReference::set_locals(frame_reference, array()); - HotSpotStackFrameReference::set_objectsMaterialized(frame_reference, JNI_FALSE); + HotSpotJVMCI::HotSpotStackFrameReference::set_locals(JVMCIENV, frame_reference(), array()); + HotSpotJVMCI::HotSpotStackFrameReference::set_objectsMaterialized(JVMCIENV, frame_reference(), JNI_FALSE); JavaValue result(T_OBJECT); JavaCallArguments args(visitor); args.push_oop(frame_reference); - call_interface(&result, SystemDictionary::InspectedFrameVisitor_klass(), vmSymbols::visitFrame_name(), vmSymbols::visitFrame_signature(), &args, CHECK_NULL); + call_interface(&result, HotSpotJVMCI::InspectedFrameVisitor::klass(), vmSymbols::visitFrame_name(), vmSymbols::visitFrame_signature(), &args, CHECK_NULL); if (result.get_jobject() != NULL) { return JNIHandles::make_local(thread, (oop) result.get_jobject()); } assert(initialSkip == 0, "There should be no match before initialSkip == 0"); - if (HotSpotStackFrameReference::objectsMaterialized(frame_reference) == JNI_TRUE) { + if (HotSpotJVMCI::HotSpotStackFrameReference::objectsMaterialized(JVMCIENV, frame_reference()) == JNI_TRUE) { // the frame has been deoptimized, we need to re-synchronize the frame and vframe - intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(frame_reference); + intptr_t* stack_pointer = (intptr_t*) HotSpotJVMCI::HotSpotStackFrameReference::stackPointer(JVMCIENV, frame_reference()); fst = StackFrameStream(thread); while (fst.current()->sp() != stack_pointer && !fst.is_done()) { fst.next(); @@ -1172,8 +1237,8 @@ assert(vf->is_compiled_frame(), "Wrong frame type"); } } - frame_reference = HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL); - HotSpotStackFrameReference::klass()->initialize(CHECK_NULL); + frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL); + HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL); } if (vf->is_top()) { @@ -1195,16 +1260,16 @@ return NULL; C2V_END -C2V_VMENTRY(void, resolveInvokeDynamicInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(void, resolveInvokeDynamicInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); CallInfo callInfo; LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokedynamic, CHECK); ConstantPoolCacheEntry* cp_cache_entry = cp->invokedynamic_cp_cache_entry_at(index); cp_cache_entry->set_dynamic_call(cp, callInfo); C2V_END -C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); Klass* holder = cp->klass_ref_at(index, CHECK); Symbol* name = cp->name_ref_at(index); if (MethodHandles::is_signature_polymorphic_name(holder, name)) { @@ -1215,8 +1280,8 @@ } C2V_END -C2V_VMENTRY(jint, isResolvedInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) - constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); +C2V_VMENTRY(jint, isResolvedInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool); ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); if (cp_cache_entry->is_resolved(Bytecodes::_invokehandle)) { // MethodHandle.invoke* --> LambdaForm? @@ -1256,16 +1321,16 @@ C2V_END -C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv*, jobject)) - objArrayHandle holders = oopFactory::new_objArray_handle(SystemDictionary::String_klass(), 2, CHECK_NULL); - Handle mh = java_lang_String::create_from_str("Ljava/lang/invoke/MethodHandle;", CHECK_NULL); - Handle vh = java_lang_String::create_from_str("Ljava/lang/invoke/VarHandle;", CHECK_NULL); - holders->obj_at_put(0, mh()); - holders->obj_at_put(1, vh()); - return JNIHandles::make_local(THREAD, holders()); +C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv* env, jobject)) + JVMCIObjectArray holders = JVMCIENV->new_String_array(2, JVMCI_CHECK_NULL); + JVMCIObject mh = JVMCIENV->create_string("Ljava/lang/invoke/MethodHandle;", JVMCI_CHECK_NULL); + JVMCIObject vh = JVMCIENV->create_string("Ljava/lang/invoke/VarHandle;", JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(holders, 0, mh); + JVMCIENV->put_object_at(holders, 1, vh); + return JVMCIENV->get_jobject(holders); C2V_END -C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject)) +C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv* env, jobject)) //see compute_recording_non_safepoints in debugInfroRec.cpp if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) { return true; @@ -1274,28 +1339,31 @@ C2V_END // public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); -C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate)) - ResourceMark rm; - - if (hs_frame == NULL) { - THROW_MSG(vmSymbols::java_lang_NullPointerException(), "stack frame is null") +C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_frame, bool invalidate)) + JVMCIObject hs_frame = JVMCIENV->wrap(_hs_frame); + if (hs_frame.is_null()) { + JVMCI_THROW_MSG(NullPointerException, "stack frame is null"); } - HotSpotStackFrameReference::klass()->initialize(CHECK); + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG(InternalError, "getNextStackFrame is only supported for HotSpot stack walking"); + } + + JVMCIENV->HotSpotStackFrameReference_initialize(JVMCI_CHECK); // look for the given stack frame StackFrameStream fst(thread); - intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + intptr_t* stack_pointer = (intptr_t*) JVMCIENV->get_HotSpotStackFrameReference_stackPointer(hs_frame); while (fst.current()->sp() != stack_pointer && !fst.is_done()) { fst.next(); } if (fst.current()->sp() != stack_pointer) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + JVMCI_THROW_MSG(IllegalStateException, "stack frame not found"); } if (invalidate) { if (!fst.current()->is_compiled_frame()) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + JVMCI_THROW_MSG(IllegalStateException, "compiled stack frame expected"); } assert(fst.current()->cb()->is_nmethod(), "nmethod expected"); ((nmethod*) fst.current()->cb())->make_not_entrant(); @@ -1307,12 +1375,12 @@ fstAfterDeopt.next(); } if (fstAfterDeopt.current()->sp() != stack_pointer) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found after deopt") + JVMCI_THROW_MSG(IllegalStateException, "stack frame not found after deopt"); } vframe* vf = vframe::new_vframe(fstAfterDeopt.current(), fstAfterDeopt.register_map(), thread); if (!vf->is_compiled_frame()) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + JVMCI_THROW_MSG(IllegalStateException, "compiled stack frame expected"); } GrowableArray* virtualFrames = new GrowableArray(10); @@ -1325,9 +1393,9 @@ vf = vf->sender(); } - int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + int last_frame_number = JVMCIENV->get_HotSpotStackFrameReference_frameNumber(hs_frame); if (last_frame_number >= virtualFrames->length()) { - THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + JVMCI_THROW_MSG(IllegalStateException, "invalid frame number"); } // Reallocate the non-escaping objects and restore their fields. @@ -1381,49 +1449,50 @@ } // all locals are materialized by now - HotSpotStackFrameReference::set_localIsVirtual(hs_frame, NULL); - + JVMCIENV->set_HotSpotStackFrameReference_localIsVirtual(hs_frame, NULL); // update the locals array - objArrayHandle array(THREAD, HotSpotStackFrameReference::locals(hs_frame)); + JVMCIObjectArray array = JVMCIENV->get_HotSpotStackFrameReference_locals(hs_frame); StackValueCollection* locals = virtualFrames->at(last_frame_number)->locals(); for (int i = 0; i < locals->size(); i++) { StackValue* var = locals->at(i); if (var->type() == T_OBJECT) { - array->obj_at_put(i, locals->at(i)->get_obj()()); + JVMCIENV->put_object_at(array, i, HotSpotJVMCI::wrap(locals->at(i)->get_obj()())); } } - HotSpotStackFrameReference::set_objectsMaterialized(hs_frame, JNI_TRUE); + HotSpotJVMCI::HotSpotStackFrameReference::set_objectsMaterialized(JVMCIENV, hs_frame, JNI_TRUE); C2V_END -C2V_VMENTRY(void, writeDebugOutput, (JNIEnv*, jobject, jbyteArray bytes, jint offset, jint length)) +C2V_VMENTRY(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length)) if (bytes == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); + JVMCI_THROW(NullPointerException); } - typeArrayOop array = (typeArrayOop) JNIHandles::resolve(bytes); + JVMCIPrimitiveArray array = JVMCIENV->wrap(bytes); // Check if offset and length are non negative. if (offset < 0 || length < 0) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + JVMCI_THROW(ArrayIndexOutOfBoundsException); } // Check if the range is valid. - if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array->length())) { - THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + int array_length = JVMCIENV->get_length(array); + if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array_length)) { + JVMCI_THROW(ArrayIndexOutOfBoundsException); } + jbyte buffer[O_BUFLEN]; while (length > 0) { - jbyte* start = array->byte_at_addr(offset); - tty->write((char*) start, MIN2(length, (jint)O_BUFLEN)); + int copy_len = MIN2(length, (jint)O_BUFLEN); + JVMCIENV->copy_bytes_to(array, buffer, offset, copy_len); + tty->write((char*) buffer, copy_len); length -= O_BUFLEN; offset += O_BUFLEN; } C2V_END -C2V_VMENTRY(void, flushDebugOutput, (JNIEnv*, jobject)) +C2V_VMENTRY(void, flushDebugOutput, (JNIEnv* env, jobject)) tty->flush(); C2V_END -C2V_VMENTRY(int, methodDataProfileDataSize, (JNIEnv*, jobject, jlong metaspace_method_data, jint position)) - ResourceMark rm; - MethodData* mdo = CompilerToVM::asMethodData(metaspace_method_data); +C2V_VMENTRY(int, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong metaspace_method_data, jint position)) + MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data); ProfileData* profile_data = mdo->data_at(position); if (mdo->is_valid(profile_data)) { return profile_data->size_in_bytes(); @@ -1437,48 +1506,115 @@ return profile_data->size_in_bytes(); } } - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid profile data position %d", position)); + JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Invalid profile data position %d", position)); C2V_END -C2V_VMENTRY(jlong, getFingerprint, (JNIEnv*, jobject, jlong metaspace_klass)) +C2V_VMENTRY(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass)) #if INCLUDE_AOT - Klass *k = CompilerToVM::asKlass(metaspace_klass); + Klass *k = (Klass*) (address) metaspace_klass; if (k->is_instance_klass()) { return InstanceKlass::cast(k)->get_stored_fingerprint(); } else { return 0; } #else - THROW_MSG_0(vmSymbols::java_lang_InternalError(), "unimplemented"); + JVMCI_THROW_MSG_0(InternalError, "unimplemented"); #endif C2V_END -C2V_VMENTRY(jobject, getHostClass, (JNIEnv*, jobject, jobject jvmci_type)) - InstanceKlass* k = InstanceKlass::cast(CompilerToVM::asKlass(jvmci_type)); +C2V_VMENTRY(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type)) + InstanceKlass* k = InstanceKlass::cast(JVMCIENV->asKlass(jvmci_type)); InstanceKlass* host = k->unsafe_anonymous_host(); JVMCIKlassHandle handle(THREAD, host); - oop result = CompilerToVM::get_jvmci_type(handle, CHECK_NULL); - return JNIHandles::make_local(THREAD, result); + JVMCIObject result = JVMCIENV->get_jvmci_type(handle, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +C2V_END + +C2V_VMENTRY(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type)) + if (jvmci_type == NULL) { + JVMCI_THROW_0(NullPointerException); + } + + Klass* klass = JVMCIENV->asKlass(jvmci_type); + if (klass == NULL) { + JVMCI_THROW_0(NullPointerException); + } + if (!klass->is_instance_klass()) { + JVMCI_THROW_MSG_0(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); + } + InstanceKlass* iklass = InstanceKlass::cast(klass); + + // Regular instance klass, fill in all local interfaces + int size = iklass->local_interfaces()->length(); + JVMCIObjectArray interfaces = JVMCIENV->new_HotSpotResolvedObjectTypeImpl_array(size, JVMCI_CHECK_NULL); + for (int index = 0; index < size; index++) { + JVMCIKlassHandle klass(THREAD); + Klass* k = iklass->local_interfaces()->at(index); + klass = k; + JVMCIObject type = JVMCIENV->get_jvmci_type(klass, JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(interfaces, index, type); + } + return JVMCIENV->get_jobject(interfaces); C2V_END -C2V_VMENTRY(int, interpreterFrameSize, (JNIEnv*, jobject, jobject bytecode_frame_handle)) - if (bytecode_frame_handle == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); +C2V_VMENTRY(jobject, getComponentType, (JNIEnv* env, jobject, jobject jvmci_type)) + if (jvmci_type == NULL) { + JVMCI_THROW_0(NullPointerException); + } + + Klass* klass = JVMCIENV->asKlass(jvmci_type); + oop mirror = klass->java_mirror(); + if (java_lang_Class::is_primitive(mirror) || + !java_lang_Class::as_Klass(mirror)->is_array_klass()) { + return NULL; } - oop top_bytecode_frame = JNIHandles::resolve_non_null(bytecode_frame_handle); - oop bytecode_frame = top_bytecode_frame; + oop component_mirror = java_lang_Class::component_mirror(mirror); + if (component_mirror == NULL) { + return NULL; + } + Klass* component_klass = java_lang_Class::as_Klass(component_mirror); + if (component_klass != NULL) { + JVMCIKlassHandle klass_handle(THREAD); + klass_handle = component_klass; + JVMCIObject result = JVMCIENV->get_jvmci_type(klass_handle, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); + } + BasicType type = java_lang_Class::primitive_type(component_mirror); + JVMCIObject result = JVMCIENV->get_jvmci_primitive_type(type); + return JVMCIENV->get_jobject(result); +C2V_END + +C2V_VMENTRY(void, ensureInitialized, (JNIEnv* env, jobject, jobject jvmci_type)) + if (jvmci_type == NULL) { + JVMCI_THROW(NullPointerException); + } + + Klass* klass = JVMCIENV->asKlass(jvmci_type); + if (klass != NULL && klass->should_be_initialized()) { + InstanceKlass* k = InstanceKlass::cast(klass); + k->initialize(CHECK); + } +C2V_END + +C2V_VMENTRY(int, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle)) + if (bytecode_frame_handle == NULL) { + JVMCI_THROW_0(NullPointerException); + } + + JVMCIObject top_bytecode_frame = JVMCIENV->wrap(bytecode_frame_handle); + JVMCIObject bytecode_frame = top_bytecode_frame; int size = 0; int callee_parameters = 0; int callee_locals = 0; - Method* method = getMethodFromHotSpotMethod(BytecodePosition::method(bytecode_frame)); - int extra_args = method->max_stack() - BytecodeFrame::numStack(bytecode_frame); + Method* method = JVMCIENV->asMethod(JVMCIENV->get_BytecodePosition_method(bytecode_frame)); + int extra_args = method->max_stack() - JVMCIENV->get_BytecodeFrame_numStack(bytecode_frame); - while (bytecode_frame != NULL) { - int locks = BytecodeFrame::numLocks(bytecode_frame); - int temps = BytecodeFrame::numStack(bytecode_frame); - bool is_top_frame = (bytecode_frame == top_bytecode_frame); - Method* method = getMethodFromHotSpotMethod(BytecodePosition::method(bytecode_frame)); + while (bytecode_frame.is_non_null()) { + int locks = JVMCIENV->get_BytecodeFrame_numLocks(bytecode_frame); + int temps = JVMCIENV->get_BytecodeFrame_numStack(bytecode_frame); + bool is_top_frame = (JVMCIENV->equals(bytecode_frame, top_bytecode_frame)); + Method* method = JVMCIENV->asMethod(JVMCIENV->get_BytecodePosition_method(bytecode_frame)); int frame_size = BytesPerWord * Interpreter::size_activation(method->max_stack(), temps + callee_parameters, @@ -1492,48 +1628,652 @@ callee_parameters = method->size_of_parameters(); callee_locals = method->max_locals(); extra_args = 0; - bytecode_frame = BytecodePosition::caller(bytecode_frame); + bytecode_frame = JVMCIENV->get_BytecodePosition_caller(bytecode_frame); } return size + Deoptimization::last_frame_adjust(0, callee_locals) * BytesPerWord; C2V_END -C2V_VMENTRY(void, compileToBytecode, (JNIEnv*, jobject, jobject lambda_form_handle)) - Handle lambda_form(THREAD, JNIHandles::resolve_non_null(lambda_form_handle)); +C2V_VMENTRY(void, compileToBytecode, (JNIEnv* env, jobject, jobject lambda_form_handle)) + Handle lambda_form = JVMCIENV->asConstant(JVMCIENV->wrap(lambda_form_handle), JVMCI_CHECK); if (lambda_form->is_a(SystemDictionary::LambdaForm_klass())) { TempNewSymbol compileToBytecode = SymbolTable::new_symbol("compileToBytecode", CHECK); JavaValue result(T_VOID); JavaCalls::call_special(&result, lambda_form, SystemDictionary::LambdaForm_klass(), compileToBytecode, vmSymbols::void_method_signature(), CHECK); } else { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Unexpected type: %s", lambda_form->klass()->external_name())); + JVMCI_THROW_MSG(IllegalArgumentException, + err_msg("Unexpected type: %s", lambda_form->klass()->external_name())) } C2V_END +C2V_VMENTRY(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object)) + Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0); + return obj->identity_hash(); +C2V_END + +C2V_VMENTRY(jboolean, isInternedString, (JNIEnv* env, jobject, jobject object)) + Handle str = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0); + if (!java_lang_String::is_instance(str())) { + return false; + } + int len; + jchar* name = java_lang_String::as_unicode_string(str(), len, CHECK_0); + return (StringTable::lookup(name, len) != NULL); +C2V_END + + +C2V_VMENTRY(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object)) + if (object == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle box = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); + BasicType type = java_lang_boxing_object::basic_type(box()); + jvalue result; + if (java_lang_boxing_object::get_value(box(), &result) == T_ILLEGAL) { + return NULL; + } + JVMCIObject boxResult = JVMCIENV->create_box(type, &result, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(boxResult); +C2V_END + +C2V_VMENTRY(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object)) + if (object == NULL) { + JVMCI_THROW_0(NullPointerException); + } + JVMCIObject box = JVMCIENV->wrap(object); + BasicType type = JVMCIENV->get_box_type(box); + if (type == T_ILLEGAL) { + return NULL; + } + jvalue value = JVMCIENV->get_boxed_value(type, box); + JavaValue box_result(T_OBJECT); + JavaCallArguments jargs; + Klass* box_klass = NULL; + Symbol* box_signature = NULL; +#define BOX_CASE(bt, v, argtype, name) \ + case bt: \ + jargs.push_##argtype(value.v); \ + box_klass = SystemDictionary::name##_klass(); \ + box_signature = vmSymbols::name##_valueOf_signature(); \ + break + + switch (type) { + BOX_CASE(T_BOOLEAN, z, int, Boolean); + BOX_CASE(T_BYTE, b, int, Byte); + BOX_CASE(T_CHAR, c, int, Character); + BOX_CASE(T_SHORT, s, int, Short); + BOX_CASE(T_INT, i, int, Integer); + BOX_CASE(T_LONG, j, long, Long); + BOX_CASE(T_FLOAT, f, float, Float); + BOX_CASE(T_DOUBLE, d, double, Double); + default: + ShouldNotReachHere(); + } +#undef BOX_CASE + + JavaCalls::call_static(&box_result, + box_klass, + vmSymbols::valueOf_name(), + box_signature, &jargs, CHECK_NULL); + oop hotspot_box = (oop) box_result.get_jobject(); + JVMCIObject result = JVMCIENV->get_object_constant(hotspot_box, false); + return JVMCIENV->get_jobject(result); +C2V_END + +C2V_VMENTRY(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, jobject holder)) + if (holder == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Klass* klass = JVMCIENV->asKlass(holder); + if (!klass->is_instance_klass()) { + JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobjectArray(methods); + } + + InstanceKlass* iklass = InstanceKlass::cast(klass); + // Ensure class is linked + iklass->link_class(CHECK_NULL); + + GrowableArray constructors_array; + for (int i = 0; i < iklass->methods()->length(); i++) { + Method* m = iklass->methods()->at(i); + if (m->is_initializer() && !m->is_static()) { + constructors_array.append(m); + } + } + JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(constructors_array.length(), JVMCI_CHECK_NULL); + for (int i = 0; i < constructors_array.length(); i++) { + JVMCIObject method = JVMCIENV->get_jvmci_method(constructors_array.at(i), JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(methods, i, method); + } + return JVMCIENV->get_jobjectArray(methods); +C2V_END + +C2V_VMENTRY(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobject holder)) + if (holder == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Klass* klass = JVMCIENV->asKlass(holder); + if (!klass->is_instance_klass()) { + JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobjectArray(methods); + } + + InstanceKlass* iklass = InstanceKlass::cast(klass); + // Ensure class is linked + iklass->link_class(CHECK_NULL); + + GrowableArray methods_array; + for (int i = 0; i < iklass->methods()->length(); i++) { + Method* m = iklass->methods()->at(i); + if (!m->is_initializer() && !m->is_overpass()) { + methods_array.append(m); + } + } + JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(methods_array.length(), JVMCI_CHECK_NULL); + for (int i = 0; i < methods_array.length(); i++) { + JVMCIObject method = JVMCIENV->get_jvmci_method(methods_array.at(i), JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(methods, i, method); + } + return JVMCIENV->get_jobjectArray(methods); +C2V_END + +C2V_VMENTRY(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject field, jboolean is_volatile)) + if (object == NULL || field == NULL) { + JVMCI_THROW_0(NullPointerException); + } + JVMCIObject field_object = JVMCIENV->wrap(field); + JVMCIObject java_type = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_type(field_object); + int modifiers = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_modifiers(field_object); + Klass* holder = JVMCIENV->asKlass(JVMCIENV->get_HotSpotResolvedJavaFieldImpl_holder(field_object)); + if (!holder->is_instance_klass()) { + JVMCI_THROW_MSG_0(InternalError, err_msg("Holder %s must be instance klass", holder->external_name())); + } + InstanceKlass* ik = InstanceKlass::cast(holder); + BasicType constant_type; + if (JVMCIENV->isa_HotSpotResolvedPrimitiveType(java_type)) { + constant_type = JVMCIENV->kindToBasicType(JVMCIENV->get_HotSpotResolvedPrimitiveType_kind(java_type), JVMCI_CHECK_NULL); + } else { + constant_type = T_OBJECT; + } + int displacement = JVMCIENV->get_HotSpotResolvedJavaFieldImpl_offset(field_object); + fieldDescriptor fd; + if (!ik->find_local_field_from_offset(displacement, (modifiers & JVM_ACC_STATIC) != 0, &fd)) { + JVMCI_THROW_MSG_0(InternalError, err_msg("Can't find field with displacement %d", displacement)); + } + JVMCIObject base = JVMCIENV->wrap(object); + Handle obj; + if (JVMCIENV->isa_HotSpotObjectConstantImpl(base)) { + obj = JVMCIENV->asConstant(base, JVMCI_CHECK_NULL); + } else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base)) { + Klass* klass = JVMCIENV->asKlass(base); + obj = Handle(THREAD, klass->java_mirror()); + } else { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + err_msg("Unexpected type: %s", JVMCIENV->klass_name(base))); + } + jlong value = 0; + JVMCIObject kind; + switch (constant_type) { + case T_OBJECT: { + oop object = is_volatile ? obj->obj_field_acquire(displacement) : obj->obj_field(displacement); + JVMCIObject result = JVMCIENV->get_object_constant(object); + if (result.is_null()) { + return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER()); + } + return JVMCIENV->get_jobject(result); + } + case T_FLOAT: { + float f = is_volatile ? obj->float_field_acquire(displacement) : obj->float_field(displacement); + JVMCIObject result = JVMCIENV->call_JavaConstant_forFloat(f, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); + } + case T_DOUBLE: { + double f = is_volatile ? obj->double_field_acquire(displacement) : obj->double_field(displacement); + JVMCIObject result = JVMCIENV->call_JavaConstant_forDouble(f, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); + } + case T_BOOLEAN: value = is_volatile ? obj->bool_field_acquire(displacement) : obj->bool_field(displacement); break; + case T_BYTE: value = is_volatile ? obj->byte_field_acquire(displacement) : obj->byte_field(displacement); break; + case T_SHORT: value = is_volatile ? obj->short_field_acquire(displacement) : obj->short_field(displacement); break; + case T_CHAR: value = is_volatile ? obj->char_field_acquire(displacement) : obj->char_field(displacement); break; + case T_INT: value = is_volatile ? obj->int_field_acquire(displacement) : obj->int_field(displacement); break; + case T_LONG: value = is_volatile ? obj->long_field_acquire(displacement) : obj->long_field(displacement); break; + default: + ShouldNotReachHere(); + } + JVMCIObject result = JVMCIENV->call_PrimitiveConstant_forTypeChar(type2char(constant_type), value, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +C2V_END + +C2V_VMENTRY(jboolean, isInstance, (JNIEnv* env, jobject, jobject holder, jobject object)) + if (object == NULL || holder == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0); + Klass* klass = JVMCIENV->asKlass(JVMCIENV->wrap(holder)); + return obj->is_a(klass); +C2V_END + +C2V_VMENTRY(jboolean, isAssignableFrom, (JNIEnv* env, jobject, jobject holder, jobject otherHolder)) + if (holder == NULL || otherHolder == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Klass* klass = JVMCIENV->asKlass(JVMCIENV->wrap(holder)); + Klass* otherKlass = JVMCIENV->asKlass(JVMCIENV->wrap(otherHolder)); + return otherKlass->is_subtype_of(klass); +C2V_END + +C2V_VMENTRY(jboolean, isTrustedForIntrinsics, (JNIEnv* env, jobject, jobject holder)) + if (holder == NULL) { + JVMCI_THROW_0(NullPointerException); + } + InstanceKlass* ik = InstanceKlass::cast(JVMCIENV->asKlass(JVMCIENV->wrap(holder))); + if (ik->class_loader_data()->is_builtin_class_loader_data()) { + return true; + } + return false; +C2V_END + +C2V_VMENTRY(jobject, asJavaType, (JNIEnv* env, jobject, jobject object)) + if (object == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); + if (java_lang_Class::is_instance(obj())) { + if (java_lang_Class::is_primitive(obj())) { + JVMCIObject type = JVMCIENV->get_jvmci_primitive_type(java_lang_Class::primitive_type(obj())); + return JVMCIENV->get_jobject(type); + } + Klass* klass = java_lang_Class::as_Klass(obj()); + JVMCIKlassHandle klass_handle(THREAD); + klass_handle = klass; + JVMCIObject type = JVMCIENV->get_jvmci_type(klass_handle, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(type); + } + return NULL; +C2V_END + + +C2V_VMENTRY(jobject, asString, (JNIEnv* env, jobject, jobject object)) + if (object == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); + const char* str = java_lang_String::as_utf8_string(obj()); + JVMCIObject result = JVMCIENV->create_string(str, JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(result); +C2V_END + + +C2V_VMENTRY(jboolean, equals, (JNIEnv* env, jobject, jobject x, jlong xHandle, jobject y, jlong yHandle)) + if (x == NULL || y == NULL) { + JVMCI_THROW_0(NullPointerException); + } + return JVMCIENV->resolve_handle(xHandle) == JVMCIENV->resolve_handle(yHandle); +C2V_END + +C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv* env, jobject, jobject object)) + if (object == NULL) { + JVMCI_THROW_0(NullPointerException); + } + JVMCIObject base_object = JVMCIENV->wrap(object); + Handle mirror; + if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base_object)) { + mirror = Handle(THREAD, JVMCIENV->asKlass(base_object)->java_mirror()); + } else if (JVMCIENV->isa_HotSpotResolvedPrimitiveType(base_object)) { + mirror = JVMCIENV->asConstant(JVMCIENV->get_HotSpotResolvedPrimitiveType_mirror(base_object), JVMCI_CHECK_NULL); + } else { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + err_msg("Unexpected type: %s", JVMCIENV->klass_name(base_object))); + } + JVMCIObject result = JVMCIENV->get_object_constant(mirror()); + return JVMCIENV->get_jobject(result); +C2V_END + + +C2V_VMENTRY(jint, getArrayLength, (JNIEnv* env, jobject, jobject x)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + if (xobj->klass()->is_array_klass()) { + return arrayOop(xobj())->length(); + } + return -1; + C2V_END + + +C2V_VMENTRY(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_NULL); + if (xobj->klass()->is_array_klass()) { + arrayOop array = arrayOop(xobj()); + BasicType element_type = ArrayKlass::cast(array->klass())->element_type(); + if (index < 0 || index >= array->length()) { + return NULL; + } + JVMCIObject result; + + if (element_type == T_OBJECT) { + result = JVMCIENV->get_object_constant(objArrayOop(xobj())->obj_at(index)); + if (result.is_null()) { + result = JVMCIENV->get_JavaConstant_NULL_POINTER(); + } + } else { + jvalue value; + switch (element_type) { + case T_DOUBLE: value.d = typeArrayOop(xobj())->double_at(index); break; + case T_FLOAT: value.f = typeArrayOop(xobj())->float_at(index); break; + case T_LONG: value.j = typeArrayOop(xobj())->long_at(index); break; + case T_INT: value.i = typeArrayOop(xobj())->int_at(index); break; + case T_SHORT: value.s = typeArrayOop(xobj())->short_at(index); break; + case T_CHAR: value.c = typeArrayOop(xobj())->char_at(index); break; + case T_BYTE: value.b = typeArrayOop(xobj())->byte_at(index); break; + case T_BOOLEAN: value.z = typeArrayOop(xobj())->byte_at(index) & 1; break; + default: ShouldNotReachHere(); + } + result = JVMCIENV->create_box(element_type, &value, JVMCI_CHECK_NULL); + } + assert(!result.is_null(), "must have a value"); + return JVMCIENV->get_jobject(result); + } + return NULL;; +C2V_END + + +C2V_VMENTRY(jint, arrayBaseOffset, (JNIEnv* env, jobject, jobject kind)) + if (kind == NULL) { + JVMCI_THROW_0(NullPointerException); + } + BasicType type = JVMCIENV->kindToBasicType(JVMCIENV->wrap(kind), JVMCI_CHECK_0); + return arrayOopDesc::header_size(type) * HeapWordSize; +C2V_END + +C2V_VMENTRY(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind)) + if (kind == NULL) { + JVMCI_THROW_0(NullPointerException); + } + BasicType type = JVMCIENV->kindToBasicType(JVMCIENV->wrap(kind), JVMCI_CHECK_0); + return type2aelembytes(type); +C2V_END + +C2V_VMENTRY(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + return xobj->byte_field(displacement); +} + +C2V_VMENTRY(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + return xobj->short_field(displacement); +} + +C2V_VMENTRY(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + return xobj->int_field(displacement); +} + +C2V_VMENTRY(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + return xobj->long_field(displacement); +} + +C2V_VMENTRY(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement)) + if (x == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + oop res = xobj->obj_field(displacement); + JVMCIObject result = JVMCIENV->get_object_constant(res); + return JVMCIENV->get_jobject(result); +} + +C2V_VMENTRY(void, deleteGlobalHandle, (JNIEnv* env, jobject, jlong h)) + jobject handle = (jobject)(address)h; + if (handle != NULL) { + assert(JVMCI::is_global_handle(handle), "Invalid delete of global JNI handle"); + *((oop*)handle) = NULL; // Mark the handle as deleted, allocate will reuse it + } +} + +C2V_VMENTRY(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror)) + if (!UseJVMCINativeLibrary) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is not enabled (requires -XX:+UseJVMCINativeLibrary)"); + } + if (!JVMCIENV->is_hotspot()) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "Cannot call registerNativeMethods from JVMCI shared library"); + } + void* shared_library = JVMCIEnv::get_shared_library_handle(); + if (shared_library == NULL) { + // Ensure the JVMCI shared library runtime is initialized. + JVMCIEnv __peer_jvmci_env__(false, __FILE__, __LINE__); + JVMCIEnv* peerEnv = &__peer_jvmci_env__; + HandleMark hm; + JVMCIRuntime* runtime = JVMCI::compiler_runtime(); + JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerEnv); + if (peerEnv->has_pending_exception()) { + peerEnv->describe_pending_exception(true); + JVMCI_THROW_MSG_0(InternalError, "Error initializing JVMCI runtime"); + } + shared_library = JVMCIEnv::get_shared_library_handle(); + } + + if (shared_library == NULL) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is unavailable"); + } + + if (mirror == NULL) { + JVMCI_THROW_0(NullPointerException); + } + Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve(mirror)); + if (klass == NULL || !klass->is_instance_klass()) { + JVMCI_THROW_MSG_0(IllegalArgumentException, "clazz is for primitive type"); + } + + InstanceKlass* iklass = InstanceKlass::cast(klass); + for (int i = 0; i < iklass->methods()->length(); i++) { + Method* method = iklass->methods()->at(i); + if (method->is_native()) { + + // Compute argument size + int args_size = 1 // JNIEnv + + (method->is_static() ? 1 : 0) // class for static methods + + method->size_of_parameters(); // actual parameters + + // 1) Try JNI short style + stringStream st; + char* pure_name = NativeLookup::pure_jni_name(method); + os::print_jni_name_prefix_on(&st, args_size); + st.print_raw(pure_name); + os::print_jni_name_suffix_on(&st, args_size); + char* jni_name = st.as_string(); + + address entry = (address) os::dll_lookup(shared_library, jni_name); + if (entry == NULL) { + // 2) Try JNI long style + st.reset(); + char* long_name = NativeLookup::long_jni_name(method); + os::print_jni_name_prefix_on(&st, args_size); + st.print_raw(pure_name); + st.print_raw(long_name); + os::print_jni_name_suffix_on(&st, args_size); + jni_name = st.as_string(); + entry = (address) os::dll_lookup(shared_library, jni_name); + } + if (entry == NULL) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, method->name_and_sig_as_C_string()); + } + if (method->has_native_function() && entry != method->native_function()) { + JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("Cannot overwrite existing native implementation for %s", + method->name_and_sig_as_C_string())); + } + method->set_native_function(entry, Method::native_bind_event_is_interesting); + if (PrintJNIResolving) { + tty->print_cr("[Dynamic-linking native method %s.%s ... JNI]", + method->method_holder()->external_name(), + method->name()->as_C_string()); + } + } + } + + JavaVM* javaVM = JVMCIEnv::get_shared_library_javavm(); + JVMCIPrimitiveArray result = JVMCIENV->new_longArray(4, JVMCI_CHECK_NULL); + JVMCIENV->put_long_at(result, 0, (jlong) (address) javaVM); + JVMCIENV->put_long_at(result, 1, (jlong) (address) javaVM->functions->reserved0); + JVMCIENV->put_long_at(result, 2, (jlong) (address) javaVM->functions->reserved1); + JVMCIENV->put_long_at(result, 3, (jlong) (address) javaVM->functions->reserved2); + return (jlongArray) JVMCIENV->get_jobject(result); +} + +C2V_VMENTRY(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle)) + if (obj_handle == NULL) { + return 0L; + } + JVMCIEnv __peer_jvmci_env__(!JVMCIENV->is_hotspot(), __FILE__, __LINE__); + JVMCIEnv* peerEnv = &__peer_jvmci_env__; + JVMCIEnv* thisEnv = JVMCIENV; + + JVMCIObject obj = thisEnv->wrap(obj_handle); + JVMCIObject result; + if (thisEnv->isa_HotSpotResolvedJavaMethodImpl(obj)) { + Method* method = thisEnv->asMethod(obj); + result = peerEnv->get_jvmci_method(method, JVMCI_CHECK_0); + } else if (thisEnv->isa_HotSpotResolvedObjectTypeImpl(obj)) { + Klass* klass = thisEnv->asKlass(obj); + JVMCIKlassHandle klass_handle(THREAD); + klass_handle = klass; + result = peerEnv->get_jvmci_type(klass_handle, JVMCI_CHECK_0); + } else if (thisEnv->isa_HotSpotResolvedPrimitiveType(obj)) { + BasicType type = JVMCIENV->kindToBasicType(JVMCIENV->get_HotSpotResolvedPrimitiveType_kind(obj), JVMCI_CHECK_0); + result = peerEnv->get_jvmci_primitive_type(type); + } else if (thisEnv->isa_IndirectHotSpotObjectConstantImpl(obj) || + thisEnv->isa_DirectHotSpotObjectConstantImpl(obj)) { + Handle constant = thisEnv->asConstant(obj, JVMCI_CHECK_0); + result = peerEnv->get_object_constant(constant()); + } else if (thisEnv->isa_HotSpotNmethod(obj)) { + nmethod* nm = thisEnv->asNmethod(obj); + if (nm != NULL) { + JVMCINMethodData* data = nm->jvmci_nmethod_data(); + if (data != NULL) { + if (peerEnv->is_hotspot()) { + // Only the mirror in the HotSpot heap is accessible + // through JVMCINMethodData + oop nmethod_mirror = data->get_nmethod_mirror(nm); + if (nmethod_mirror != NULL) { + result = HotSpotJVMCI::wrap(nmethod_mirror); + } + } + } + } + if (result.is_null()) { + JVMCIObject methodObject = thisEnv->get_HotSpotNmethod_method(obj); + methodHandle mh = thisEnv->asMethod(methodObject); + jboolean isDefault = thisEnv->get_HotSpotNmethod_isDefault(obj); + jlong compileIdSnapshot = thisEnv->get_HotSpotNmethod_compileIdSnapshot(obj); + JVMCIObject name_string = thisEnv->get_InstalledCode_name(obj); + const char* cstring = name_string.is_null() ? NULL : thisEnv->as_utf8_string(name_string); + // Create a new HotSpotNmethod instance in the peer runtime + result = peerEnv->new_HotSpotNmethod(mh(), cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0); + if (nm == NULL) { + // nmethod must have been unloaded + } else { + // Link the new HotSpotNmethod to the nmethod + peerEnv->initialize_installed_code(result, nm, JVMCI_CHECK_0); + // Only HotSpotNmethod instances in the HotSpot heap are tracked directly by the runtime. + if (peerEnv->is_hotspot()) { + JVMCINMethodData* data = nm->jvmci_nmethod_data(); + if (data == NULL) { + JVMCI_THROW_MSG_0(IllegalArgumentException, "Cannot set HotSpotNmethod mirror for default nmethod"); + } + if (data->get_nmethod_mirror(nm) != NULL) { + JVMCI_THROW_MSG_0(IllegalArgumentException, "Cannot overwrite existing HotSpotNmethod mirror for nmethod"); + } + oop nmethod_mirror = HotSpotJVMCI::resolve(result); + data->set_nmethod_mirror(nm, nmethod_mirror); + } + } + } + } else { + JVMCI_THROW_MSG_0(IllegalArgumentException, + err_msg("Cannot translate object of type: %s", thisEnv->klass_name(obj))); + } + return (jlong) peerEnv->make_global(result).as_jobject(); +} + +C2V_VMENTRY(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) + if (obj_handle == 0L) { + return NULL; + } + jobject global_handle = (jobject) obj_handle; + JVMCIObject global_handle_obj = JVMCIENV->wrap((jobject) obj_handle); + jobject result = JVMCIENV->make_local(global_handle_obj).as_jobject(); + + JVMCIENV->destroy_global(global_handle_obj); + return result; +} + +C2V_VMENTRY(void, updateHotSpotNmethod, (JNIEnv* env, jobject, jobject code_handle)) + JVMCIObject code = JVMCIENV->wrap(code_handle); + // Execute this operation for the side effect of updating the InstalledCode state + JVMCIENV->asNmethod(code); +} + +C2V_VMENTRY(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle)) + JVMCIObject code = JVMCIENV->wrap(code_handle); + CodeBlob* cb = JVMCIENV->asCodeBlob(code); + if (cb == NULL) { + return NULL; + } + int code_size = cb->code_size(); + JVMCIPrimitiveArray result = JVMCIENV->new_byteArray(code_size, JVMCI_CHECK_NULL); + JVMCIENV->copy_bytes_from((jbyte*) cb->code_begin(), result, 0, code_size); + return JVMCIENV->get_jbyteArray(result); +} + C2V_VMENTRY(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method)) - methodHandle m = CompilerToVM::asMethod(jvmci_method); + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); + } + methodHandle m = JVMCIENV->asMethod(jvmci_method); oop executable; if (m->is_initializer()) { if (m->is_static_initializer()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Cannot create java.lang.reflect.Method for class initializer"); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, + "Cannot create java.lang.reflect.Method for class initializer"); } executable = Reflection::new_constructor(m, CHECK_NULL); } else { executable = Reflection::new_method(m, false, CHECK_NULL); } - return JNIHandles::make_local(thread, executable); + return JNIHandles::make_local(THREAD, executable); } C2V_VMENTRY(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index)) - Klass* klass = CompilerToVM::asKlass(jvmci_type); + if (env != JavaThread::current()->jni_environment()) { + JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot"); + } + Klass* klass = JVMCIENV->asKlass(jvmci_type); if (!klass->is_instance_klass()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Expected non-primitive type, got %s", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); Array* fields = iklass->fields(); - if (index < 0 || index > fields->length()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + if (index < 0 ||index > fields->length()) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Field index %d out of bounds for %s", index, klass->external_name())); } fieldDescriptor fd(iklass, index); @@ -1541,27 +2281,90 @@ return JNIHandles::make_local(env, reflected); } +C2V_VMENTRY(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current)) + FailedSpeculation* head = *((FailedSpeculation**)(address) failed_speculations_address); + int result_length = 0; + for (FailedSpeculation* fs = head; fs != NULL; fs = fs->next()) { + result_length++; + } + int current_length = 0; + JVMCIObjectArray current_array = NULL; + if (current != NULL) { + current_array = JVMCIENV->wrap(current); + current_length = JVMCIENV->get_length(current_array); + if (current_length == result_length) { + // No new failures + return current; + } + } + JVMCIObjectArray result = JVMCIENV->new_byte_array_array(result_length, JVMCI_CHECK_NULL); + int result_index = 0; + for (FailedSpeculation* fs = head; result_index < result_length; fs = fs->next()) { + assert(fs != NULL, "npe"); + JVMCIPrimitiveArray entry; + if (result_index < current_length) { + entry = (JVMCIPrimitiveArray) JVMCIENV->get_object_at(current_array, result_index); + } else { + entry = JVMCIENV->new_byteArray(fs->data_len(), JVMCI_CHECK_NULL); + JVMCIENV->copy_bytes_from((jbyte*) fs->data(), entry, 0, fs->data_len()); + } + JVMCIENV->put_object_at(result, result_index++, entry); + } + return JVMCIENV->get_jobjectArray(result); +} + +C2V_VMENTRY(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method)) + methodHandle method = JVMCIENV->asMethod(jvmci_method); + MethodData* method_data = method->method_data(); + if (method_data == NULL) { + ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); + method_data = MethodData::allocate(loader_data, method, CHECK_0); + method->set_method_data(method_data); + } + return (jlong) method_data->get_failed_speculations_address(); +} + +C2V_VMENTRY(void, releaseFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address)) + FailedSpeculation::free_failed_speculations((FailedSpeculation**)(address) failed_speculations_address); +} + +C2V_VMENTRY(bool, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj)) + JVMCIPrimitiveArray speculation_handle = JVMCIENV->wrap(speculation_obj); + int speculation_len = JVMCIENV->get_length(speculation_handle); + char* speculation = NEW_RESOURCE_ARRAY(char, speculation_len); + JVMCIENV->copy_bytes_to(speculation_handle, (jbyte*) speculation, 0, speculation_len); + return FailedSpeculation::add_failed_speculation(NULL, (FailedSpeculation**)(address) failed_speculations_address, (address) speculation, speculation_len); +} + #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) #define STRING "Ljava/lang/String;" #define OBJECT "Ljava/lang/Object;" #define CLASS "Ljava/lang/Class;" +#define OBJECTCONSTANT "Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;" +#define HANDLECONSTANT "Ljdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl;" #define EXECUTABLE "Ljava/lang/reflect/Executable;" #define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" #define INSTALLED_CODE "Ljdk/vm/ci/code/InstalledCode;" #define TARGET_DESCRIPTION "Ljdk/vm/ci/code/TargetDescription;" #define BYTECODE_FRAME "Ljdk/vm/ci/code/BytecodeFrame;" +#define JAVACONSTANT "Ljdk/vm/ci/meta/JavaConstant;" #define INSPECTED_FRAME_VISITOR "Ljdk/vm/ci/code/stack/InspectedFrameVisitor;" #define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" #define HS_RESOLVED_METHOD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;" #define HS_RESOLVED_KLASS "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;" +#define HS_RESOLVED_TYPE "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaType;" +#define HS_RESOLVED_FIELD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaField;" +#define HS_INSTALLED_CODE "Ljdk/vm/ci/hotspot/HotSpotInstalledCode;" +#define HS_NMETHOD "Ljdk/vm/ci/hotspot/HotSpotNmethod;" #define HS_CONSTANT_POOL "Ljdk/vm/ci/hotspot/HotSpotConstantPool;" #define HS_COMPILED_CODE "Ljdk/vm/ci/hotspot/HotSpotCompiledCode;" #define HS_CONFIG "Ljdk/vm/ci/hotspot/HotSpotVMConfig;" #define HS_METADATA "Ljdk/vm/ci/hotspot/HotSpotMetaData;" #define HS_STACK_FRAME_REF "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;" #define HS_SPECULATION_LOG "Ljdk/vm/ci/hotspot/HotSpotSpeculationLog;" +#define METASPACE_OBJECT "Ljdk/vm/ci/hotspot/MetaspaceObject;" #define REFLECTION_EXECUTABLE "Ljava/lang/reflect/Executable;" #define REFLECTION_FIELD "Ljava/lang/reflect/Field;" #define METASPACE_METHOD_DATA "J" @@ -1578,17 +2381,18 @@ {CC "isCompilable", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(isCompilable)}, {CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)}, - {CC "lookupType", CC "(" STRING CLASS "Z)" HS_RESOLVED_KLASS, FN_PTR(lookupType)}, + {CC "lookupType", CC "(" STRING HS_RESOLVED_KLASS "Z)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, + {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)}, {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, {CC "lookupSignatureInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupSignatureInPool)}, {CC "lookupKlassRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupKlassRefIndexInPool)}, {CC "lookupKlassInPool", CC "(" HS_CONSTANT_POOL "I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, - {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC "lookupAppendixInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(lookupAppendixInPool)}, {CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL "IB)" HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, {CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, - {CC "resolveConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolveConstantInPool)}, - {CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC "resolveConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(resolveConstantInPool)}, + {CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECTCONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)}, {CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, {CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[I)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, {CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)}, @@ -1601,20 +2405,21 @@ {CC "hasFinalizableSubclass", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(hasFinalizableSubclass)}, {CC "getMaxCallTargetOffset", CC "(J)J", FN_PTR(getMaxCallTargetOffset)}, {CC "asResolvedJavaMethod", CC "(" EXECUTABLE ")" HS_RESOLVED_METHOD, FN_PTR(asResolvedJavaMethod)}, - {CC "getResolvedJavaMethod", CC "(Ljava/lang/Object;J)" HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, - {CC "getConstantPool", CC "(Ljava/lang/Object;)" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, - {CC "getResolvedJavaType", CC "(Ljava/lang/Object;JZ)" HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, + {CC "getResolvedJavaMethod", CC "(" OBJECTCONSTANT "J)" HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC "getConstantPool", CC "(" METASPACE_OBJECT ")" HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC "getResolvedJavaType0", CC "(Ljava/lang/Object;JZ)" HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType0)}, {CC "readConfiguration", CC "()[" OBJECT, FN_PTR(readConfiguration)}, - {CC "installCode", CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE HS_SPECULATION_LOG ")I", FN_PTR(installCode)}, + {CC "installCode", CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE "J[B)I", FN_PTR(installCode)}, {CC "getMetadata", CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA ")I", FN_PTR(getMetadata)}, {CC "resetCompilationStatistics", CC "()V", FN_PTR(resetCompilationStatistics)}, {CC "disassembleCodeBlob", CC "(" INSTALLED_CODE ")" STRING, FN_PTR(disassembleCodeBlob)}, - {CC "executeInstalledCode", CC "([" OBJECT INSTALLED_CODE ")" OBJECT, FN_PTR(executeInstalledCode)}, + {CC "executeHotSpotNmethod", CC "([" OBJECT HS_NMETHOD ")" OBJECT, FN_PTR(executeHotSpotNmethod)}, {CC "getLineNumberTable", CC "(" HS_RESOLVED_METHOD ")[J", FN_PTR(getLineNumberTable)}, {CC "getLocalVariableTableStart", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getLocalVariableTableStart)}, {CC "getLocalVariableTableLength", CC "(" HS_RESOLVED_METHOD ")I", FN_PTR(getLocalVariableTableLength)}, {CC "reprofile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(reprofile)}, - {CC "invalidateInstalledCode", CC "(" INSTALLED_CODE ")V", FN_PTR(invalidateInstalledCode)}, + {CC "invalidateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(invalidateHotSpotNmethod)}, + {CC "readUncompressedOop", CC "(J)" OBJECTCONSTANT, FN_PTR(readUncompressedOop)}, {CC "collectCounters", CC "()[J", FN_PTR(collectCounters)}, {CC "allocateCompileId", CC "(" HS_RESOLVED_METHOD "I)I", FN_PTR(allocateCompileId)}, {CC "isMature", CC "(" METASPACE_METHOD_DATA ")Z", FN_PTR(isMature)}, @@ -1629,10 +2434,48 @@ {CC "getFingerprint", CC "(J)J", FN_PTR(getFingerprint)}, {CC "getHostClass", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_KLASS, FN_PTR(getHostClass)}, {CC "interpreterFrameSize", CC "(" BYTECODE_FRAME ")I", FN_PTR(interpreterFrameSize)}, - {CC "compileToBytecode", CC "(" OBJECT ")V", FN_PTR(compileToBytecode)}, + {CC "compileToBytecode", CC "(" OBJECTCONSTANT ")V", FN_PTR(compileToBytecode)}, {CC "getFlagValue", CC "(" STRING ")" OBJECT, FN_PTR(getFlagValue)}, + {CC "getObjectAtAddress", CC "(J)" OBJECT, FN_PTR(getObjectAtAddress)}, + {CC "getInterfaces", CC "(" HS_RESOLVED_KLASS ")[" HS_RESOLVED_KLASS, FN_PTR(getInterfaces)}, + {CC "getComponentType", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_TYPE, FN_PTR(getComponentType)}, + {CC "ensureInitialized", CC "(" HS_RESOLVED_KLASS ")V", FN_PTR(ensureInitialized)}, + {CC "getIdentityHashCode", CC "(" OBJECTCONSTANT ")I", FN_PTR(getIdentityHashCode)}, + {CC "isInternedString", CC "(" OBJECTCONSTANT ")Z", FN_PTR(isInternedString)}, + {CC "unboxPrimitive", CC "(" OBJECTCONSTANT ")" OBJECT, FN_PTR(unboxPrimitive)}, + {CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)}, + {CC "getDeclaredConstructors", CC "(" HS_RESOLVED_KLASS ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)}, + {CC "getDeclaredMethods", CC "(" HS_RESOLVED_KLASS ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)}, + {CC "readFieldValue", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_FIELD "Z)" JAVACONSTANT, FN_PTR(readFieldValue)}, + {CC "readFieldValue", CC "(" OBJECTCONSTANT HS_RESOLVED_FIELD "Z)" JAVACONSTANT, FN_PTR(readFieldValue)}, + {CC "isInstance", CC "(" HS_RESOLVED_KLASS OBJECTCONSTANT ")Z", FN_PTR(isInstance)}, + {CC "isAssignableFrom", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_KLASS ")Z", FN_PTR(isAssignableFrom)}, + {CC "isTrustedForIntrinsics", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(isTrustedForIntrinsics)}, + {CC "asJavaType", CC "(" OBJECTCONSTANT ")" HS_RESOLVED_TYPE, FN_PTR(asJavaType)}, + {CC "asString", CC "(" OBJECTCONSTANT ")" STRING, FN_PTR(asString)}, + {CC "equals", CC "(" OBJECTCONSTANT "J" OBJECTCONSTANT "J)Z", FN_PTR(equals)}, + {CC "getJavaMirror", CC "(" HS_RESOLVED_TYPE ")" OBJECTCONSTANT, FN_PTR(getJavaMirror)}, + {CC "getArrayLength", CC "(" OBJECTCONSTANT ")I", FN_PTR(getArrayLength)}, + {CC "readArrayElement", CC "(" OBJECTCONSTANT "I)Ljava/lang/Object;", FN_PTR(readArrayElement)}, + {CC "arrayBaseOffset", CC "(Ljdk/vm/ci/meta/JavaKind;)I", FN_PTR(arrayBaseOffset)}, + {CC "arrayIndexScale", CC "(Ljdk/vm/ci/meta/JavaKind;)I", FN_PTR(arrayIndexScale)}, + {CC "getByte", CC "(" OBJECTCONSTANT "J)B", FN_PTR(getByte)}, + {CC "getShort", CC "(" OBJECTCONSTANT "J)S", FN_PTR(getShort)}, + {CC "getInt", CC "(" OBJECTCONSTANT "J)I", FN_PTR(getInt)}, + {CC "getLong", CC "(" OBJECTCONSTANT "J)J", FN_PTR(getLong)}, + {CC "getObject", CC "(" OBJECTCONSTANT "J)" OBJECTCONSTANT, FN_PTR(getObject)}, + {CC "deleteGlobalHandle", CC "(J)V", FN_PTR(deleteGlobalHandle)}, + {CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)}, + {CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)}, + {CC "unhand", CC "(J)" OBJECT, FN_PTR(unhand)}, + {CC "updateHotSpotNmethod", CC "(" HS_NMETHOD ")V", FN_PTR(updateHotSpotNmethod)}, + {CC "getCode", CC "(" HS_INSTALLED_CODE ")[B", FN_PTR(getCode)}, {CC "asReflectionExecutable", CC "(" HS_RESOLVED_METHOD ")" REFLECTION_EXECUTABLE, FN_PTR(asReflectionExecutable)}, {CC "asReflectionField", CC "(" HS_RESOLVED_KLASS "I)" REFLECTION_FIELD, FN_PTR(asReflectionField)}, + {CC "getFailedSpeculations", CC "(J[[B)[[B", FN_PTR(getFailedSpeculations)}, + {CC "getFailedSpeculationsAddress", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getFailedSpeculationsAddress)}, + {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, + {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, }; int CompilerToVM::methods_count() { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCompilerToVM.hpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Wed May 01 12:31:29 2019 -0700 @@ -24,40 +24,12 @@ #ifndef SHARE_JVMCI_JVMCICOMPILERTOVM_HPP #define SHARE_JVMCI_JVMCICOMPILERTOVM_HPP -#include "jni.h" +#include "gc/shared/cardTable.hpp" +#include "jvmci/jvmciExceptions.hpp" #include "runtime/javaCalls.hpp" -#include "jvmci/jvmciJavaClasses.hpp" - -// Helper class to ensure that references to Klass* are kept alive for G1 -class JVMCIKlassHandle : public StackObj { - private: - Klass* _klass; - Handle _holder; - Thread* _thread; - - Klass* klass() const { return _klass; } - Klass* non_null_klass() const { assert(_klass != NULL, "resolving NULL _klass"); return _klass; } +#include "runtime/signature.hpp" - public: - /* Constructors */ - JVMCIKlassHandle (Thread* thread) : _klass(NULL), _thread(thread) {} - JVMCIKlassHandle (Thread* thread, Klass* klass); - - JVMCIKlassHandle (const JVMCIKlassHandle &h): _klass(h._klass), _holder(h._holder), _thread(h._thread) {} - JVMCIKlassHandle& operator=(const JVMCIKlassHandle &s); - JVMCIKlassHandle& operator=(Klass* klass); - - /* Operators for ease of use */ - Klass* operator () () const { return klass(); } - Klass* operator -> () const { return non_null_klass(); } - - bool operator == (Klass* o) const { return klass() == o; } - bool operator == (const JVMCIKlassHandle& h) const { return klass() == h.klass(); } - - /* Null checks */ - bool is_null() const { return _klass == NULL; } - bool not_null() const { return _klass != NULL; } -}; +class JVMCIObjectArray; class CompilerToVM { public: @@ -118,7 +90,7 @@ static address symbol_clinit; public: - static void initialize(TRAPS); + static void initialize(JVMCI_TRAPS); static int max_oop_map_stack_offset() { assert(_max_oop_map_stack_offset > 0, "must be initialized"); @@ -141,59 +113,14 @@ } static JNINativeMethod methods[]; + static JNINativeMethod jni_methods[]; - static objArrayHandle initialize_intrinsics(TRAPS); + static JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS); public: static int methods_count(); - static inline Method* asMethod(jobject jvmci_method) { - return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); - } - - static inline Method* asMethod(Handle jvmci_method) { - return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); - } - - static inline Method* asMethod(oop jvmci_method) { - return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); - } - - static inline ConstantPool* asConstantPool(jobject jvmci_constant_pool) { - return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); - } - - static inline ConstantPool* asConstantPool(Handle jvmci_constant_pool) { - return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); - } - - static inline ConstantPool* asConstantPool(oop jvmci_constant_pool) { - return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); - } +}; - static inline Klass* asKlass(jobject jvmci_type) { - return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); - } - - static inline Klass* asKlass(Handle jvmci_type) { - return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); - } - - static inline Klass* asKlass(oop jvmci_type) { - return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); - } - - static inline Klass* asKlass(jlong metaspaceKlass) { - return (Klass*) (address) metaspaceKlass; - } - - static inline MethodData* asMethodData(jlong metaspaceMethodData) { - return (MethodData*) (address) metaspaceMethodData; - } - - static oop get_jvmci_method(const methodHandle& method, TRAPS); - - static oop get_jvmci_type(JVMCIKlassHandle& klass, TRAPS); -}; class JavaArgumentUnboxer : public SignatureIterator { protected: diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,10 @@ #include "ci/ciUtilities.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTable.hpp" -#include "memory/oopFactory.hpp" -#include "oops/objArrayOop.inline.hpp" -#include "jvmci/jvmciRuntime.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciCompilerToVM.hpp" #include "jvmci/vmStructs_jvmci.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" @@ -88,7 +85,7 @@ address CompilerToVM::Data::symbol_init; address CompilerToVM::Data::symbol_clinit; -void CompilerToVM::Data::initialize(TRAPS) { +void CompilerToVM::Data::initialize(JVMCI_TRAPS) { Klass_vtable_start_offset = in_bytes(Klass::vtable_start_offset()); Klass_vtable_length_offset = in_bytes(Klass::vtable_length_offset()); @@ -157,29 +154,23 @@ #undef SET_TRIGFUNC } -objArrayHandle CompilerToVM::initialize_intrinsics(TRAPS) { - objArrayHandle vmIntrinsics = oopFactory::new_objArray_handle(VMIntrinsicMethod::klass(), (vmIntrinsics::ID_LIMIT - 1), CHECK_(objArrayHandle())); +JVMCIObjectArray CompilerToVM::initialize_intrinsics(JVMCI_TRAPS) { + JVMCIObjectArray vmIntrinsics = JVMCIENV->new_VMIntrinsicMethod_array(vmIntrinsics::ID_LIMIT - 1, JVMCI_CHECK_NULL); int index = 0; - // The intrinsics for a class are usually adjacent to each other. - // When they are, the string for the class name can be reused. vmSymbols::SID kls_sid = vmSymbols::NO_SID; - Handle kls_str; + JVMCIObject kls_str; #define VM_SYMBOL_TO_STRING(s) \ - java_lang_String::create_from_symbol(vmSymbols::symbol_at(vmSymbols::VM_SYMBOL_ENUM_NAME(s)), CHECK_(objArrayHandle())) + JVMCIENV->create_string(vmSymbols::symbol_at(vmSymbols::VM_SYMBOL_ENUM_NAME(s)), JVMCI_CHECK_NULL) #define VM_INTRINSIC_INFO(id, kls, name, sig, ignore_fcode) { \ - instanceHandle vmIntrinsicMethod = InstanceKlass::cast(VMIntrinsicMethod::klass())->allocate_instance_handle(CHECK_(objArrayHandle())); \ vmSymbols::SID sid = vmSymbols::VM_SYMBOL_ENUM_NAME(kls); \ if (kls_sid != sid) { \ kls_str = VM_SYMBOL_TO_STRING(kls); \ kls_sid = sid; \ } \ - Handle name_str = VM_SYMBOL_TO_STRING(name); \ - Handle sig_str = VM_SYMBOL_TO_STRING(sig); \ - VMIntrinsicMethod::set_declaringClass(vmIntrinsicMethod, kls_str()); \ - VMIntrinsicMethod::set_name(vmIntrinsicMethod, name_str()); \ - VMIntrinsicMethod::set_descriptor(vmIntrinsicMethod, sig_str()); \ - VMIntrinsicMethod::set_id(vmIntrinsicMethod, vmIntrinsics::id); \ - vmIntrinsics->obj_at_put(index++, vmIntrinsicMethod()); \ + JVMCIObject name_str = VM_SYMBOL_TO_STRING(name); \ + JVMCIObject sig_str = VM_SYMBOL_TO_STRING(sig); \ + JVMCIObject vmIntrinsicMethod = JVMCIENV->new_VMIntrinsicMethod(kls_str, name_str, sig_str, (jint) vmIntrinsics::id, JVMCI_CHECK_NULL); \ + JVMCIENV->put_object_at(vmIntrinsics, index++, vmIntrinsicMethod); \ } VM_INTRINSICS_DO(VM_INTRINSIC_INFO, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) @@ -190,9 +181,6 @@ return vmIntrinsics; } -/** - * The set of VM flags known to be used. - */ #define PREDEFINED_CONFIG_FLAGS(do_bool_flag, do_intx_flag, do_uintx_flag) \ do_intx_flag(AllocateInstancePrefetchLines) \ do_intx_flag(AllocatePrefetchDistance) \ @@ -258,30 +246,28 @@ do_bool_flag(UseTLAB) \ do_bool_flag(VerifyOops) \ -#define BOXED_BOOLEAN(name, value) oop name = ((jboolean)(value) ? boxedTrue() : boxedFalse()) -#define BOXED_DOUBLE(name, value) oop name; do { jvalue p; p.d = (jdouble) (value); name = java_lang_boxing_object::create(T_DOUBLE, &p, CHECK_NULL);} while(0) +#define BOXED_BOOLEAN(name, value) name = ((jboolean)(value) ? boxedTrue : boxedFalse) +#define BOXED_DOUBLE(name, value) do { jvalue p; p.d = (jdouble) (value); name = JVMCIENV->create_box(T_DOUBLE, &p, JVMCI_CHECK_NULL);} while(0) #define BOXED_LONG(name, value) \ - oop name; \ do { \ jvalue p; p.j = (jlong) (value); \ - Handle* e = longs.get(p.j); \ + JVMCIObject* e = longs.get(p.j); \ if (e == NULL) { \ - oop o = java_lang_boxing_object::create(T_LONG, &p, CHECK_NULL); \ - Handle h(THREAD, o); \ + JVMCIObject h = JVMCIENV->create_box(T_LONG, &p, JVMCI_CHECK_NULL); \ longs.put(p.j, h); \ - name = h(); \ + name = h; \ } else { \ - name = (*e)(); \ + name = (*e); \ } \ } while (0) #define CSTRING_TO_JSTRING(name, value) \ - Handle name; \ + JVMCIObject name; \ do { \ if (value != NULL) { \ - Handle* e = strings.get(value); \ + JVMCIObject* e = strings.get(value); \ if (e == NULL) { \ - Handle h = java_lang_String::create_from_str(value, CHECK_NULL); \ + JVMCIObject h = JVMCIENV->create_string(value, JVMCI_CHECK_NULL); \ strings.put(value, h); \ name = h; \ } else { \ @@ -290,51 +276,42 @@ } \ } while (0) -jobjectArray readConfiguration0(JNIEnv *env, TRAPS) { - ResourceMark rm; - HandleMark hm; - - // Used to canonicalize Long and String values. - ResourceHashtable longs; - ResourceHashtable strings; +jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS) { + Thread* THREAD = Thread::current(); + ResourceHashtable longs; + ResourceHashtable strings; jvalue prim; - prim.z = true; oop boxedTrueOop = java_lang_boxing_object::create(T_BOOLEAN, &prim, CHECK_NULL); - Handle boxedTrue(THREAD, boxedTrueOop); - prim.z = false; oop boxedFalseOop = java_lang_boxing_object::create(T_BOOLEAN, &prim, CHECK_NULL); - Handle boxedFalse(THREAD, boxedFalseOop); + prim.z = true; JVMCIObject boxedTrue = JVMCIENV->create_box(T_BOOLEAN, &prim, JVMCI_CHECK_NULL); + prim.z = false; JVMCIObject boxedFalse = JVMCIENV->create_box(T_BOOLEAN, &prim, JVMCI_CHECK_NULL); - CompilerToVM::Data::initialize(CHECK_NULL); + CompilerToVM::Data::initialize(JVMCI_CHECK_NULL); - VMField::klass()->initialize(CHECK_NULL); - VMFlag::klass()->initialize(CHECK_NULL); - VMIntrinsicMethod::klass()->initialize(CHECK_NULL); + JVMCIENV->VMField_initialize(JVMCI_CHECK_NULL); + JVMCIENV->VMFlag_initialize(JVMCI_CHECK_NULL); + JVMCIENV->VMIntrinsicMethod_initialize(JVMCI_CHECK_NULL); int len = JVMCIVMStructs::localHotSpotVMStructs_count(); - objArrayHandle vmFields = oopFactory::new_objArray_handle(VMField::klass(), len, CHECK_NULL); + JVMCIObjectArray vmFields = JVMCIENV->new_VMField_array(len, JVMCI_CHECK_NULL); for (int i = 0; i < len ; i++) { VMStructEntry vmField = JVMCIVMStructs::localHotSpotVMStructs[i]; - instanceHandle vmFieldObj = InstanceKlass::cast(VMField::klass())->allocate_instance_handle(CHECK_NULL); size_t name_buf_len = strlen(vmField.typeName) + strlen(vmField.fieldName) + 2 /* "::" */; char* name_buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, name_buf_len + 1); sprintf(name_buf, "%s::%s", vmField.typeName, vmField.fieldName); CSTRING_TO_JSTRING(name, name_buf); CSTRING_TO_JSTRING(type, vmField.typeString); - VMField::set_name(vmFieldObj, name()); - VMField::set_type(vmFieldObj, type()); - VMField::set_offset(vmFieldObj, vmField.offset); - VMField::set_address(vmFieldObj, (jlong) vmField.address); + JVMCIObject box; if (vmField.isStatic && vmField.typeString != NULL) { if (strcmp(vmField.typeString, "bool") == 0) { BOXED_BOOLEAN(box, *(jbyte*) vmField.address); - VMField::set_value(vmFieldObj, box); + assert(box.is_non_null(), "must have a box"); } else if (strcmp(vmField.typeString, "int") == 0 || strcmp(vmField.typeString, "jint") == 0) { BOXED_LONG(box, *(jint*) vmField.address); - VMField::set_value(vmFieldObj, box); + assert(box.is_non_null(), "must have a box"); } else if (strcmp(vmField.typeString, "uint64_t") == 0) { BOXED_LONG(box, *(uint64_t*) vmField.address); - VMField::set_value(vmFieldObj, box); + assert(box.is_non_null(), "must have a box"); } else if (strcmp(vmField.typeString, "address") == 0 || strcmp(vmField.typeString, "intptr_t") == 0 || strcmp(vmField.typeString, "uintptr_t") == 0 || @@ -343,43 +320,47 @@ // All foo* types are addresses. vmField.typeString[strlen(vmField.typeString) - 1] == '*') { BOXED_LONG(box, *((address*) vmField.address)); - VMField::set_value(vmFieldObj, box); + assert(box.is_non_null(), "must have a box"); } else { JVMCI_ERROR_NULL("VM field %s has unsupported type %s", name_buf, vmField.typeString); } } - vmFields->obj_at_put(i, vmFieldObj()); + JVMCIObject vmFieldObj = JVMCIENV->new_VMField(name, type, vmField.offset, (jlong) vmField.address, box, JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(vmFields, i, vmFieldObj); } int ints_len = JVMCIVMStructs::localHotSpotVMIntConstants_count(); int longs_len = JVMCIVMStructs::localHotSpotVMLongConstants_count(); len = ints_len + longs_len; - objArrayHandle vmConstants = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), len * 2, CHECK_NULL); + JVMCIObjectArray vmConstants = JVMCIENV->new_Object_array(len * 2, JVMCI_CHECK_NULL); int insert = 0; for (int i = 0; i < ints_len ; i++) { VMIntConstantEntry c = JVMCIVMStructs::localHotSpotVMIntConstants[i]; CSTRING_TO_JSTRING(name, c.name); + JVMCIObject value; BOXED_LONG(value, c.value); - vmConstants->obj_at_put(insert++, name()); - vmConstants->obj_at_put(insert++, value); + JVMCIENV->put_object_at(vmConstants, insert++, name); + JVMCIENV->put_object_at(vmConstants, insert++, value); } for (int i = 0; i < longs_len ; i++) { VMLongConstantEntry c = JVMCIVMStructs::localHotSpotVMLongConstants[i]; CSTRING_TO_JSTRING(name, c.name); + JVMCIObject value; BOXED_LONG(value, c.value); - vmConstants->obj_at_put(insert++, name()); - vmConstants->obj_at_put(insert++, value); + JVMCIENV->put_object_at(vmConstants, insert++, name); + JVMCIENV->put_object_at(vmConstants, insert++, value); } assert(insert == len * 2, "must be"); len = JVMCIVMStructs::localHotSpotVMAddresses_count(); - objArrayHandle vmAddresses = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), len * 2, CHECK_NULL); + JVMCIObjectArray vmAddresses = JVMCIENV->new_Object_array(len * 2, JVMCI_CHECK_NULL); for (int i = 0; i < len ; i++) { VMAddressEntry a = JVMCIVMStructs::localHotSpotVMAddresses[i]; CSTRING_TO_JSTRING(name, a.name); + JVMCIObject value; BOXED_LONG(value, a.value); - vmAddresses->obj_at_put(i * 2, name()); - vmAddresses->obj_at_put(i * 2 + 1, value); + JVMCIENV->put_object_at(vmAddresses, i * 2, name); + JVMCIENV->put_object_at(vmAddresses, i * 2 + 1, value); } #define COUNT_FLAG(ignore) +1 @@ -393,40 +374,32 @@ #define CHECK_FLAG(type, name) #endif -#define ADD_FLAG(type, name, convert) { \ - CHECK_FLAG(type, name) \ - instanceHandle vmFlagObj = InstanceKlass::cast(VMFlag::klass())->allocate_instance_handle(CHECK_NULL); \ - CSTRING_TO_JSTRING(fname, #name); \ - CSTRING_TO_JSTRING(ftype, #type); \ - VMFlag::set_name(vmFlagObj, fname()); \ - VMFlag::set_type(vmFlagObj, ftype()); \ - convert(value, name); \ - VMFlag::set_value(vmFlagObj, value); \ - vmFlags->obj_at_put(i++, vmFlagObj()); \ +#define ADD_FLAG(type, name, convert) { \ + CHECK_FLAG(type, name) \ + CSTRING_TO_JSTRING(fname, #name); \ + CSTRING_TO_JSTRING(ftype, #type); \ + convert(value, name); \ + JVMCIObject vmFlagObj = JVMCIENV->new_VMFlag(fname, ftype, value, JVMCI_CHECK_NULL); \ + JVMCIENV->put_object_at(vmFlags, i++, vmFlagObj); \ } #define ADD_BOOL_FLAG(name) ADD_FLAG(bool, name, BOXED_BOOLEAN) #define ADD_INTX_FLAG(name) ADD_FLAG(intx, name, BOXED_LONG) #define ADD_UINTX_FLAG(name) ADD_FLAG(uintx, name, BOXED_LONG) len = 0 + PREDEFINED_CONFIG_FLAGS(COUNT_FLAG, COUNT_FLAG, COUNT_FLAG); - objArrayHandle vmFlags = oopFactory::new_objArray_handle(VMFlag::klass(), len, CHECK_NULL); + JVMCIObjectArray vmFlags = JVMCIENV->new_VMFlag_array(len, JVMCI_CHECK_NULL); int i = 0; + JVMCIObject value; PREDEFINED_CONFIG_FLAGS(ADD_BOOL_FLAG, ADD_INTX_FLAG, ADD_UINTX_FLAG) - objArrayHandle vmIntrinsics = CompilerToVM::initialize_intrinsics(CHECK_NULL); - - objArrayOop data = oopFactory::new_objArray(SystemDictionary::Object_klass(), 5, CHECK_NULL); - data->obj_at_put(0, vmFields()); - data->obj_at_put(1, vmConstants()); - data->obj_at_put(2, vmAddresses()); - data->obj_at_put(3, vmFlags()); - data->obj_at_put(4, vmIntrinsics()); + JVMCIObjectArray vmIntrinsics = CompilerToVM::initialize_intrinsics(JVMCI_CHECK_NULL); - return (jobjectArray) JNIHandles::make_local(THREAD, data); -#undef COUNT_FLAG -#undef ADD_FLAG -#undef ADD_BOOL_FLAG -#undef ADD_INTX_FLAG -#undef ADD_UINTX_FLAG -#undef CHECK_FLAG + JVMCIObjectArray data = JVMCIENV->new_Object_array(5, JVMCI_CHECK_NULL); + JVMCIENV->put_object_at(data, 0, vmFields); + JVMCIENV->put_object_at(data, 1, vmConstants); + JVMCIENV->put_object_at(data, 2, vmAddresses); + JVMCIENV->put_object_at(data, 3, vmFlags); + JVMCIENV->put_object_at(data, 4, vmIntrinsics); + + return JVMCIENV->get_jobjectArray(data); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciEnv.cpp --- a/src/hotspot/share/jvmci/jvmciEnv.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp Wed May 01 12:31:29 2019 -0700 @@ -23,44 +23,22 @@ */ #include "precompiled.hpp" -#include "jvmci/jvmciEnv.hpp" -#include "classfile/javaAssertions.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" +#include "classfile/stringTable.hpp" #include "code/codeCache.hpp" -#include "code/scopeDesc.hpp" -#include "compiler/compileBroker.hpp" -#include "compiler/compileLog.hpp" -#include "compiler/compilerOracle.hpp" -#include "interpreter/linkResolver.hpp" -#include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/constantPool.inline.hpp" -#include "oops/cpCache.inline.hpp" -#include "oops/method.inline.hpp" -#include "oops/methodData.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "runtime/fieldDescriptor.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/init.hpp" -#include "runtime/reflection.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/sweeper.hpp" -#include "utilities/dtrace.hpp" +#include "oops/typeArrayOop.inline.hpp" +#include "runtime/jniHandles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jniAccessMark.inline.hpp" #include "jvmci/jvmciRuntime.hpp" -#include "jvmci/jvmciJavaClasses.hpp" -JVMCIEnv::JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter): +JVMCICompileState::JVMCICompileState(CompileTask* task, int system_dictionary_modification_counter): _task(task), _system_dictionary_modification_counter(system_dictionary_modification_counter), _retryable(true), _failure_reason(NULL), - _failure_reason_on_C_heap(false) -{ + _failure_reason_on_C_heap(false) { // Get Jvmti capabilities under lock to get consistent values. MutexLocker mu(JvmtiThreadState_lock); _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint() ? 1 : 0; @@ -69,7 +47,7 @@ _jvmti_can_pop_frame = JvmtiExport::can_pop_frame() ? 1 : 0; } -bool JVMCIEnv::jvmti_state_changed() const { +bool JVMCICompileState::jvmti_state_changed() const { if (!jvmti_can_access_local_variables() && JvmtiExport::can_access_local_variables()) { return true; @@ -89,532 +67,1587 @@ return false; } -// ------------------------------------------------------------------ -// Note: the logic of this method should mirror the logic of -// constantPoolOopDesc::verify_constant_pool_resolve. -bool JVMCIEnv::check_klass_accessibility(Klass* accessing_klass, Klass* resolved_klass) { - if (accessing_klass->is_objArray_klass()) { - accessing_klass = ObjArrayKlass::cast(accessing_klass)->bottom_klass(); - } - if (!accessing_klass->is_instance_klass()) { - return true; - } +JavaVM* JVMCIEnv::_shared_library_javavm = NULL; +void* JVMCIEnv::_shared_library_handle = NULL; +char* JVMCIEnv::_shared_library_path = NULL; - if (resolved_klass->is_objArray_klass()) { - // Find the element klass, if this is an array. - resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass(); - } - if (resolved_klass->is_instance_klass()) { - Reflection::VerifyClassAccessResults result = - Reflection::verify_class_access(accessing_klass, InstanceKlass::cast(resolved_klass), true); - return result == Reflection::ACCESS_OK; - } - return true; -} +void JVMCIEnv::copy_saved_properties() { + assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image"); + + JavaThread* THREAD = JavaThread::current(); -// ------------------------------------------------------------------ -Klass* JVMCIEnv::get_klass_by_name_impl(Klass* accessing_klass, - const constantPoolHandle& cpool, - Symbol* sym, - bool require_local) { - JVMCI_EXCEPTION_CONTEXT; - - // Now we need to check the SystemDictionary - if (sym->char_at(0) == 'L' && - sym->char_at(sym->utf8_length()-1) == ';') { - // This is a name from a signature. Strip off the trimmings. - // Call recursive to keep scope of strippedsym. - TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, - sym->utf8_length()-2, - CHECK_NULL); - return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local); + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_services_Services(), Handle(), Handle(), true, THREAD); + if (HAS_PENDING_EXCEPTION) { + JVMCIRuntime::exit_on_pending_exception(NULL, "Error initializing jdk.vm.ci.services.Services"); } - - Handle loader(THREAD, (oop)NULL); - Handle domain(THREAD, (oop)NULL); - if (accessing_klass != NULL) { - loader = Handle(THREAD, accessing_klass->class_loader()); - domain = Handle(THREAD, accessing_klass->protection_domain()); - } - - Klass* found_klass = NULL; - { - ttyUnlocker ttyul; // release tty lock to avoid ordering problems - MutexLocker ml(Compile_lock); - if (!require_local) { - found_klass = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, CHECK_NULL); - } else { - found_klass = SystemDictionary::find_instance_or_array_klass(sym, loader, domain, CHECK_NULL); + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->should_be_initialized()) { + ik->initialize(THREAD); + if (HAS_PENDING_EXCEPTION) { + JVMCIRuntime::exit_on_pending_exception(NULL, "Error initializing jdk.vm.ci.services.Services"); } } - // If we fail to find an array klass, look again for its element type. - // The element type may be available either locally or via constraints. - // In either case, if we can find the element type in the system dictionary, - // we must build an array type around it. The CI requires array klasses - // to be loaded if their element klasses are loaded, except when memory - // is exhausted. - if (sym->char_at(0) == '[' && - (sym->char_at(1) == '[' || sym->char_at(1) == 'L')) { - // We have an unloaded array. - // Build it on the fly if the element class exists. - TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, - sym->utf8_length()-1, - CHECK_NULL); + // Get the serialized saved properties from HotSpot + TempNewSymbol serializeSavedProperties = SymbolTable::new_symbol("serializeSavedProperties", CHECK_EXIT); + JavaValue result(T_OBJECT); + JavaCallArguments args; + JavaCalls::call_static(&result, ik, serializeSavedProperties, vmSymbols::serializePropertiesToByteArray_signature(), &args, THREAD); + if (HAS_PENDING_EXCEPTION) { + JVMCIRuntime::exit_on_pending_exception(NULL, "Error calling jdk.vm.ci.services.Services.serializeSavedProperties"); + } + oop res = (oop) result.get_jobject(); + assert(res->is_typeArray(), "must be"); + assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be"); + typeArrayOop ba = typeArrayOop(res); + int serialized_properties_len = ba->length(); + + // Copy serialized saved properties from HotSpot object into native buffer + jbyte* serialized_properties = NEW_RESOURCE_ARRAY(jbyte, serialized_properties_len); + memcpy(serialized_properties, ba->byte_at_addr(0), serialized_properties_len); + + // Copy native buffer into shared library object + JVMCIPrimitiveArray buf = new_byteArray(serialized_properties_len, this); + if (has_pending_exception()) { + describe_pending_exception(true); + fatal("Error in copy_saved_properties"); + } + copy_bytes_from(serialized_properties, buf, 0, serialized_properties_len); + if (has_pending_exception()) { + describe_pending_exception(true); + fatal("Error in copy_saved_properties"); + } + + // Initialize saved properties in shared library + jclass servicesClass = JNIJVMCI::Services::clazz(); + jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method(); + JNIAccessMark jni(this); + jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject()); + if (jni()->ExceptionCheck()) { + jni()->ExceptionDescribe(); + fatal("Error calling jdk.vm.ci.services.Services.initializeSavedProperties"); + } +} - // Get element Klass recursively. - Klass* elem_klass = - get_klass_by_name_impl(accessing_klass, - cpool, - elem_sym, - require_local); - if (elem_klass != NULL) { - // Now make an array for it - return elem_klass->array_klass(THREAD); +JNIEnv* JVMCIEnv::attach_shared_library() { + if (_shared_library_javavm == NULL) { + MutexLocker locker(JVMCI_lock); + if (_shared_library_javavm == NULL) { + + char path[JVM_MAXPATHLEN]; + char ebuf[1024]; + if (JVMCILibPath != NULL) { + if (!os::dll_locate_lib(path, sizeof(path), JVMCILibPath, JVMCI_SHARED_LIBRARY_NAME)) { + vm_exit_during_initialization("Unable to create JVMCI shared library path from -XX:JVMCILibPath value", JVMCILibPath); + } + } else { + if (!os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), JVMCI_SHARED_LIBRARY_NAME)) { + vm_exit_during_initialization("Unable to create path to JVMCI shared library"); + } + } + + void* handle = os::dll_load(path, ebuf, sizeof ebuf); + if (handle == NULL) { + vm_exit_during_initialization("Unable to load JVMCI shared library", ebuf); + } + _shared_library_handle = handle; + _shared_library_path = strdup(path); + jint (*JNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args); + typedef jint (*JNI_CreateJavaVM_t)(JavaVM **pvm, void **penv, void *args); + + JNI_CreateJavaVM = CAST_TO_FN_PTR(JNI_CreateJavaVM_t, os::dll_lookup(handle, "JNI_CreateJavaVM")); + JNIEnv* env; + if (JNI_CreateJavaVM == NULL) { + vm_exit_during_initialization("Unable to find JNI_CreateJavaVM", path); + } + + ResourceMark rm; + JavaVMInitArgs vm_args; + vm_args.version = JNI_VERSION_1_2; + vm_args.ignoreUnrecognized = JNI_TRUE; + vm_args.options = NULL; + vm_args.nOptions = 0; + + JavaVM* the_javavm = NULL; + int result = (*JNI_CreateJavaVM)(&the_javavm, (void**) &env, &vm_args); + if (result == JNI_OK) { + guarantee(env != NULL, "missing env"); + _shared_library_javavm = the_javavm; + return env; + } else { + vm_exit_during_initialization(err_msg("JNI_CreateJavaVM failed with return value %d", result), path); + } } } + JNIEnv* env; + if (_shared_library_javavm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) { + guarantee(env != NULL, "missing env"); + return env; + } + fatal("Error attaching current thread to JVMCI shared library JNI interface"); + return NULL; +} - if (found_klass == NULL && !cpool.is_null() && cpool->has_preresolution()) { - // Look inside the constant pool for pre-resolved class entries. - for (int i = cpool->length() - 1; i >= 1; i--) { - if (cpool->tag_at(i).is_klass()) { - Klass* kls = cpool->resolved_klass_at(i); - if (kls->name() == sym) { - return kls; - } - } +void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) { + // By default there is only one runtime which is the compiler runtime. + _runtime = JVMCI::compiler_runtime(); + if (!UseJVMCINativeLibrary) { + // In HotSpot mode, JNI isn't used at all. + _is_hotspot = true; + _env = NULL; + return; + } + + if (parent_env != NULL) { + // If the parent JNI environment is non-null then figure out whether it + // is a HotSpot or shared library JNIEnv and set the state appropriately. + JavaThread* thread = JavaThread::current(); + if (thread->jni_environment() == parent_env) { + // Select the Java runtime + _runtime = JVMCI::java_runtime(); + _is_hotspot = true; + _env = NULL; + return; } } - return found_klass; + // Running in JVMCI shared library mode so get a shared library JNIEnv + _is_hotspot = false; + _env = attach_shared_library(); + assert(parent_env == NULL || _env == parent_env, "must be"); + + if (parent_env == NULL) { + // There is no parent shared library JNI env so push + // a JNI local frame to release all local handles in + // this JVMCIEnv scope when it's closed. + assert(_throw_to_caller == false, "must be"); + JNIAccessMark jni(this); + jint result = _env->PushLocalFrame(32); + if (result != JNI_OK) { + char message[256]; + jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line); + JVMCIRuntime::exit_on_pending_exception(this, message); + } + } +} + +JVMCIEnv::JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line): + _throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) { + init_env_mode_runtime(NULL); +} + +JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): + _throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) { + init_env_mode_runtime(NULL); +} + +JVMCIEnv::JVMCIEnv(JNIEnv* parent_env, const char* file, int line): + _throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) { + init_env_mode_runtime(parent_env); + assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment"); } -// ------------------------------------------------------------------ -Klass* JVMCIEnv::get_klass_by_name(Klass* accessing_klass, - Symbol* klass_name, - bool require_local) { - ResourceMark rm; - constantPoolHandle cpool; - return get_klass_by_name_impl(accessing_klass, - cpool, - klass_name, - require_local); +void JVMCIEnv::init(bool is_hotspot, const char* file, int line) { + _compile_state = NULL; + _throw_to_caller = false; + _file = file; + _line = line; + if (is_hotspot) { + _env = NULL; + _is_hotspot = true; + _runtime = JVMCI::java_runtime(); + } else { + init_env_mode_runtime(NULL); + } } -// ------------------------------------------------------------------ -// Implementation of get_klass_by_index. -Klass* JVMCIEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, - int index, - bool& is_accessible, - Klass* accessor) { - JVMCI_EXCEPTION_CONTEXT; - Klass* klass = ConstantPool::klass_at_if_loaded(cpool, index); - Symbol* klass_name = NULL; - if (klass == NULL) { - klass_name = cpool->klass_name_at(index); +// Prints a pending exception (if any) and its stack trace. +void JVMCIEnv::describe_pending_exception(bool clear) { + if (!is_hotspot()) { + JNIAccessMark jni(this); + if (jni()->ExceptionCheck()) { + jthrowable ex = !clear ? jni()->ExceptionOccurred() : NULL; + jni()->ExceptionDescribe(); + if (ex != NULL) { + jni()->Throw(ex); + } + } + } else { + Thread* THREAD = Thread::current(); + if (HAS_PENDING_EXCEPTION) { + JVMCIRuntime::describe_pending_hotspot_exception((JavaThread*) THREAD, clear); + } + } +} + +void JVMCIEnv::translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable) { + assert(!is_hotspot(), "must_be"); + // Resolve HotSpotJVMCIRuntime class explicitly as HotSpotJVMCI::compute_offsets + // may not have been called. + Klass* runtimeKlass = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_hotspot_HotSpotJVMCIRuntime(), true, CHECK); + JavaCallArguments jargs; + jargs.push_oop(throwable); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + runtimeKlass, + vmSymbols::encodeThrowable_name(), + vmSymbols::encodeThrowable_signature(), &jargs, THREAD); + if (HAS_PENDING_EXCEPTION) { + JVMCIRuntime::exit_on_pending_exception(this, "HotSpotJVMCIRuntime.encodeThrowable should not throw an exception"); } - if (klass == NULL) { - // Not found in constant pool. Use the name to do the lookup. - Klass* k = get_klass_by_name_impl(accessor, - cpool, - klass_name, - false); - // Calculate accessibility the hard way. - if (k == NULL) { - is_accessible = false; - } else if (k->class_loader() != accessor->class_loader() && - get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) { - // Loaded only remotely. Not linked yet. - is_accessible = false; + oop encoded_throwable_string = (oop) result.get_jobject(); + + ResourceMark rm; + const char* encoded_throwable_chars = java_lang_String::as_utf8_string(encoded_throwable_string); + + JNIAccessMark jni(this); + jobject jni_encoded_throwable_string = jni()->NewStringUTF(encoded_throwable_chars); + jthrowable jni_throwable = (jthrowable) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::decodeThrowable_method(), + jni_encoded_throwable_string); + jni()->Throw(jni_throwable); +} + +JVMCIEnv::~JVMCIEnv() { + if (_throw_to_caller) { + if (is_hotspot()) { + // Nothing to do } else { - // Linked locally, and we must also check public/private, etc. - is_accessible = check_klass_accessibility(accessor, k); + if (Thread::current()->is_Java_thread()) { + JavaThread* THREAD = JavaThread::current(); + if (HAS_PENDING_EXCEPTION) { + Handle throwable = Handle(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + translate_hotspot_exception_to_jni_exception(THREAD, throwable); + } + } } - if (!is_accessible) { - return NULL; + } else { + if (!is_hotspot()) { + // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope. + JNIAccessMark jni(this); + jni()->PopLocalFrame(NULL); + } + + if (has_pending_exception()) { + char message[256]; + jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line); + JVMCIRuntime::exit_on_pending_exception(this, message); } - return k; + } +} + +jboolean JVMCIEnv::has_pending_exception() { + if (is_hotspot()) { + Thread* THREAD = Thread::current(); + return HAS_PENDING_EXCEPTION; + } else { + JNIAccessMark jni(this); + return jni()->ExceptionCheck(); } +} + +void JVMCIEnv::clear_pending_exception() { + if (is_hotspot()) { + Thread* THREAD = Thread::current(); + CLEAR_PENDING_EXCEPTION; + } else { + JNIAccessMark jni(this); + jni()->ExceptionClear(); + } +} - // It is known to be accessible, since it was found in the constant pool. - is_accessible = true; - return klass; +int JVMCIEnv::get_length(JVMCIArray array) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(array)->length(); + } else { + JNIAccessMark jni(this); + return jni()->GetArrayLength(get_jarray(array)); + } +} + +JVMCIObject JVMCIEnv::get_object_at(JVMCIObjectArray array, int index) { + if (is_hotspot()) { + oop result = HotSpotJVMCI::resolve(array)->obj_at(index); + return wrap(result); + } else { + JNIAccessMark jni(this); + jobject result = jni()->GetObjectArrayElement(get_jobjectArray(array), index); + return wrap(result); + } +} + +void JVMCIEnv::put_object_at(JVMCIObjectArray array, int index, JVMCIObject value) { + if (is_hotspot()) { + HotSpotJVMCI::resolve(array)->obj_at_put(index, HotSpotJVMCI::resolve(value)); + } else { + JNIAccessMark jni(this); + jni()->SetObjectArrayElement(get_jobjectArray(array), index, get_jobject(value)); + } } -// ------------------------------------------------------------------ -// Get a klass from the constant pool. -Klass* JVMCIEnv::get_klass_by_index(const constantPoolHandle& cpool, - int index, - bool& is_accessible, - Klass* accessor) { - ResourceMark rm; - return get_klass_by_index_impl(cpool, index, is_accessible, accessor); +jboolean JVMCIEnv::get_bool_at(JVMCIPrimitiveArray array, int index) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(array)->bool_at(index); + } else { + JNIAccessMark jni(this); + jboolean result; + jni()->GetBooleanArrayRegion(array.as_jbooleanArray(), index, 1, &result); + return result; + } +} +void JVMCIEnv::put_bool_at(JVMCIPrimitiveArray array, int index, jboolean value) { + if (is_hotspot()) { + HotSpotJVMCI::resolve(array)->bool_at_put(index, value); + } else { + JNIAccessMark jni(this); + jni()->SetBooleanArrayRegion(array.as_jbooleanArray(), index, 1, &value); + } +} + +jbyte JVMCIEnv::get_byte_at(JVMCIPrimitiveArray array, int index) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(array)->byte_at(index); + } else { + JNIAccessMark jni(this); + jbyte result; + jni()->GetByteArrayRegion(array.as_jbyteArray(), index, 1, &result); + return result; + } +} +void JVMCIEnv::put_byte_at(JVMCIPrimitiveArray array, int index, jbyte value) { + if (is_hotspot()) { + HotSpotJVMCI::resolve(array)->byte_at_put(index, value); + } else { + JNIAccessMark jni(this); + jni()->SetByteArrayRegion(array.as_jbyteArray(), index, 1, &value); + } +} + +jint JVMCIEnv::get_int_at(JVMCIPrimitiveArray array, int index) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(array)->int_at(index); + } else { + JNIAccessMark jni(this); + jint result; + jni()->GetIntArrayRegion(array.as_jintArray(), index, 1, &result); + return result; + } +} +void JVMCIEnv::put_int_at(JVMCIPrimitiveArray array, int index, jint value) { + if (is_hotspot()) { + HotSpotJVMCI::resolve(array)->int_at_put(index, value); + } else { + JNIAccessMark jni(this); + jni()->SetIntArrayRegion(array.as_jintArray(), index, 1, &value); + } +} + +long JVMCIEnv::get_long_at(JVMCIPrimitiveArray array, int index) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(array)->long_at(index); + } else { + JNIAccessMark jni(this); + jlong result; + jni()->GetLongArrayRegion(array.as_jlongArray(), index, 1, &result); + return result; + } +} +void JVMCIEnv::put_long_at(JVMCIPrimitiveArray array, int index, jlong value) { + if (is_hotspot()) { + HotSpotJVMCI::resolve(array)->long_at_put(index, value); + } else { + JNIAccessMark jni(this); + jni()->SetLongArrayRegion(array.as_jlongArray(), index, 1, &value); + } +} + +void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes) { + if (size_in_bytes == 0) { + return; + } + if (is_hotspot()) { + memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), size_in_bytes); + } else { + JNIAccessMark jni(this); + jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest); + } +} +void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) { + if (size_in_bytes == 0) { + return; + } + if (is_hotspot()) { + memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, size_in_bytes); + } else { + JNIAccessMark jni(this); + jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src); + } } -// ------------------------------------------------------------------ -// Implementation of get_field_by_index. -// -// Implementation note: the results of field lookups are cached -// in the accessor klass. -void JVMCIEnv::get_field_by_index_impl(InstanceKlass* klass, fieldDescriptor& field_desc, - int index) { - JVMCI_EXCEPTION_CONTEXT; +jboolean JVMCIEnv::is_boxing_object(BasicType type, JVMCIObject object) { + if (is_hotspot()) { + return java_lang_boxing_object::is_instance(HotSpotJVMCI::resolve(object), type); + } else { + JNIAccessMark jni(this); + return jni()->IsInstanceOf(get_jobject(object), JNIJVMCI::box_class(type)); + } +} + +// Get the primitive value from a Java boxing object. It's hard error to +// pass a non-primitive BasicType. +jvalue JVMCIEnv::get_boxed_value(BasicType type, JVMCIObject object) { + jvalue result; + if (is_hotspot()) { + if (java_lang_boxing_object::get_value(HotSpotJVMCI::resolve(object), &result) == T_ILLEGAL) { + ShouldNotReachHere(); + } + } else { + JNIAccessMark jni(this); + jfieldID field = JNIJVMCI::box_field(type); + switch (type) { + case T_BOOLEAN: result.z = jni()->GetBooleanField(get_jobject(object), field); break; + case T_BYTE: result.b = jni()->GetByteField(get_jobject(object), field); break; + case T_SHORT: result.s = jni()->GetShortField(get_jobject(object), field); break; + case T_CHAR: result.c = jni()->GetCharField(get_jobject(object), field); break; + case T_INT: result.i = jni()->GetIntField(get_jobject(object), field); break; + case T_LONG: result.j = jni()->GetLongField(get_jobject(object), field); break; + case T_FLOAT: result.f = jni()->GetFloatField(get_jobject(object), field); break; + case T_DOUBLE: result.d = jni()->GetDoubleField(get_jobject(object), field); break; + default: + ShouldNotReachHere(); + } + } + return result; +} + +// Return the BasicType of the object if it's a boxing object, otherwise return T_ILLEGAL. +BasicType JVMCIEnv::get_box_type(JVMCIObject object) { + if (is_hotspot()) { + return java_lang_boxing_object::basic_type(HotSpotJVMCI::resolve(object)); + } else { + JNIAccessMark jni(this); + jclass clazz = jni()->GetObjectClass(get_jobject(object)); + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_BOOLEAN))) return T_BOOLEAN; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_BYTE))) return T_BYTE; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_SHORT))) return T_SHORT; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_CHAR))) return T_CHAR; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_INT))) return T_INT; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_LONG))) return T_LONG; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_FLOAT))) return T_FLOAT; + if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_DOUBLE))) return T_DOUBLE; + return T_ILLEGAL; + } +} - assert(klass->is_linked(), "must be linked before using its constant-pool"); +// Create a boxing object of the appropriate primitive type. +JVMCIObject JVMCIEnv::create_box(BasicType type, jvalue* value, JVMCI_TRAPS) { + switch (type) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + break; + default: + JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject()); + } + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject())); + return HotSpotJVMCI::wrap(box); + } else { + JNIAccessMark jni(this); + jobject box = jni()->NewObjectA(JNIJVMCI::box_class(type), JNIJVMCI::box_constructor(type), value); + assert(box != NULL, ""); + return wrap(box); + } +} - constantPoolHandle cpool(thread, klass->constants()); +const char* JVMCIEnv::as_utf8_string(JVMCIObject str) { + if (is_hotspot()) { + return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str)); + } else { + JNIAccessMark jni(this); + int length = jni()->GetStringLength(str.as_jstring()); + char* result = NEW_RESOURCE_ARRAY(char, length + 1); + jni()->GetStringUTFRegion(str.as_jstring(), 0, length, result); + return result; + } +} - // Get the field's name, signature, and type. - Symbol* name = cpool->name_ref_at(index); +char* JVMCIEnv::as_utf8_string(JVMCIObject str, char* buf, int buflen) { + if (is_hotspot()) { + return java_lang_String::as_utf8_string(HotSpotJVMCI::resolve(str), buf, buflen); + } else { + JNIAccessMark jni(this); + int length = jni()->GetStringLength(str.as_jstring()); + if (length >= buflen) { + length = buflen; + } + jni()->GetStringUTFRegion(str.as_jstring(), 0, length, buf); + return buf; + } +} + +#define DO_THROW(name) \ +void JVMCIEnv::throw_##name(const char* msg) { \ + if (is_hotspot()) { \ + JavaThread* THREAD = JavaThread::current(); \ + THROW_MSG(HotSpotJVMCI::name::symbol(), msg); \ + } else { \ + JNIAccessMark jni(this); \ + jni()->ThrowNew(JNIJVMCI::name::clazz(), msg); \ + } \ +} + +DO_THROW(InternalError) +DO_THROW(ArrayIndexOutOfBoundsException) +DO_THROW(IllegalStateException) +DO_THROW(NullPointerException) +DO_THROW(IllegalArgumentException) +DO_THROW(InvalidInstalledCodeException) +DO_THROW(UnsatisfiedLinkError) + +#undef DO_THROW - int nt_index = cpool->name_and_type_ref_index_at(index); - int sig_index = cpool->signature_ref_index_at(nt_index); - Symbol* signature = cpool->symbol_at(sig_index); +void JVMCIEnv::fthrow_error(const char* file, int line, const char* format, ...) { + const int max_msg_size = 1024; + va_list ap; + va_start(ap, format); + char msg[max_msg_size]; + vsnprintf(msg, max_msg_size, format, ap); + msg[max_msg_size-1] = '\0'; + va_end(ap); + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + Handle h_loader = Handle(); + Handle h_protection_domain = Handle(); + Exceptions::_throw_msg(THREAD, file, line, vmSymbols::jdk_vm_ci_common_JVMCIError(), msg, h_loader, h_protection_domain); + } else { + JNIAccessMark jni(this); + jni()->ThrowNew(JNIJVMCI::JVMCIError::clazz(), msg); + } +} + +JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_compileMethod (JVMCIObject runtime, JVMCIObject method, int entry_bci, + jlong compile_state, int id) { + if (is_hotspot()) { + Thread* THREAD = Thread::current(); + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(method))); + jargs.push_int(entry_bci); + jargs.push_long(compile_state); + jargs.push_int(id); + JavaValue result(T_OBJECT); + JavaCalls::call_special(&result, + HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), + vmSymbols::compileMethod_name(), + vmSymbols::compileMethod_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = jni()->CallNonvirtualObjectMethod(runtime.as_jobject(), + JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::compileMethod_method(), + method.as_jobject(), entry_bci, compile_state, id); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} + +void JVMCIEnv::call_HotSpotJVMCIRuntime_bootstrapFinished (JVMCIObject runtime, JVMCIEnv* JVMCIENV) { + if (is_hotspot()) { + Thread* THREAD = Thread::current(); + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::bootstrapFinished_name(), vmSymbols::void_method_signature(), &jargs, CHECK); + } else { + JNIAccessMark jni(this); + jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::bootstrapFinished_method()); + + } +} - // Get the field's declared holder. - int holder_index = cpool->klass_ref_index_at(index); - bool holder_is_accessible; - Klass* declared_holder = get_klass_by_index(cpool, holder_index, - holder_is_accessible, - klass); +void JVMCIEnv::call_HotSpotJVMCIRuntime_shutdown (JVMCIObject runtime) { + HandleMark hm; + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), &jargs, THREAD); + } else { + JNIAccessMark jni(this); + jni()->CallNonvirtualVoidMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::shutdown_method()); + } + if (has_pending_exception()) { + // This should never happen as HotSpotJVMCIRuntime.shutdown() should + // handle all exceptions. + describe_pending_exception(true); + } +} - // The declared holder of this field may not have been loaded. - // Bail out with partial field information. - if (!holder_is_accessible) { - return; +JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_runtime (JVMCIEnv* JVMCIENV) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::runtime_name(), vmSymbols::runtime_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), JNIJVMCI::HotSpotJVMCIRuntime::runtime_method()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); } +} + +JVMCIObject JVMCIEnv::call_JVMCI_getRuntime (JVMCIEnv* JVMCIENV) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, HotSpotJVMCI::JVMCI::klass(), vmSymbols::getRuntime_name(), vmSymbols::getRuntime_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::JVMCI::clazz(), JNIJVMCI::JVMCI::getRuntime_method()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_getCompiler (JVMCIObject runtime, JVMCIEnv* JVMCIENV) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(runtime))); + JavaValue result(T_OBJECT); + JavaCalls::call_virtual(&result, HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), vmSymbols::getCompiler_name(), vmSymbols::getCompiler_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = jni()->CallObjectMethod(runtime.as_jobject(), JNIJVMCI::HotSpotJVMCIRuntime::getCompiler_method()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} - // Perform the field lookup. - Klass* canonical_holder = - InstanceKlass::cast(declared_holder)->find_field(name, signature, &field_desc); - if (canonical_holder == NULL) { - return; +JVMCIObject JVMCIEnv::call_HotSpotJVMCIRuntime_callToString(JVMCIObject object, JVMCIEnv* JVMCIENV) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(object))); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + HotSpotJVMCI::HotSpotJVMCIRuntime::klass(), + vmSymbols::callToString_name(), + vmSymbols::callToString_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotJVMCIRuntime::clazz(), + JNIJVMCI::HotSpotJVMCIRuntime::callToString_method(), + object.as_jobject()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); } - - assert(canonical_holder == field_desc.field_holder(), "just checking"); -} - -// ------------------------------------------------------------------ -// Get a field by index from a klass's constant pool. -void JVMCIEnv::get_field_by_index(InstanceKlass* accessor, fieldDescriptor& fd, int index) { - ResourceMark rm; - return get_field_by_index_impl(accessor, fd, index); -} - -// ------------------------------------------------------------------ -// Perform an appropriate method lookup based on accessor, holder, -// name, signature, and bytecode. -methodHandle JVMCIEnv::lookup_method(InstanceKlass* accessor, - Klass* holder, - Symbol* name, - Symbol* sig, - Bytecodes::Code bc, - constantTag tag) { - // Accessibility checks are performed in JVMCIEnv::get_method_by_index_impl(). - assert(check_klass_accessibility(accessor, holder), "holder not accessible"); - - methodHandle dest_method; - LinkInfo link_info(holder, name, sig, accessor, LinkInfo::needs_access_check, tag); - switch (bc) { - case Bytecodes::_invokestatic: - dest_method = - LinkResolver::resolve_static_call_or_null(link_info); - break; - case Bytecodes::_invokespecial: - dest_method = - LinkResolver::resolve_special_call_or_null(link_info); - break; - case Bytecodes::_invokeinterface: - dest_method = - LinkResolver::linktime_resolve_interface_method_or_null(link_info); - break; - case Bytecodes::_invokevirtual: - dest_method = - LinkResolver::linktime_resolve_virtual_method_or_null(link_info); - break; - default: ShouldNotReachHere(); - } - - return dest_method; } -// ------------------------------------------------------------------ -methodHandle JVMCIEnv::get_method_by_index_impl(const constantPoolHandle& cpool, - int index, Bytecodes::Code bc, - InstanceKlass* accessor) { - if (bc == Bytecodes::_invokedynamic) { - ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); - bool is_resolved = !cpce->is_f1_null(); - if (is_resolved) { - // Get the invoker Method* from the constant pool. - // (The appendix argument, if any, will be noted in the method's signature.) - Method* adapter = cpce->f1_as_method(); - return methodHandle(adapter); +JVMCIObject JVMCIEnv::call_PrimitiveConstant_forTypeChar(jchar kind, jlong value, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_int(kind); + jargs.push_long(value); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + HotSpotJVMCI::PrimitiveConstant::klass(), + vmSymbols::forTypeChar_name(), + vmSymbols::forTypeChar_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::PrimitiveConstant::clazz(), + JNIJVMCI::PrimitiveConstant::forTypeChar_method(), + kind, value); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::call_JavaConstant_forFloat(float value, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_float(value); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + HotSpotJVMCI::JavaConstant::klass(), + vmSymbols::forFloat_name(), + vmSymbols::forFloat_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(), + JNIJVMCI::JavaConstant::forFloat_method(), + value); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::call_JavaConstant_forDouble(double value, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + JavaCallArguments jargs; + jargs.push_double(value); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, + HotSpotJVMCI::JavaConstant::klass(), + vmSymbols::forDouble_name(), + vmSymbols::forDouble_signature(), &jargs, CHECK_(JVMCIObject())); + return wrap((oop) result.get_jobject()); + } else { + JNIAccessMark jni(this); + jobject result = (jstring) jni()->CallStaticObjectMethod(JNIJVMCI::JavaConstant::clazz(), + JNIJVMCI::JavaConstant::forDouble_method(), + value); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::get_jvmci_primitive_type(BasicType type) { + JVMCIObjectArray primitives = get_HotSpotResolvedPrimitiveType_primitives(); + JVMCIObject result = get_object_at(primitives, type); + return result; +} + +JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + Symbol* method_name_sym; + Symbol* file_name_sym; + int line_number; + Handle mirror (THREAD, method->method_holder()->java_mirror()); + java_lang_StackTraceElement::decode(mirror, method, bci, method_name_sym, file_name_sym, line_number); + + InstanceKlass* holder = method->method_holder(); + const char* declaring_class_str = holder->external_name(); + + if (is_hotspot()) { + HotSpotJVMCI::StackTraceElement::klass()->initialize(CHECK_(JVMCIObject())); + oop objOop = HotSpotJVMCI::StackTraceElement::klass()->allocate_instance(CHECK_(JVMCIObject())); + Handle obj = Handle(THREAD, objOop); + + oop declaring_class = StringTable::intern((char*) declaring_class_str, CHECK_(JVMCIObject())); + HotSpotJVMCI::StackTraceElement::set_declaringClass(this, obj(), declaring_class); + + oop method_name = StringTable::intern(method_name_sym, CHECK_(JVMCIObject())); + HotSpotJVMCI::StackTraceElement::set_methodName(this, obj(), method_name); + + if (file_name_sym != NULL) { + oop file_name = StringTable::intern(file_name_sym, CHECK_(JVMCIObject())); + HotSpotJVMCI::StackTraceElement::set_fileName(this, obj(), file_name); + } + HotSpotJVMCI::StackTraceElement::set_lineNumber(this, obj(), line_number); + return wrap(obj()); + } else { + JNIAccessMark jni(this); + jobject declaring_class = jni()->NewStringUTF(declaring_class_str); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + jobject method_name = jni()->NewStringUTF(method_name_sym->as_C_string()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + jobject file_name = NULL; + if (file_name != NULL) { + file_name = jni()->NewStringUTF(file_name_sym->as_C_string()); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } } - return NULL; + jobject result = jni()->NewObject(JNIJVMCI::StackTraceElement::clazz(), + JNIJVMCI::StackTraceElement::constructor(), + declaring_class, method_name, file_name, line_number); + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::new_HotSpotNmethod(const methodHandle& method, const char* name, jboolean isDefault, jlong compileId, JVMCI_TRAPS) { + JavaThread* THREAD = JavaThread::current(); + + JVMCIObject methodObject = get_jvmci_method(method(), JVMCI_CHECK_(JVMCIObject())); + + if (is_hotspot()) { + InstanceKlass* ik = InstanceKlass::cast(HotSpotJVMCI::HotSpotNmethod::klass()); + if (ik->should_be_initialized()) { + ik->initialize(CHECK_(JVMCIObject())); + } + oop obj = ik->allocate_instance(CHECK_(JVMCIObject())); + Handle obj_h(THREAD, obj); + Handle nameStr = java_lang_String::create_from_str(name, CHECK_(JVMCIObject())); + + // Call constructor + JavaCallArguments jargs; + jargs.push_oop(obj_h); + jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(methodObject))); + jargs.push_oop(nameStr); + jargs.push_int(isDefault); + jargs.push_long(compileId); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, ik, + vmSymbols::object_initializer_name(), + vmSymbols::method_string_bool_long_signature(), + &jargs, CHECK_(JVMCIObject())); + return wrap(obj_h()); + } else { + JNIAccessMark jni(this); + jobject nameStr = name == NULL ? NULL : jni()->NewStringUTF(name); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + + jobject result = jni()->NewObject(JNIJVMCI::HotSpotNmethod::clazz(), + JNIJVMCI::HotSpotNmethod::constructor(), + methodObject.as_jobject(), nameStr, isDefault); + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::make_local(JVMCIObject object) { + if (object.is_null()) { + return JVMCIObject(); + } + if (is_hotspot()) { + return wrap(JNIHandles::make_local(HotSpotJVMCI::resolve(object))); + } else { + JNIAccessMark jni(this); + return wrap(jni()->NewLocalRef(object.as_jobject())); + } +} + +JVMCIObject JVMCIEnv::make_global(JVMCIObject object) { + if (object.is_null()) { + return JVMCIObject(); + } + if (is_hotspot()) { + return wrap(JNIHandles::make_global(Handle(Thread::current(), HotSpotJVMCI::resolve(object)))); + } else { + JNIAccessMark jni(this); + return wrap(jni()->NewGlobalRef(object.as_jobject())); + } +} + +JVMCIObject JVMCIEnv::make_weak(JVMCIObject object) { + if (object.is_null()) { + return JVMCIObject(); + } + if (is_hotspot()) { + return wrap(JNIHandles::make_weak_global(Handle(Thread::current(), HotSpotJVMCI::resolve(object)))); + } else { + JNIAccessMark jni(this); + return wrap(jni()->NewWeakGlobalRef(object.as_jobject())); + } +} + +void JVMCIEnv::destroy_local(JVMCIObject object) { + if (is_hotspot()) { + JNIHandles::destroy_local(object.as_jobject()); + } else { + JNIAccessMark jni(this); + jni()->DeleteLocalRef(object.as_jobject()); + } +} + +void JVMCIEnv::destroy_global(JVMCIObject object) { + if (is_hotspot()) { + JNIHandles::destroy_global(object.as_jobject()); + } else { + JNIAccessMark jni(this); + jni()->DeleteGlobalRef(object.as_jobject()); + } +} + +void JVMCIEnv::destroy_weak(JVMCIObject object) { + if (is_hotspot()) { + JNIHandles::destroy_weak_global(object.as_jweak()); + } else { + JNIAccessMark jni(this); + jni()->DeleteWeakGlobalRef(object.as_jweak()); + } +} + +const char* JVMCIEnv::klass_name(JVMCIObject object) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(object)->klass()->signature_name(); + } else { + JVMCIObject name; + { + JNIAccessMark jni(this); + jclass jcl = jni()->GetObjectClass(object.as_jobject()); + jobject result = jni()->CallObjectMethod(jcl, JNIJVMCI::Class_getName_method()); + name = JVMCIObject::create(result, is_hotspot()); + } + return as_utf8_string(name); + } +} + +JVMCIObject JVMCIEnv::get_jvmci_method(const methodHandle& method, JVMCI_TRAPS) { + JVMCIObject method_object; + if (method() == NULL) { + return method_object; } - int holder_index = cpool->klass_ref_index_at(index); - bool holder_is_accessible; - Klass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); + Thread* THREAD = Thread::current(); + jmetadata handle = JVMCI::allocate_handle(method); + jboolean exception = false; + if (is_hotspot()) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) handle); + JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotResolvedJavaMethodImpl::klass(), + vmSymbols::fromMetaspace_name(), + vmSymbols::method_fromMetaspace_signature(), &args, THREAD); + if (HAS_PENDING_EXCEPTION) { + exception = true; + } else { + method_object = wrap((oop)result.get_jobject()); + } + } else { + JNIAccessMark jni(this); + method_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedJavaMethodImpl::clazz(), + JNIJVMCI::HotSpotResolvedJavaMethodImpl_fromMetaspace_method(), + (jlong) handle)); + exception = jni()->ExceptionCheck(); + } - // Get the method's name and signature. - Symbol* name_sym = cpool->name_ref_at(index); - Symbol* sig_sym = cpool->signature_ref_at(index); + if (exception) { + JVMCI::release_handle(handle); + return JVMCIObject(); + } + + assert(asMethod(method_object) == method(), "must be"); + if (get_HotSpotResolvedJavaMethodImpl_metadataHandle(method_object) != (jlong) handle) { + JVMCI::release_handle(handle); + } + assert(!method_object.is_null(), "must be"); + return method_object; +} + +JVMCIObject JVMCIEnv::get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS) { + JVMCIObject type; + if (klass.is_null()) { + return type; + } +#ifdef INCLUDE_ALL_GCS + if (UseG1GC) { + // The klass might have come from a weak location so enqueue + // the Class to make sure it's noticed by G1 + G1SATBCardTableModRefBS::enqueue(klass()->java_mirror()); + } +#endif // Klass* don't require tracking as Metadata* - if (cpool->has_preresolution() - || ((holder == SystemDictionary::MethodHandle_klass() || holder == SystemDictionary::VarHandle_klass()) && - MethodHandles::is_signature_polymorphic_name(holder, name_sym))) { - // Short-circuit lookups for JSR 292-related call sites. - // That is, do not rely only on name-based lookups, because they may fail - // if the names are not resolvable in the boot class loader (7056328). - switch (bc) { - case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - case Bytecodes::_invokespecial: - case Bytecodes::_invokestatic: - { - Method* m = ConstantPool::method_at_if_loaded(cpool, index); - if (m != NULL) { - return m; - } - } - break; - default: - break; + jlong pointer = (jlong) klass(); + JavaThread* THREAD = JavaThread::current(); + JVMCIObject signature = create_string(klass->signature_name(), JVMCI_CHECK_(JVMCIObject())); + jboolean exception = false; + if (is_hotspot()) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long(pointer); + args.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(signature))); + JavaCalls::call_static(&result, + HotSpotJVMCI::HotSpotResolvedObjectTypeImpl::klass(), + vmSymbols::fromMetaspace_name(), + vmSymbols::klass_fromMetaspace_signature(), &args, THREAD); + + if (HAS_PENDING_EXCEPTION) { + exception = true; + } else { + type = wrap((oop)result.get_jobject()); } + } else { + JNIAccessMark jni(this); + + HandleMark hm(THREAD); + type = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedObjectTypeImpl::clazz(), + JNIJVMCI::HotSpotResolvedObjectTypeImpl_fromMetaspace_method(), + pointer, signature.as_jstring())); + exception = jni()->ExceptionCheck(); + } + if (exception) { + return JVMCIObject(); + } + + assert(type.is_non_null(), "must have result"); + return type; +} + +JVMCIObject JVMCIEnv::get_jvmci_constant_pool(const constantPoolHandle& cp, JVMCI_TRAPS) { + JVMCIObject cp_object; + jmetadata handle = JVMCI::allocate_handle(cp); + jboolean exception = false; + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) handle); + JavaCalls::call_static(&result, + HotSpotJVMCI::HotSpotConstantPool::klass(), + vmSymbols::fromMetaspace_name(), + vmSymbols::constantPool_fromMetaspace_signature(), &args, THREAD); + if (HAS_PENDING_EXCEPTION) { + exception = true; + } else { + cp_object = wrap((oop)result.get_jobject()); + } + } else { + JNIAccessMark jni(this); + cp_object = JNIJVMCI::wrap(jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotConstantPool::clazz(), + JNIJVMCI::HotSpotConstantPool_fromMetaspace_method(), + (jlong) handle)); + exception = jni()->ExceptionCheck(); + } + + if (exception) { + JVMCI::release_handle(handle); + return JVMCIObject(); } - if (holder_is_accessible) { // Our declared holder is loaded. - constantTag tag = cpool->tag_ref_at(index); - methodHandle m = lookup_method(accessor, holder, name_sym, sig_sym, bc, tag); - if (!m.is_null()) { - // We found the method. - return m; - } + assert(!cp_object.is_null(), "must be"); + // Constant pools aren't cached so this is always a newly created object using the handle + assert(get_HotSpotConstantPool_metadataHandle(cp_object) == (jlong) handle, "must use same handle"); + return cp_object; +} + +JVMCIPrimitiveArray JVMCIEnv::new_booleanArray(int length, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + typeArrayOop result = oopFactory::new_boolArray(length, CHECK_(JVMCIObject())); + return wrap(result); + } else { + JNIAccessMark jni(this); + jbooleanArray result = jni()->NewBooleanArray(length); + return wrap(result); + } +} + +JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + typeArrayOop result = oopFactory::new_byteArray(length, CHECK_(JVMCIObject())); + return wrap(result); + } else { + JNIAccessMark jni(this); + jbyteArray result = jni()->NewByteArray(length); + return wrap(result); } +} - // Either the declared holder was not loaded, or the method could - // not be found. +JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject())); + objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject())); + return wrap(result); + } else { + JNIAccessMark jni(this); + jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), NULL); + return wrap(result); + } +} - return NULL; +JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + typeArrayOop result = oopFactory::new_intArray(length, CHECK_(JVMCIObject())); + return wrap(result); + } else { + JNIAccessMark jni(this); + jintArray result = jni()->NewIntArray(length); + return wrap(result); + } +} + +JVMCIPrimitiveArray JVMCIEnv::new_longArray(int length, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + typeArrayOop result = oopFactory::new_longArray(length, CHECK_(JVMCIObject())); + return wrap(result); + } else { + JNIAccessMark jni(this); + jlongArray result = jni()->NewLongArray(length); + return wrap(result); + } } -// ------------------------------------------------------------------ -InstanceKlass* JVMCIEnv::get_instance_klass_for_declared_method_holder(Klass* method_holder) { - // For the case of .clone(), the method holder can be an ArrayKlass* - // instead of an InstanceKlass*. For that case simply pretend that the - // declared holder is Object.clone since that's where the call will bottom out. - if (method_holder->is_instance_klass()) { - return InstanceKlass::cast(method_holder); - } else if (method_holder->is_array_klass()) { - return SystemDictionary::Object_klass(); +JVMCIObject JVMCIEnv::new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + HotSpotJVMCI::VMField::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::VMField::klass()->allocate_instance(CHECK_(JVMCIObject())); + HotSpotJVMCI::VMField::set_name(this, obj, HotSpotJVMCI::resolve(name)); + HotSpotJVMCI::VMField::set_type(this, obj, HotSpotJVMCI::resolve(type)); + HotSpotJVMCI::VMField::set_offset(this, obj, offset); + HotSpotJVMCI::VMField::set_address(this, obj, address); + HotSpotJVMCI::VMField::set_value(this, obj, HotSpotJVMCI::resolve(value)); + return wrap(obj); + } else { + JNIAccessMark jni(this); + jobject result = jni()->NewObject(JNIJVMCI::VMField::clazz(), + JNIJVMCI::VMField::constructor(), + get_jobject(name), get_jobject(type), offset, address, get_jobject(value)); + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + HotSpotJVMCI::VMFlag::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::VMFlag::klass()->allocate_instance(CHECK_(JVMCIObject())); + HotSpotJVMCI::VMFlag::set_name(this, obj, HotSpotJVMCI::resolve(name)); + HotSpotJVMCI::VMFlag::set_type(this, obj, HotSpotJVMCI::resolve(type)); + HotSpotJVMCI::VMFlag::set_value(this, obj, HotSpotJVMCI::resolve(value)); + return wrap(obj); + } else { + JNIAccessMark jni(this); + jobject result = jni()->NewObject(JNIJVMCI::VMFlag::clazz(), + JNIJVMCI::VMFlag::constructor(), + get_jobject(name), get_jobject(type), get_jobject(value)); + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + HotSpotJVMCI::VMIntrinsicMethod::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::VMIntrinsicMethod::klass()->allocate_instance(CHECK_(JVMCIObject())); + HotSpotJVMCI::VMIntrinsicMethod::set_declaringClass(this, obj, HotSpotJVMCI::resolve(declaringClass)); + HotSpotJVMCI::VMIntrinsicMethod::set_name(this, obj, HotSpotJVMCI::resolve(name)); + HotSpotJVMCI::VMIntrinsicMethod::set_descriptor(this, obj, HotSpotJVMCI::resolve(descriptor)); + HotSpotJVMCI::VMIntrinsicMethod::set_id(this, obj, id); + return wrap(obj); + } else { + JNIAccessMark jni(this); + jobject result = jni()->NewObject(JNIJVMCI::VMIntrinsicMethod::clazz(), + JNIJVMCI::VMIntrinsicMethod::constructor(), + get_jobject(declaringClass), get_jobject(name), get_jobject(descriptor), id); + return wrap(result); + } +} + +JVMCIObject JVMCIEnv::new_HotSpotStackFrameReference(JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance(CHECK_(JVMCIObject())); + return wrap(obj); } else { ShouldNotReachHere(); + return JVMCIObject(); } - return NULL; +} +JVMCIObject JVMCIEnv::new_JVMCIError(JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + HotSpotJVMCI::JVMCIError::klass()->initialize(CHECK_(JVMCIObject())); + oop obj = HotSpotJVMCI::JVMCIError::klass()->allocate_instance(CHECK_(JVMCIObject())); + return wrap(obj); + } else { + ShouldNotReachHere(); + return JVMCIObject(); + } } -// ------------------------------------------------------------------ -methodHandle JVMCIEnv::get_method_by_index(const constantPoolHandle& cpool, - int index, Bytecodes::Code bc, - InstanceKlass* accessor) { - ResourceMark rm; - return get_method_by_index_impl(cpool, index, bc, accessor); +JVMCIObject JVMCIEnv::get_object_constant(oop objOop, bool compressed, bool dont_register) { + JavaThread* THREAD = JavaThread::current(); + Handle obj = Handle(THREAD, objOop); + if (obj.is_null()) { + return JVMCIObject(); + } + if (is_hotspot()) { + HotSpotJVMCI::DirectHotSpotObjectConstantImpl::klass()->initialize(CHECK_(JVMCIObject())); + oop constant = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::klass()->allocate_instance(CHECK_(JVMCIObject())); + HotSpotJVMCI::DirectHotSpotObjectConstantImpl::set_object(this, constant, obj()); + HotSpotJVMCI::HotSpotObjectConstantImpl::set_compressed(this, constant, compressed); + return wrap(constant); + } else { + jlong handle = make_handle(obj); + JNIAccessMark jni(this); + jobject result = jni()->NewObject(JNIJVMCI::IndirectHotSpotObjectConstantImpl::clazz(), + JNIJVMCI::IndirectHotSpotObjectConstantImpl::constructor(), + handle, compressed, dont_register); + return wrap(result); + } +} + + +Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) { + if (constant.is_null()) { + return Handle(); + } + JavaThread* THREAD = JavaThread::current(); + if (is_hotspot()) { + assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type"); + oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant)); + return Handle(THREAD, obj); + } else { + assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type"); + jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); + oop result = resolve_handle(object_handle); + if (result == NULL) { + JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle()); + } + return Handle(THREAD, result); + } +} + +JVMCIObject JVMCIEnv::wrap(jobject object) { + return JVMCIObject::create(object, is_hotspot()); +} + +jlong JVMCIEnv::make_handle(const Handle& obj) { + assert(!obj.is_null(), "should only create handle for non-NULL oops"); + jobject handle = JVMCI::make_global(obj); + return (jlong) handle; +} + +oop JVMCIEnv::resolve_handle(jlong objectHandle) { + assert(objectHandle != 0, "should be a valid handle"); + oop obj = *((oopDesc**)objectHandle); + if (obj != NULL) { + oopDesc::verify(obj); + } + return obj; +} + +JVMCIObject JVMCIEnv::create_string(const char* str, JVMCI_TRAPS) { + if (is_hotspot()) { + JavaThread* THREAD = JavaThread::current(); + Handle result = java_lang_String::create_from_str(str, CHECK_(JVMCIObject())); + return HotSpotJVMCI::wrap(result()); + } else { + jobject result; + jboolean exception = false; + { + JNIAccessMark jni(this); + result = jni()->NewStringUTF(str); + exception = jni()->ExceptionCheck(); + } + return wrap(result); + } +} + +bool JVMCIEnv::equals(JVMCIObject a, JVMCIObject b) { + if (is_hotspot()) { + return HotSpotJVMCI::resolve(a) == HotSpotJVMCI::resolve(b); + } else { + JNIAccessMark jni(this); + return jni()->IsSameObject(a.as_jobject(), b.as_jobject()) != 0; + } } -// ------------------------------------------------------------------ -// Check for changes to the system dictionary during compilation -// class loads, evolution, breakpoints -JVMCIEnv::CodeInstallResult JVMCIEnv::validate_compile_task_dependencies(Dependencies* dependencies, Handle compiled_code, - JVMCIEnv* env, char** failure_detail) { - // If JVMTI capabilities were enabled during compile, the compilation is invalidated. - if (env != NULL && env->jvmti_state_changed()) { - *failure_detail = (char*) "Jvmti state change during compilation invalidated dependencies"; - return JVMCIEnv::dependencies_failed; +BasicType JVMCIEnv::kindToBasicType(JVMCIObject kind, JVMCI_TRAPS) { + if (kind.is_null()) { + JVMCI_THROW_(NullPointerException, T_ILLEGAL); + } + jchar ch = get_JavaKind_typeChar(kind); + switch(ch) { + case 'Z': return T_BOOLEAN; + case 'B': return T_BYTE; + case 'S': return T_SHORT; + case 'C': return T_CHAR; + case 'I': return T_INT; + case 'F': return T_FLOAT; + case 'J': return T_LONG; + case 'D': return T_DOUBLE; + case 'A': return T_OBJECT; + case '-': return T_ILLEGAL; + default: + JVMCI_ERROR_(T_ILLEGAL, "unexpected Kind: %c", ch); + } +} + +void JVMCIEnv::initialize_installed_code(JVMCIObject installed_code, CodeBlob* cb, JVMCI_TRAPS) { + // Ensure that all updates to the InstalledCode fields are consistent. + if (get_InstalledCode_address(installed_code) != 0) { + JVMCI_THROW_MSG(InternalError, "InstalledCode instance already in use"); + } + if (!isa_HotSpotInstalledCode(installed_code)) { + JVMCI_THROW_MSG(InternalError, "InstalledCode instance must be a subclass of HotSpotInstalledCode"); } - // Dependencies must be checked when the system dictionary changes - // or if we don't know whether it has changed (i.e., env == NULL). - bool counter_changed = env == NULL || env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); - CompileTask* task = env == NULL ? NULL : env->task(); - Dependencies::DepType result = dependencies->validate_dependencies(task, counter_changed, failure_detail); - if (result == Dependencies::end_marker) { - return JVMCIEnv::ok; + // Ignore the version which can stay at 0 + if (cb->is_nmethod()) { + nmethod* nm = cb->as_nmethod_or_null(); + if (!nm->is_alive()) { + JVMCI_THROW_MSG(InternalError, "nmethod has been reclaimed"); + } + if (nm->is_in_use()) { + set_InstalledCode_entryPoint(installed_code, (jlong) nm->verified_entry_point()); + } + } else { + set_InstalledCode_entryPoint(installed_code, (jlong) cb->code_begin()); + } + set_InstalledCode_address(installed_code, (jlong) cb); + set_HotSpotInstalledCode_size(installed_code, cb->size()); + set_HotSpotInstalledCode_codeStart(installed_code, (jlong) cb->code_begin()); + set_HotSpotInstalledCode_codeSize(installed_code, cb->code_size()); +} + + +void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, JVMCI_TRAPS) { + if (mirror.is_null()) { + JVMCI_THROW(NullPointerException); } - if (!Dependencies::is_klass_type(result) || counter_changed) { - return JVMCIEnv::dependencies_failed; + jlong nativeMethod = get_InstalledCode_address(mirror); + nmethod* nm = JVMCIENV->asNmethod(mirror); + if (nm == NULL) { + // Nothing to do + return; + } + + Thread* THREAD = Thread::current(); + if (!mirror.is_hotspot() && !THREAD->is_Java_thread()) { + // Calling back into native might cause the execution to block, so only allow this when calling + // from a JavaThread, which is the normal case anyway. + JVMCI_THROW_MSG(IllegalArgumentException, + "Cannot invalidate HotSpotNmethod object in shared library VM heap from non-JavaThread"); } - // The dependencies were invalid at the time of installation - // without any intervening modification of the system - // dictionary. That means they were invalidly constructed. - return JVMCIEnv::dependencies_invalid; + + nmethodLocker nml(nm); + if (nm->is_alive()) { + // Invalidating the HotSpotNmethod means we want the nmethod + // to be deoptimized. + nm->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + + // A HotSpotNmethod instance can only reference a single nmethod + // during its lifetime so simply clear it here. + set_InstalledCode_address(mirror, 0); +} + +Klass* JVMCIEnv::asKlass(JVMCIObject obj) { + return (Klass*) get_HotSpotResolvedObjectTypeImpl_metadataPointer(obj); +} + +Method* JVMCIEnv::asMethod(JVMCIObject obj) { + Method** metadataHandle = (Method**) get_HotSpotResolvedJavaMethodImpl_metadataHandle(obj); + return *metadataHandle; } -// ------------------------------------------------------------------ -JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( - const methodHandle& method, - nmethod*& nm, - int entry_bci, - CodeOffsets* offsets, - int orig_pc_offset, - CodeBuffer* code_buffer, - int frame_words, - OopMapSet* oop_map_set, - ExceptionHandlerTable* handler_table, - AbstractCompiler* compiler, - DebugInformationRecorder* debug_info, - Dependencies* dependencies, - JVMCIEnv* env, - int compile_id, - bool has_unsafe_access, - bool has_wide_vector, - Handle installed_code, - Handle compiled_code, - Handle speculation_log) { - JVMCI_EXCEPTION_CONTEXT; - nm = NULL; - int comp_level = CompLevel_full_optimization; - char* failure_detail = NULL; - JVMCIEnv::CodeInstallResult result; - { - // To prevent compile queue updates. - MutexLocker locker(MethodCompileQueue_lock, THREAD); +ConstantPool* JVMCIEnv::asConstantPool(JVMCIObject obj) { + ConstantPool** metadataHandle = (ConstantPool**) get_HotSpotConstantPool_metadataHandle(obj); + return *metadataHandle; +} - // Prevent SystemDictionary::add_to_hierarchy from running - // and invalidating our dependencies until we install this method. - MutexLocker ml(Compile_lock); - - // Encode the dependencies now, so we can check them right away. - dependencies->encode_content_bytes(); - - // Record the dependencies for the current compile in the log - if (LogCompilation) { - for (Dependencies::DepStream deps(dependencies); deps.next(); ) { - deps.log_dependency(); - } - } - - // Check for {class loads, evolution, breakpoints} during compilation - result = validate_compile_task_dependencies(dependencies, compiled_code, env, &failure_detail); - if (result != JVMCIEnv::ok) { - // While not a true deoptimization, it is a preemptive decompile. - MethodData* mdp = method()->method_data(); - if (mdp != NULL) { - mdp->inc_decompile_count(); -#ifdef ASSERT - if (mdp->decompile_count() > (uint)PerMethodRecompilationCutoff) { - ResourceMark m; - tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string()); - } -#endif - } - // All buffers in the CodeBuffer are allocated in the CodeCache. - // If the code buffer is created on each compile attempt - // as in C2, then it must be freed. - //code_buffer->free_blob(); - } else { - ImplicitExceptionTable implicit_tbl; - nm = nmethod::new_nmethod(method, - compile_id, - entry_bci, - offsets, - orig_pc_offset, - debug_info, dependencies, code_buffer, - frame_words, oop_map_set, - handler_table, &implicit_tbl, - compiler, comp_level, - JNIHandles::make_weak_global(installed_code), - JNIHandles::make_weak_global(speculation_log)); - - // Free codeBlobs - //code_buffer->free_blob(); - if (nm == NULL) { - // The CodeCache is full. Print out warning and disable compilation. - { - MutexUnlocker ml(Compile_lock); - MutexUnlocker locker(MethodCompileQueue_lock); - CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level)); - } - } else { - nm->set_has_unsafe_access(has_unsafe_access); - nm->set_has_wide_vectors(has_wide_vector); - - // Record successful registration. - // (Put nm into the task handle *before* publishing to the Java heap.) - CompileTask* task = env == NULL ? NULL : env->task(); - if (task != NULL) { - task->set_code(nm); +CodeBlob* JVMCIEnv::asCodeBlob(JVMCIObject obj) { + address code = (address) get_InstalledCode_address(obj); + if (code == NULL) { + return NULL; + } + if (isa_HotSpotNmethod(obj)) { + jlong compile_id_snapshot = get_HotSpotNmethod_compileIdSnapshot(obj); + if (compile_id_snapshot != 0L) { + // A HotSpotNMethod not in an nmethod's oops table so look up + // the nmethod and then update the fields based on its state. + CodeBlob* cb = CodeCache::find_blob_unsafe(code); + if (cb == (CodeBlob*) code) { + // Found a live CodeBlob with the same address, make sure it's the same nmethod + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL && nm->compile_id() == compile_id_snapshot) { + if (!nm->is_alive()) { + // Break the links from the mirror to the nmethod + set_InstalledCode_address(obj, 0); + set_InstalledCode_entryPoint(obj, 0); + } else if (nm->is_not_entrant()) { + // Zero the entry point so that the nmethod + // cannot be invoked by the mirror but can + // still be deoptimized. + set_InstalledCode_entryPoint(obj, 0); + } + return cb; } - - if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) { - if (entry_bci == InvocationEntryBci) { - if (TieredCompilation) { - // If there is an old version we're done with it - CompiledMethod* old = method->code(); - if (TraceMethodReplacement && old != NULL) { - ResourceMark rm; - char *method_name = method->name_and_sig_as_C_string(); - tty->print_cr("Replacing method %s", method_name); - } - if (old != NULL ) { - old->make_not_entrant(); - } - } - if (TraceNMethodInstalls) { - ResourceMark rm; - char *method_name = method->name_and_sig_as_C_string(); - ttyLocker ttyl; - tty->print_cr("Installing method (%d) %s [entry point: %p]", - comp_level, - method_name, nm->entry_point()); - } - // Allow the code to be executed - method->set_code(method, nm); - } else { - if (TraceNMethodInstalls ) { - ResourceMark rm; - char *method_name = method->name_and_sig_as_C_string(); - ttyLocker ttyl; - tty->print_cr("Installing osr method (%d) %s @ %d", - comp_level, - method_name, - entry_bci); - } - InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); - } - } - nm->make_in_use(); } - result = nm != NULL ? JVMCIEnv::ok :JVMCIEnv::cache_full; + // Clear the InstalledCode fields of this HotSpotNmethod + // that no longer refers to an nmethod in the code cache. + set_InstalledCode_address(obj, 0); + set_InstalledCode_entryPoint(obj, 0); + return NULL; } } + return (CodeBlob*) code; +} - // String creation must be done outside lock - if (failure_detail != NULL) { - // A failure to allocate the string is silently ignored. - Handle message = java_lang_String::create_from_str(failure_detail, THREAD); - HotSpotCompiledNmethod::set_installationFailureMessage(compiled_code, message()); + +// Generate implementations for the initialize, new, isa, get and set methods for all the types and +// fields declared in the JVMCI_CLASSES_DO macro. + +#define START_CLASS(className, fullClassName) \ + void JVMCIEnv::className##_initialize(JVMCI_TRAPS) { \ + if (is_hotspot()) { \ + HotSpotJVMCI::className::initialize(JVMCI_CHECK); \ + } else { \ + JNIJVMCI::className::initialize(JVMCI_CHECK); \ + } \ + } \ + JVMCIObjectArray JVMCIEnv::new_##className##_array(int length, JVMCI_TRAPS) { \ + if (is_hotspot()) { \ + Thread* THREAD = Thread::current(); \ + objArrayOop array = oopFactory::new_objArray(HotSpotJVMCI::className::klass(), length, CHECK_(JVMCIObject())); \ + return (JVMCIObjectArray) wrap(array); \ + } else { \ + JNIAccessMark jni(this); \ + jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::className::clazz(), NULL); \ + return wrap(result); \ + } \ + } \ + bool JVMCIEnv::isa_##className(JVMCIObject object) { \ + if (is_hotspot()) { \ + return HotSpotJVMCI::className::is_instance(this, object); \ + } else { \ + return JNIJVMCI::className::is_instance(this, object); \ + } \ + } + +#define END_CLASS + +#define FIELD(className, name, type, accessor, cast) \ + type JVMCIEnv::get_##className##_##name(JVMCIObject obj) { \ + if (is_hotspot()) { \ + return HotSpotJVMCI::className::get_##name(this, obj); \ + } else { \ + return JNIJVMCI::className::get_##name(this, obj); \ + } \ + } \ + void JVMCIEnv::set_##className##_##name(JVMCIObject obj, type x) { \ + if (is_hotspot()) { \ + HotSpotJVMCI::className::set_##name(this, obj, x); \ + } else { \ + JNIJVMCI::className::set_##name(this, obj, x); \ + } \ } - // JVMTI -- compiled method notification (must be done outside lock) - if (nm != NULL) { - nm->post_compiled_method_load_event(); +#define EMPTY_CAST +#define CHAR_FIELD(className, name) FIELD(className, name, jchar, Char, EMPTY_CAST) +#define INT_FIELD(className, name) FIELD(className, name, jint, Int, EMPTY_CAST) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, jboolean, Boolean, EMPTY_CAST) +#define LONG_FIELD(className, name) FIELD(className, name, jlong, Long, EMPTY_CAST) +#define FLOAT_FIELD(className, name) FIELD(className, name, jfloat, Float, EMPTY_CAST) + +#define OBJECT_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObject, Object, EMPTY_CAST) +#define OBJECTARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) +#define PRIMARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIPrimitiveArray, Object, (JVMCIPrimitiveArray)) + +#define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObject, Object, (JVMCIObject)) +#define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) - if (env == NULL) { - // This compile didn't come through the CompileBroker so perform the printing here - DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); - nm->maybe_print_nmethod(directive); - DirectivesStack::release(directive); - } +#define OOPISH_FIELD(className, name, type, accessor, cast) \ + type JVMCIEnv::get_##className##_##name(JVMCIObject obj) { \ + if (is_hotspot()) { \ + return HotSpotJVMCI::className::get_##name(this, obj); \ + } else { \ + return JNIJVMCI::className::get_##name(this, obj); \ + } \ + } \ + void JVMCIEnv::set_##className##_##name(JVMCIObject obj, type x) { \ + if (is_hotspot()) { \ + HotSpotJVMCI::className::set_##name(this, obj, x); \ + } else { \ + JNIJVMCI::className::set_##name(this, obj, x); \ + } \ } - return result; -} +#define STATIC_OOPISH_FIELD(className, name, type, accessor, cast) \ + type JVMCIEnv::get_##className##_##name() { \ + if (is_hotspot()) { \ + return HotSpotJVMCI::className::get_##name(this); \ + } else { \ + return JNIJVMCI::className::get_##name(this); \ + } \ + } \ + void JVMCIEnv::set_##className##_##name(type x) { \ + if (is_hotspot()) { \ + HotSpotJVMCI::className::set_##name(this, x); \ + } else { \ + JNIJVMCI::className::set_##name(this, x); \ + } \ + } + +#define STATIC_PRIMITIVE_FIELD(className, name, type, accessor, cast) \ + type JVMCIEnv::get_##className##_##name() { \ + if (is_hotspot()) { \ + return HotSpotJVMCI::className::get_##name(this); \ + } else { \ + return JNIJVMCI::className::get_##name(this); \ + } \ + } \ + void JVMCIEnv::set_##className##_##name(type x) { \ + if (is_hotspot()) { \ + HotSpotJVMCI::className::set_##name(this, x); \ + } else { \ + JNIJVMCI::className::set_##name(this, x); \ + } \ + } +#define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint, Int, EMPTY_CAST) +#define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean, Boolean, EMPTY_CAST) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) + +JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) + +#undef START_CLASS +#undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciEnv.hpp --- a/src/hotspot/share/jvmci/jvmciEnv.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp Wed May 01 12:31:29 2019 -0700 @@ -25,14 +25,16 @@ #ifndef SHARE_JVMCI_JVMCIENV_HPP #define SHARE_JVMCI_JVMCIENV_HPP -#include "classfile/systemDictionary.hpp" -#include "code/debugInfoRec.hpp" -#include "code/dependencies.hpp" -#include "code/exceptionHandlerTable.hpp" -#include "compiler/oopMap.hpp" +#include "classfile/javaClasses.hpp" +#include "jvmci/jvmciJavaClasses.hpp" #include "runtime/thread.hpp" class CompileTask; +class JVMCIObject; +class JVMCIObjectArray; +class JVMCIPrimitiveArray; +class JVMCICompiler; +class JVMCIRuntime; // Bring the JVMCI compiler thread into the VM state. #define JVMCI_VM_ENTRY_MARK \ @@ -47,64 +49,58 @@ JavaThread* thread=JavaThread::current(); \ Thread* THREAD = thread; -// -// This class is the top level broker for requests from the compiler -// to the VM. -class JVMCIEnv : StackObj { - CI_PACKAGE_ACCESS_TO - - friend class JVMCIVMStructs; - friend class CompileBroker; - friend class Dependencies; // for get_object, during logging +// Helper to log more context on a JNI exception +#define JVMCI_EXCEPTION_CHECK(env, ...) \ + do { \ + if (env->ExceptionCheck()) { \ + if (env != JavaThread::current()->jni_environment() && JVMCIEnv::get_shared_library_path() != NULL) { \ + tty->print_cr("In JVMCI shared library (%s):", JVMCIEnv::get_shared_library_path()); \ + } \ + tty->print_cr(__VA_ARGS__); \ + return; \ + } \ + } while(0) -public: +// Helper class to ensure that references to Klass* are kept alive for G1 +class JVMCIKlassHandle : public StackObj { + private: + Klass* _klass; + Handle _holder; + Thread* _thread; - enum CodeInstallResult { - ok, - dependencies_failed, - dependencies_invalid, - cache_full, - code_too_large - }; + Klass* klass() const { return _klass; } + Klass* non_null_klass() const { assert(_klass != NULL, "resolving NULL _klass"); return _klass; } - // Look up a klass by name from a particular class loader (the accessor's). - // If require_local, result must be defined in that class loader, or NULL. - // If !require_local, a result from remote class loader may be reported, - // if sufficient class loader constraints exist such that initiating - // a class loading request from the given loader is bound to return - // the class defined in the remote loader (or throw an error). - // - // Return an unloaded klass if !require_local and no class at all is found. - // - // The CI treats a klass as loaded if it is consistently defined in - // another loader, even if it hasn't yet been loaded in all loaders - // that could potentially see it via delegation. - static Klass* get_klass_by_name(Klass* accessing_klass, Symbol* klass_name, bool require_local); + public: + /* Constructors */ + JVMCIKlassHandle (Thread* thread) : _klass(NULL), _thread(thread) {} + JVMCIKlassHandle (Thread* thread, Klass* klass); + + JVMCIKlassHandle (const JVMCIKlassHandle &h): _klass(h._klass), _holder(h._holder), _thread(h._thread) {} + JVMCIKlassHandle& operator=(const JVMCIKlassHandle &s); + JVMCIKlassHandle& operator=(Klass* klass); + + /* Operators for ease of use */ + Klass* operator () () const { return klass(); } + Klass* operator -> () const { return non_null_klass(); } - // Constant pool access. - static Klass* get_klass_by_index(const constantPoolHandle& cpool, - int klass_index, - bool& is_accessible, - Klass* loading_klass); - static void get_field_by_index(InstanceKlass* loading_klass, fieldDescriptor& fd, - int field_index); - static methodHandle get_method_by_index(const constantPoolHandle& cpool, - int method_index, Bytecodes::Code bc, - InstanceKlass* loading_klass); + bool operator == (Klass* o) const { return klass() == o; } + bool operator == (const JVMCIKlassHandle& h) const { return klass() == h.klass(); } - JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter); + /* Null checks */ + bool is_null() const { return _klass == NULL; } + bool not_null() const { return _klass != NULL; } +}; -private: +// A class that maintains the state needed for compilations requested +// by the CompileBroker. It is created in the broker and passed through +// into the code installation step. +class JVMCICompileState : public ResourceObj { + friend class VMStructs; + private: CompileTask* _task; int _system_dictionary_modification_counter; - // Compilation result values - bool _retryable; - const char* _failure_reason; - - // Specifies if _failure_reason is on the C heap. - bool _failure_reason_on_C_heap; - // Cache JVMTI state. Defined as bytes so that reading them from Java // via Unsafe is well defined (the C++ type for bool is implementation // defined and may not be the same as a Java boolean). @@ -113,43 +109,20 @@ jbyte _jvmti_can_post_on_exceptions; jbyte _jvmti_can_pop_frame; - // Implementation methods for loading and constant pool access. - static Klass* get_klass_by_name_impl(Klass* accessing_klass, - const constantPoolHandle& cpool, - Symbol* klass_name, - bool require_local); - static Klass* get_klass_by_index_impl(const constantPoolHandle& cpool, - int klass_index, - bool& is_accessible, - Klass* loading_klass); - static void get_field_by_index_impl(InstanceKlass* loading_klass, fieldDescriptor& fd, - int field_index); - static methodHandle get_method_by_index_impl(const constantPoolHandle& cpool, - int method_index, Bytecodes::Code bc, - InstanceKlass* loading_klass); + // Compilation result values. + bool _retryable; + const char* _failure_reason; - // Helper methods - static bool check_klass_accessibility(Klass* accessing_klass, Klass* resolved_klass); - static methodHandle lookup_method(InstanceKlass* accessor, - Klass* holder, - Symbol* name, - Symbol* sig, - Bytecodes::Code bc, - constantTag tag); + // Specifies if _failure_reason is on the C heap. If so, it is allocated + // with the mtJVMCI NMT flag. + bool _failure_reason_on_C_heap; - private: - - // Is this thread currently in the VM state? - static bool is_in_vm(); + public: + JVMCICompileState(CompileTask* task, int system_dictionary_modification_counter); - // Helper routine for determining the validity of a compilation - // with respect to concurrent class loading. - static JVMCIEnv::CodeInstallResult validate_compile_task_dependencies(Dependencies* target, Handle compiled_code, - JVMCIEnv* env, char** failure_detail); - -public: CompileTask* task() { return _task; } + int system_dictionary_modification_counter() { return _system_dictionary_modification_counter; } bool jvmti_state_changed() const; bool jvmti_can_hotswap_or_post_breakpoint() const { return _jvmti_can_hotswap_or_post_breakpoint != 0; } bool jvmti_can_access_local_variables() const { return _jvmti_can_access_local_variables != 0; } @@ -165,34 +138,355 @@ _failure_reason_on_C_heap = reason_on_C_heap; _retryable = retryable; } +}; - // Register the result of a compilation. - static JVMCIEnv::CodeInstallResult register_method( - const methodHandle& target, - nmethod*& nm, - int entry_bci, - CodeOffsets* offsets, - int orig_pc_offset, - CodeBuffer* code_buffer, - int frame_words, - OopMapSet* oop_map_set, - ExceptionHandlerTable* handler_table, - AbstractCompiler* compiler, - DebugInformationRecorder* debug_info, - Dependencies* dependencies, - JVMCIEnv* env, - int compile_id, - bool has_unsafe_access, - bool has_wide_vector, - Handle installed_code, - Handle compiled_code, - Handle speculation_log); + +// This class is a top level wrapper around interactions between HotSpot +// and the JVMCI Java code. It supports both a HotSpot heap based +// runtime with HotSpot oop based accessors as well as a shared library +// based runtime that is accessed through JNI. It abstracts away all +// interactions with JVMCI objects so that a single version of the +// HotSpot C++ code can can work with either runtime. +class JVMCIEnv : public ResourceObj { + friend class JNIAccessMark; + + static char* _shared_library_path; // argument to os:dll_load + static void* _shared_library_handle; // result of os::dll_load + static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library + + // Attaches the current thread to the JavaVM in the shared library, + // initializing the shared library VM first if necessary. + // Returns the JNI interface pointer of the current thread. + // The _shared_library_* fields are initialized by the first + // call to this method. + static JNIEnv* attach_shared_library(); + + // Initializes the _env, _mode and _runtime fields. + void init_env_mode_runtime(JNIEnv* parent_env); + + void init(bool is_hotspot, const char* file, int line); + + JNIEnv* _env; // JNI env for calling into shared library + JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime + bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in + bool _throw_to_caller; // Propagate an exception raised in this env to the caller? + const char* _file; // The file and ... + int _line; // ... line where this JNIEnv was created + + // Translates an exception on the HotSpot heap to an exception on + // the shared library heap. The translation includes the stack and + // causes of `throwable`. The translated exception is pending in the + // shared library thread upon returning. + void translate_hotspot_exception_to_jni_exception(JavaThread* THREAD, const Handle& throwable); + +public: + // Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM). + // An exception occurring within the scope is left pending when the + // scope closes so that it will be propagated back to Java. + // The JVMCIEnv destructor translates the exception object for the + // Java runtime if necessary. + JVMCIEnv(JNIEnv* env, const char* file, int line); + + // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker. + // An exception occurring within the scope must not be propagated back to + // the CompileBroker. + JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line); + + // Opens a JNIEnv scope for a call from within the VM. An exception occurring + // within the scope must not be propagated back to the caller. + JVMCIEnv(JavaThread* env, const char* file, int line); + + // Opens a JNIEnv scope for accessing `for_object`. An exception occurring + // within the scope must not be propagated back to the caller. + JVMCIEnv(JVMCIObject for_object, const char* file, int line) { + // A JNI call to access an object in the shared library heap + // can block or take a long time so do not allow such access + // on the VM thread. + assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(), + "cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object"); + init(for_object.is_hotspot(), file, line); + } + + // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true + // otherwise for the shared library runtime. An exception occurring + // within the scope must not be propagated back to the caller. + JVMCIEnv(bool is_hotspot, const char* file, int line) { + init(is_hotspot, file, line); + } + + ~JVMCIEnv(); + + JVMCIRuntime* runtime() { + return _runtime; + } + + // Initializes Services.savedProperties in the shared library by copying + // the values from the same field in the HotSpot heap. + void copy_saved_properties(); + + jboolean has_pending_exception(); + void clear_pending_exception(); + + // Prints an exception and stack trace of a pending exception. + void describe_pending_exception(bool clear); + + int get_length(JVMCIArray array); + + JVMCIObject get_object_at(JVMCIObjectArray array, int index); + void put_object_at(JVMCIObjectArray array, int index, JVMCIObject value); + + jboolean get_bool_at(JVMCIPrimitiveArray array, int index); + void put_bool_at(JVMCIPrimitiveArray array, int index, jboolean value); + + jbyte get_byte_at(JVMCIPrimitiveArray array, int index); + void put_byte_at(JVMCIPrimitiveArray array, int index, jbyte value); + + jint get_int_at(JVMCIPrimitiveArray array, int index); + void put_int_at(JVMCIPrimitiveArray array, int index, jint value); + + long get_long_at(JVMCIPrimitiveArray array, int index); + void put_long_at(JVMCIPrimitiveArray array, int index, jlong value); + + void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes); + void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes); + + JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS); + + jboolean is_boxing_object(BasicType type, JVMCIObject object); + + // Get the primitive value from a Java boxing object. It's hard error to + // pass a non-primitive BasicType. + jvalue get_boxed_value(BasicType type, JVMCIObject object); + + // Return the BasicType of the object if it's a boxing object, otherwise return T_ILLEGAL. + BasicType get_box_type(JVMCIObject object); + + // Create a boxing object of the appropriate primitive type. + JVMCIObject create_box(BasicType type, jvalue* value, JVMCI_TRAPS); + + const char* as_utf8_string(JVMCIObject str); + char* as_utf8_string(JVMCIObject str, char* buf, int buflen); + + JVMCIObject create_string(Symbol* str, JVMCI_TRAPS) { + return create_string(str->as_C_string(), JVMCI_CHECK_(JVMCIObject())); + } + + JVMCIObject create_string(const char* str, JVMCI_TRAPS); + + bool equals(JVMCIObject a, JVMCIObject b); + + // Convert into a JNI handle for the appropriate runtime + jobject get_jobject(JVMCIObject object) { assert(object.as_jobject() == NULL || is_hotspot() == object.is_hotspot(), "mismatch"); return object.as_jobject(); } + jarray get_jarray(JVMCIArray array) { assert(array.as_jobject() == NULL || is_hotspot() == array.is_hotspot(), "mismatch"); return array.as_jobject(); } + jobjectArray get_jobjectArray(JVMCIObjectArray objectArray) { assert(objectArray.as_jobject() == NULL || is_hotspot() == objectArray.is_hotspot(), "mismatch"); return objectArray.as_jobject(); } + jbyteArray get_jbyteArray(JVMCIPrimitiveArray primitiveArray) { assert(primitiveArray.as_jobject() == NULL || is_hotspot() == primitiveArray.is_hotspot(), "mismatch"); return primitiveArray.as_jbyteArray(); } + + JVMCIObject wrap(jobject obj); + JVMCIObjectArray wrap(jobjectArray obj) { return (JVMCIObjectArray) wrap((jobject) obj); } + JVMCIPrimitiveArray wrap(jintArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); } + JVMCIPrimitiveArray wrap(jbooleanArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); } + JVMCIPrimitiveArray wrap(jbyteArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); } + JVMCIPrimitiveArray wrap(jlongArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); } + + private: + JVMCIObject wrap(oop obj) { assert(is_hotspot(), "must be"); return wrap(JNIHandles::make_local(obj)); } + JVMCIObjectArray wrap(objArrayOop obj) { assert(is_hotspot(), "must be"); return (JVMCIObjectArray) wrap(JNIHandles::make_local(obj)); } + JVMCIPrimitiveArray wrap(typeArrayOop obj) { assert(is_hotspot(), "must be"); return (JVMCIPrimitiveArray) wrap(JNIHandles::make_local(obj)); } + + public: + // Compiles a method with the JVMIC compiler. + // Caller must handle pending exception. + JVMCIObject call_HotSpotJVMCIRuntime_compileMethod(JVMCIObject runtime, JVMCIObject method, int entry_bci, + jlong compile_state, int id); + + void call_HotSpotJVMCIRuntime_bootstrapFinished(JVMCIObject runtime, JVMCI_TRAPS); + void call_HotSpotJVMCIRuntime_shutdown(JVMCIObject runtime); + JVMCIObject call_HotSpotJVMCIRuntime_runtime(JVMCI_TRAPS); + JVMCIObject call_JVMCI_getRuntime(JVMCI_TRAPS); + JVMCIObject call_HotSpotJVMCIRuntime_getCompiler(JVMCIObject runtime, JVMCI_TRAPS); + + JVMCIObject call_HotSpotJVMCIRuntime_callToString(JVMCIObject object, JVMCI_TRAPS); + + JVMCIObject call_PrimitiveConstant_forTypeChar(jchar kind, jlong value, JVMCI_TRAPS); + JVMCIObject call_JavaConstant_forFloat(float value, JVMCI_TRAPS); + JVMCIObject call_JavaConstant_forDouble(double value, JVMCI_TRAPS); + + BasicType kindToBasicType(JVMCIObject kind, JVMCI_TRAPS); - // converts the Klass* representing the holder of a method into a - // InstanceKlass*. This is needed since the holder of a method in - // the bytecodes could be an array type. Basically this converts - // array types into java/lang/Object and other types stay as they are. - static InstanceKlass* get_instance_klass_for_declared_method_holder(Klass* klass); +#define DO_THROW(name) \ + void throw_##name(const char* msg = NULL); + + DO_THROW(InternalError) + DO_THROW(ArrayIndexOutOfBoundsException) + DO_THROW(IllegalStateException) + DO_THROW(NullPointerException) + DO_THROW(IllegalArgumentException) + DO_THROW(InvalidInstalledCodeException) + DO_THROW(UnsatisfiedLinkError) + +#undef DO_THROW + + void fthrow_error(const char* file, int line, const char* format, ...) ATTRIBUTE_PRINTF(4, 5); + + // Given an instance of HotSpotInstalledCode return the corresponding CodeBlob* + CodeBlob* asCodeBlob(JVMCIObject code); + + nmethod* asNmethod(JVMCIObject code) { + CodeBlob* cb = asCodeBlob(code); + if (cb == NULL) { + return NULL; + } + nmethod* nm = cb->as_nmethod_or_null(); + guarantee(nm != NULL, "not an nmethod"); + return nm; + } + + MethodData* asMethodData(jlong metaspaceMethodData) { + return (MethodData*) (address) metaspaceMethodData; + } + + const char* klass_name(JVMCIObject object); + + // Unpack an instance of HotSpotResolvedJavaMethodImpl into the original Method* + Method* asMethod(JVMCIObject jvmci_method); + Method* asMethod(jobject jvmci_method) { return asMethod(wrap(jvmci_method)); } + + // Unpack an instance of HotSpotResolvedObjectTypeImpl into the original Klass* + Klass* asKlass(JVMCIObject jvmci_type); + Klass* asKlass(jobject jvmci_type) { return asKlass(wrap(jvmci_type)); } + + JVMCIObject get_jvmci_method(const methodHandle& method, JVMCI_TRAPS); + + JVMCIObject get_jvmci_type(const JVMCIKlassHandle& klass, JVMCI_TRAPS); + + // Unpack an instance of HotSpotConstantPool into the original ConstantPool* + ConstantPool* asConstantPool(JVMCIObject constant_pool); + ConstantPool* asConstantPool(jobject constant_pool) { return asConstantPool(wrap(constant_pool)); } + + JVMCIObject get_jvmci_constant_pool(const constantPoolHandle& cp, JVMCI_TRAPS); + JVMCIObject get_jvmci_primitive_type(BasicType type); + + Handle asConstant(JVMCIObject object, JVMCI_TRAPS); + JVMCIObject get_object_constant(oop objOop, bool compressed = false, bool dont_register = false); + + JVMCIPrimitiveArray new_booleanArray(int length, JVMCI_TRAPS); + JVMCIPrimitiveArray new_byteArray(int length, JVMCI_TRAPS); + JVMCIPrimitiveArray new_intArray(int length, JVMCI_TRAPS); + JVMCIPrimitiveArray new_longArray(int length, JVMCI_TRAPS); + + JVMCIObjectArray new_byte_array_array(int length, JVMCI_TRAPS); + + JVMCIObject new_StackTraceElement(const methodHandle& method, int bci, JVMCI_TRAPS); + JVMCIObject new_HotSpotNmethod(const methodHandle& method, const char* name, jboolean isDefault, jlong compileId, JVMCI_TRAPS); + JVMCIObject new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS); + JVMCIObject new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS); + JVMCIObject new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS); + JVMCIObject new_HotSpotStackFrameReference(JVMCI_TRAPS); + JVMCIObject new_JVMCIError(JVMCI_TRAPS); + + jlong make_handle(const Handle& obj); + oop resolve_handle(jlong objectHandle); + + // These are analagous to the JNI routines + JVMCIObject make_local(JVMCIObject object); + JVMCIObject make_global(JVMCIObject object); + JVMCIObject make_weak(JVMCIObject object); + void destroy_local(JVMCIObject object); + void destroy_global(JVMCIObject object); + void destroy_weak(JVMCIObject object); + + // Deoptimizes the nmethod (if any) in the HotSpotNmethod.address + // field of mirror. The field is subsequently zeroed. + void invalidate_nmethod_mirror(JVMCIObject mirror, JVMCI_TRAPS); + + void initialize_installed_code(JVMCIObject installed_code, CodeBlob* cb, JVMCI_TRAPS); + + private: + JVMCICompileState* _compile_state; + + public: + static JavaVM* get_shared_library_javavm() { return _shared_library_javavm; } + static void* get_shared_library_handle() { return _shared_library_handle; } + static char* get_shared_library_path() { return _shared_library_path; } + + // Determines if this is for the JVMCI runtime in the HotSpot + // heap (true) or the shared library heap (false). + bool is_hotspot() { return _is_hotspot; } + + JVMCICompileState* compile_state() { return _compile_state; } + void set_compile_state(JVMCICompileState* compile_state) { + assert(_compile_state == NULL, "set only once"); + _compile_state = compile_state; + } + // Generate declarations for the initialize, new, isa, get and set methods for all the types and + // fields declared in the JVMCI_CLASSES_DO macro. + +#define START_CLASS(className, fullClassName) \ + void className##_initialize(JVMCI_TRAPS); \ + JVMCIObjectArray new_##className##_array(int length, JVMCI_TRAPS); \ + bool isa_##className(JVMCIObject object); + +#define END_CLASS + +#define FIELD(className, name, type, accessor) \ + type get_ ## className ## _ ## name(JVMCIObject obj); \ + void set_ ## className ## _ ## name(JVMCIObject obj, type x); + +#define OOPISH_FIELD(className, name, type, hstype, accessor) \ + FIELD(className, name, type, accessor) + +#define STATIC_FIELD(className, name, type) \ + type get_ ## className ## _ ## name(); \ + void set_ ## className ## _ ## name(type x); + +#define STATIC_OOPISH_FIELD(className, name, type, hstype) \ + STATIC_FIELD(className, name, type) + +#define EMPTY_CAST +#define CHAR_FIELD(className, name) FIELD(className, name, jchar, char_field) +#define INT_FIELD(className, name) FIELD(className, name, jint, int_field) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, jboolean, bool_field) +#define LONG_FIELD(className, name) FIELD(className, name, jlong, long_field) +#define FLOAT_FIELD(className, name) FIELD(className, name, jfloat, float_field) +#define OBJECT_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObject, oop, obj_field) +#define OBJECTARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObjectArray, objArrayOop, obj_field) +#define PRIMARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIPrimitiveArray, typeArrayOop, obj_field) + +#define STATIC_INT_FIELD(className, name) STATIC_FIELD(className, name, jint) +#define STATIC_BOOLEAN_FIELD(className, name) STATIC_FIELD(className, name, jboolean) +#define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObject, oop) +#define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObjectArray, objArrayOop) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) + + JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) + +#undef JNI_START_CLASS +#undef START_CLASS +#undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef FIELD +#undef OOPISH_FIELD +#undef STATIC_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + + // End of JVMCIEnv }; #endif // SHARE_JVMCI_JVMCIENV_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciExceptions.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/jvmciExceptions.hpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JVMCI_JVMCIEXCEPTIONS_HPP +#define SHARE_JVMCI_JVMCIEXCEPTIONS_HPP + +class JVMCIEnv; + +// JVMCIEnv exception utility macros. Analagous to the regular CHECK, TRAP and THREAD macros. + +#define JVMCIENV __jvmci_env__ +#define JVMCI_TRAPS JVMCIEnv* JVMCIENV + +#define JNI_JVMCIENV(env) \ + JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__); \ + JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ + +#define THREAD_JVMCIENV(thread) \ + JVMCIEnv __stack_jvmci_env__(thread, __FILE__, __LINE__); \ + JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ + +#define JVMCI_PENDING_EXCEPTION (JVMCIENV->pending_exception()) +#define JVMCI_HAS_PENDING_EXCEPTION (JVMCIENV->has_pending_exception()) +#define JVMCI_CLEAR_PENDING_EXCEPTION (JVMCIENV->clear_pending_exception()) + +#define JVMCI_CHECK JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) return ; (void)(0 +#define JVMCI_CHECK_(result) JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) return result; (void)(0 +#define JVMCI_CHECK_0 JVMCI_CHECK_(0) +#define JVMCI_CHECK_NULL JVMCI_CHECK_(NULL) +#define JVMCI_CHECK_false JVMCI_CHECK_(false) +#define JVMCI_CHECK_OK JVMCI_CHECK_(JVMCI::ok) + +#define JVMCI_ERROR(...) \ + { JVMCIENV->fthrow_error(__FILE__, __LINE__, __VA_ARGS__); return; } + +#define JVMCI_ERROR_(ret, ...) \ + { JVMCIENV->fthrow_error( __FILE__, __LINE__, __VA_ARGS__); return ret; } + +#define JVMCI_ERROR_0(...) JVMCI_ERROR_(0, __VA_ARGS__) +#define JVMCI_ERROR_NULL(...) JVMCI_ERROR_(NULL, __VA_ARGS__) +#define JVMCI_ERROR_OK(...) JVMCI_ERROR_(JVMCI::ok, __VA_ARGS__) + +#define JVMCI_THROW(name) { JVMCIENV->throw_##name(); return; } +#define JVMCI_THROW_NULL(name) { JVMCIENV->throw_##name(); return NULL; } +#define JVMCI_THROW_0(name) { JVMCIENV->throw_##name(); return 0; } +#define JVMCI_THROW_MSG_NULL(name, msg) { JVMCIENV->throw_##name(msg); return NULL; } +#define JVMCI_THROW_MSG_(name, msg, value) { JVMCIENV->throw_##name(msg); return (value); } +#define JVMCI_THROW_MSG_0(name, msg) { JVMCIENV->throw_##name(msg); return 0; } +#define JVMCI_THROW_MSG(name, msg) { JVMCIENV->throw_##name(msg); return; } +#define JVMCI_THROW_(name, value) { JVMCIENV->throw_##name(); return (value); } + +#define JVMCI_CATCH \ + JVMCIENV); if (JVMCI_HAS_PENDING_EXCEPTION) { \ + JVMCIENV->describe_pending_exception(true); \ + ShouldNotReachHere(); \ + } (void)(0 + +#endif // SHARE_JVMCI_JVMCIEXCEPTIONS_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciJavaClasses.cpp --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,95 +23,43 @@ #include "precompiled.hpp" #include "classfile/symbolTable.hpp" +#include "interpreter/linkResolver.hpp" +#include "jvmci/jniAccessMark.inline.hpp" #include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" #include "memory/resourceArea.hpp" -#include "oops/oop.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" +// ------------------------------------------------------------------ -// This macro expands for non-inline functions, in class declarations. +oop HotSpotJVMCI::resolve(JVMCIObject obj) { + return JNIHandles::resolve(obj.as_jobject()); +} -#define START_CLASS(name) \ - void name::check(oop obj, const char* field_name, int offset) { \ - assert(obj != NULL, "NULL field access of %s.%s", #name, field_name); \ - assert(obj->is_a(SystemDictionary::name##_klass()), "wrong class, " #name " expected, found %s", obj->klass()->external_name()); \ - assert(offset != 0, "must be valid offset"); \ - } +arrayOop HotSpotJVMCI::resolve(JVMCIArray obj) { + return (arrayOop) JNIHandles::resolve(obj.as_jobject()); +} -#define END_CLASS - -#define FIELD(klass, name, type, accessor, cast) \ - type klass::name(jobject obj) { check(JNIHandles::resolve(obj), #name, _##name##_offset); return cast JNIHandles::resolve(obj)->accessor(_##name##_offset); } \ - void klass::set_##name(jobject obj, type x) { check(JNIHandles::resolve(obj), #name, _##name##_offset); JNIHandles::resolve(obj)->accessor##_put(_##name##_offset, x); } +objArrayOop HotSpotJVMCI::resolve(JVMCIObjectArray obj) { + return (objArrayOop) JNIHandles::resolve(obj.as_jobject()); +} -#define EMPTY_CAST -#define CHAR_FIELD(klass, name) FIELD(klass, name, jchar, char_field, EMPTY_CAST) -#define INT_FIELD(klass, name) FIELD(klass, name, jint, int_field, EMPTY_CAST) -#define BOOLEAN_FIELD(klass, name) FIELD(klass, name, jboolean, bool_field, EMPTY_CAST) -#define LONG_FIELD(klass, name) FIELD(klass, name, jlong, long_field, EMPTY_CAST) -#define FLOAT_FIELD(klass, name) FIELD(klass, name, jfloat, float_field, EMPTY_CAST) -#define OOP_FIELD(klass, name, signature) FIELD(klass, name, oop, obj_field, EMPTY_CAST) -#define OBJARRAYOOP_FIELD(klass, name, signature) FIELD(klass, name, objArrayOop, obj_field, (objArrayOop)) -#define TYPEARRAYOOP_FIELD(klass, name, signature) FIELD(klass, name, typeArrayOop, obj_field, (typeArrayOop)) -#define STATIC_OOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, oop, signature) -#define STATIC_OBJARRAYOOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, objArrayOop, signature) -#define STATIC_OOPISH_FIELD(klassName, name, type, signature) \ - type klassName::name() { \ - assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ - InstanceKlass* ik = klassName::klass(); \ - oop base = ik->static_field_base_raw(); \ - oop result = HeapAccess<>::oop_load_at(base, _##name##_offset); \ - return type(result); \ - } \ - void klassName::set_##name(type x) { \ - assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ - assert(klassName::klass() != NULL, "Class not yet loaded: " #klassName); \ - InstanceKlass* ik = klassName::klass(); \ - oop base = ik->static_field_base_raw(); \ - HeapAccess<>::oop_store_at(base, _##name##_offset, x); \ - } -#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \ - jtypename klassName::name() { \ - assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ - InstanceKlass* ik = klassName::klass(); \ - oop base = ik->static_field_base_raw(); \ - return HeapAccess<>::load_at(base, _##name##_offset); \ - } \ - void klassName::set_##name(jtypename x) { \ - assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ - InstanceKlass* ik = klassName::klass(); \ - oop base = ik->static_field_base_raw(); \ - HeapAccess<>::store_at(base, _##name##_offset, x); \ - } +typeArrayOop HotSpotJVMCI::resolve(JVMCIPrimitiveArray obj) { + return (typeArrayOop) JNIHandles::resolve(obj.as_jobject()); +} -#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint) -#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean) +JVMCIObject HotSpotJVMCI::wrap(oop obj) { + assert(Thread::current()->is_Java_thread(), "must be"); + return JVMCIObject(JNIHandles::make_local(obj), true); +} -COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_OBJARRAYOOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) -#undef START_CLASS -#undef END_CLASS -#undef FIELD -#undef CHAR_FIELD -#undef INT_FIELD -#undef BOOLEAN_FIELD -#undef LONG_FIELD -#undef FLOAT_FIELD -#undef OOP_FIELD -#undef TYPEARRAYOOP_FIELD -#undef OBJARRAYOOP_FIELD -#undef STATIC_OOPISH_FIELD -#undef STATIC_OOP_FIELD -#undef STATIC_OBJARRAYOOP_FIELD -#undef STATIC_INT_FIELD -#undef STATIC_BOOLEAN_FIELD -#undef STATIC_PRIMITIVE_FIELD -#undef EMPTY_CAST - -// This function is similar to javaClasses.cpp, it computes the field offset of a (static or instance) field. -// It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. - -void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS) { +/** + * Computes the field offset of a static or instance field. + * It looks up the name and signature symbols without creating new ones; + * all the symbols of these classes need to be already loaded. + */ +void HotSpotJVMCI::compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS) { InstanceKlass* ik = InstanceKlass::cast(klass); Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); @@ -125,7 +73,7 @@ fieldDescriptor fd; if (!ik->find_field(name_symbol, signature_symbol, &fd)) { ResourceMark rm; - fatal("Invalid layout of %s %s at %s", name_symbol->as_C_string(), signature_symbol->as_C_string(), ik->external_name()); + fatal("Could not find field %s.%s with signature %s", ik->external_name(), name, signature); } guarantee(fd.is_static() == static_field, "static/instance mismatch"); dest_offset = fd.offset(); @@ -137,33 +85,548 @@ } } -// This piece of macro magic creates the contents of the jvmci_compute_offsets method that initializes the field indices of all the access classes. +#ifndef PRODUCT +static void check_resolve_method(const char* call_type, Klass* resolved_klass, Symbol* method_name, Symbol* method_signature, TRAPS) { + methodHandle method; + LinkInfo link_info(resolved_klass, method_name, method_signature, NULL, LinkInfo::skip_access_check); + if (strcmp(call_type, "call_static") == 0) { + method = LinkResolver::resolve_static_call_or_null(link_info); + } else if (strcmp(call_type, "call_virtual") == 0) { + method = LinkResolver::resolve_virtual_call_or_null(resolved_klass, link_info); + } else if (strcmp(call_type, "call_special") == 0) { + method = LinkResolver::resolve_special_call_or_null(link_info); + } else { + fatal("Unknown or unsupported call type: %s", call_type); + } + if (method.is_null()) { + fatal("Could not resolve %s.%s%s", resolved_klass->external_name(), method_name->as_C_string(), method_signature->as_C_string()); + } +} +#endif -#define START_CLASS(name) { Klass* k = SystemDictionary::name##_klass(); assert(k != NULL, "Could not find class " #name ""); +jclass JNIJVMCI::_box_classes[T_CONFLICT+1]; +jclass JNIJVMCI::_byte_array; +jfieldID JNIJVMCI::_box_fields[T_CONFLICT+1]; +jmethodID JNIJVMCI::_box_constructors[T_CONFLICT+1]; +jmethodID JNIJVMCI::_Class_getName_method; + +jmethodID JNIJVMCI::_HotSpotResolvedJavaMethodImpl_fromMetaspace_method; +jmethodID JNIJVMCI::_HotSpotConstantPool_fromMetaspace_method; +jmethodID JNIJVMCI::_HotSpotResolvedObjectTypeImpl_fromMetaspace_method; +jmethodID JNIJVMCI::_HotSpotResolvedPrimitiveType_fromMetaspace_method; + +#define START_CLASS(className, fullClassName) { \ + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::fullClassName(), true, CHECK); \ + className::_klass = InstanceKlass::cast(k); \ + className::_klass->initialize(CHECK); #define END_CLASS } -#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field, CHECK); -#define CHAR_FIELD(klass, name) FIELD(klass, name, "C", false) -#define INT_FIELD(klass, name) FIELD(klass, name, "I", false) -#define BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", false) -#define LONG_FIELD(klass, name) FIELD(klass, name, "J", false) -#define FLOAT_FIELD(klass, name) FIELD(klass, name, "F", false) -#define OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, false) -#define STATIC_OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, true) -#define STATIC_INT_FIELD(klass, name) FIELD(klass, name, "I", true) -#define STATIC_BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", true) +#define FIELD(className, name, signature, static_field) compute_offset(className::_##name##_offset, className::_klass, #name, signature, static_field, CHECK); +#define CHAR_FIELD(className, name) FIELD(className, name, "C", false) +#define INT_FIELD(className, name) FIELD(className, name, "I", false) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", false) +#define LONG_FIELD(className, name) FIELD(className, name, "J", false) +#define FLOAT_FIELD(className, name) FIELD(className, name, "F", false) +#define OBJECT_FIELD(className, name, signature) FIELD(className, name, signature, false) +#define STATIC_OBJECT_FIELD(className, name, signature) FIELD(className, name, signature, true) +#define STATIC_INT_FIELD(className, name) FIELD(className, name, "I", true) +#define STATIC_BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", true) +#ifdef PRODUCT +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) +#else +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ + check_resolve_method(#hsCallType, k, vmSymbols::methodName##_name(), vmSymbols::signatureSymbolName(), CHECK); +#define CONSTRUCTOR(className, signature) { \ + TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK); \ + check_resolve_method("call_special", k, vmSymbols::object_initializer_name(), sig, CHECK); \ + } +#endif +/** + * Computes and initializes the offsets used by HotSpotJVMCI. + */ +void HotSpotJVMCI::compute_offsets(TRAPS) { + JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, OBJECT_FIELD, OBJECT_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECT_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) +} + +#undef START_CLASS +#undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef STATIC_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + +// ------------------------------------------------------------------ + +#define START_CLASS(className, fullClassName) \ + void HotSpotJVMCI::className::initialize(JVMCI_TRAPS) { \ + Thread* THREAD = Thread::current(); \ + className::klass()->initialize(CHECK); \ + } \ + bool HotSpotJVMCI::className::is_instance(JVMCIEnv* env, JVMCIObject object) { \ + return resolve(object)->is_a(className::klass()); \ + } \ + void HotSpotJVMCI::className::check(oop obj, const char* field_name, int offset) { \ + assert(obj != NULL, "NULL field access of %s.%s", #className, field_name); \ + assert(obj->is_a(className::klass()), "wrong class, " #className " expected, found %s", obj->klass()->external_name()); \ + assert(offset != 0, "must be valid offset"); \ + } \ + InstanceKlass* HotSpotJVMCI::className::_klass = NULL; + +#define END_CLASS + +#define FIELD(className, name, type, accessor, cast) \ + type HotSpotJVMCI::className::name(JVMCIEnv* env, oop obj) { className::check(obj, #name, className::_##name##_offset); return cast obj->accessor(className::_##name##_offset); } \ + void HotSpotJVMCI::className::set_##name(JVMCIEnv* env, oop obj, type x) { className::check(obj, #name, className::_##name##_offset); obj->accessor##_put(className::_##name##_offset, x); } + +#define EMPTY_CAST +#define CHAR_FIELD(className, name) FIELD(className, name, jchar, char_field, EMPTY_CAST) +#define INT_FIELD(className, name) FIELD(className, name, jint, int_field, EMPTY_CAST) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, jboolean, bool_field, EMPTY_CAST) +#define LONG_FIELD(className, name) FIELD(className, name, jlong, long_field, EMPTY_CAST) +#define FLOAT_FIELD(className, name) FIELD(className, name, jfloat, float_field, EMPTY_CAST) + +#define OBJECT_FIELD(className, name, signature) FIELD(className, name, oop, obj_field, EMPTY_CAST) +#define OBJECTARRAY_FIELD(className, name, signature) FIELD(className, name, objArrayOop, obj_field, (objArrayOop)) +#define PRIMARRAY_FIELD(className, name, signature) FIELD(className, name, typeArrayOop, obj_field, (typeArrayOop)) +#define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, oop) +#define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, objArrayOop) +#define STATIC_OOPISH_FIELD(className, name, type) \ + type HotSpotJVMCI::className::name(JVMCIEnv* env) { \ + assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ + InstanceKlass* ik = className::klass(); \ + oop base = ik->static_field_base_raw(); \ + oop result = HeapAccess<>::oop_load_at(base, className::_##name##_offset); \ + return type(result); \ + } \ + void HotSpotJVMCI::className::set_##name(JVMCIEnv* env, type x) { \ + assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ + assert(className::klass() != NULL, "Class not yet loaded: " #className); \ + InstanceKlass* ik = className::klass(); \ + oop base = ik->static_field_base_raw(); \ + HeapAccess<>::oop_store_at(base, className::_##name##_offset, x); \ + } +#define STATIC_PRIMITIVE_FIELD(className, name, jtypename) \ + jtypename HotSpotJVMCI::className::get_##name(JVMCIEnv* env) { \ + assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ + InstanceKlass* ik = className::klass(); \ + oop base = ik->static_field_base_raw(); \ + return HeapAccess<>::load_at(base, className::_##name##_offset); \ + } \ + void HotSpotJVMCI::className::set_##name(JVMCIEnv* env, jtypename x) { \ + assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ + InstanceKlass* ik = className::klass(); \ + oop base = ik->static_field_base_raw(); \ + HeapAccess<>::store_at(base, _##name##_offset, x); \ + } + +#define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint) +#define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) + +/** + * Generates the method and field definitions for the classes in HotSpotJVMCI. For example: + * + * void HotSpotJVMCI::Architecture::initialize(JVMCIEnv* env) { ... } + * bool HotSpotJVMCI::Architecture::is_instance(JVMCIEnv* env, JVMCIObject object) { ... } + * void HotSpotJVMCI::Architecture::check(oop obj, const char* field_name, int offset) { ... } + * oop HotSpotJVMCI::Architecture::wordKind(JVMCIEnv* env, oop obj) { ... } + * void HotSpotJVMCI::Architecture::set_wordKind(JVMCIEnv* env, oop obj, oop x) { ... } + * + * InstanceKlass *HotSpotJVMCI::Architecture::_klass = NULL; + */ +JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) + +#undef START_CLASS +#undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef STATIC_PRIMITIVE_FIELD +#undef EMPTY_CAST + +/** + * Initializes the JNI id of a field. As per the JNI specification, + * this ensures the declaring class is initialized. + */ +void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz, const char* class_name, const char* name, const char* signature, bool static_field) { + if (JVMCILibDumpJNIConfig != NULL) { + fileStream* st = JVMCIGlobals::get_jni_config_file(); + st->print_cr("field %s %s %s", class_name, name, signature); + return; + } + if (env->ExceptionCheck()) { + return; + } + if (static_field) { + // Class initialization barrier + fieldid = env->GetStaticFieldID(clazz, name, signature); + } else { + // Class initialization barrier + fieldid = env->GetFieldID(clazz, name, signature); + } + + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + ResourceMark rm; + Thread* THREAD = Thread::current(); + fatal("Could not find field %s.%s with signature %s", class_name, name, signature); + } +} +#define START_CLASS(className, fullClassName) { \ + current_class_name = vmSymbols::fullClassName()->as_C_string(); \ + if (JVMCILibDumpJNIConfig != NULL) { \ + fileStream* st = JVMCIGlobals::get_jni_config_file(); \ + st->print_cr("class %s", current_class_name); \ + } else { \ + jclass k = env->FindClass(current_class_name); \ + JVMCI_EXCEPTION_CHECK(env, "FindClass(%s)", current_class_name); \ + assert(k != NULL, #fullClassName " not initialized"); \ + className::_class = (jclass) env->NewGlobalRef(k); \ + } -void JVMCIJavaClasses::compute_offsets(TRAPS) { - COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, OOP_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) +#define END_CLASS current_class_name = NULL; } + +#define FIELD(className, name, signature, static_field) initialize_field_id(env, className::_##name##_field_id, className::_class, current_class_name, #name, signature, static_field); +#define CHAR_FIELD(className, name) FIELD(className, name, "C", false) +#define INT_FIELD(className, name) FIELD(className, name, "I", false) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", false) +#define LONG_FIELD(className, name) FIELD(className, name, "J", false) +#define FLOAT_FIELD(className, name) FIELD(className, name, "F", false) +#define OBJECT_FIELD(className, name, signature) FIELD(className, name, signature, false) +#define STATIC_OBJECT_FIELD(className, name, signature) FIELD(className, name, signature, true) +#define STATIC_INT_FIELD(className, name) FIELD(className, name, "I", true) +#define STATIC_BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", true) + +#define GET_JNI_METHOD(jniGetMethod, dst, clazz, methodName, signature) \ + if (JVMCILibDumpJNIConfig != NULL) { \ + fileStream* st = JVMCIGlobals::get_jni_config_file(); \ + st->print_cr("method %s %s %s", current_class_name, methodName, signature); \ + } else { \ + dst = env->jniGetMethod(clazz, methodName, signature); \ + JVMCI_EXCEPTION_CHECK(env, #jniGetMethod "(%s.%s%s)", current_class_name, methodName, signature); \ + assert(dst != NULL, "uninitialized"); \ + } + +#define GET_JNI_CONSTRUCTOR(clazz, signature) \ + GET_JNI_METHOD(GetMethodID, JNIJVMCI::clazz::_constructor, clazz::_class, "", signature) \ + +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ + GET_JNI_METHOD(jniGetMethod, \ + className::_##methodName##_method, \ + className::clazz(), \ + vmSymbols::methodName##_name()->as_C_string(), \ + vmSymbols::signatureSymbolName()->as_C_string()) + +#define CONSTRUCTOR(className, signature) \ + GET_JNI_CONSTRUCTOR(className, signature) + +extern "C" { + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); + jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); } +#define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string() +/** + * Initializes the JNI method and field ids used in JNIJVMCI. + */ +void JNIJVMCI::initialize_ids(JNIEnv* env) { + ResourceMark rm; + const char* current_class_name = NULL; + JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, OBJECT_FIELD, OBJECT_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECT_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) + + IN_CLASS(java_lang_Class); + GET_JNI_METHOD(GetMethodID, _Class_getName_method, Class::_class, "getName", "()Ljava/lang/String;"); + + IN_CLASS(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType); + GET_JNI_METHOD(GetStaticMethodID, _HotSpotResolvedPrimitiveType_fromMetaspace_method, HotSpotResolvedPrimitiveType::_class, + vmSymbols::fromMetaspace_name()->as_C_string(), + vmSymbols::primitive_fromMetaspace_signature()->as_C_string()); + IN_CLASS(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl); + GET_JNI_METHOD(GetStaticMethodID, _HotSpotResolvedObjectTypeImpl_fromMetaspace_method, HotSpotResolvedObjectTypeImpl::_class, + vmSymbols::fromMetaspace_name()->as_C_string(), + vmSymbols::klass_fromMetaspace_signature()->as_C_string()); + IN_CLASS(jdk_vm_ci_hotspot_HotSpotConstantPool); + GET_JNI_METHOD(GetStaticMethodID, _HotSpotConstantPool_fromMetaspace_method, HotSpotConstantPool::_class, + vmSymbols::fromMetaspace_name()->as_C_string(), + vmSymbols::constantPool_fromMetaspace_signature()->as_C_string()); + IN_CLASS(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl); + GET_JNI_METHOD(GetStaticMethodID, _HotSpotResolvedJavaMethodImpl_fromMetaspace_method, HotSpotResolvedJavaMethodImpl::_class, + vmSymbols::fromMetaspace_name()->as_C_string(), + vmSymbols::method_fromMetaspace_signature()->as_C_string()); + +#define BOX_CLASSES(generate) \ + generate(Boolean, T_BOOLEAN, Z) \ + generate(Byte, T_BYTE, B) \ + generate(Character, T_CHAR, C) \ + generate(Short, T_SHORT, S) \ + generate(Integer, T_INT, I) \ + generate(Long, T_LONG, J) \ + generate(Float, T_FLOAT, F) \ + generate(Double, T_DOUBLE, D) \ + +#define DO_BOX_CLASS(klass, basicType, type) \ + current_class_name = "java/lang/" #klass; \ + if (JVMCILibDumpJNIConfig == NULL) { \ + _box_classes[basicType] = env->FindClass("java/lang/" #klass); \ + JVMCI_EXCEPTION_CHECK(env, "FindClass(%s)", #klass); \ + _box_classes[basicType] = (jclass) env->NewGlobalRef(_box_classes[basicType]); \ + assert(_box_classes[basicType] != NULL, "uninitialized"); \ + _box_fields[basicType] = env->GetFieldID(_box_classes[basicType], "value", #type); \ + JVMCI_EXCEPTION_CHECK(env, "GetFieldID(%s, value, %s)", #klass, #type); \ + GET_JNI_METHOD(GetMethodID, _box_constructors[basicType], _box_classes[basicType], "", "(" #type ")V"); \ + } else { \ + fileStream* st = JVMCIGlobals::get_jni_config_file(); \ + st->print_cr("field %s value %s", current_class_name, #type); \ + st->print_cr("method %s (%s)V", current_class_name, #type); \ + } + + BOX_CLASSES(DO_BOX_CLASS); + + if (JVMCILibDumpJNIConfig == NULL) { + _byte_array = env->FindClass("[B"); + JVMCI_EXCEPTION_CHECK(env, "FindClass([B)"); + _byte_array = (jclass) env->NewGlobalRef(_byte_array); + assert(_byte_array != NULL, "uninitialized"); + } else { + fileStream* st = JVMCIGlobals::get_jni_config_file(); + st->print_cr("class [B"); + } + +#define DUMP_ALL_NATIVE_METHODS(class_symbol) do { \ + current_class_name = class_symbol->as_C_string(); \ + Klass* k = SystemDictionary::resolve_or_fail(class_symbol, true, CHECK_EXIT); \ + InstanceKlass* iklass = InstanceKlass::cast(k); \ + Array* methods = iklass->methods(); \ + for (int i = 0; i < methods->length(); i++) { \ + Method* m = methods->at(i); \ + if (m->is_native()) { \ + st->print_cr("method %s %s %s", current_class_name, m->name()->as_C_string(), m->signature()->as_C_string()); \ + } \ + } \ +} while(0) + + if (JVMCILibDumpJNIConfig != NULL) { + Thread* THREAD = Thread::current(); + fileStream* st = JVMCIGlobals::get_jni_config_file(); + + DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()); + + st->flush(); + tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig); + vm_exit(0); + } + +#undef DUMP_ALL_NATIVE_METHODS +#undef DO_BOX_CLASS +#undef BOX_CLASSES +#undef IN_CLASS + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(f)) + + if (env != JavaThread::current()->jni_environment()) { + jclass clazz = env->FindClass("jdk/vm/ci/hotspot/CompilerToVM"); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + guarantee(false, "Could not find class jdk/vm/ci/hotspot/CompilerToVM"); + } + JNINativeMethod CompilerToVM_native_methods[] = { + { CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }, + }; + env->RegisterNatives(clazz, CompilerToVM_native_methods, 1); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + guarantee(false, ""); + } + + JNINativeMethod JVMCI_native_methods[] = { + { CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }, + }; + env->RegisterNatives(JVMCI::clazz(), JVMCI_native_methods, 1); + if (env->ExceptionCheck()) { + env->ExceptionDescribe(); + guarantee(false, ""); + } + } +} + +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD2 + #define EMPTY0 #define EMPTY1(x) #define EMPTY2(x,y) -#define FIELD2(klass, name) int klass::_##name##_offset = 0; -#define FIELD3(klass, name, sig) FIELD2(klass, name) +#define FIELD3(className, name, sig) FIELD2(className, name) +#define FIELD2(className, name) \ + jfieldID JNIJVMCI::className::_##name##_field_id = 0; \ + int HotSpotJVMCI::className::_##name##_offset = 0; +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) + +// Generates the definitions of static fields used by the accessors. For example: +// jfieldID JNIJVMCI::Architecture::_wordKind_field_id = 0; +// jfieldID HotSpotJVMCI::Architecture::_wordKind_offset = 0; +JVMCI_CLASSES_DO(EMPTY2, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD3, FIELD3, FIELD3, FIELD2, FIELD2, METHOD, CONSTRUCTOR) + +#undef START_CLASS +#undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef STATIC_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + + +#define START_CLASS(className, fullClassName) \ + void JNIJVMCI::className::initialize(JVMCI_TRAPS) { \ + /* should already be initialized */ \ + } \ + bool JNIJVMCI::className::is_instance(JVMCIEnv* jvmciEnv, JVMCIObject object) { \ + JNIAccessMark jni(jvmciEnv); \ + return jni()->IsInstanceOf(object.as_jobject(), className::clazz()) != 0; \ + } \ + void JNIJVMCI::className::check(JVMCIEnv* jvmciEnv, JVMCIObject obj, const char* field_name, jfieldID offset) { \ + assert(obj.is_non_null(), "NULL field access of %s.%s", #className, field_name); \ + assert(jvmciEnv->isa_##className(obj), "wrong class, " #className " expected, found %s", jvmciEnv->klass_name(obj)); \ + assert(offset != 0, "must be valid offset"); \ + } \ + jclass JNIJVMCI::className::_class = NULL; + +#define END_CLASS + +#define FIELD(className, name, type, accessor, cast) \ + type JNIJVMCI::className::get_##name(JVMCIEnv* jvmciEnv, JVMCIObject obj) { \ + className::check(jvmciEnv, obj, #name, className::_##name##_field_id); \ + JNIAccessMark jni(jvmciEnv); \ + return cast jni()->Get##accessor##Field(resolve_handle(obj), className::_##name##_field_id); \ + } \ + void JNIJVMCI::className::set_##name(JVMCIEnv* jvmciEnv, JVMCIObject obj, type x) { \ + className::check(jvmciEnv, obj, #name, className::_##name##_field_id); \ + JNIAccessMark jni(jvmciEnv); \ + jni()->Set##accessor##Field(resolve_handle(obj), className::_##name##_field_id, x); \ + } \ + +#define EMPTY_CAST +#define CHAR_FIELD(className, name) FIELD(className, name, jchar, Char, EMPTY_CAST) +#define INT_FIELD(className, name) FIELD(className, name, jint, Int, EMPTY_CAST) +#define BOOLEAN_FIELD(className, name) FIELD(className, name, jboolean, Boolean, EMPTY_CAST) +#define LONG_FIELD(className, name) FIELD(className, name, jlong, Long, EMPTY_CAST) +#define FLOAT_FIELD(className, name) FIELD(className, name, jfloat, Float, EMPTY_CAST) -COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD3, FIELD3, FIELD3, FIELD2, FIELD2) +#define OBJECT_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObject, Object, EMPTY_CAST) +#define OBJECTARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) +#define PRIMARRAY_FIELD(className, name, signature) OOPISH_FIELD(className, name, JVMCIPrimitiveArray, Object, (JVMCIPrimitiveArray)) + +#define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObject, Object, (JVMCIObject)) +#define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObjectArray, Object, (JVMCIObjectArray)) + +#define OOPISH_FIELD(className, name, type, accessor, cast) \ + type JNIJVMCI::className::get_##name(JVMCIEnv* jvmciEnv, JVMCIObject obj) { \ + className::check(jvmciEnv, obj, #name, className::_##name##_field_id); \ + JNIAccessMark jni(jvmciEnv); \ + return cast wrap(jni()->Get##accessor##Field(resolve_handle(obj), className::_##name##_field_id)); \ + } \ + void JNIJVMCI::className::set_##name(JVMCIEnv* jvmciEnv, JVMCIObject obj, type x) { \ + className::check(jvmciEnv, obj, #name, className::_##name##_field_id); \ + JNIAccessMark jni(jvmciEnv); \ + jni()->Set##accessor##Field(resolve_handle(obj), className::_##name##_field_id, resolve_handle(x)); \ + } + +#define STATIC_OOPISH_FIELD(className, name, type, accessor, cast) \ + type JNIJVMCI::className::get_##name(JVMCIEnv* jvmciEnv) { \ + JNIAccessMark jni(jvmciEnv); \ + return cast wrap(jni()->GetStatic##accessor##Field(className::clazz(), className::_##name##_field_id)); \ + } \ + void JNIJVMCI::className::set_##name(JVMCIEnv* jvmciEnv, type x) { \ + JNIAccessMark jni(jvmciEnv); \ + jni()->SetStatic##accessor##Field(className::clazz(), className::_##name##_field_id, resolve_handle(x)); \ + } +#define STATIC_PRIMITIVE_FIELD(className, name, type, accessor, cast) \ + type JNIJVMCI::className::get_##name(JVMCIEnv* jvmciEnv) { \ + JNIAccessMark jni(jvmciEnv); \ + return cast jni()->GetStatic##accessor##Field(className::clazz(), className::_##name##_field_id); \ + } \ + void JNIJVMCI::className::set_##name(JVMCIEnv* jvmciEnv, type x) { \ + JNIAccessMark jni(jvmciEnv); \ + jni()->SetStatic##accessor##Field(className::clazz(), className::_##name##_field_id, x); \ + } + +#define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint, Int, EMPTY_CAST) +#define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean, Boolean, EMPTY_CAST) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ + jmethodID JNIJVMCI::className::_##methodName##_method; + +#define CONSTRUCTOR(className, signature) \ + jmethodID JNIJVMCI::className::_constructor; + +/** + * Generates the method definitions for the classes in HotSpotJVMCI. + */ +JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) + +#undef METHOD +#undef CONSTRUCTOR +#undef START_CLASS +#undef END_CLASS +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef STATIC_PRIMITIVE_FIELD +#undef OOPISH_FIELD +#undef EMPTY_CAST diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciJavaClasses.hpp --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp Wed May 01 12:31:29 2019 -0700 @@ -24,361 +24,644 @@ #ifndef SHARE_JVMCI_JVMCIJAVACLASSES_HPP #define SHARE_JVMCI_JVMCIJAVACLASSES_HPP -#include "classfile/systemDictionary.hpp" -#include "oops/access.hpp" -#include "oops/instanceMirrorKlass.hpp" -#include "oops/oop.hpp" +#include "classfile/vmSymbols.hpp" +#include "jvmci/jvmciExceptions.hpp" +#include "jvmci/jvmciObject.hpp" +#include "runtime/jniHandles.hpp" -class JVMCIJavaClasses : AllStatic { - public: - static void compute_offsets(TRAPS); -}; - -/* This macro defines the structure of the JVMCI classes accessed from VM code. - * It will generate classes with accessors similar to javaClasses.hpp, but with specializations for oops, Handles and jni handles. +/* + * This macro defines the structure of the JVMCI classes accessed from VM code. It is used to + * generate accessors similar to javaClasses.hpp, but with specializations for HotSpot and JNI based + * access. * - * The public interface of these classes will look like this: - - * class StackSlot : AllStatic { - * public: - * static Klass* klass(); - * static jint index(oop obj); - * static jint index(Handle obj); - * static jint index(jobject obj); - * static void set_index(oop obj, jint x); - * static void set_index(Handle obj, jint x); - * static void set_index(jobject obj, jint x); - * }; + * HotSpotJVMCI: This class contains accessors based on the VM internal + * interface to Java. It is used for JVMCI Java code executing on the HotSpot heap. * + * JNIJVMCI: This class contains JNI based accessors and is used for JVMCI + * Java code executing in the JVMCI shared library. */ -#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, typeArrayOop_field, objArrayOop_field, static_oop_field, static_objArrayOop_field, static_int_field, static_boolean_field) \ - start_class(Architecture) \ - oop_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;") \ - end_class \ - start_class(TargetDescription) \ - oop_field(TargetDescription, arch, "Ljdk/vm/ci/code/Architecture;") \ - end_class \ - start_class(HotSpotResolvedObjectTypeImpl) \ - oop_field(HotSpotResolvedObjectTypeImpl, javaClass, "Ljava/lang/Class;") \ - end_class \ - start_class(HotSpotResolvedJavaMethodImpl) \ - long_field(HotSpotResolvedJavaMethodImpl, metaspaceMethod) \ - end_class \ - start_class(InstalledCode) \ - long_field(InstalledCode, address) \ - long_field(InstalledCode, entryPoint) \ - long_field(InstalledCode, version) \ - oop_field(InstalledCode, name, "Ljava/lang/String;") \ - end_class \ - start_class(HotSpotInstalledCode) \ - int_field(HotSpotInstalledCode, size) \ - long_field(HotSpotInstalledCode, codeStart) \ - int_field(HotSpotInstalledCode, codeSize) \ - end_class \ - start_class(HotSpotNmethod) \ - boolean_field(HotSpotNmethod, isDefault) \ - end_class \ - start_class(HotSpotCompiledCode) \ - oop_field(HotSpotCompiledCode, name, "Ljava/lang/String;") \ - typeArrayOop_field(HotSpotCompiledCode, targetCode, "[B") \ - int_field(HotSpotCompiledCode, targetCodeSize) \ - objArrayOop_field(HotSpotCompiledCode, sites, "[Ljdk/vm/ci/code/site/Site;") \ - objArrayOop_field(HotSpotCompiledCode, assumptions, "[Ljdk/vm/ci/meta/Assumptions$Assumption;") \ - objArrayOop_field(HotSpotCompiledCode, methods, "[Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ - objArrayOop_field(HotSpotCompiledCode, comments, "[Ljdk/vm/ci/hotspot/HotSpotCompiledCode$Comment;") \ - typeArrayOop_field(HotSpotCompiledCode, dataSection, "[B") \ - int_field(HotSpotCompiledCode, dataSectionAlignment) \ - objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/vm/ci/code/site/DataPatch;") \ - boolean_field(HotSpotCompiledCode, isImmutablePIC) \ - int_field(HotSpotCompiledCode, totalFrameSize) \ - oop_field(HotSpotCompiledCode, deoptRescueSlot, "Ljdk/vm/ci/code/StackSlot;") \ - end_class \ - start_class(HotSpotCompiledCode_Comment) \ - oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \ - int_field(HotSpotCompiledCode_Comment, pcOffset) \ - end_class \ - start_class(HotSpotCompiledNmethod) \ - oop_field(HotSpotCompiledNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ - oop_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;") \ - int_field(HotSpotCompiledNmethod, entryBCI) \ - int_field(HotSpotCompiledNmethod, id) \ - long_field(HotSpotCompiledNmethod, jvmciEnv) \ - boolean_field(HotSpotCompiledNmethod, hasUnsafeAccess) \ - end_class \ - start_class(HotSpotJVMCIMetaAccessContext) \ - static_objArrayOop_field(HotSpotJVMCIMetaAccessContext, allContexts, "[Ljava/lang/ref/WeakReference;") \ - objArrayOop_field(HotSpotJVMCIMetaAccessContext, metadataRoots, "[Ljava/lang/Object;") \ - end_class \ - start_class(HotSpotForeignCallTarget) \ - long_field(HotSpotForeignCallTarget, address) \ - end_class \ - start_class(VMField) \ - oop_field(VMField, name, "Ljava/lang/String;") \ - oop_field(VMField, type, "Ljava/lang/String;") \ - long_field(VMField, offset) \ - long_field(VMField, address) \ - oop_field(VMField, value, "Ljava/lang/Object;") \ - end_class \ - start_class(VMFlag) \ - oop_field(VMFlag, name, "Ljava/lang/String;") \ - oop_field(VMFlag, type, "Ljava/lang/String;") \ - oop_field(VMFlag, value, "Ljava/lang/Object;") \ - end_class \ - start_class(VMIntrinsicMethod) \ - oop_field(VMIntrinsicMethod, declaringClass, "Ljava/lang/String;") \ - oop_field(VMIntrinsicMethod, name, "Ljava/lang/String;") \ - oop_field(VMIntrinsicMethod, descriptor, "Ljava/lang/String;") \ - int_field(VMIntrinsicMethod, id) \ - end_class \ - start_class(Assumptions_NoFinalizableSubclass) \ - oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - end_class \ - start_class(Assumptions_ConcreteSubtype) \ - oop_field(Assumptions_ConcreteSubtype, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - oop_field(Assumptions_ConcreteSubtype, subtype, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - end_class \ - start_class(Assumptions_LeafType) \ - oop_field(Assumptions_LeafType, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - end_class \ - start_class(Assumptions_ConcreteMethod) \ - oop_field(Assumptions_ConcreteMethod, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ - oop_field(Assumptions_ConcreteMethod, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - oop_field(Assumptions_ConcreteMethod, impl, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ - end_class \ - start_class(Assumptions_CallSiteTargetValue) \ - oop_field(Assumptions_CallSiteTargetValue, callSite, "Ljdk/vm/ci/meta/JavaConstant;") \ - oop_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljdk/vm/ci/meta/JavaConstant;") \ - end_class \ - start_class(site_Site) \ - int_field(site_Site, pcOffset) \ - end_class \ - start_class(site_Call) \ - oop_field(site_Call, target, "Ljdk/vm/ci/meta/InvokeTarget;") \ - oop_field(site_Call, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ - end_class \ - start_class(site_DataPatch) \ - oop_field(site_DataPatch, reference, "Ljdk/vm/ci/code/site/Reference;") \ - end_class \ - start_class(site_ConstantReference) \ - oop_field(site_ConstantReference, constant, "Ljdk/vm/ci/meta/VMConstant;") \ - end_class \ - start_class(site_DataSectionReference) \ - int_field(site_DataSectionReference, offset) \ - end_class \ - start_class(site_InfopointReason) \ - static_oop_field(site_InfopointReason, SAFEPOINT, "Ljdk/vm/ci/code/site/InfopointReason;") \ - static_oop_field(site_InfopointReason, CALL, "Ljdk/vm/ci/code/site/InfopointReason;") \ - static_oop_field(site_InfopointReason, IMPLICIT_EXCEPTION, "Ljdk/vm/ci/code/site/InfopointReason;") \ - end_class \ - start_class(site_Infopoint) \ - oop_field(site_Infopoint, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ - oop_field(site_Infopoint, reason, "Ljdk/vm/ci/code/site/InfopointReason;") \ - end_class \ - start_class(site_ExceptionHandler) \ - int_field(site_ExceptionHandler, handlerPos) \ - end_class \ - start_class(site_Mark) \ - oop_field(site_Mark, id, "Ljava/lang/Object;") \ - end_class \ - start_class(HotSpotCompilationRequestResult) \ - oop_field(HotSpotCompilationRequestResult, failureMessage, "Ljava/lang/String;") \ - boolean_field(HotSpotCompilationRequestResult, retry) \ - int_field(HotSpotCompilationRequestResult, inlinedBytecodes) \ - end_class \ - start_class(DebugInfo) \ - oop_field(DebugInfo, bytecodePosition, "Ljdk/vm/ci/code/BytecodePosition;") \ - oop_field(DebugInfo, referenceMap, "Ljdk/vm/ci/code/ReferenceMap;") \ - oop_field(DebugInfo, calleeSaveInfo, "Ljdk/vm/ci/code/RegisterSaveLayout;") \ - objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/vm/ci/code/VirtualObject;") \ - end_class \ - start_class(HotSpotReferenceMap) \ - objArrayOop_field(HotSpotReferenceMap, objects, "[Ljdk/vm/ci/code/Location;") \ - objArrayOop_field(HotSpotReferenceMap, derivedBase, "[Ljdk/vm/ci/code/Location;") \ - typeArrayOop_field(HotSpotReferenceMap, sizeInBytes, "[I") \ - int_field(HotSpotReferenceMap, maxRegisterSize) \ - end_class \ - start_class(RegisterSaveLayout) \ - objArrayOop_field(RegisterSaveLayout, registers, "[Ljdk/vm/ci/code/Register;") \ - typeArrayOop_field(RegisterSaveLayout, slots, "[I") \ - end_class \ - start_class(BytecodeFrame) \ - objArrayOop_field(BytecodeFrame, values, "[Ljdk/vm/ci/meta/JavaValue;") \ - objArrayOop_field(BytecodeFrame, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ - int_field(BytecodeFrame, numLocals) \ - int_field(BytecodeFrame, numStack) \ - int_field(BytecodeFrame, numLocks) \ - boolean_field(BytecodeFrame, rethrowException) \ - boolean_field(BytecodeFrame, duringCall) \ - static_int_field(BytecodeFrame, UNKNOWN_BCI) \ - static_int_field(BytecodeFrame, UNWIND_BCI) \ - static_int_field(BytecodeFrame, BEFORE_BCI) \ - static_int_field(BytecodeFrame, AFTER_BCI) \ - static_int_field(BytecodeFrame, AFTER_EXCEPTION_BCI) \ - static_int_field(BytecodeFrame, INVALID_FRAMESTATE_BCI) \ - end_class \ - start_class(BytecodePosition) \ - oop_field(BytecodePosition, caller, "Ljdk/vm/ci/code/BytecodePosition;") \ - oop_field(BytecodePosition, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ - int_field(BytecodePosition, bci) \ - end_class \ - start_class(JavaConstant) \ - end_class \ - start_class(PrimitiveConstant) \ - oop_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ - long_field(PrimitiveConstant, primitive) \ - end_class \ - start_class(RawConstant) \ - long_field(RawConstant, primitive) \ - end_class \ - start_class(NullConstant) \ - end_class \ - start_class(HotSpotCompressedNullConstant) \ - end_class \ - start_class(HotSpotObjectConstantImpl) \ - oop_field(HotSpotObjectConstantImpl, object, "Ljava/lang/Object;") \ - boolean_field(HotSpotObjectConstantImpl, compressed) \ - end_class \ - start_class(HotSpotMetaspaceConstantImpl) \ - oop_field(HotSpotMetaspaceConstantImpl, metaspaceObject, "Ljdk/vm/ci/hotspot/MetaspaceWrapperObject;") \ - boolean_field(HotSpotMetaspaceConstantImpl, compressed) \ - end_class \ - start_class(HotSpotSentinelConstant) \ - end_class \ - start_class(JavaKind) \ - char_field(JavaKind, typeChar) \ - static_oop_field(JavaKind, Boolean, "Ljdk/vm/ci/meta/JavaKind;") \ - static_oop_field(JavaKind, Byte, "Ljdk/vm/ci/meta/JavaKind;") \ - static_oop_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;") \ - static_oop_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;") \ - static_oop_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;") \ - static_oop_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;") \ - end_class \ - start_class(ValueKind) \ - oop_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \ - end_class \ - start_class(Value) \ - oop_field(Value, valueKind, "Ljdk/vm/ci/meta/ValueKind;") \ - static_oop_field(Value, ILLEGAL, "Ljdk/vm/ci/meta/AllocatableValue;") \ - end_class \ - start_class(RegisterValue) \ - oop_field(RegisterValue, reg, "Ljdk/vm/ci/code/Register;") \ - end_class \ - start_class(code_Location) \ - oop_field(code_Location, reg, "Ljdk/vm/ci/code/Register;") \ - int_field(code_Location, offset) \ - end_class \ - start_class(code_Register) \ - int_field(code_Register, number) \ - int_field(code_Register, encoding) \ - end_class \ - start_class(StackSlot) \ - int_field(StackSlot, offset) \ - boolean_field(StackSlot, addFrameSize) \ - end_class \ - start_class(VirtualObject) \ - int_field(VirtualObject, id) \ - oop_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ - objArrayOop_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;") \ - objArrayOop_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ - end_class \ - start_class(StackLockValue) \ - oop_field(StackLockValue, owner, "Ljdk/vm/ci/meta/JavaValue;") \ - oop_field(StackLockValue, slot, "Ljdk/vm/ci/meta/AllocatableValue;") \ - boolean_field(StackLockValue, eliminated) \ - end_class \ - start_class(HotSpotSpeculationLog) \ - long_field(HotSpotSpeculationLog, lastFailed) \ - end_class \ - start_class(HotSpotStackFrameReference) \ - oop_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/vm/ci/hotspot/CompilerToVM;") \ - boolean_field(HotSpotStackFrameReference, objectsMaterialized) \ - long_field(HotSpotStackFrameReference, stackPointer) \ - int_field(HotSpotStackFrameReference, frameNumber) \ - int_field(HotSpotStackFrameReference, bci) \ - oop_field(HotSpotStackFrameReference, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ - objArrayOop_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;") \ - typeArrayOop_field(HotSpotStackFrameReference, localIsVirtual, "[Z") \ - end_class \ - start_class(HotSpotMetaData) \ - typeArrayOop_field(HotSpotMetaData, pcDescBytes, "[B") \ - typeArrayOop_field(HotSpotMetaData, scopesDescBytes, "[B") \ - typeArrayOop_field(HotSpotMetaData, relocBytes, "[B") \ - typeArrayOop_field(HotSpotMetaData, exceptionBytes, "[B") \ - typeArrayOop_field(HotSpotMetaData, oopMaps, "[B") \ - objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/Object;") \ - end_class \ - start_class(HotSpotConstantPool) \ - long_field(HotSpotConstantPool, metaspaceConstantPool) \ - end_class \ - start_class(HotSpotJVMCIRuntime) \ - objArrayOop_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \ - end_class \ +#define JVMCI_CLASSES_DO(start_class, \ + end_class, \ + char_field, \ + int_field, \ + boolean_field, \ + long_field, \ + float_field, \ + object_field, \ + primarray_field, \ + objectarray_field, \ + static_object_field, \ + static_objectarray_field, \ + static_int_field, \ + static_boolean_field, \ + jvmci_method, \ + jvmci_constructor) \ + start_class(Services, jdk_vm_ci_services_Services) \ + jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, Services, initializeSavedProperties, byte_array_void_signature, (JVMCIObject serializedProperties)) \ + end_class \ + start_class(Architecture, jdk_vm_ci_code_Architecture) \ + object_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + end_class \ + start_class(TargetDescription, jdk_vm_ci_code_TargetDescription) \ + object_field(TargetDescription, arch, "Ljdk/vm/ci/code/Architecture;") \ + end_class \ + start_class(HotSpotResolvedObjectTypeImpl, jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl) \ + long_field(HotSpotResolvedObjectTypeImpl, metadataPointer) \ + end_class \ + start_class(HotSpotResolvedPrimitiveType, jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType) \ + object_field(HotSpotResolvedPrimitiveType, mirror, "Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;") \ + object_field(HotSpotResolvedPrimitiveType, kind, "Ljdk/vm/ci/meta/JavaKind;") \ + static_objectarray_field(HotSpotResolvedPrimitiveType, primitives, "[Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;") \ + end_class \ + start_class(HotSpotResolvedJavaFieldImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaFieldImpl) \ + object_field(HotSpotResolvedJavaFieldImpl, type, "Ljdk/vm/ci/meta/JavaType;") \ + object_field(HotSpotResolvedJavaFieldImpl, holder, "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \ + int_field(HotSpotResolvedJavaFieldImpl, offset) \ + int_field(HotSpotResolvedJavaFieldImpl, modifiers) \ + end_class \ + start_class(HotSpotResolvedJavaMethodImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) \ + long_field(HotSpotResolvedJavaMethodImpl, metadataHandle) \ + end_class \ + start_class(InstalledCode, jdk_vm_ci_code_InstalledCode) \ + long_field(InstalledCode, address) \ + long_field(InstalledCode, entryPoint) \ + long_field(InstalledCode, version) \ + object_field(InstalledCode, name, "Ljava/lang/String;") \ + end_class \ + start_class(HotSpotInstalledCode, jdk_vm_ci_hotspot_HotSpotInstalledCode) \ + int_field(HotSpotInstalledCode, size) \ + long_field(HotSpotInstalledCode, codeStart) \ + int_field(HotSpotInstalledCode, codeSize) \ + end_class \ + start_class(HotSpotNmethod, jdk_vm_ci_hotspot_HotSpotNmethod) \ + boolean_field(HotSpotNmethod, isDefault) \ + long_field(HotSpotNmethod, compileIdSnapshot) \ + object_field(HotSpotNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;") \ + jvmci_constructor(HotSpotNmethod, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \ + end_class \ + start_class(HotSpotCompiledCode, jdk_vm_ci_hotspot_HotSpotCompiledCode) \ + object_field(HotSpotCompiledCode, name, "Ljava/lang/String;") \ + primarray_field(HotSpotCompiledCode, targetCode, "[B") \ + int_field(HotSpotCompiledCode, targetCodeSize) \ + objectarray_field(HotSpotCompiledCode, sites, "[Ljdk/vm/ci/code/site/Site;") \ + objectarray_field(HotSpotCompiledCode, assumptions, "[Ljdk/vm/ci/meta/Assumptions$Assumption;") \ + objectarray_field(HotSpotCompiledCode, methods, "[Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + objectarray_field(HotSpotCompiledCode, comments, "[Ljdk/vm/ci/hotspot/HotSpotCompiledCode$Comment;") \ + primarray_field(HotSpotCompiledCode, dataSection, "[B") \ + int_field(HotSpotCompiledCode, dataSectionAlignment) \ + objectarray_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/vm/ci/code/site/DataPatch;") \ + boolean_field(HotSpotCompiledCode, isImmutablePIC) \ + int_field(HotSpotCompiledCode, totalFrameSize) \ + object_field(HotSpotCompiledCode, deoptRescueSlot, "Ljdk/vm/ci/code/StackSlot;") \ + end_class \ + start_class(HotSpotCompiledCode_Comment, jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment) \ + object_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \ + int_field(HotSpotCompiledCode_Comment, pcOffset) \ + end_class \ + start_class(HotSpotCompiledNmethod, jdk_vm_ci_hotspot_HotSpotCompiledNmethod) \ + object_field(HotSpotCompiledNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + object_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;") \ + int_field(HotSpotCompiledNmethod, entryBCI) \ + int_field(HotSpotCompiledNmethod, id) \ + long_field(HotSpotCompiledNmethod, compileState) \ + boolean_field(HotSpotCompiledNmethod, hasUnsafeAccess) \ + end_class \ + start_class(HotSpotForeignCallTarget, jdk_vm_ci_hotspot_HotSpotForeignCallTarget) \ + long_field(HotSpotForeignCallTarget, address) \ + end_class \ + start_class(VMField, jdk_vm_ci_hotspot_VMField) \ + object_field(VMField, name, "Ljava/lang/String;") \ + object_field(VMField, type, "Ljava/lang/String;") \ + long_field(VMField, offset) \ + long_field(VMField, address) \ + object_field(VMField, value, "Ljava/lang/Object;") \ + jvmci_constructor(VMField, "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/Object;)V") \ + end_class \ + start_class(VMFlag, jdk_vm_ci_hotspot_VMFlag) \ + object_field(VMFlag, name, "Ljava/lang/String;") \ + object_field(VMFlag, type, "Ljava/lang/String;") \ + object_field(VMFlag, value, "Ljava/lang/Object;") \ + jvmci_constructor(VMFlag, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V") \ + end_class \ + start_class(VMIntrinsicMethod, jdk_vm_ci_hotspot_VMIntrinsicMethod) \ + object_field(VMIntrinsicMethod, declaringClass, "Ljava/lang/String;") \ + object_field(VMIntrinsicMethod, name, "Ljava/lang/String;") \ + object_field(VMIntrinsicMethod, descriptor, "Ljava/lang/String;") \ + int_field(VMIntrinsicMethod, id) \ + jvmci_constructor(VMIntrinsicMethod, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V") \ + end_class \ + start_class(Assumptions_NoFinalizableSubclass, jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass) \ + object_field(Assumptions_NoFinalizableSubclass, receiverType, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteSubtype, jdk_vm_ci_meta_Assumptions_ConcreteSubtype) \ + object_field(Assumptions_ConcreteSubtype, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + object_field(Assumptions_ConcreteSubtype, subtype, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_LeafType, jdk_vm_ci_meta_Assumptions_LeafType) \ + object_field(Assumptions_LeafType, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteMethod, jdk_vm_ci_meta_Assumptions_ConcreteMethod) \ + object_field(Assumptions_ConcreteMethod, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + object_field(Assumptions_ConcreteMethod, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + object_field(Assumptions_ConcreteMethod, impl, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(Assumptions_CallSiteTargetValue, jdk_vm_ci_meta_Assumptions_CallSiteTargetValue) \ + object_field(Assumptions_CallSiteTargetValue, callSite, "Ljdk/vm/ci/meta/JavaConstant;") \ + object_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljdk/vm/ci/meta/JavaConstant;") \ + end_class \ + start_class(site_Site, jdk_vm_ci_code_site_Site) \ + int_field(site_Site, pcOffset) \ + end_class \ + start_class(site_Call, jdk_vm_ci_code_site_Call) \ + object_field(site_Call, target, "Ljdk/vm/ci/meta/InvokeTarget;") \ + end_class \ + start_class(site_DataPatch, jdk_vm_ci_code_site_DataPatch) \ + object_field(site_DataPatch, reference, "Ljdk/vm/ci/code/site/Reference;") \ + end_class \ + start_class(site_ConstantReference, jdk_vm_ci_code_site_ConstantReference) \ + object_field(site_ConstantReference, constant, "Ljdk/vm/ci/meta/VMConstant;") \ + end_class \ + start_class(site_DataSectionReference, jdk_vm_ci_code_site_DataSectionReference) \ + int_field(site_DataSectionReference, offset) \ + end_class \ + start_class(site_InfopointReason, jdk_vm_ci_code_site_InfopointReason) \ + static_object_field(site_InfopointReason, SAFEPOINT, "Ljdk/vm/ci/code/site/InfopointReason;") \ + static_object_field(site_InfopointReason, CALL, "Ljdk/vm/ci/code/site/InfopointReason;") \ + static_object_field(site_InfopointReason, IMPLICIT_EXCEPTION, "Ljdk/vm/ci/code/site/InfopointReason;") \ + end_class \ + start_class(site_Infopoint, jdk_vm_ci_code_site_Infopoint) \ + object_field(site_Infopoint, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ + object_field(site_Infopoint, reason, "Ljdk/vm/ci/code/site/InfopointReason;") \ + end_class \ + start_class(site_ExceptionHandler, jdk_vm_ci_code_site_ExceptionHandler) \ + int_field(site_ExceptionHandler, handlerPos) \ + end_class \ + start_class(site_Mark, jdk_vm_ci_code_site_Mark) \ + object_field(site_Mark, id, "Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotCompilationRequestResult, jdk_vm_ci_hotspot_HotSpotCompilationRequestResult) \ + object_field(HotSpotCompilationRequestResult, failureMessage, "Ljava/lang/String;") \ + boolean_field(HotSpotCompilationRequestResult, retry) \ + int_field(HotSpotCompilationRequestResult, inlinedBytecodes) \ + end_class \ + start_class(DebugInfo, jdk_vm_ci_code_DebugInfo) \ + object_field(DebugInfo, bytecodePosition, "Ljdk/vm/ci/code/BytecodePosition;") \ + object_field(DebugInfo, referenceMap, "Ljdk/vm/ci/code/ReferenceMap;") \ + object_field(DebugInfo, calleeSaveInfo, "Ljdk/vm/ci/code/RegisterSaveLayout;") \ + objectarray_field(DebugInfo, virtualObjectMapping, "[Ljdk/vm/ci/code/VirtualObject;") \ + end_class \ + start_class(HotSpotReferenceMap, jdk_vm_ci_hotspot_HotSpotReferenceMap) \ + objectarray_field(HotSpotReferenceMap, objects, "[Ljdk/vm/ci/code/Location;") \ + objectarray_field(HotSpotReferenceMap, derivedBase, "[Ljdk/vm/ci/code/Location;") \ + primarray_field(HotSpotReferenceMap, sizeInBytes, "[I") \ + int_field(HotSpotReferenceMap, maxRegisterSize) \ + end_class \ + start_class(RegisterSaveLayout, jdk_vm_ci_code_RegisterSaveLayout) \ + objectarray_field(RegisterSaveLayout, registers, "[Ljdk/vm/ci/code/Register;") \ + primarray_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BytecodeFrame, jdk_vm_ci_code_BytecodeFrame) \ + objectarray_field(BytecodeFrame, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objectarray_field(BytecodeFrame, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + int_field(BytecodeFrame, numLocals) \ + int_field(BytecodeFrame, numStack) \ + int_field(BytecodeFrame, numLocks) \ + boolean_field(BytecodeFrame, rethrowException) \ + boolean_field(BytecodeFrame, duringCall) \ + static_int_field(BytecodeFrame, UNKNOWN_BCI) \ + static_int_field(BytecodeFrame, UNWIND_BCI) \ + static_int_field(BytecodeFrame, BEFORE_BCI) \ + static_int_field(BytecodeFrame, AFTER_BCI) \ + static_int_field(BytecodeFrame, AFTER_EXCEPTION_BCI) \ + static_int_field(BytecodeFrame, INVALID_FRAMESTATE_BCI) \ + end_class \ + start_class(BytecodePosition, jdk_vm_ci_code_BytecodePosition) \ + object_field(BytecodePosition, caller, "Ljdk/vm/ci/code/BytecodePosition;") \ + object_field(BytecodePosition, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + int_field(BytecodePosition, bci) \ + end_class \ + start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \ + static_object_field(JavaConstant, NULL_POINTER, "Ljdk/vm/ci/meta/JavaConstant;") \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forFloat, forFloat_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forDouble, forDouble_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \ + end_class \ + start_class(ResolvedJavaMethod, jdk_vm_ci_meta_ResolvedJavaMethod) \ + end_class \ + start_class(PrimitiveConstant, jdk_vm_ci_meta_PrimitiveConstant) \ + object_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ + long_field(PrimitiveConstant, primitive) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, PrimitiveConstant, forTypeChar, forTypeChar_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \ + end_class \ + start_class(RawConstant, jdk_vm_ci_meta_RawConstant) \ + end_class \ + start_class(NullConstant, jdk_vm_ci_meta_NullConstant) \ + end_class \ + start_class(HotSpotCompressedNullConstant, jdk_vm_ci_hotspot_HotSpotCompressedNullConstant) \ + end_class \ + start_class(HotSpotObjectConstantImpl, jdk_vm_ci_hotspot_HotSpotObjectConstantImpl) \ + boolean_field(HotSpotObjectConstantImpl, compressed) \ + end_class \ + start_class(DirectHotSpotObjectConstantImpl, jdk_vm_ci_hotspot_DirectHotSpotObjectConstantImpl) \ + object_field(DirectHotSpotObjectConstantImpl, object, "Ljava/lang/Object;") \ + jvmci_constructor(DirectHotSpotObjectConstantImpl, "(Ljava/lang/Object;Z)V") \ + end_class \ + start_class(IndirectHotSpotObjectConstantImpl, jdk_vm_ci_hotspot_IndirectHotSpotObjectConstantImpl) \ + long_field(IndirectHotSpotObjectConstantImpl, objectHandle) \ + jvmci_constructor(IndirectHotSpotObjectConstantImpl, "(JZZ)V") \ + end_class \ + start_class(HotSpotMetaspaceConstantImpl, jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl) \ + object_field(HotSpotMetaspaceConstantImpl, metaspaceObject, "Ljdk/vm/ci/hotspot/MetaspaceObject;") \ + boolean_field(HotSpotMetaspaceConstantImpl, compressed) \ + end_class \ + start_class(HotSpotSentinelConstant, jdk_vm_ci_hotspot_HotSpotSentinelConstant) \ + end_class \ + start_class(JavaKind, jdk_vm_ci_meta_JavaKind) \ + char_field(JavaKind, typeChar) \ + static_object_field(JavaKind, Boolean, "Ljdk/vm/ci/meta/JavaKind;") \ + static_object_field(JavaKind, Byte, "Ljdk/vm/ci/meta/JavaKind;") \ + static_object_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;") \ + static_object_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;") \ + static_object_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;") \ + static_object_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;") \ + end_class \ + start_class(ValueKind, jdk_vm_ci_meta_ValueKind) \ + object_field(ValueKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + end_class \ + start_class(Value, jdk_vm_ci_meta_Value) \ + object_field(Value, valueKind, "Ljdk/vm/ci/meta/ValueKind;") \ + static_object_field(Value, ILLEGAL, "Ljdk/vm/ci/meta/AllocatableValue;") \ + end_class \ + start_class(RegisterValue, jdk_vm_ci_code_RegisterValue) \ + object_field(RegisterValue, reg, "Ljdk/vm/ci/code/Register;") \ + end_class \ + start_class(code_Location, jdk_vm_ci_code_Location) \ + object_field(code_Location, reg, "Ljdk/vm/ci/code/Register;") \ + int_field(code_Location, offset) \ + end_class \ + start_class(code_Register, jdk_vm_ci_code_Register) \ + int_field(code_Register, number) \ + int_field(code_Register, encoding) \ + end_class \ + start_class(StackSlot, jdk_vm_ci_code_StackSlot) \ + int_field(StackSlot, offset) \ + boolean_field(StackSlot, addFrameSize) \ + end_class \ + start_class(VirtualObject, jdk_vm_ci_code_VirtualObject) \ + int_field(VirtualObject, id) \ + object_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + objectarray_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objectarray_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + end_class \ + start_class(StackLockValue, jdk_vm_ci_code_StackLockValue) \ + object_field(StackLockValue, owner, "Ljdk/vm/ci/meta/JavaValue;") \ + object_field(StackLockValue, slot, "Ljdk/vm/ci/meta/AllocatableValue;") \ + boolean_field(StackLockValue, eliminated) \ + end_class \ + start_class(HotSpotStackFrameReference, jdk_vm_ci_hotspot_HotSpotStackFrameReference) \ + object_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/vm/ci/hotspot/CompilerToVM;") \ + boolean_field(HotSpotStackFrameReference, objectsMaterialized) \ + long_field(HotSpotStackFrameReference, stackPointer) \ + int_field(HotSpotStackFrameReference, frameNumber) \ + int_field(HotSpotStackFrameReference, bci) \ + object_field(HotSpotStackFrameReference, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + objectarray_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;") \ + primarray_field(HotSpotStackFrameReference, localIsVirtual, "[Z") \ + end_class \ + start_class(HotSpotMetaData, jdk_vm_ci_hotspot_HotSpotMetaData) \ + primarray_field(HotSpotMetaData, pcDescBytes, "[B") \ + primarray_field(HotSpotMetaData, scopesDescBytes, "[B") \ + primarray_field(HotSpotMetaData, relocBytes, "[B") \ + primarray_field(HotSpotMetaData, exceptionBytes, "[B") \ + primarray_field(HotSpotMetaData, oopMaps, "[B") \ + object_field(HotSpotMetaData, metadata, "[Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotConstantPool, jdk_vm_ci_hotspot_HotSpotConstantPool) \ + long_field(HotSpotConstantPool, metadataHandle) \ + end_class \ + start_class(HotSpotJVMCIRuntime, jdk_vm_ci_hotspot_HotSpotJVMCIRuntime) \ + objectarray_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \ + jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \ + jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ + jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature, (JVMCI_TRAPS)) \ + jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, callToString, callToString_signature, (JVMCIObject object, JVMCI_TRAPS)) \ + end_class \ + start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \ + jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \ + end_class \ + start_class(InspectedFrameVisitor, jdk_vm_ci_code_stack_InspectedFrameVisitor) \ + end_class \ + start_class(JVMCI, jdk_vm_ci_runtime_JVMCI) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, getRuntime, getRuntime_signature, (JVMCI_TRAPS)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, initializeRuntime, initializeRuntime_signature, (JVMCI_TRAPS)) \ + end_class \ + start_class(Object, java_lang_Object) \ + end_class \ + start_class(String, java_lang_String) \ + end_class \ + start_class(Class, java_lang_Class) \ + jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, Class, getName, void_string_signature, (JVMCI_TRAPS)) \ + end_class \ + start_class(ArrayIndexOutOfBoundsException, java_lang_ArrayIndexOutOfBoundsException) \ + jvmci_constructor(ArrayIndexOutOfBoundsException, "(Ljava/lang/String;)V") \ + end_class \ + start_class(IllegalStateException, java_lang_IllegalStateException) \ + jvmci_constructor(IllegalStateException, "(Ljava/lang/String;)V") \ + end_class \ + start_class(NullPointerException, java_lang_NullPointerException) \ + jvmci_constructor(NullPointerException, "(Ljava/lang/String;)V") \ + end_class \ + start_class(IllegalArgumentException, java_lang_IllegalArgumentException) \ + jvmci_constructor(IllegalArgumentException, "(Ljava/lang/String;)V") \ + end_class \ + start_class(InternalError, java_lang_InternalError) \ + jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \ + end_class \ + start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \ + jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \ + end_class \ + start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \ + jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \ + end_class \ + start_class(StackTraceElement, java_lang_StackTraceElement) \ + object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \ + object_field(StackTraceElement, methodName, "Ljava/lang/String;") \ + object_field(StackTraceElement, fileName, "Ljava/lang/String;") \ + int_field(StackTraceElement, lineNumber) \ + jvmci_constructor(StackTraceElement, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V") \ + end_class \ + start_class(Throwable, java_lang_Throwable) \ + object_field(Throwable, detailMessage, "Ljava/lang/String;") \ + end_class \ /* end*/ -#define START_CLASS(name) \ -class name : AllStatic { \ - private: \ - friend class JVMCICompiler; \ - static void check(oop obj, const char* field_name, int offset); \ - static void compute_offsets(TRAPS); \ - public: \ - static InstanceKlass* klass() { return SystemDictionary::name##_klass_is_loaded() ? SystemDictionary::name##_klass() : NULL; } +class JVMCICompiler; +class JVMCIEnv; + +#define START_CLASS(simpleClassName, fullClassName) \ + class simpleClassName { \ + friend class JVMCIEnv; \ + static void initialize(JVMCI_TRAPS); \ + static bool is_instance(JVMCIEnv* jvmciEnv, JVMCIObject object); \ #define END_CLASS }; -#define FIELD(name, type, accessor, cast) \ - static int _##name##_offset; \ - static type name(oop obj) { check(obj, #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ - static type name(Handle obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ - static type name(jobject obj); \ - static void set_##name(oop obj, type x) { check(obj, #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ - static void set_##name(Handle obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ - static void set_##name(jobject obj, type x); \ +#define EMPTY_CAST +#define CHAR_FIELD(simpleClassName, name) FIELD(simpleClassName, name, jchar) +#define INT_FIELD(simpleClassName, name) FIELD(simpleClassName, name, jint) +#define BOOLEAN_FIELD(simpleClassName, name) FIELD(simpleClassName, name, jboolean) +#define LONG_FIELD(simpleClassName, name) FIELD(simpleClassName, name, jlong) +#define FLOAT_FIELD(simpleClassName, name) FIELD(simpleClassName, name, jfloat) + +#define OBJECT_FIELD(simpleClassName, name, signature) OOPISH_FIELD(simpleClassName, name, JVMCIObject, oop) +#define OBJECTARRAY_FIELD(simpleClassName, name, signature) OOPISH_FIELD(simpleClassName, name, JVMCIObjectArray, objArrayOop) +#define PRIMARRAY_FIELD(simpleClassName, name, signature) OOPISH_FIELD(simpleClassName, name, JVMCIPrimitiveArray, typeArrayOop) + +#define STATIC_INT_FIELD(simpleClassName, name) STATIC_FIELD(simpleClassName, name, jint) +#define STATIC_BOOLEAN_FIELD(simpleClassName, name) STATIC_FIELD(simpleClassName, name, jboolean) +#define STATIC_OBJECT_FIELD(simpleClassName, name, signature) STATIC_OOPISH_FIELD(simpleClassName, name, JVMCIObject, oop) +#define STATIC_OBJECTARRAY_FIELD(simpleClassName, name, signature) STATIC_OOPISH_FIELD(simpleClassName, name, JVMCIObjectArray, objArrayOop) + +#define HS_START_CLASS(simpleClassName, fullClassName) \ + START_CLASS(simpleClassName, fullClassName) \ + friend class HotSpotJVMCI; \ + private: \ + static void check(oop obj, const char* field_name, int offset); \ + static InstanceKlass* _klass; \ + public: \ + static InstanceKlass* klass() { assert(_klass != NULL, "uninit"); return _klass; } \ + static Symbol* symbol() { return vmSymbols::fullClassName(); } + +#define FIELD(simpleClassName, name, type) \ + private: \ + static int _##name##_offset; \ + public: \ + static type get_ ## name(JVMCIEnv* env, JVMCIObject obj) { return name(env, resolve(obj)); } \ + static void set_ ## name(JVMCIEnv* env, JVMCIObject obj, type x) { set_ ## name(env, resolve(obj), x); } \ + static type name(JVMCIEnv* env, oop obj); \ + static void set_ ## name(JVMCIEnv* env, oop obj, type x); + +#define OOPISH_FIELD(simpleClassName, name, type, hstype) \ + private: \ + static int _##name##_offset; \ + public: \ + static type get_ ## name(JVMCIEnv* env, JVMCIObject obj) { return (type) wrap(name(env, resolve(obj))); } \ + static void set_ ## name(JVMCIEnv* env, JVMCIObject obj, type x) { set_ ## name(env, resolve(obj), (hstype) resolve(x)); } \ + static hstype name(JVMCIEnv* env, oop obj); \ + static void set_ ## name(JVMCIEnv* env, oop obj, hstype x); + +#define STATIC_FIELD(simpleClassName, name, type) \ + private: \ + static int _##name##_offset; \ + public: \ + static type get_ ## name(JVMCIEnv* env); \ + static void set_ ## name(JVMCIEnv* env, type x); + +#define STATIC_OOPISH_FIELD(simpleClassName, name, type, hstype) \ + private: \ + static int _##name##_offset; \ + public: \ + static type get_ ## name(JVMCIEnv* env) { return (type) wrap(name(env)); } \ + static void set_ ## name(JVMCIEnv* env, type x) { set_ ## name(env, (hstype) resolve(x)); } \ + static hstype name(JVMCIEnv* env); \ + static void set_ ## name(JVMCIEnv* env, hstype hstype); + +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, simpleClassName, methodName, signatureSymbolName, args) +#define CONSTRUCTOR(className, signature) + +/** + * VM internal interface to Java classes, methods and objects. For example: + * + * class HotSpotJVMCI { + * ... + * class Architecture { + * static void initialize(JVMCIEnv* env); + * static bool is_instance(JVMCIEnv* env, JVMCIObject object); + * private: + * static void check(oop obj, const char *field_name, int offset); + * public: + * static InstanceKlass *klass() { ... } + * static Symbol *symbol() { return vmSymbols::jdk_vm_ci_code_Architecture(); } + * private: + * static int _wordKind_offset; + * public: + * static JVMCIObject get_wordKind(JVMCIEnv *env, JVMCIObject obj) { ... } + * static void set_wordKind(JVMCIEnv *env, JVMCIObject obj, JVMCIObject x) { ... } + * static oop wordKind(JVMCIEnv *env, oop obj); + * static void set_wordKind(JVMCIEnv *env, oop obj, oop x); + * } + * ... + * }; + */ +class HotSpotJVMCI { + friend class JVMCIEnv; + + public: + + static oop resolve(JVMCIObject obj); + + static arrayOop resolve(JVMCIArray obj); + static objArrayOop resolve(JVMCIObjectArray obj); + static typeArrayOop resolve(JVMCIPrimitiveArray obj); + + static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, true); } + static JVMCIObject wrap(oop obj); + + static inline Method* asMethod(JVMCIEnv* env, oop jvmci_method) { + return *(Method**) HotSpotResolvedJavaMethodImpl::metadataHandle(env, jvmci_method); + } + static inline ConstantPool* asConstantPool(JVMCIEnv* env, oop jvmci_constant_pool) { + return *(ConstantPool**) HotSpotConstantPool::metadataHandle(env, jvmci_constant_pool); + } + static inline Klass* asKlass(JVMCIEnv* env, oop jvmci_type) { + return (Klass*) HotSpotResolvedObjectTypeImpl::metadataPointer(env, jvmci_type); + } + + static void compute_offsets(TRAPS); + static void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS); -#define EMPTY_CAST -#define CHAR_FIELD(klass, name) FIELD(name, jchar, char_field, EMPTY_CAST) -#define INT_FIELD(klass, name) FIELD(name, jint, int_field, EMPTY_CAST) -#define BOOLEAN_FIELD(klass, name) FIELD(name, jboolean, bool_field, EMPTY_CAST) -#define LONG_FIELD(klass, name) FIELD(name, jlong, long_field, EMPTY_CAST) -#define FLOAT_FIELD(klass, name) FIELD(name, jfloat, float_field, EMPTY_CAST) -#define OOP_FIELD(klass, name, signature) FIELD(name, oop, obj_field, EMPTY_CAST) -#define OBJARRAYOOP_FIELD(klass, name, signature) FIELD(name, objArrayOop, obj_field, (objArrayOop)) -#define TYPEARRAYOOP_FIELD(klass, name, signature) FIELD(name, typeArrayOop, obj_field, (typeArrayOop)) -#define STATIC_OOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, oop, signature) -#define STATIC_OBJARRAYOOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, objArrayOop, signature) -#define STATIC_OOPISH_FIELD(klassName, name, type, signature) \ - static int _##name##_offset; \ - static type name(); \ - static void set_##name(type x); -#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \ - static int _##name##_offset; \ - static jtypename name(); \ - static void set_##name(jtypename x); + JVMCI_CLASSES_DO(HS_START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) +}; + +#undef HS_START_CLASS + +#define JNI_START_CLASS(simpleClassName, fullClassName) \ + START_CLASS(simpleClassName, fullClassName) \ + friend class JNIJVMCI; \ + private: \ + static void check(JVMCIEnv* jvmciEnv, JVMCIObject obj, const char* field_name, jfieldID offset); \ + static jclass _class; \ +public: \ + static jclass clazz() { assert(_class != NULL, #fullClassName " uninitialized"); return _class; } \ + static jclass fullClassName ##_class() { assert(_class != NULL, "uninit"); return _class; } + +#undef METHOD +#undef CONSTRUCTOR +#undef FIELD +#undef OOPISH_FIELD +#undef STATIC_FIELD +#undef STATIC_OOPISH_FIELD + +#define FIELD(simpleClassName, name, type) \ + private: \ + static jfieldID _##name##_field_id; \ + public: \ + static type get_ ## name(JVMCIEnv* jvmciEnv, JVMCIObject obj); \ + static void set_ ## name(JVMCIEnv* jvmciEnv, JVMCIObject obj, type x); + +#define OOPISH_FIELD(simpleClassName, name, type, hstype) \ + FIELD(simpleClassName, name, type) + +#define STATIC_FIELD(simpleClassName, name, type) \ + private: \ + static jfieldID _##name##_field_id; \ + public: \ + static type get_ ## name(JVMCIEnv* jvmciEnv); \ + static void set_ ## name(JVMCIEnv* jvmciEnv, type x); + +#define STATIC_OOPISH_FIELD(simpleClassName, name, type, hstype) \ + STATIC_FIELD(simpleClassName, name, type) + +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ + public: \ + static jmethodID methodName##_method() { return _##methodName##_method; } \ + private: \ + static jmethodID _##methodName##_method; + +#define CONSTRUCTOR(className, signature) \ + public: \ + static jmethodID constructor() { return _constructor; } \ + private: \ + static jmethodID _constructor; -#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint) -#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean) +/** + * JNI based interface to Java classes, methods and objects. For example: + * + * class JNIJVMCI { + * ... + * class Architecture { + * static void initialize(JVMCIEnv* env); + * static bool is_instance(JVMCIEnv* env, JVMCIObject object); + * private: + * static void check(oop obj, const char *field_name, int offset); + * static jclass _class; + * public: + * static jclass clazz() { return _class; } + * static jclass jdk_vm_ci_code_Architecture_class() { return _class; } + * private: + * static jfieldID _wordKind_field_id; + * public: + * static JVMCIObject get_wordKind(JVMCIEnv *env, JVMCIObject obj) { ... } + * static void set_wordKind(JVMCIEnv *env, JVMCIObject obj, JVMCIObject x) { ... } + * } + * ... + * }; + */ +class JNIJVMCI { + friend class JVMCIEnv; -COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_OBJARRAYOOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) + static jclass _byte_array; + static jclass _box_classes[T_CONFLICT+1]; + static jfieldID _box_fields[T_CONFLICT+1]; + static jmethodID _box_constructors[T_CONFLICT+1]; + static jmethodID _Class_getName_method; + + static jmethodID _HotSpotResolvedJavaMethodImpl_fromMetaspace_method; + static jmethodID _HotSpotConstantPool_fromMetaspace_method; + static jmethodID _HotSpotResolvedObjectTypeImpl_fromMetaspace_method; + static jmethodID _HotSpotResolvedPrimitiveType_fromMetaspace_method; + + public: + static jmethodID Class_getName_method() { return _Class_getName_method; } + + static jclass byte_array() { assert(_byte_array != NULL, "uninit"); return _byte_array; } + + static jclass box_class(BasicType type) { assert(_box_classes[type]!= NULL, "uninit"); return _box_classes[type]; } + static jfieldID box_field(BasicType type) { assert(_box_fields[type]!= NULL, "uninit"); return _box_fields[type]; } + static jmethodID box_constructor(BasicType type) { assert(_box_constructors[type]!= NULL, "uninit"); return _box_constructors[type]; } + + static jmethodID HotSpotResolvedJavaMethodImpl_fromMetaspace_method() { assert(_HotSpotResolvedJavaMethodImpl_fromMetaspace_method != NULL, "uninit"); return _HotSpotResolvedJavaMethodImpl_fromMetaspace_method; } + static jmethodID HotSpotConstantPool_fromMetaspace_method() { assert(_HotSpotConstantPool_fromMetaspace_method != NULL, "uninit"); return _HotSpotConstantPool_fromMetaspace_method; } + static jmethodID HotSpotResolvedObjectTypeImpl_fromMetaspace_method() { assert(_HotSpotResolvedObjectTypeImpl_fromMetaspace_method != NULL, "uninit"); return _HotSpotResolvedObjectTypeImpl_fromMetaspace_method; } + static jmethodID HotSpotResolvedPrimitiveType_fromMetaspace_method() { assert(_HotSpotResolvedPrimitiveType_fromMetaspace_method != NULL, "uninit"); return _HotSpotResolvedPrimitiveType_fromMetaspace_method; } + + static void initialize_ids(JNIEnv* env); + static void initialize_field_id(JNIEnv* env, jfieldID &dest_offset, jclass klass, const char* klass_name, const char* name, const char* signature, bool static_field); + + static jobject resolve_handle(JVMCIObject obj) { return obj.as_jobject(); } + static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, false); } + + JVMCI_CLASSES_DO(JNI_START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) +}; + +#undef JNI_START_CLASS #undef START_CLASS #undef END_CLASS +#undef METHOD +#undef CONSTRUCTOR #undef FIELD #undef CHAR_FIELD #undef INT_FIELD #undef BOOLEAN_FIELD #undef LONG_FIELD #undef FLOAT_FIELD -#undef OOP_FIELD -#undef TYPEARRAYOOP_FIELD -#undef OBJARRAYOOP_FIELD +#undef OBJECT_FIELD +#undef PRIMARRAY_FIELD +#undef OBJECTARRAY_FIELD +#undef FIELD +#undef OOPISH_FIELD +#undef STATIC_FIELD #undef STATIC_OOPISH_FIELD -#undef STATIC_OOP_FIELD -#undef STATIC_OBJARRAYOOP_FIELD +#undef STATIC_FIELD +#undef STATIC_OBJECT_FIELD +#undef STATIC_OBJECTARRAY_FIELD #undef STATIC_INT_FIELD #undef STATIC_BOOLEAN_FIELD #undef STATIC_PRIMITIVE_FIELD #undef EMPTY_CAST -void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field, TRAPS); - #endif // SHARE_JVMCI_JVMCIJAVACLASSES_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciObject.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/jvmciObject.hpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_JVMCI_JVMCIOBJECT_HPP +#define SHARE_JVMCI_JVMCIOBJECT_HPP + +#include "jni.h" +#include "utilities/debug.hpp" + +class JVMCIArray; +class JVMCIPrimitiveArray; +class JVMCIObjectArray; + +class JVMCIObject { + + private: + jobject _object; + bool _is_hotspot; + + public: + JVMCIObject(): _object(NULL), _is_hotspot(false) {} + JVMCIObject(jobject o, bool is_hotspot): _object(o), _is_hotspot(is_hotspot) { } + + static JVMCIObject create(jobject o, bool is_hotspot) { JVMCIObject r(o, is_hotspot); return r; } + jobject as_jobject() { return _object; } + jobject as_jweak() { return (jweak) _object; } + jstring as_jstring() { return (jstring) _object; } + bool is_hotspot() { return _is_hotspot; } + + bool is_null() const { return _object == NULL; } + bool is_non_null() const { return _object != NULL; } + + operator JVMCIArray(); + operator JVMCIPrimitiveArray(); + operator JVMCIObjectArray(); +}; + +class JVMCIArray : public JVMCIObject { + public: + JVMCIArray() {} + JVMCIArray(jobject o, bool is_hotspot): JVMCIObject(o, is_hotspot) {} + jarray as_jobject() { return (jarray) JVMCIObject::as_jobject(); } +}; + +class JVMCIObjectArray : public JVMCIArray { + public: + JVMCIObjectArray() {} + JVMCIObjectArray(void* v): JVMCIArray() { assert(v == NULL, "must be NULL"); } + JVMCIObjectArray(jobject o, bool is_hotspot): JVMCIArray(o, is_hotspot) {} + + jobjectArray as_jobject() { return (jobjectArray) JVMCIArray::as_jobject(); } +}; + +class JVMCIPrimitiveArray : public JVMCIArray { + public: + JVMCIPrimitiveArray() {} + JVMCIPrimitiveArray(void* v): JVMCIArray() { assert(v == NULL, "must be NULL"); } + JVMCIPrimitiveArray(jobject o, bool is_hotspot): JVMCIArray(o, is_hotspot) {} + + jbooleanArray as_jbooleanArray() { return (jbooleanArray) as_jobject(); } + jbyteArray as_jbyteArray() { return (jbyteArray) as_jobject(); } + jcharArray as_jcharArray() { return (jcharArray) as_jobject(); } + jshortArray as_jshortArray() { return (jshortArray) as_jobject(); } + jintArray as_jintArray() { return (jintArray) as_jobject(); } + jfloatArray as_jfloatArray() { return (jfloatArray) as_jobject(); } + jlongArray as_jlongArray() { return (jlongArray) as_jobject(); } + jdoubleArray as_jdoubleArray() { return (jdoubleArray) as_jobject(); } +}; + +inline JVMCIObject::operator JVMCIArray() { return JVMCIArray(_object, _is_hotspot); } +inline JVMCIObject::operator JVMCIPrimitiveArray() { return JVMCIPrimitiveArray(_object, _is_hotspot); } +inline JVMCIObject::operator JVMCIObjectArray() { return JVMCIObjectArray(_object, _is_hotspot); } + +#endif // SHARE_JVMCI_JVMCIOBJECT_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciRuntime.cpp --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Wed May 01 12:31:29 2019 -0700 @@ -22,69 +22,24 @@ */ #include "precompiled.hpp" -#include "jvm.h" -#include "asm/codeBuffer.hpp" -#include "classfile/javaClasses.inline.hpp" -#include "classfile/moduleEntry.hpp" -#include "code/codeCache.hpp" -#include "code/compiledMethod.inline.hpp" #include "compiler/compileBroker.hpp" -#include "compiler/disassembler.hpp" -#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jniAccessMark.inline.hpp" #include "jvmci/jvmciCompilerToVM.hpp" -#include "jvmci/jvmciCompiler.hpp" -#include "jvmci/jvmciJavaClasses.hpp" -#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" #include "logging/log.hpp" -#include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" -#include "memory/resourceArea.hpp" +#include "oops/constantPool.inline.hpp" +#include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/objArrayOop.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/jniHandles.inline.hpp" -#include "runtime/reflection.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/threadSMR.hpp" -#include "utilities/debug.hpp" -#include "utilities/defaultStream.hpp" -#include "utilities/macros.hpp" #if INCLUDE_G1GC #include "gc/g1/g1ThreadLocalData.hpp" #endif // INCLUDE_G1GC -#if defined(_MSC_VER) -#define strtoll _strtoi64 -#endif - -jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; -bool JVMCIRuntime::_well_known_classes_initialized = false; -bool JVMCIRuntime::_shutdown_called = false; - -BasicType JVMCIRuntime::kindToBasicType(Handle kind, TRAPS) { - if (kind.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), T_ILLEGAL); - } - jchar ch = JavaKind::typeChar(kind); - switch(ch) { - case 'Z': return T_BOOLEAN; - case 'B': return T_BYTE; - case 'S': return T_SHORT; - case 'C': return T_CHAR; - case 'I': return T_INT; - case 'F': return T_FLOAT; - case 'J': return T_LONG; - case 'D': return T_DOUBLE; - case 'A': return T_OBJECT; - case '-': return T_ILLEGAL; - default: - JVMCI_ERROR_(T_ILLEGAL, "unexpected Kind: %c", ch); - } -} - // Simple helper to see if the caller of a runtime stub which // entered the VM has been deoptimized @@ -151,23 +106,23 @@ JRT_BLOCK; assert(klass->is_klass(), "not a class"); Handle holder(THREAD, klass->klass_holder()); // keep the klass alive - InstanceKlass* ik = InstanceKlass::cast(klass); + InstanceKlass* h = InstanceKlass::cast(klass); { RetryableAllocationMark ram(thread, null_on_fail); - ik->check_valid_for_instantiation(true, CHECK); + h->check_valid_for_instantiation(true, CHECK); oop obj; if (null_on_fail) { - if (!ik->is_initialized()) { + if (!h->is_initialized()) { // Cannot re-execute class initialization without side effects // so return without attempting the initialization return; } } else { // make sure klass is initialized - ik->initialize(CHECK); + h->initialize(CHECK); } // allocate instance and return via TLS - obj = ik->allocate_instance(CHECK); + obj = h->allocate_instance(CHECK); thread->set_vm_result(obj); } JRT_BLOCK_END; @@ -289,6 +244,7 @@ } #ifdef ASSERT assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); + assert(oopDesc::is_oop(exception()), "just checking"); // Check that exception is a subclass of Throwable, otherwise we have a VerifyError if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { if (ExitVMOnVerifyError) vm_exit(-1); @@ -369,10 +325,11 @@ thread->set_exception_oop(exception()); thread->set_exception_pc(pc); - // the exception cache is used only by non-implicit exceptions - // Update the exception cache only when there didn't happen - // another exception during the computation of the compiled - // exception handler. Checking for exception oop equality is not + // The exception cache is used only for non-implicit exceptions + // Update the exception cache only when another exception did + // occur during the computation of the compiled exception handler + // (e.g., when loading the class of the catch type). + // Checking for exception oop equality is not // sufficient because some exceptions are pre-allocated and reused. if (continuation != NULL && !recursive_exception && !SharedRuntime::deopt_blob()->contains(continuation)) { cm->add_handler_for_exception_and_pc(exception, pc, continuation); @@ -429,12 +386,11 @@ TRACE_jvmci_3("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock)); tty->flush(); } -#ifdef ASSERT if (PrintBiasedLockingStatistics) { Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); } -#endif Handle h_obj(thread, obj); + assert(oopDesc::is_oop(h_obj()), "must be NULL or an object"); if (UseBiasedLocking) { // Retry fast entry if bias is revoked to avoid unnecessary inflation ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); @@ -455,7 +411,7 @@ // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown EXCEPTION_MARK; -#ifdef DEBUG +#ifdef ASSERT if (!oopDesc::is_oop(obj)) { ResetNoHandleMark rhm; nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); @@ -586,10 +542,8 @@ size_t detail_msg_length = strlen(buf) * 2; detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); jio_snprintf(detail_msg, detail_msg_length, buf, value); - report_vm_error(__FILE__, __LINE__, error_msg, "%s", detail_msg); - } else { - report_vm_error(__FILE__, __LINE__, error_msg); } + report_vm_error(__FILE__, __LINE__, error_msg, "%s", detail_msg); JRT_END JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) @@ -693,205 +647,934 @@ } JRT_END -JRT_ENTRY(int, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) +JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) deopt_caller(); - return value; + return (jint) value; JRT_END -void JVMCIRuntime::force_initialization(TRAPS) { - JVMCIRuntime::initialize_well_known_classes(CHECK); - - ResourceMark rm; - TempNewSymbol getCompiler = SymbolTable::new_symbol("getCompiler", CHECK); - TempNewSymbol sig = SymbolTable::new_symbol("()Ljdk/vm/ci/runtime/JVMCICompiler;", CHECK); - Handle jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK); - JavaValue result(T_OBJECT); - JavaCalls::call_virtual(&result, jvmciRuntime, HotSpotJVMCIRuntime::klass(), getCompiler, sig, CHECK); -} // private static JVMCIRuntime JVMCI.initializeRuntime() -JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) +JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) + JNI_JVMCIENV(env); if (!EnableJVMCI) { - THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled"); } - JVMCIRuntime::initialize_HotSpotJVMCIRuntime(CHECK_NULL); - jobject ret = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CHECK_NULL); - return ret; + JVMCIENV->runtime()->initialize_HotSpotJVMCIRuntime(JVMCI_CHECK_NULL); + JVMCIObject runtime = JVMCIENV->runtime()->get_HotSpotJVMCIRuntime(JVMCI_CHECK_NULL); + return JVMCIENV->get_jobject(runtime); JVM_END -Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) { - TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle())); - Klass* klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle())); - TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle())); - TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK_(Handle())); - JavaValue result(T_OBJECT); - if (args == NULL) { - JavaCalls::call_static(&result, klass, runtime, sig, CHECK_(Handle())); +void JVMCIRuntime::call_getCompiler(TRAPS) { + THREAD_JVMCIENV(JavaThread::current()); + JVMCIObject jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_CHECK); + initialize(JVMCIENV); + JVMCIENV->call_HotSpotJVMCIRuntime_getCompiler(jvmciRuntime, JVMCI_CHECK); +} + +void JVMCINMethodData::initialize( + int nmethod_mirror_index, + const char* name, + FailedSpeculation** failed_speculations) +{ + _failed_speculations = failed_speculations; + _nmethod_mirror_index = nmethod_mirror_index; + if (name != NULL) { + _has_name = true; + char* dest = (char*) this->name(); + strcpy(dest, name); } else { - JavaCalls::call_static(&result, klass, runtime, sig, args, CHECK_(Handle())); + _has_name = false; + } +} + +void JVMCINMethodData::add_failed_speculation(nmethod* nm, jlong speculation) { + uint index = (speculation >> 32) & 0xFFFFFFFF; + int length = (int) speculation; + if (index + length > (uint) nm->speculations_size()) { + fatal(INTPTR_FORMAT "[index: %d, length: %d] out of bounds wrt encoded speculations of length %u", speculation, index, length, nm->speculations_size()); + } + address data = nm->speculations_begin() + index; + FailedSpeculation::add_failed_speculation(nm, _failed_speculations, data, length); +} + +oop JVMCINMethodData::get_nmethod_mirror(nmethod* nm) { + if (_nmethod_mirror_index == -1) { + return NULL; } - return Handle(THREAD, (oop)result.get_jobject()); + return nm->oop_at(_nmethod_mirror_index); +} + +void JVMCINMethodData::set_nmethod_mirror(nmethod* nm, oop new_mirror) { + assert(_nmethod_mirror_index != -1, "cannot set JVMCI mirror for nmethod"); + oop* addr = nm->oop_addr_at(_nmethod_mirror_index); + assert(new_mirror != NULL, "use clear_nmethod_mirror to clear the mirror"); + assert(*addr == NULL, "cannot overwrite non-null mirror"); + + *addr = new_mirror; + + // Since we've patched some oops in the nmethod, + // (re)register it with the heap. + Universe::heap()->register_nmethod(nm); +} + +void JVMCINMethodData::clear_nmethod_mirror(nmethod* nm) { + if (_nmethod_mirror_index != -1) { + oop* addr = nm->oop_addr_at(_nmethod_mirror_index); + *addr = NULL; + } } -Handle JVMCIRuntime::get_HotSpotJVMCIRuntime(TRAPS) { - initialize_JVMCI(CHECK_(Handle())); - return Handle(THREAD, JNIHandles::resolve_non_null(_HotSpotJVMCIRuntime_instance)); +void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) { + oop nmethod_mirror = get_nmethod_mirror(nm); + if (nmethod_mirror == NULL) { + return; + } + + // Update the values in the mirror if it still refers to nm. + // We cannot use JVMCIObject to wrap the mirror as this is called + // during GC, forbidding the creation of JNIHandles. + JVMCIEnv* jvmciEnv = NULL; + nmethod* current = (nmethod*) HotSpotJVMCI::InstalledCode::address(jvmciEnv, nmethod_mirror); + if (nm == current) { + if (!nm->is_alive()) { + // Break the link from the mirror to nm such that + // future invocations via the mirror will result in + // an InvalidInstalledCodeException. + HotSpotJVMCI::InstalledCode::set_address(jvmciEnv, nmethod_mirror, 0); + HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, 0); + } else if (nm->is_not_entrant()) { + // Zero the entry point so any new invocation will fail but keep + // the address link around that so that existing activations can + // be deoptimized via the mirror (i.e. JVMCIEnv::invalidate_installed_code). + HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, 0); + } + } +} + +void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) { + if (is_HotSpotJVMCIRuntime_initialized()) { + if (JVMCIENV->is_hotspot() && UseJVMCINativeLibrary) { + JVMCI_THROW_MSG(InternalError, "JVMCI has already been enabled in the JVMCI shared library"); + } + } + + initialize(JVMCIENV); + + // This should only be called in the context of the JVMCI class being initialized + JVMCIObject result = JVMCIENV->call_HotSpotJVMCIRuntime_runtime(JVMCI_CHECK); + + _HotSpotJVMCIRuntime_instance = JVMCIENV->make_global(result); +} + +void JVMCIRuntime::initialize(JVMCIEnv* JVMCIENV) { + assert(this != NULL, "sanity"); + // Check first without JVMCI_lock + if (_initialized) { + return; + } + + MutexLocker locker(JVMCI_lock); + // Check again under JVMCI_lock + if (_initialized) { + return; + } + + while (_being_initialized) { + JVMCI_lock->wait(); + if (_initialized) { + return; + } + } + + _being_initialized = true; + + { + MutexUnlocker unlock(JVMCI_lock); + + HandleMark hm; + ResourceMark rm; + JavaThread* THREAD = JavaThread::current(); + if (JVMCIENV->is_hotspot()) { + HotSpotJVMCI::compute_offsets(CHECK_EXIT); + } else { + JNIAccessMark jni(JVMCIENV); + + JNIJVMCI::initialize_ids(jni.env()); + if (jni()->ExceptionCheck()) { + jni()->ExceptionDescribe(); + fatal("JNI exception during init"); + } + } + create_jvmci_primitive_type(T_BOOLEAN, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_BYTE, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_CHAR, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_SHORT, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_INT, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_LONG, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_FLOAT, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_DOUBLE, JVMCI_CHECK_EXIT_((void)0)); + create_jvmci_primitive_type(T_VOID, JVMCI_CHECK_EXIT_((void)0)); + + if (!JVMCIENV->is_hotspot()) { + JVMCIENV->copy_saved_properties(); + } + } + + _initialized = true; + _being_initialized = false; + JVMCI_lock->notify_all(); } -void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { - guarantee(!is_HotSpotJVMCIRuntime_initialized(), "cannot reinitialize HotSpotJVMCIRuntime"); - JVMCIRuntime::initialize_well_known_classes(CHECK); - // This should only be called in the context of the JVMCI class being initialized - InstanceKlass* klass = SystemDictionary::JVMCI_klass(); - guarantee(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD), - "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); +JVMCIObject JVMCIRuntime::create_jvmci_primitive_type(BasicType type, JVMCI_TRAPS) { + Thread* THREAD = Thread::current(); + // These primitive types are long lived and are created before the runtime is fully set up + // so skip registering them for scanning. + JVMCIObject mirror = JVMCIENV->get_object_constant(java_lang_Class::primitive_mirror(type), false, true); + if (JVMCIENV->is_hotspot()) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(mirror))); + args.push_int(type2char(type)); + JavaCalls::call_static(&result, HotSpotJVMCI::HotSpotResolvedPrimitiveType::klass(), vmSymbols::fromMetaspace_name(), vmSymbols::primitive_fromMetaspace_signature(), &args, CHECK_(JVMCIObject())); - Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime", - "runtime", - "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK); - _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result); + return JVMCIENV->wrap(JNIHandles::make_local((oop)result.get_jobject())); + } else { + JNIAccessMark jni(JVMCIENV); + jobject result = jni()->CallStaticObjectMethod(JNIJVMCI::HotSpotResolvedPrimitiveType::clazz(), + JNIJVMCI::HotSpotResolvedPrimitiveType_fromMetaspace_method(), + mirror.as_jobject(), type2char(type)); + if (jni()->ExceptionCheck()) { + return JVMCIObject(); + } + return JVMCIENV->wrap(result); + } +} + +void JVMCIRuntime::initialize_JVMCI(JVMCI_TRAPS) { + if (!is_HotSpotJVMCIRuntime_initialized()) { + initialize(JVMCI_CHECK); + JVMCIENV->call_JVMCI_getRuntime(JVMCI_CHECK); + } +} + +JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) { + initialize(JVMCIENV); + initialize_JVMCI(JVMCI_CHECK_(JVMCIObject())); + return _HotSpotJVMCIRuntime_instance; } -void JVMCIRuntime::initialize_JVMCI(TRAPS) { - if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { - callStatic("jdk/vm/ci/runtime/JVMCI", - "getRuntime", - "()Ljdk/vm/ci/runtime/JVMCIRuntime;", NULL, CHECK); + +// private void CompilerToVM.registerNatives() +JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) + +#ifdef _LP64 +#ifndef TARGET_ARCH_sparc + uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); + uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; + guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"); +#endif // TARGET_ARCH_sparc +#else + fatal("check TLAB allocation code for address space conflicts"); +#endif + + JNI_JVMCIENV(env); + + if (!EnableJVMCI) { + JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled"); } - assert(is_HotSpotJVMCIRuntime_initialized(), "what?"); + + JVMCIENV->runtime()->initialize(JVMCIENV); + + { + ResourceMark rm; + HandleMark hm(thread); + ThreadToNativeFromVM trans(thread); + + // Ensure _non_oop_bits is initialized + Universe::non_oop_word(); + + if (JNI_OK != env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count())) { + if (!env->ExceptionCheck()) { + for (int i = 0; i < CompilerToVM::methods_count(); i++) { + if (JNI_OK != env->RegisterNatives(c2vmClass, CompilerToVM::methods + i, 1)) { + guarantee(false, "Error registering JNI method %s%s", CompilerToVM::methods[i].name, CompilerToVM::methods[i].signature); + break; + } + } + } else { + env->ExceptionDescribe(); + } + guarantee(false, "Failed registering CompilerToVM native methods"); + } + } +JVM_END + + +void JVMCIRuntime::shutdown() { + if (is_HotSpotJVMCIRuntime_initialized()) { + _shutdown_called = true; + + THREAD_JVMCIENV(JavaThread::current()); + JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance); + } +} + +void JVMCIRuntime::bootstrap_finished(TRAPS) { + if (is_HotSpotJVMCIRuntime_initialized()) { + THREAD_JVMCIENV(JavaThread::current()); + JVMCIENV->call_HotSpotJVMCIRuntime_bootstrapFinished(_HotSpotJVMCIRuntime_instance, JVMCIENV); + } } -bool JVMCIRuntime::can_initialize_JVMCI() { - // Initializing JVMCI requires the module system to be initialized past phase 3. - // The JVMCI API itself isn't available until phase 2 and ServiceLoader (which - // JVMCI initialization requires) isn't usable until after phase 3. Testing - // whether the system loader is initialized satisfies all these invariants. - if (SystemDictionary::java_system_loader() == NULL) { - return false; +void JVMCIRuntime::describe_pending_hotspot_exception(JavaThread* THREAD, bool clear) { + if (HAS_PENDING_EXCEPTION) { + Handle exception(THREAD, PENDING_EXCEPTION); + const char* exception_file = THREAD->exception_file(); + int exception_line = THREAD->exception_line(); + CLEAR_PENDING_EXCEPTION; + if (exception->is_a(SystemDictionary::ThreadDeath_klass())) { + // Don't print anything if we are being killed. + } else { + java_lang_Throwable::print(exception(), tty); + tty->cr(); + java_lang_Throwable::print_stack_trace(exception, tty); + + // Clear and ignore any exceptions raised during printing + CLEAR_PENDING_EXCEPTION; + } + if (!clear) { + THREAD->set_pending_exception(exception(), exception_file, exception_line); + } } - assert(Universe::is_module_initialized(), "must be"); +} + + +void JVMCIRuntime::exit_on_pending_exception(JVMCIEnv* JVMCIENV, const char* message) { + JavaThread* THREAD = JavaThread::current(); + + static volatile int report_error = 0; + if (!report_error && Atomic::cmpxchg(1, &report_error, 0) == 0) { + // Only report an error once + tty->print_raw_cr(message); + if (JVMCIENV != NULL) { + JVMCIENV->describe_pending_exception(true); + } else { + describe_pending_hotspot_exception(THREAD, true); + } + } else { + // Allow error reporting thread to print the stack trace. Windows + // doesn't allow uninterruptible wait for JavaThreads + const bool interruptible = true; + os::sleep(THREAD, 200, interruptible); + } + + before_exit(THREAD); + vm_exit(-1); +} + +// ------------------------------------------------------------------ +// Note: the logic of this method should mirror the logic of +// constantPoolOopDesc::verify_constant_pool_resolve. +bool JVMCIRuntime::check_klass_accessibility(Klass* accessing_klass, Klass* resolved_klass) { + if (accessing_klass->is_objArray_klass()) { + accessing_klass = ObjArrayKlass::cast(accessing_klass)->bottom_klass(); + } + if (!accessing_klass->is_instance_klass()) { + return true; + } + + if (resolved_klass->is_objArray_klass()) { + // Find the element klass, if this is an array. + resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass(); + } + if (resolved_klass->is_instance_klass()) { + Reflection::VerifyClassAccessResults result = + Reflection::verify_class_access(accessing_klass, InstanceKlass::cast(resolved_klass), true); + return result == Reflection::ACCESS_OK; + } return true; } -void JVMCIRuntime::initialize_well_known_classes(TRAPS) { - if (JVMCIRuntime::_well_known_classes_initialized == false) { - guarantee(can_initialize_JVMCI(), "VM is not yet sufficiently booted to initialize JVMCI"); - SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID; - SystemDictionary::resolve_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK); - JVMCIJavaClasses::compute_offsets(CHECK); - JVMCIRuntime::_well_known_classes_initialized = true; - } -} +// ------------------------------------------------------------------ +Klass* JVMCIRuntime::get_klass_by_name_impl(Klass*& accessing_klass, + const constantPoolHandle& cpool, + Symbol* sym, + bool require_local) { + JVMCI_EXCEPTION_CONTEXT; -void JVMCIRuntime::metadata_do(void f(Metadata*)) { - // For simplicity, the existence of HotSpotJVMCIMetaAccessContext in - // the SystemDictionary well known classes should ensure the other - // classes have already been loaded, so make sure their order in the - // table enforces that. - assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) < - SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); - assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotConstantPool) < - SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); - assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl) < - SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); - - if (HotSpotJVMCIMetaAccessContext::klass() == NULL || - !HotSpotJVMCIMetaAccessContext::klass()->is_linked()) { - // Nothing could be registered yet - return; + // Now we need to check the SystemDictionary + if (sym->char_at(0) == 'L' && + sym->char_at(sym->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-2, + CHECK_NULL); + return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local); } - // WeakReference[] - objArrayOop allContexts = HotSpotJVMCIMetaAccessContext::allContexts(); - if (allContexts == NULL) { - return; + Handle loader(THREAD, (oop)NULL); + Handle domain(THREAD, (oop)NULL); + if (accessing_klass != NULL) { + loader = Handle(THREAD, accessing_klass->class_loader()); + domain = Handle(THREAD, accessing_klass->protection_domain()); } - // These must be loaded at this point but the linking state doesn't matter. - assert(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass() != NULL, "must be loaded"); - assert(SystemDictionary::HotSpotConstantPool_klass() != NULL, "must be loaded"); - assert(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass() != NULL, "must be loaded"); + Klass* found_klass; + { + ttyUnlocker ttyul; // release tty lock to avoid ordering problems + MutexLocker ml(Compile_lock); + if (!require_local) { + found_klass = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, CHECK_NULL); + } else { + found_klass = SystemDictionary::find_instance_or_array_klass(sym, loader, domain, CHECK_NULL); + } + } - for (int i = 0; i < allContexts->length(); i++) { - oop ref = allContexts->obj_at(i); - if (ref != NULL) { - oop referent = java_lang_ref_Reference::referent(ref); - if (referent != NULL) { - // Chunked Object[] with last element pointing to next chunk - objArrayOop metadataRoots = HotSpotJVMCIMetaAccessContext::metadataRoots(referent); - while (metadataRoots != NULL) { - for (int typeIndex = 0; typeIndex < metadataRoots->length() - 1; typeIndex++) { - oop reference = metadataRoots->obj_at(typeIndex); - if (reference == NULL) { - continue; - } - oop metadataRoot = java_lang_ref_Reference::referent(reference); - if (metadataRoot == NULL) { - continue; - } - if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { - Method* method = CompilerToVM::asMethod(metadataRoot); - f(method); - } else if (metadataRoot->is_a(SystemDictionary::HotSpotConstantPool_klass())) { - ConstantPool* constantPool = CompilerToVM::asConstantPool(metadataRoot); - f(constantPool); - } else if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { - Klass* klass = CompilerToVM::asKlass(metadataRoot); - f(klass); - } else { - metadataRoot->print(); - ShouldNotReachHere(); - } - } - metadataRoots = (objArrayOop)metadataRoots->obj_at(metadataRoots->length() - 1); - assert(metadataRoots == NULL || metadataRoots->is_objArray(), "wrong type"); + // If we fail to find an array klass, look again for its element type. + // The element type may be available either locally or via constraints. + // In either case, if we can find the element type in the system dictionary, + // we must build an array type around it. The CI requires array klasses + // to be loaded if their element klasses are loaded, except when memory + // is exhausted. + if (sym->char_at(0) == '[' && + (sym->char_at(1) == '[' || sym->char_at(1) == 'L')) { + // We have an unloaded array. + // Build it on the fly if the element class exists. + TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-1, + CHECK_NULL); + + // Get element Klass recursively. + Klass* elem_klass = + get_klass_by_name_impl(accessing_klass, + cpool, + elem_sym, + require_local); + if (elem_klass != NULL) { + // Now make an array for it + return elem_klass->array_klass(THREAD); + } + } + + if (found_klass == NULL && !cpool.is_null() && cpool->has_preresolution()) { + // Look inside the constant pool for pre-resolved class entries. + for (int i = cpool->length() - 1; i >= 1; i--) { + if (cpool->tag_at(i).is_klass()) { + Klass* kls = cpool->resolved_klass_at(i); + if (kls->name() == sym) { + return kls; } } } } + + return found_klass; +} + +// ------------------------------------------------------------------ +Klass* JVMCIRuntime::get_klass_by_name(Klass* accessing_klass, + Symbol* klass_name, + bool require_local) { + ResourceMark rm; + constantPoolHandle cpool; + return get_klass_by_name_impl(accessing_klass, + cpool, + klass_name, + require_local); +} + +// ------------------------------------------------------------------ +// Implementation of get_klass_by_index. +Klass* JVMCIRuntime::get_klass_by_index_impl(const constantPoolHandle& cpool, + int index, + bool& is_accessible, + Klass* accessor) { + JVMCI_EXCEPTION_CONTEXT; + Klass* klass = ConstantPool::klass_at_if_loaded(cpool, index); + Symbol* klass_name = NULL; + if (klass == NULL) { + klass_name = cpool->klass_name_at(index); + } + + if (klass == NULL) { + // Not found in constant pool. Use the name to do the lookup. + Klass* k = get_klass_by_name_impl(accessor, + cpool, + klass_name, + false); + // Calculate accessibility the hard way. + if (k == NULL) { + is_accessible = false; + } else if (k->class_loader() != accessor->class_loader() && + get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) { + // Loaded only remotely. Not linked yet. + is_accessible = false; + } else { + // Linked locally, and we must also check public/private, etc. + is_accessible = check_klass_accessibility(accessor, k); + } + if (!is_accessible) { + return NULL; + } + return k; + } + + // It is known to be accessible, since it was found in the constant pool. + is_accessible = true; + return klass; +} + +// ------------------------------------------------------------------ +// Get a klass from the constant pool. +Klass* JVMCIRuntime::get_klass_by_index(const constantPoolHandle& cpool, + int index, + bool& is_accessible, + Klass* accessor) { + ResourceMark rm; + Klass* result = get_klass_by_index_impl(cpool, index, is_accessible, accessor); + return result; } -// private static void CompilerToVM.registerNatives() -JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) - if (!EnableJVMCI) { - THROW_MSG(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled"); +// ------------------------------------------------------------------ +// Implementation of get_field_by_index. +// +// Implementation note: the results of field lookups are cached +// in the accessor klass. +void JVMCIRuntime::get_field_by_index_impl(InstanceKlass* klass, fieldDescriptor& field_desc, + int index) { + JVMCI_EXCEPTION_CONTEXT; + + assert(klass->is_linked(), "must be linked before using its constant-pool"); + + constantPoolHandle cpool(thread, klass->constants()); + + // Get the field's name, signature, and type. + Symbol* name = cpool->name_ref_at(index); + + int nt_index = cpool->name_and_type_ref_index_at(index); + int sig_index = cpool->signature_ref_index_at(nt_index); + Symbol* signature = cpool->symbol_at(sig_index); + + // Get the field's declared holder. + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + Klass* declared_holder = get_klass_by_index(cpool, holder_index, + holder_is_accessible, + klass); + + // The declared holder of this field may not have been loaded. + // Bail out with partial field information. + if (!holder_is_accessible) { + return; + } + + + // Perform the field lookup. + Klass* canonical_holder = + InstanceKlass::cast(declared_holder)->find_field(name, signature, &field_desc); + if (canonical_holder == NULL) { + return; + } + + assert(canonical_holder == field_desc.field_holder(), "just checking"); +} + +// ------------------------------------------------------------------ +// Get a field by index from a klass's constant pool. +void JVMCIRuntime::get_field_by_index(InstanceKlass* accessor, fieldDescriptor& fd, int index) { + ResourceMark rm; + return get_field_by_index_impl(accessor, fd, index); +} + +// ------------------------------------------------------------------ +// Perform an appropriate method lookup based on accessor, holder, +// name, signature, and bytecode. +methodHandle JVMCIRuntime::lookup_method(InstanceKlass* accessor, + Klass* holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc, + constantTag tag) { + // Accessibility checks are performed in JVMCIEnv::get_method_by_index_impl(). + assert(check_klass_accessibility(accessor, holder), "holder not accessible"); + + methodHandle dest_method; + LinkInfo link_info(holder, name, sig, accessor, LinkInfo::needs_access_check, tag); + switch (bc) { + case Bytecodes::_invokestatic: + dest_method = + LinkResolver::resolve_static_call_or_null(link_info); + break; + case Bytecodes::_invokespecial: + dest_method = + LinkResolver::resolve_special_call_or_null(link_info); + break; + case Bytecodes::_invokeinterface: + dest_method = + LinkResolver::linktime_resolve_interface_method_or_null(link_info); + break; + case Bytecodes::_invokevirtual: + dest_method = + LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + break; + default: ShouldNotReachHere(); } -#ifdef _LP64 -#ifndef SPARC - uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); - uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; - guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"); -#endif // !SPARC -#else - fatal("check TLAB allocation code for address space conflicts"); -#endif // _LP64 + return dest_method; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIRuntime::get_method_by_index_impl(const constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + InstanceKlass* accessor) { + if (bc == Bytecodes::_invokedynamic) { + ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); + bool is_resolved = !cpce->is_f1_null(); + if (is_resolved) { + // Get the invoker Method* from the constant pool. + // (The appendix argument, if any, will be noted in the method's signature.) + Method* adapter = cpce->f1_as_method(); + return methodHandle(adapter); + } + + return NULL; + } + + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + Klass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); + + // Get the method's name and signature. + Symbol* name_sym = cpool->name_ref_at(index); + Symbol* sig_sym = cpool->signature_ref_at(index); - JVMCIRuntime::initialize_well_known_classes(CHECK); + if (cpool->has_preresolution() + || ((holder == SystemDictionary::MethodHandle_klass() || holder == SystemDictionary::VarHandle_klass()) && + MethodHandles::is_signature_polymorphic_name(holder, name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + Method* m = ConstantPool::method_at_if_loaded(cpool, index); + if (m != NULL) { + return m; + } + } + break; + default: + break; + } + } + + if (holder_is_accessible) { // Our declared holder is loaded. + constantTag tag = cpool->tag_ref_at(index); + methodHandle m = lookup_method(accessor, holder, name_sym, sig_sym, bc, tag); + if (!m.is_null()) { + // We found the method. + return m; + } + } + + // Either the declared holder was not loaded, or the method could + // not be found. + + return NULL; +} + +// ------------------------------------------------------------------ +InstanceKlass* JVMCIRuntime::get_instance_klass_for_declared_method_holder(Klass* method_holder) { + // For the case of .clone(), the method holder can be an ArrayKlass* + // instead of an InstanceKlass*. For that case simply pretend that the + // declared holder is Object.clone since that's where the call will bottom out. + if (method_holder->is_instance_klass()) { + return InstanceKlass::cast(method_holder); + } else if (method_holder->is_array_klass()) { + return InstanceKlass::cast(SystemDictionary::Object_klass()); + } else { + ShouldNotReachHere(); + } + return NULL; +} + - { - ThreadToNativeFromVM trans(thread); - env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); +// ------------------------------------------------------------------ +methodHandle JVMCIRuntime::get_method_by_index(const constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + InstanceKlass* accessor) { + ResourceMark rm; + return get_method_by_index_impl(cpool, index, bc, accessor); +} + +// ------------------------------------------------------------------ +// Check for changes to the system dictionary during compilation +// class loads, evolution, breakpoints +JVMCI::CodeInstallResult JVMCIRuntime::validate_compile_task_dependencies(Dependencies* dependencies, JVMCICompileState* compile_state, char** failure_detail) { + // If JVMTI capabilities were enabled during compile, the compilation is invalidated. + if (compile_state != NULL && compile_state->jvmti_state_changed()) { + *failure_detail = (char*) "Jvmti state change during compilation invalidated dependencies"; + return JVMCI::dependencies_failed; } -JVM_END + + // Dependencies must be checked when the system dictionary changes + // or if we don't know whether it has changed (i.e., compile_state == NULL). + bool counter_changed = compile_state == NULL || compile_state->system_dictionary_modification_counter() != SystemDictionary::number_of_modifications(); + CompileTask* task = compile_state == NULL ? NULL : compile_state->task(); + Dependencies::DepType result = dependencies->validate_dependencies(task, counter_changed, failure_detail); + if (result == Dependencies::end_marker) { + return JVMCI::ok; + } + + if (!Dependencies::is_klass_type(result) || counter_changed) { + return JVMCI::dependencies_failed; + } + // The dependencies were invalid at the time of installation + // without any intervening modification of the system + // dictionary. That means they were invalidly constructed. + return JVMCI::dependencies_invalid; +} + + +void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, const methodHandle& method, int entry_bci) { + JVMCI_EXCEPTION_CONTEXT + + JVMCICompileState* compile_state = JVMCIENV->compile_state(); -void JVMCIRuntime::shutdown(TRAPS) { - if (_HotSpotJVMCIRuntime_instance != NULL) { - _shutdown_called = true; - HandleMark hm(THREAD); - Handle receiver = get_HotSpotJVMCIRuntime(CHECK); - JavaValue result(T_VOID); - JavaCallArguments args; - args.push_oop(receiver); - JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK); + bool is_osr = entry_bci != InvocationEntryBci; + if (compiler->is_bootstrapping() && is_osr) { + // no OSR compilations during bootstrap - the compiler is just too slow at this point, + // and we know that there are no endless loops + compile_state->set_failure(true, "No OSR during boostrap"); + return; + } + + HandleMark hm; + JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV); + if (JVMCIENV->has_pending_exception()) { + JVMCIENV->describe_pending_exception(true); + compile_state->set_failure(false, "exception getting HotSpotJVMCIRuntime object"); + return; + } + JVMCIObject jvmci_method = JVMCIENV->get_jvmci_method(method, JVMCIENV); + if (JVMCIENV->has_pending_exception()) { + JVMCIENV->describe_pending_exception(true); + compile_state->set_failure(false, "exception getting JVMCI wrapper method"); + return; + } + + JVMCIObject result_object = JVMCIENV->call_HotSpotJVMCIRuntime_compileMethod(receiver, jvmci_method, entry_bci, + (jlong) compile_state, compile_state->task()->compile_id()); + if (!JVMCIENV->has_pending_exception()) { + if (result_object.is_non_null()) { + JVMCIObject failure_message = JVMCIENV->get_HotSpotCompilationRequestResult_failureMessage(result_object); + if (failure_message.is_non_null()) { + // Copy failure reason into resource memory first ... + const char* failure_reason = JVMCIENV->as_utf8_string(failure_message); + // ... and then into the C heap. + failure_reason = os::strdup(failure_reason, mtJVMCI); + bool retryable = JVMCIENV->get_HotSpotCompilationRequestResult_retry(result_object) != 0; + compile_state->set_failure(retryable, failure_reason, true); + } else { + if (compile_state->task()->code() == NULL) { + compile_state->set_failure(true, "no nmethod produced"); + } else { + compile_state->task()->set_num_inlined_bytecodes(JVMCIENV->get_HotSpotCompilationRequestResult_inlinedBytecodes(result_object)); + compiler->inc_methods_compiled(); + } + } + } else { + assert(false, "JVMCICompiler.compileMethod should always return non-null"); + } + } else { + // An uncaught exception was thrown during compilation. Generally these + // should be handled by the Java code in some useful way but if they leak + // through to here report them instead of dying or silently ignoring them. + JVMCIENV->describe_pending_exception(true); + compile_state->set_failure(false, "unexpected exception thrown"); + } + if (compiler->is_bootstrapping()) { + compiler->set_bootstrap_compilation_request_handled(); } } -void JVMCIRuntime::bootstrap_finished(TRAPS) { - HandleMark hm(THREAD); - Handle receiver = get_HotSpotJVMCIRuntime(CHECK); - JavaValue result(T_VOID); - JavaCallArguments args; - args.push_oop(receiver); - JavaCalls::call_special(&result, receiver->klass(), vmSymbols::bootstrapFinished_method_name(), vmSymbols::void_method_signature(), &args, CHECK); + +// ------------------------------------------------------------------ +JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, + const methodHandle& method, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + JVMCIObject compiled_code, + JVMCIObject nmethod_mirror, + FailedSpeculation** failed_speculations, + char* speculations, + int speculations_len) { + JVMCI_EXCEPTION_CONTEXT; + nm = NULL; + int comp_level = CompLevel_full_optimization; + char* failure_detail = NULL; + + bool install_default = JVMCIENV->get_HotSpotNmethod_isDefault(nmethod_mirror) != 0; + assert(JVMCIENV->isa_HotSpotNmethod(nmethod_mirror), "must be"); + JVMCIObject name = JVMCIENV->get_InstalledCode_name(nmethod_mirror); + const char* nmethod_mirror_name = name.is_null() ? NULL : JVMCIENV->as_utf8_string(name); + int nmethod_mirror_index; + if (!install_default) { + // Reserve or initialize mirror slot in the oops table. + OopRecorder* oop_recorder = debug_info->oop_recorder(); + nmethod_mirror_index = oop_recorder->allocate_oop_index(nmethod_mirror.is_hotspot() ? nmethod_mirror.as_jobject() : NULL); + } else { + // A default HotSpotNmethod mirror is never tracked by the nmethod + nmethod_mirror_index = -1; + } + + JVMCI::CodeInstallResult result; + { + // To prevent compile queue updates. + MutexLocker locker(MethodCompileQueue_lock, THREAD); + + // Prevent SystemDictionary::add_to_hierarchy from running + // and invalidating our dependencies until we install this method. + MutexLocker ml(Compile_lock); + + // Encode the dependencies now, so we can check them right away. + dependencies->encode_content_bytes(); + + // Record the dependencies for the current compile in the log + if (LogCompilation) { + for (Dependencies::DepStream deps(dependencies); deps.next(); ) { + deps.log_dependency(); + } + } + + // Check for {class loads, evolution, breakpoints} during compilation + result = validate_compile_task_dependencies(dependencies, JVMCIENV->compile_state(), &failure_detail); + if (result != JVMCI::ok) { + // While not a true deoptimization, it is a preemptive decompile. + MethodData* mdp = method()->method_data(); + if (mdp != NULL) { + mdp->inc_decompile_count(); +#ifdef ASSERT + if (mdp->decompile_count() > (uint)PerMethodRecompilationCutoff) { + ResourceMark m; + tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string()); + } +#endif + } + + // All buffers in the CodeBuffer are allocated in the CodeCache. + // If the code buffer is created on each compile attempt + // as in C2, then it must be freed. + //code_buffer->free_blob(); + } else { + ImplicitExceptionTable implicit_tbl; + nm = nmethod::new_nmethod(method, + compile_id, + entry_bci, + offsets, + orig_pc_offset, + debug_info, dependencies, code_buffer, + frame_words, oop_map_set, + handler_table, &implicit_tbl, + compiler, comp_level, + speculations, speculations_len, + nmethod_mirror_index, nmethod_mirror_name, failed_speculations); + + + // Free codeBlobs + if (nm == NULL) { + // The CodeCache is full. Print out warning and disable compilation. + { + MutexUnlocker ml(Compile_lock); + MutexUnlocker locker(MethodCompileQueue_lock); + CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level)); + } + } else { + nm->set_has_unsafe_access(has_unsafe_access); + nm->set_has_wide_vectors(has_wide_vector); + + // Record successful registration. + // (Put nm into the task handle *before* publishing to the Java heap.) + if (JVMCIENV->compile_state() != NULL) { + JVMCIENV->compile_state()->task()->set_code(nm); + } + + JVMCINMethodData* data = nm->jvmci_nmethod_data(); + assert(data != NULL, "must be"); + if (install_default) { + assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm) == NULL, "must be"); + if (entry_bci == InvocationEntryBci) { + if (TieredCompilation) { + // If there is an old version we're done with it + CompiledMethod* old = method->code(); + if (TraceMethodReplacement && old != NULL) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + tty->print_cr("Replacing method %s", method_name); + } + if (old != NULL ) { + old->make_not_entrant(); + } + } + if (TraceNMethodInstalls) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing method (%d) %s [entry point: %p]", + comp_level, + method_name, nm->entry_point()); + } + // Allow the code to be executed + method->set_code(method, nm); + } else { + if (TraceNMethodInstalls ) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing osr method (%d) %s @ %d", + comp_level, + method_name, + entry_bci); + } + InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); + } + } else { + assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm) == HotSpotJVMCI::resolve(nmethod_mirror), "must be"); + } + nm->make_in_use(); + } + result = nm != NULL ? JVMCI::ok :JVMCI::cache_full; + } + } + + // String creation must be done outside lock + if (failure_detail != NULL) { + // A failure to allocate the string is silently ignored. + JVMCIObject message = JVMCIENV->create_string(failure_detail, JVMCIENV); + JVMCIENV->set_HotSpotCompiledNmethod_installationFailureMessage(compiled_code, message); + } + + // JVMTI -- compiled method notification (must be done outside lock) + if (nm != NULL) { + nm->post_compiled_method_load_event(); + } + + return result; } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmciRuntime.hpp --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp Wed May 01 12:31:29 2019 -0700 @@ -24,23 +24,68 @@ #ifndef SHARE_JVMCI_JVMCIRUNTIME_HPP #define SHARE_JVMCI_JVMCIRUNTIME_HPP -#include "interpreter/interpreter.hpp" -#include "memory/allocation.hpp" -#include "runtime/arguments.hpp" -#include "runtime/deoptimization.hpp" +#include "code/nmethod.hpp" +#include "jvmci/jvmci.hpp" +#include "jvmci/jvmciExceptions.hpp" +#include "jvmci/jvmciObject.hpp" + +class JVMCIEnv; +class JVMCICompiler; +class JVMCICompileState; -#define JVMCI_ERROR(...) \ - { Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::jdk_vm_ci_common_JVMCIError(), __VA_ARGS__); return; } +// Encapsulates the JVMCI metadata for an nmethod. +// JVMCINMethodData objects are inlined into nmethods +// at nmethod::_jvmci_data_offset. +class JVMCINMethodData { + // Index for the HotSpotNmethod mirror in the nmethod's oops table. + // This is -1 if there is no mirror in the oops table. + int _nmethod_mirror_index; + + // Is HotSpotNmethod.name non-null? If so, the value is + // embedded in the end of this object. + bool _has_name; + + // Address of the failed speculations list to which a speculation + // is appended when it causes a deoptimization. + FailedSpeculation** _failed_speculations; -#define JVMCI_ERROR_(ret, ...) \ - { Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::jdk_vm_ci_common_JVMCIError(), __VA_ARGS__); return ret; } +public: + // Computes the size of a JVMCINMethodData object + static int compute_size(const char* nmethod_mirror_name) { + int size = sizeof(JVMCINMethodData); + if (nmethod_mirror_name != NULL) { + size += (int) strlen(nmethod_mirror_name) + 1; + } + return size; + } + + void initialize(int nmethod_mirror_index, + const char* name, + FailedSpeculation** failed_speculations); + + // Adds `speculation` to the failed speculations list. + void add_failed_speculation(nmethod* nm, jlong speculation); -#define JVMCI_ERROR_0(...) JVMCI_ERROR_(0, __VA_ARGS__) -#define JVMCI_ERROR_NULL(...) JVMCI_ERROR_(NULL, __VA_ARGS__) -#define JVMCI_ERROR_OK(...) JVMCI_ERROR_(JVMCIEnv::ok, __VA_ARGS__) -#define CHECK_OK CHECK_(JVMCIEnv::ok) + // Gets the JVMCI name of the nmethod (which may be NULL). + const char* name() { return _has_name ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : NULL; } + + // Clears the HotSpotNmethod.address field in the mirror. If nm + // is dead, the HotSpotNmethod.entryPoint field is also cleared. + void invalidate_nmethod_mirror(nmethod* nm); + + // Gets the mirror from nm's oops table. + oop get_nmethod_mirror(nmethod* nm); -class JVMCIRuntime: public AllStatic { + // Sets the mirror in nm's oops table. + void set_nmethod_mirror(nmethod* nm, oop mirror); + + // Clears the mirror in nm's oops table. + void clear_nmethod_mirror(nmethod* nm); +}; + +// A top level class that represents an initialized JVMCI runtime. +// There is one instance of this class per HotSpotJVMCIRuntime object. +class JVMCIRuntime: public CHeapObj { public: // Constants describing whether JVMCI wants to be able to adjust the compilation // level selected for a method by the VM compilation policy and if so, based on @@ -52,57 +97,187 @@ }; private: - static jobject _HotSpotJVMCIRuntime_instance; - static bool _well_known_classes_initialized; + volatile bool _being_initialized; + volatile bool _initialized; + + JVMCIObject _HotSpotJVMCIRuntime_instance; + + bool _shutdown_called; + + JVMCIObject create_jvmci_primitive_type(BasicType type, JVMCI_TRAPS); - static bool _shutdown_called; + // Implementation methods for loading and constant pool access. + static Klass* get_klass_by_name_impl(Klass*& accessing_klass, + const constantPoolHandle& cpool, + Symbol* klass_name, + bool require_local); + static Klass* get_klass_by_index_impl(const constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + Klass* loading_klass); + static void get_field_by_index_impl(InstanceKlass* loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index_impl(const constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + InstanceKlass* loading_klass); + + // Helper methods + static bool check_klass_accessibility(Klass* accessing_klass, Klass* resolved_klass); + static methodHandle lookup_method(InstanceKlass* accessor, + Klass* holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc, + constantTag tag); public: - static bool is_HotSpotJVMCIRuntime_initialized() { - return _HotSpotJVMCIRuntime_instance != NULL; + JVMCIRuntime() { + _initialized = false; + _being_initialized = false; + _shutdown_called = false; } /** + * Compute offsets and construct any state required before executing JVMCI code. + */ + void initialize(JVMCIEnv* jvmciEnv); + + /** * Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary */ - static Handle get_HotSpotJVMCIRuntime(TRAPS); + JVMCIObject get_HotSpotJVMCIRuntime(JVMCI_TRAPS); - static jobject get_HotSpotJVMCIRuntime_jobject(TRAPS) { - initialize_JVMCI(CHECK_NULL); - assert(_HotSpotJVMCIRuntime_instance != NULL, "must be"); - return _HotSpotJVMCIRuntime_instance; + bool is_HotSpotJVMCIRuntime_initialized() { + return _HotSpotJVMCIRuntime_instance.is_non_null(); } - static Handle callStatic(const char* className, const char* methodName, const char* returnType, JavaCallArguments* args, TRAPS); - - /** - * Determines if the VM is sufficiently booted to initialize JVMCI. - */ - static bool can_initialize_JVMCI(); - /** * Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime() */ - static void initialize_JVMCI(TRAPS); + void initialize_JVMCI(JVMCI_TRAPS); /** * Explicitly initialize HotSpotJVMCIRuntime itself */ - static void initialize_HotSpotJVMCIRuntime(TRAPS); + void initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS); - static void initialize_well_known_classes(TRAPS); - - static void metadata_do(void f(Metadata*)); + void call_getCompiler(TRAPS); - static void shutdown(TRAPS); + void shutdown(); - static void bootstrap_finished(TRAPS); - - static bool shutdown_called() { + bool shutdown_called() { return _shutdown_called; } - static BasicType kindToBasicType(Handle kind, TRAPS); + void bootstrap_finished(TRAPS); + + // Look up a klass by name from a particular class loader (the accessor's). + // If require_local, result must be defined in that class loader, or NULL. + // If !require_local, a result from remote class loader may be reported, + // if sufficient class loader constraints exist such that initiating + // a class loading request from the given loader is bound to return + // the class defined in the remote loader (or throw an error). + // + // Return an unloaded klass if !require_local and no class at all is found. + // + // The CI treats a klass as loaded if it is consistently defined in + // another loader, even if it hasn't yet been loaded in all loaders + // that could potentially see it via delegation. + static Klass* get_klass_by_name(Klass* accessing_klass, + Symbol* klass_name, + bool require_local); + + // Constant pool access. + static Klass* get_klass_by_index(const constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + Klass* loading_klass); + static void get_field_by_index(InstanceKlass* loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index(const constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + InstanceKlass* loading_klass); + + // converts the Klass* representing the holder of a method into a + // InstanceKlass*. This is needed since the holder of a method in + // the bytecodes could be an array type. Basically this converts + // array types into java/lang/Object and other types stay as they are. + static InstanceKlass* get_instance_klass_for_declared_method_holder(Klass* klass); + + // Helper routine for determining the validity of a compilation + // with respect to concurrent class loading. + static JVMCI::CodeInstallResult validate_compile_task_dependencies(Dependencies* target, JVMCICompileState* task, char** failure_detail); + + // Compiles `target` with the JVMCI compiler. + void compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, const methodHandle& target, int entry_bci); + + // Register the result of a compilation. + JVMCI::CodeInstallResult register_method(JVMCIEnv* JVMCIENV, + const methodHandle& target, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + JVMCIObject compiled_code, + JVMCIObject nmethod_mirror, + FailedSpeculation** failed_speculations, + char* speculations, + int speculations_len); + + /** + * Exits the VM due to an unexpected exception. + */ + static void exit_on_pending_exception(JVMCIEnv* JVMCIENV, const char* message); + + static void describe_pending_hotspot_exception(JavaThread* THREAD, bool clear); + +#define CHECK_EXIT THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::exit_on_pending_exception(NULL, buf); \ + return; \ + } \ + (void)(0 + +#define CHECK_EXIT_(v) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::exit_on_pending_exception(NULL, buf); \ + return v; \ + } \ + (void)(0 + +#define JVMCI_CHECK_EXIT JVMCIENV); \ + if (JVMCIENV->has_pending_exception()) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::exit_on_pending_exception(JVMCIENV, buf); \ + return; \ + } \ + (void)(0 + +#define JVMCI_CHECK_EXIT_(result) JVMCIENV); \ + if (JVMCIENV->has_pending_exception()) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::exit_on_pending_exception(JVMCIENV, buf); \ + return result; \ + } \ + (void)(0 + + static BasicType kindToBasicType(const Handle& kind, TRAPS); static void new_instance_common(JavaThread* thread, Klass* klass, bool null_on_fail); static void new_array_common(JavaThread* thread, Klass* klass, jint length, bool null_on_fail); @@ -162,11 +337,8 @@ static void throw_klass_external_name_exception(JavaThread* thread, const char* exception, Klass* klass); static void throw_class_cast_exception(JavaThread* thread, const char* exception, Klass* caster_klass, Klass* target_klass); - // Forces initialization of the JVMCI runtime. - static void force_initialization(TRAPS); - // Test only function - static int test_deoptimize_call_int(JavaThread* thread, int value); + static jint test_deoptimize_call_int(JavaThread* thread, int value); }; // Tracing macros. @@ -177,10 +349,10 @@ #define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else #define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; else -#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print("JVMCITrace-1: "), true))) ; else tty->print_cr -#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(" JVMCITrace-2: "), true))) ; else tty->print_cr -#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(" JVMCITrace-3: "), true))) ; else tty->print_cr -#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(" JVMCITrace-4: "), true))) ; else tty->print_cr -#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(" JVMCITrace-5: "), true))) ; else tty->print_cr +#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print(PTR_FORMAT " JVMCITrace-1: ", p2i(JavaThread::current())), true))) ; else tty->print_cr +#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(PTR_FORMAT " JVMCITrace-2: ", p2i(JavaThread::current())), true))) ; else tty->print_cr +#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(PTR_FORMAT " JVMCITrace-3: ", p2i(JavaThread::current())), true))) ; else tty->print_cr +#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(PTR_FORMAT " JVMCITrace-4: ", p2i(JavaThread::current())), true))) ; else tty->print_cr +#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(PTR_FORMAT " JVMCITrace-5: ", p2i(JavaThread::current())), true))) ; else tty->print_cr #endif // SHARE_JVMCI_JVMCIRUNTIME_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmci_globals.cpp --- a/src/hotspot/share/jvmci/jvmci_globals.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,11 @@ #include "jvmci/jvmci_globals.hpp" #include "gc/shared/gcConfig.hpp" #include "utilities/defaultStream.hpp" +#include "utilities/ostream.hpp" #include "runtime/globals_extension.hpp" +fileStream* JVMCIGlobals::_jni_config_file = NULL; + JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ MATERIALIZE_PRODUCT_FLAG, \ @@ -79,6 +82,10 @@ return false; } FLAG_SET_DEFAULT(EnableJVMCI, true); + if (BootstrapJVMCI && UseJVMCINativeLibrary) { + jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary"); + return false; + } } if (!EnableJVMCI) { @@ -97,7 +104,9 @@ CHECK_NOT_SET(JVMCINMethodSizeLimit, EnableJVMCI) CHECK_NOT_SET(MethodProfileWidth, EnableJVMCI) CHECK_NOT_SET(JVMCIPrintProperties, EnableJVMCI) - CHECK_NOT_SET(TraceUncollectedSpeculations, EnableJVMCI) + CHECK_NOT_SET(UseJVMCINativeLibrary, EnableJVMCI) + CHECK_NOT_SET(JVMCILibPath, EnableJVMCI) + CHECK_NOT_SET(JVMCILibDumpJNIConfig, EnableJVMCI) #ifndef PRODUCT #define JVMCI_CHECK4(type, name, value, doc) assert(name##checked, #name " flag not checked"); @@ -110,10 +119,21 @@ #undef JVMCI_CHECK3 #undef JVMCI_CHECK4 #undef JVMCI_FLAG_CHECKED -#endif +#endif // PRODUCT #undef CHECK_NOT_SET + + if (JVMCILibDumpJNIConfig != NULL) { + _jni_config_file = new(ResourceObj::C_HEAP, mtJVMCI) fileStream(JVMCILibDumpJNIConfig); + if (_jni_config_file == NULL || !_jni_config_file->is_open()) { + jio_fprintf(defaultStream::error_stream(), + "Could not open file for dumping JVMCI shared library JNI config: %s\n", JVMCILibDumpJNIConfig); + return false; + } + } + return true; } + void JVMCIGlobals::check_jvmci_supported_gc() { if (EnableJVMCI) { // Check if selected GC is supported by JVMCI and Java compiler diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/jvmci_globals.hpp --- a/src/hotspot/share/jvmci/jvmci_globals.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp Wed May 01 12:31:29 2019 -0700 @@ -25,7 +25,7 @@ #ifndef SHARE_JVMCI_JVMCI_GLOBALS_HPP #define SHARE_JVMCI_JVMCI_GLOBALS_HPP -#include "runtime/globals.hpp" +#include "utilities/ostream.hpp" // // Defines all global flags used by the JVMCI compiler. Only flags that need @@ -62,11 +62,13 @@ "Print JVMCI bootstrap progress and summary") \ \ experimental(intx, JVMCIThreads, 1, \ - "Force number of JVMCI compiler threads to use") \ + "Force number of JVMCI compiler threads to use. Ignored if " \ + "UseJVMCICompiler is false.") \ range(1, max_jint) \ \ experimental(intx, JVMCIHostThreads, 1, \ - "Force number of compiler threads for JVMCI host compiler") \ + "Force number of C1 compiler threads. Ignored if " \ + "UseJVMCICompiler is false.") \ range(1, max_jint) \ \ NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ @@ -97,8 +99,17 @@ experimental(intx, MethodProfileWidth, 0, \ "Number of methods to record in call profile") \ \ - develop(bool, TraceUncollectedSpeculations, false, \ - "Print message when a failed speculation was not collected") \ + experimental(ccstr, JVMCILibPath, NULL, \ + "LD path for loading the JVMCI shared library") \ + \ + experimental(ccstr, JVMCILibDumpJNIConfig, NULL, \ + "Dumps to the given file a description of the classes, fields " \ + "and methods the JVMCI shared library must provide") \ + \ + experimental(bool, UseJVMCINativeLibrary, false, \ + "Execute JVMCI Java code from a shared library " \ + "instead of loading it from class files and executing it " \ + "on the HotSpot heap") \ \ NOT_COMPILER2(diagnostic(bool, UseMultiplyToLenIntrinsic, false, \ "Enables intrinsification of BigInteger.multiplyToLen()")) \ @@ -130,14 +141,22 @@ IGNORE_CONSTRAINT, \ IGNORE_WRITEABLE) +// The base name for the shared library containing the JVMCI based compiler +#define JVMCI_SHARED_LIBRARY_NAME "jvmcicompiler" + class JVMCIGlobals { + private: + static fileStream* _jni_config_file; public: - // Return true if jvmci flags are consistent. If not consistent, + + // Returns true if jvmci flags are consistent. If not consistent, // an error message describing the inconsistency is printed before // returning false. static bool check_jvmci_flags_are_consistent(); // Check and exit VM with error if selected GC is not supported by JVMCI. static void check_jvmci_supported_gc(); + + static fileStream* get_jni_config_file() { return _jni_config_file; } }; #endif // SHARE_JVMCI_JVMCI_GLOBALS_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/metadataHandleBlock.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/metadataHandleBlock.cpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "jvmci/metadataHandleBlock.hpp" + +MetadataHandleBlock* MetadataHandleBlock::_last = NULL; +intptr_t MetadataHandleBlock::_free_list = 0; +int MetadataHandleBlock::_allocate_before_rebuild = 0; + +jmetadata MetadataHandleBlock::allocate_metadata_handle(Metadata* obj) { + assert(obj->is_valid() && obj->is_metadata(), "must be"); + + if (_last == NULL) { + // This is the first allocation. + _last = this; + } + + HandleRecord* handle = get_handle(); + + if (handle != NULL) { + handle->set_value(obj); +#ifdef METADATA_TRACK_NAMES + handle->set_name(obj->print_value_string()); +#endif + return (jmetadata) handle; + } + + // Check if unused block follow last + if (_last->_next != NULL) { + // update last and retry + _last = _last->_next; + return allocate_metadata_handle(obj); + } + + // No space available, we have to rebuild free list or expand + if (_allocate_before_rebuild == 0) { + rebuild_free_list(); // updates _allocate_before_rebuild counter + } else { + // Append new block + // This can block, but the caller has a metadata handle around this object. + _last->_next = allocate_block(); + _last = _last->_next; + _allocate_before_rebuild--; + } + return allocate_metadata_handle(obj); // retry +} + + +void MetadataHandleBlock::rebuild_free_list() { + assert(_allocate_before_rebuild == 0 && _free_list == 0, "just checking"); + int free = 0; + int blocks = 0; + for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) { + for (int index = 0; index < current->_top; index++) { + HandleRecord* handle = &(current->_handles)[index]; + if (handle->value() == NULL) { + // this handle was cleared out by a delete call, reuse it + chain_free_list(handle); + free++; + } + } + // we should not rebuild free list if there are unused handles at the end + assert(current->_top == block_size_in_handles, "just checking"); + blocks++; + } + // Heuristic: if more than half of the handles are NOT free we rebuild next time + // as well, otherwise we append a corresponding number of new blocks before + // attempting a free list rebuild again. + int total = blocks * block_size_in_handles; + int extra = total - 2*free; + if (extra > 0) { + // Not as many free handles as we would like - compute number of new blocks to append + _allocate_before_rebuild = (extra + block_size_in_handles - 1) / block_size_in_handles; + } +} + +void MetadataHandleBlock::metadata_do(void f(Metadata*)) { + for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) { + for (int index = 0; index < current->_top; index++) { + HandleRecord* root = &(current->_handles)[index]; + Metadata* value = root->value(); + // traverse heap pointers only, not deleted handles or free list + // pointers + if (value != NULL && ((intptr_t) value & ptr_tag) == 0) { + assert(value->is_valid(), "invalid metadata %s", get_name(index)); + f(value); + } + } + // the next handle block is valid only if current block is full + if (current->_top < block_size_in_handles) { + break; + } + } +} + +// Visit any live metadata handles and clean them up. Since clearing of these handles is driven by +// weak references they will be cleared at some point in the future when the reference cleaning logic is run. +void MetadataHandleBlock::do_unloading() { + for (MetadataHandleBlock* current = this; current != NULL; current = current->_next) { + for (int index = 0; index < current->_top; index++) { + HandleRecord* handle = &(current->_handles)[index]; + Metadata* value = handle->value(); + // traverse heap pointers only, not deleted handles or free list + // pointers + if (value != NULL && ((intptr_t) value & ptr_tag) == 0) { + Klass* klass = NULL; + if (value->is_klass()) { + klass = (Klass*)value; + } else if (value->is_method()) { + Method* m = (Method*)value; + klass = m->method_holder(); + } else if (value->is_constantPool()) { + ConstantPool* cp = (ConstantPool*)value; + klass = cp->pool_holder(); + } else { + ShouldNotReachHere(); + } + if (klass->class_loader_data()->is_unloading()) { + // This needs to be marked so that it's no longer scanned + // but can't be put on the free list yet. The + // HandleCleaner will set this to NULL and + // put it on the free list. + jlong old_value = Atomic::cmpxchg((jlong) (ptr_tag), (jlong*)handle, (jlong) value); + if (old_value == (jlong) value) { + // Success + } else { + guarantee(old_value == 0, "only other possible value"); + } + } + } + } + // the next handle block is valid only if current block is full + if (current->_top < block_size_in_handles) { + break; + } + } +} diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/metadataHandleBlock.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/jvmci/metadataHandleBlock.hpp Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_JVMCI_METADATAHANDLEBLOCK_HPP +#define SHARE_JVMCI_METADATAHANDLEBLOCK_HPP + +#include "oops/constantPool.hpp" +#include "oops/metadata.hpp" +#include "oops/method.hpp" +#include "runtime/handles.hpp" +#include "runtime/os.hpp" + +#ifdef ASSERT +#define METADATA_TRACK_NAMES +#endif + +struct _jmetadata { + private: + Metadata* _value; +#ifdef METADATA_TRACK_NAMES + // Debug data for tracking stale metadata + const char* _name; +#endif + + public: + Metadata* value() { return _value; } + +#ifdef METADATA_TRACK_NAMES + void initialize() { + _value = NULL; + _name = NULL; + } +#endif + + void set_value(Metadata* value) { + _value = value; + } + +#ifdef METADATA_TRACK_NAMES + const char* name() { return _name; } + void set_name(const char* name) { + if (_name != NULL) { + os::free((void*) _name); + _name = NULL; + } + if (name != NULL) { + _name = os::strdup(name); + } + } +#endif +}; + +typedef struct _jmetadata HandleRecord; +typedef struct _jmetadata *jmetadata; + +// JVMCI maintains direct references to metadata. To make these references safe in the face of +// class redefinition, they are held in handles so they can be scanned during GC. They are +// managed in a cooperative way between the Java code and HotSpot. A handle is filled in and +// passed back to the Java code which is responsible for setting the handle to NULL when it +// is no longer in use. This is done by jdk.vm.ci.hotspot.HandleCleaner. The +// rebuild_free_list function notices when the handle is clear and reclaims it for re-use. +class MetadataHandleBlock : public CHeapObj { + private: + enum SomeConstants { + block_size_in_handles = 32, // Number of handles per handle block + ptr_tag = 1, + ptr_mask = ~((intptr_t)ptr_tag) + }; + + + // Free handles always have their low bit set so those pointers can + // be distinguished from handles which are in use. The last handle + // on the free list has a NULL pointer with the tag bit set, so it's + // clear that the handle has been reclaimed. The _free_list is + // always a real pointer to a handle. + + HandleRecord _handles[block_size_in_handles]; // The handles + int _top; // Index of next unused handle + MetadataHandleBlock* _next; // Link to next block + + // The following instance variables are only used by the first block in a chain. + // Having two types of blocks complicates the code and the space overhead is negligible. + static MetadataHandleBlock* _last; // Last block in use + static intptr_t _free_list; // Handle free list + static int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list + + MetadataHandleBlock() { + _top = 0; + _next = NULL; +#ifdef METADATA_TRACK_NAMES + for (int i = 0; i < block_size_in_handles; i++) { + _handles[i].initialize(); + } +#endif + } + + const char* get_name(int index) { +#ifdef METADATA_TRACK_NAMES + return _handles[index].name(); +#else + return ""; +#endif + } + + static HandleRecord* get_free_handle() { + assert(_free_list != 0, "should check before calling"); + HandleRecord* handle = (HandleRecord*) (_free_list & ptr_mask); + _free_list = (ptr_mask & (intptr_t) (handle->value())); + assert(_free_list != ptr_tag, "should be null"); + handle->set_value(NULL); + return handle; + } + + static HandleRecord* get_handle() { + assert(_last != NULL, "sanity"); + // Try last block + if (_last->_top < block_size_in_handles) { + return &(_last->_handles)[_last->_top++]; + } else if (_free_list != 0) { + // Try free list + return get_free_handle(); + } + return NULL; + } + + void rebuild_free_list(); + + jmetadata allocate_metadata_handle(Metadata* metadata); + + public: + jmetadata allocate_handle(const methodHandle& handle) { return allocate_metadata_handle(handle()); } + jmetadata allocate_handle(const constantPoolHandle& handle) { return allocate_metadata_handle(handle()); } + + static MetadataHandleBlock* allocate_block() { return new MetadataHandleBlock(); } + + // Adds `handle` to the free list in this block + static void chain_free_list(HandleRecord* handle) { + handle->set_value((Metadata*) (ptr_tag | _free_list)); +#ifdef METADATA_TRACK_NAMES + handle->set_name(NULL); +#endif + _free_list = (intptr_t) handle; + } + + void metadata_do(void f(Metadata*)); + + void do_unloading(); +}; + +#endif // SHARE_JVMCI_METADATAHANDLEBLOCK_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/systemDictionary_jvmci.hpp --- a/src/hotspot/share/jvmci/systemDictionary_jvmci.hpp Wed May 01 12:41:26 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef SHARE_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP -#define SHARE_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP - -#if !INCLUDE_JVMCI -#define JVMCI_WK_KLASSES_DO(do_klass) -#else -#define JVMCI_WK_KLASSES_DO(do_klass) \ - /* JVMCI classes. These are loaded on-demand. */ \ - do_klass(JVMCI_klass, jdk_vm_ci_runtime_JVMCI ) \ - do_klass(HotSpotCompiledCode_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode ) \ - do_klass(HotSpotCompiledCode_Comment_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment ) \ - do_klass(HotSpotCompiledNmethod_klass, jdk_vm_ci_hotspot_HotSpotCompiledNmethod ) \ - do_klass(HotSpotForeignCallTarget_klass, jdk_vm_ci_hotspot_HotSpotForeignCallTarget ) \ - do_klass(HotSpotReferenceMap_klass, jdk_vm_ci_hotspot_HotSpotReferenceMap ) \ - do_klass(HotSpotInstalledCode_klass, jdk_vm_ci_hotspot_HotSpotInstalledCode ) \ - do_klass(HotSpotNmethod_klass, jdk_vm_ci_hotspot_HotSpotNmethod ) \ - do_klass(HotSpotResolvedJavaMethodImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl ) \ - do_klass(HotSpotResolvedObjectTypeImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl ) \ - do_klass(HotSpotCompressedNullConstant_klass, jdk_vm_ci_hotspot_HotSpotCompressedNullConstant ) \ - do_klass(HotSpotObjectConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotObjectConstantImpl ) \ - do_klass(HotSpotMetaspaceConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl ) \ - do_klass(HotSpotSentinelConstant_klass, jdk_vm_ci_hotspot_HotSpotSentinelConstant ) \ - do_klass(HotSpotStackFrameReference_klass, jdk_vm_ci_hotspot_HotSpotStackFrameReference ) \ - do_klass(HotSpotMetaData_klass, jdk_vm_ci_hotspot_HotSpotMetaData ) \ - do_klass(HotSpotConstantPool_klass, jdk_vm_ci_hotspot_HotSpotConstantPool ) \ - do_klass(HotSpotJVMCIMetaAccessContext_klass, jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext ) \ - do_klass(HotSpotJVMCIRuntime_klass, jdk_vm_ci_hotspot_HotSpotJVMCIRuntime ) \ - do_klass(HotSpotSpeculationLog_klass, jdk_vm_ci_hotspot_HotSpotSpeculationLog ) \ - do_klass(HotSpotCompilationRequestResult_klass, jdk_vm_ci_hotspot_HotSpotCompilationRequestResult) \ - do_klass(VMField_klass, jdk_vm_ci_hotspot_VMField ) \ - do_klass(VMFlag_klass, jdk_vm_ci_hotspot_VMFlag ) \ - do_klass(VMIntrinsicMethod_klass, jdk_vm_ci_hotspot_VMIntrinsicMethod ) \ - do_klass(Assumptions_ConcreteMethod_klass, jdk_vm_ci_meta_Assumptions_ConcreteMethod ) \ - do_klass(Assumptions_NoFinalizableSubclass_klass, jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass ) \ - do_klass(Assumptions_ConcreteSubtype_klass, jdk_vm_ci_meta_Assumptions_ConcreteSubtype ) \ - do_klass(Assumptions_LeafType_klass, jdk_vm_ci_meta_Assumptions_LeafType ) \ - do_klass(Assumptions_CallSiteTargetValue_klass, jdk_vm_ci_meta_Assumptions_CallSiteTargetValue ) \ - do_klass(Architecture_klass, jdk_vm_ci_code_Architecture ) \ - do_klass(TargetDescription_klass, jdk_vm_ci_code_TargetDescription ) \ - do_klass(BytecodePosition_klass, jdk_vm_ci_code_BytecodePosition ) \ - do_klass(DebugInfo_klass, jdk_vm_ci_code_DebugInfo ) \ - do_klass(RegisterSaveLayout_klass, jdk_vm_ci_code_RegisterSaveLayout ) \ - do_klass(BytecodeFrame_klass, jdk_vm_ci_code_BytecodeFrame ) \ - do_klass(InstalledCode_klass, jdk_vm_ci_code_InstalledCode ) \ - do_klass(code_Location_klass, jdk_vm_ci_code_Location ) \ - do_klass(code_Register_klass, jdk_vm_ci_code_Register ) \ - do_klass(RegisterValue_klass, jdk_vm_ci_code_RegisterValue ) \ - do_klass(StackSlot_klass, jdk_vm_ci_code_StackSlot ) \ - do_klass(StackLockValue_klass, jdk_vm_ci_code_StackLockValue ) \ - do_klass(VirtualObject_klass, jdk_vm_ci_code_VirtualObject ) \ - do_klass(site_Call_klass, jdk_vm_ci_code_site_Call ) \ - do_klass(site_ConstantReference_klass, jdk_vm_ci_code_site_ConstantReference ) \ - do_klass(site_DataPatch_klass, jdk_vm_ci_code_site_DataPatch ) \ - do_klass(site_DataSectionReference_klass, jdk_vm_ci_code_site_DataSectionReference ) \ - do_klass(site_ExceptionHandler_klass, jdk_vm_ci_code_site_ExceptionHandler ) \ - do_klass(site_Mark_klass, jdk_vm_ci_code_site_Mark ) \ - do_klass(site_Infopoint_klass, jdk_vm_ci_code_site_Infopoint ) \ - do_klass(site_Site_klass, jdk_vm_ci_code_site_Site ) \ - do_klass(site_InfopointReason_klass, jdk_vm_ci_code_site_InfopointReason ) \ - do_klass(InspectedFrameVisitor_klass, jdk_vm_ci_code_stack_InspectedFrameVisitor ) \ - do_klass(JavaConstant_klass, jdk_vm_ci_meta_JavaConstant ) \ - do_klass(PrimitiveConstant_klass, jdk_vm_ci_meta_PrimitiveConstant ) \ - do_klass(RawConstant_klass, jdk_vm_ci_meta_RawConstant ) \ - do_klass(NullConstant_klass, jdk_vm_ci_meta_NullConstant ) \ - do_klass(ExceptionHandler_klass, jdk_vm_ci_meta_ExceptionHandler ) \ - do_klass(JavaKind_klass, jdk_vm_ci_meta_JavaKind ) \ - do_klass(ValueKind_klass, jdk_vm_ci_meta_ValueKind ) \ - do_klass(Value_klass, jdk_vm_ci_meta_Value ) -#endif - -#endif // SHARE_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/vmStructs_jvmci.cpp --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Wed May 01 12:31:29 2019 -0700 @@ -23,27 +23,16 @@ */ #include "precompiled.hpp" -#include "code/codeBlob.hpp" -#include "compiler/abstractCompiler.hpp" #include "compiler/compileBroker.hpp" -#include "gc/shared/cardTable.hpp" #include "gc/shared/collectedHeap.hpp" #include "jvmci/jvmciCodeInstaller.hpp" #include "jvmci/jvmciCompilerToVM.hpp" -#include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciRuntime.hpp" #include "jvmci/vmStructs_compiler_runtime.hpp" #include "jvmci/vmStructs_jvmci.hpp" -#include "oops/oop.hpp" -#include "oops/oopHandle.hpp" #include "oops/objArrayKlass.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/globals.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/thread.hpp" -#include "runtime/vm_version.hpp" #if INCLUDE_G1GC -#include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/g1ThreadLocalData.hpp" @@ -180,7 +169,7 @@ volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ nonstatic_field(JavaThread, _osthread, OSThread*) \ nonstatic_field(JavaThread, _pending_deoptimization, int) \ - nonstatic_field(JavaThread, _pending_failed_speculation, long) \ + nonstatic_field(JavaThread, _pending_failed_speculation, jlong) \ nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \ @@ -189,12 +178,6 @@ static_field(java_lang_Class, _klass_offset, int) \ static_field(java_lang_Class, _array_klass_offset, int) \ \ - nonstatic_field(JVMCIEnv, _task, CompileTask*) \ - nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, jbyte) \ - nonstatic_field(JVMCIEnv, _jvmti_can_access_local_variables, jbyte) \ - nonstatic_field(JVMCIEnv, _jvmti_can_post_on_exceptions, jbyte) \ - nonstatic_field(JVMCIEnv, _jvmti_can_pop_frame, jbyte) \ - \ nonstatic_field(InvocationCounter, _counter, unsigned int) \ \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ @@ -209,6 +192,7 @@ nonstatic_field(Klass, _java_mirror, OopHandle) \ nonstatic_field(Klass, _modifier_flags, jint) \ nonstatic_field(Klass, _access_flags, AccessFlags) \ + nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ \ nonstatic_field(LocalVariableTableElement, start_bci, u2) \ nonstatic_field(LocalVariableTableElement, length, u2) \ @@ -359,6 +343,7 @@ declare_toplevel_type(JVMFlag) \ declare_toplevel_type(JVMFlag*) \ declare_toplevel_type(InvocationCounter) \ + declare_toplevel_type(JVMCICompileState) \ declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(LocalVariableTableElement) \ declare_toplevel_type(narrowKlass) \ @@ -401,6 +386,7 @@ declare_preprocessor_constant("JVM_ACC_ANNOTATION", JVM_ACC_ANNOTATION) \ declare_preprocessor_constant("JVM_ACC_ENUM", JVM_ACC_ENUM) \ declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_ACC_INTERFACE", JVM_ACC_INTERFACE) \ \ declare_constant(JVM_CONSTANT_Utf8) \ declare_constant(JVM_CONSTANT_Unicode) \ @@ -544,11 +530,11 @@ declare_constant(JumpData::taken_off_set) \ declare_constant(JumpData::displacement_off_set) \ \ - declare_constant(JVMCIEnv::ok) \ - declare_constant(JVMCIEnv::dependencies_failed) \ - declare_constant(JVMCIEnv::dependencies_invalid) \ - declare_constant(JVMCIEnv::cache_full) \ - declare_constant(JVMCIEnv::code_too_large) \ + declare_preprocessor_constant("JVMCIEnv::ok", JVMCI::ok) \ + declare_preprocessor_constant("JVMCIEnv::dependencies_failed", JVMCI::dependencies_failed) \ + declare_preprocessor_constant("JVMCIEnv::dependencies_invalid", JVMCI::dependencies_invalid) \ + declare_preprocessor_constant("JVMCIEnv::cache_full", JVMCI::cache_full) \ + declare_preprocessor_constant("JVMCIEnv::code_too_large", JVMCI::code_too_large) \ declare_constant(JVMCIRuntime::none) \ declare_constant(JVMCIRuntime::by_holder) \ declare_constant(JVMCIRuntime::by_full_signature) \ diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/jvmci/vmSymbols_jvmci.hpp --- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp Wed May 01 12:31:29 2019 -0700 @@ -28,78 +28,110 @@ #if !INCLUDE_JVMCI #define JVMCI_VM_SYMBOLS_DO(template, do_alias) #else -#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \ - template(jdk_vm_ci_runtime_JVMCI, "jdk/vm/ci/runtime/JVMCI") \ - template(jdk_vm_ci_hotspot_HotSpotCompiledCode, "jdk/vm/ci/hotspot/HotSpotCompiledCode") \ - template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment") \ - template(jdk_vm_ci_hotspot_HotSpotCompiledNmethod, "jdk/vm/ci/hotspot/HotSpotCompiledNmethod") \ - template(jdk_vm_ci_hotspot_HotSpotForeignCallTarget, "jdk/vm/ci/hotspot/HotSpotForeignCallTarget") \ - template(jdk_vm_ci_hotspot_HotSpotReferenceMap, "jdk/vm/ci/hotspot/HotSpotReferenceMap") \ - template(jdk_vm_ci_hotspot_CompilerToVM, "jdk/vm/ci/hotspot/CompilerToVM") \ - template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ - template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ - template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ - template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ - template(jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, "jdk/vm/ci/hotspot/HotSpotCompressedNullConstant") \ - template(jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/HotSpotObjectConstantImpl") \ - template(jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, "jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl") \ - template(jdk_vm_ci_hotspot_HotSpotSentinelConstant, "jdk/vm/ci/hotspot/HotSpotSentinelConstant") \ - template(jdk_vm_ci_hotspot_HotSpotStackFrameReference, "jdk/vm/ci/hotspot/HotSpotStackFrameReference") \ - template(jdk_vm_ci_hotspot_HotSpotMetaData, "jdk/vm/ci/hotspot/HotSpotMetaData") \ - template(jdk_vm_ci_hotspot_HotSpotConstantPool, "jdk/vm/ci/hotspot/HotSpotConstantPool") \ - template(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext, "jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext") \ - template(jdk_vm_ci_hotspot_HotSpotJVMCIRuntime, "jdk/vm/ci/hotspot/HotSpotJVMCIRuntime") \ - template(jdk_vm_ci_hotspot_HotSpotSpeculationLog, "jdk/vm/ci/hotspot/HotSpotSpeculationLog") \ - template(jdk_vm_ci_hotspot_HotSpotCompilationRequestResult, "jdk/vm/ci/hotspot/HotSpotCompilationRequestResult") \ - template(jdk_vm_ci_hotspot_VMField, "jdk/vm/ci/hotspot/VMField") \ - template(jdk_vm_ci_hotspot_VMFlag, "jdk/vm/ci/hotspot/VMFlag") \ - template(jdk_vm_ci_hotspot_VMIntrinsicMethod, "jdk/vm/ci/hotspot/VMIntrinsicMethod") \ - template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ - template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ - template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ - template(jdk_vm_ci_meta_NullConstant, "jdk/vm/ci/meta/NullConstant") \ - template(jdk_vm_ci_meta_ExceptionHandler, "jdk/vm/ci/meta/ExceptionHandler") \ - template(jdk_vm_ci_meta_JavaKind, "jdk/vm/ci/meta/JavaKind") \ - template(jdk_vm_ci_meta_ValueKind, "jdk/vm/ci/meta/ValueKind") \ - template(jdk_vm_ci_meta_Value, "jdk/vm/ci/meta/Value") \ - template(jdk_vm_ci_meta_Assumptions_ConcreteSubtype, "jdk/vm/ci/meta/Assumptions$ConcreteSubtype") \ - template(jdk_vm_ci_meta_Assumptions_LeafType, "jdk/vm/ci/meta/Assumptions$LeafType") \ - template(jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, "jdk/vm/ci/meta/Assumptions$NoFinalizableSubclass") \ - template(jdk_vm_ci_meta_Assumptions_ConcreteMethod, "jdk/vm/ci/meta/Assumptions$ConcreteMethod") \ - template(jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, "jdk/vm/ci/meta/Assumptions$CallSiteTargetValue") \ - template(jdk_vm_ci_code_Architecture, "jdk/vm/ci/code/Architecture") \ - template(jdk_vm_ci_code_BytecodeFrame, "jdk/vm/ci/code/BytecodeFrame") \ - template(jdk_vm_ci_code_BytecodePosition, "jdk/vm/ci/code/BytecodePosition") \ - template(jdk_vm_ci_code_DebugInfo, "jdk/vm/ci/code/DebugInfo") \ - template(jdk_vm_ci_code_InstalledCode, "jdk/vm/ci/code/InstalledCode") \ - template(jdk_vm_ci_code_Location, "jdk/vm/ci/code/Location") \ - template(jdk_vm_ci_code_Register, "jdk/vm/ci/code/Register") \ - template(jdk_vm_ci_code_RegisterValue, "jdk/vm/ci/code/RegisterValue") \ - template(jdk_vm_ci_code_StackSlot, "jdk/vm/ci/code/StackSlot") \ - template(jdk_vm_ci_code_StackLockValue, "jdk/vm/ci/code/StackLockValue") \ - template(jdk_vm_ci_code_TargetDescription, "jdk/vm/ci/code/TargetDescription") \ - template(jdk_vm_ci_code_VirtualObject, "jdk/vm/ci/code/VirtualObject") \ - template(jdk_vm_ci_code_RegisterSaveLayout, "jdk/vm/ci/code/RegisterSaveLayout") \ - template(jdk_vm_ci_code_InvalidInstalledCodeException, "jdk/vm/ci/code/InvalidInstalledCodeException") \ - template(jdk_vm_ci_code_site_Call, "jdk/vm/ci/code/site/Call") \ - template(jdk_vm_ci_code_site_ConstantReference, "jdk/vm/ci/code/site/ConstantReference") \ - template(jdk_vm_ci_code_site_DataPatch, "jdk/vm/ci/code/site/DataPatch") \ - template(jdk_vm_ci_code_site_DataSectionReference, "jdk/vm/ci/code/site/DataSectionReference") \ - template(jdk_vm_ci_code_site_ExceptionHandler, "jdk/vm/ci/code/site/ExceptionHandler") \ - template(jdk_vm_ci_code_site_Mark, "jdk/vm/ci/code/site/Mark") \ - template(jdk_vm_ci_code_site_Infopoint, "jdk/vm/ci/code/site/Infopoint") \ - template(jdk_vm_ci_code_stack_InspectedFrameVisitor, "jdk/vm/ci/code/stack/InspectedFrameVisitor") \ - template(jdk_vm_ci_code_site_Site, "jdk/vm/ci/code/site/Site") \ - template(jdk_vm_ci_code_site_InfopointReason, "jdk/vm/ci/code/site/InfopointReason") \ - template(jdk_vm_ci_common_JVMCIError, "jdk/vm/ci/common/JVMCIError") \ - template(visitFrame_name, "visitFrame") \ - template(visitFrame_signature, "(Ljdk/vm/ci/code/stack/InspectedFrame;)Ljava/lang/Object;") \ - template(compileMethod_name, "compileMethod") \ +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \ + template(jdk_vm_ci_services_Services, "jdk/vm/ci/services/Services") \ + template(jdk_vm_ci_runtime_JVMCI, "jdk/vm/ci/runtime/JVMCI") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode, "jdk/vm/ci/hotspot/HotSpotCompiledCode") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledNmethod, "jdk/vm/ci/hotspot/HotSpotCompiledNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotForeignCallTarget, "jdk/vm/ci/hotspot/HotSpotForeignCallTarget") \ + template(jdk_vm_ci_hotspot_HotSpotReferenceMap, "jdk/vm/ci/hotspot/HotSpotReferenceMap") \ + template(jdk_vm_ci_hotspot_CompilerToVM, "jdk/vm/ci/hotspot/CompilerToVM") \ + template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ + template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType, "jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaFieldImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl") \ + template(jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, "jdk/vm/ci/hotspot/HotSpotCompressedNullConstant") \ + template(jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/HotSpotObjectConstantImpl") \ + template(jdk_vm_ci_hotspot_DirectHotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl") \ + template(jdk_vm_ci_hotspot_IndirectHotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, "jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotSentinelConstant, "jdk/vm/ci/hotspot/HotSpotSentinelConstant") \ + template(jdk_vm_ci_hotspot_HotSpotStackFrameReference, "jdk/vm/ci/hotspot/HotSpotStackFrameReference") \ + template(jdk_vm_ci_hotspot_HotSpotMetaData, "jdk/vm/ci/hotspot/HotSpotMetaData") \ + template(jdk_vm_ci_hotspot_HotSpotConstantPool, "jdk/vm/ci/hotspot/HotSpotConstantPool") \ + template(jdk_vm_ci_hotspot_HotSpotJVMCIRuntime, "jdk/vm/ci/hotspot/HotSpotJVMCIRuntime") \ + template(jdk_vm_ci_hotspot_HotSpotSpeculationLog, "jdk/vm/ci/hotspot/HotSpotSpeculationLog") \ + template(jdk_vm_ci_hotspot_HotSpotCompilationRequestResult, "jdk/vm/ci/hotspot/HotSpotCompilationRequestResult") \ + template(jdk_vm_ci_hotspot_VMField, "jdk/vm/ci/hotspot/VMField") \ + template(jdk_vm_ci_hotspot_VMFlag, "jdk/vm/ci/hotspot/VMFlag") \ + template(jdk_vm_ci_hotspot_VMIntrinsicMethod, "jdk/vm/ci/hotspot/VMIntrinsicMethod") \ + template(jdk_vm_ci_meta_ResolvedJavaMethod, "jdk/vm/ci/meta/ResolvedJavaMethod") \ + template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ + template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ + template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ + template(jdk_vm_ci_meta_NullConstant, "jdk/vm/ci/meta/NullConstant") \ + template(jdk_vm_ci_meta_ExceptionHandler, "jdk/vm/ci/meta/ExceptionHandler") \ + template(jdk_vm_ci_meta_JavaKind, "jdk/vm/ci/meta/JavaKind") \ + template(jdk_vm_ci_meta_ValueKind, "jdk/vm/ci/meta/ValueKind") \ + template(jdk_vm_ci_meta_Value, "jdk/vm/ci/meta/Value") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteSubtype, "jdk/vm/ci/meta/Assumptions$ConcreteSubtype") \ + template(jdk_vm_ci_meta_Assumptions_LeafType, "jdk/vm/ci/meta/Assumptions$LeafType") \ + template(jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, "jdk/vm/ci/meta/Assumptions$NoFinalizableSubclass") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteMethod, "jdk/vm/ci/meta/Assumptions$ConcreteMethod") \ + template(jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, "jdk/vm/ci/meta/Assumptions$CallSiteTargetValue") \ + template(jdk_vm_ci_code_Architecture, "jdk/vm/ci/code/Architecture") \ + template(jdk_vm_ci_code_BytecodeFrame, "jdk/vm/ci/code/BytecodeFrame") \ + template(jdk_vm_ci_code_BytecodePosition, "jdk/vm/ci/code/BytecodePosition") \ + template(jdk_vm_ci_code_DebugInfo, "jdk/vm/ci/code/DebugInfo") \ + template(jdk_vm_ci_code_InstalledCode, "jdk/vm/ci/code/InstalledCode") \ + template(jdk_vm_ci_code_Location, "jdk/vm/ci/code/Location") \ + template(jdk_vm_ci_code_Register, "jdk/vm/ci/code/Register") \ + template(jdk_vm_ci_code_RegisterValue, "jdk/vm/ci/code/RegisterValue") \ + template(jdk_vm_ci_code_StackSlot, "jdk/vm/ci/code/StackSlot") \ + template(jdk_vm_ci_code_StackLockValue, "jdk/vm/ci/code/StackLockValue") \ + template(jdk_vm_ci_code_TargetDescription, "jdk/vm/ci/code/TargetDescription") \ + template(jdk_vm_ci_code_VirtualObject, "jdk/vm/ci/code/VirtualObject") \ + template(jdk_vm_ci_code_RegisterSaveLayout, "jdk/vm/ci/code/RegisterSaveLayout") \ + template(jdk_vm_ci_code_InvalidInstalledCodeException, "jdk/vm/ci/code/InvalidInstalledCodeException") \ + template(jdk_vm_ci_code_site_Call, "jdk/vm/ci/code/site/Call") \ + template(jdk_vm_ci_code_site_ConstantReference, "jdk/vm/ci/code/site/ConstantReference") \ + template(jdk_vm_ci_code_site_DataPatch, "jdk/vm/ci/code/site/DataPatch") \ + template(jdk_vm_ci_code_site_DataSectionReference, "jdk/vm/ci/code/site/DataSectionReference") \ + template(jdk_vm_ci_code_site_ExceptionHandler, "jdk/vm/ci/code/site/ExceptionHandler") \ + template(jdk_vm_ci_code_site_Mark, "jdk/vm/ci/code/site/Mark") \ + template(jdk_vm_ci_code_site_Infopoint, "jdk/vm/ci/code/site/Infopoint") \ + template(jdk_vm_ci_code_stack_InspectedFrameVisitor, "jdk/vm/ci/code/stack/InspectedFrameVisitor") \ + template(jdk_vm_ci_code_site_Site, "jdk/vm/ci/code/site/Site") \ + template(jdk_vm_ci_code_site_InfopointReason, "jdk/vm/ci/code/site/InfopointReason") \ + template(jdk_vm_ci_common_JVMCIError, "jdk/vm/ci/common/JVMCIError") \ + \ + template(visitFrame_name, "visitFrame") \ + template(visitFrame_signature, "(Ljdk/vm/ci/code/stack/InspectedFrame;)Ljava/lang/Object;") \ + template(compileMethod_name, "compileMethod") \ template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)Ljdk/vm/ci/hotspot/HotSpotCompilationRequestResult;") \ - template(fromMetaspace_name, "fromMetaspace") \ - template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ - template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \ - template(klass_fromMetaspace_signature, "(Ljava/lang/Class;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") + template(encodeThrowable_name, "encodeThrowable") \ + template(encodeThrowable_signature, "(Ljava/lang/Throwable;)Ljava/lang/String;") \ + template(decodeThrowable_name, "decodeThrowable") \ + template(decodeThrowable_signature, "(Ljava/lang/String;)Ljava/lang/Throwable;") \ + template(fromMetaspace_name, "fromMetaspace") \ + template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \ + template(klass_fromMetaspace_signature, "(JLjava/lang/String;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \ + template(primitive_fromMetaspace_signature, "(Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;C)Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;") \ + template(getRuntime_name, "getRuntime") \ + template(getRuntime_signature, "()Ljdk/vm/ci/runtime/JVMCIRuntime;") \ + template(initializeRuntime_name, "initializeRuntime") \ + do_alias(initializeRuntime_signature, getRuntime_signature) \ + template(runtime_name, "runtime") \ + template(runtime_signature, "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;") \ + template(getCompiler_name, "getCompiler") \ + template(getCompiler_signature, "()Ljdk/vm/ci/runtime/JVMCICompiler;") \ + template(callToString_name, "callToString") \ + template(callToString_signature, "(Ljava/lang/Object;)Ljava/lang/String;") \ + template(getName_name, "getName") \ + template(bootstrapFinished_name, "bootstrapFinished") \ + template(forTypeChar_name, "forTypeChar") \ + template(forTypeChar_signature, "(CJ)Ljdk/vm/ci/meta/PrimitiveConstant;") \ + template(forFloat_name, "forFloat") \ + template(forFloat_signature, "(F)Ljdk/vm/ci/meta/PrimitiveConstant;") \ + template(forDouble_name, "forDouble") \ + template(forDouble_signature, "(D)Ljdk/vm/ci/meta/PrimitiveConstant;") \ + template(method_string_bool_long_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \ + template(initializeSavedProperties_name, "initializeSavedProperties") \ + #endif #endif // SHARE_JVMCI_VMSYMBOLS_JVMCI_HPP diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/memory/allocation.hpp --- a/src/hotspot/share/memory/allocation.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/memory/allocation.hpp Wed May 01 12:31:29 2019 -0700 @@ -118,6 +118,7 @@ f(mtCode, "Code") /* generated code */ \ f(mtGC, "GC") \ f(mtCompiler, "Compiler") \ + f(mtJVMCI, "JVMCI") \ f(mtInternal, "Internal") /* memory used by VM, but does not belong to */ \ /* any of above categories, and not used by */ \ /* NMT */ \ diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/oops/method.cpp --- a/src/hotspot/share/oops/method.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/oops/method.cpp Wed May 01 12:31:29 2019 -0700 @@ -116,6 +116,11 @@ void Method::deallocate_contents(ClassLoaderData* loader_data) { MetadataFactory::free_metadata(loader_data, constMethod()); set_constMethod(NULL); +#if INCLUDE_JVMCI + if (method_data()) { + FailedSpeculation::free_failed_speculations(method_data()->get_failed_speculations_address()); + } +#endif MetadataFactory::free_metadata(loader_data, method_data()); set_method_data(NULL); MetadataFactory::free_metadata(loader_data, method_counters()); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/oops/methodData.cpp --- a/src/hotspot/share/oops/methodData.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/oops/methodData.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -846,6 +846,86 @@ return false; } +#if INCLUDE_JVMCI + +void* FailedSpeculation::operator new(size_t size, size_t fs_size) throw() { + return CHeapObj::operator new(fs_size, std::nothrow); +} + +FailedSpeculation::FailedSpeculation(address speculation, int speculation_len) : _data_len(speculation_len), _next(NULL) { + memcpy(data(), speculation, speculation_len); +} + +// A heuristic check to detect nmethods that outlive a failed speculations list. +static void guarantee_failed_speculations_alive(nmethod* nm, FailedSpeculation** failed_speculations_address) { + jlong head = (jlong)(address) *failed_speculations_address; + if ((head & 0x1) == 0x1) { + stringStream st; + if (nm != NULL) { + st.print("%d", nm->compile_id()); + Method* method = nm->method(); + st.print_raw("{"); + if (method != NULL) { + method->print_name(&st); + } else { + const char* jvmci_name = nm->jvmci_name(); + if (jvmci_name != NULL) { + st.print_raw(jvmci_name); + } + } + st.print_raw("}"); + } else { + st.print(""); + } + fatal("Adding to failed speculations list that appears to have been freed. Source: %s", st.as_string()); + } +} + +bool FailedSpeculation::add_failed_speculation(nmethod* nm, FailedSpeculation** failed_speculations_address, address speculation, int speculation_len) { + assert(failed_speculations_address != NULL, "must be"); + size_t fs_size = sizeof(FailedSpeculation) + speculation_len; + FailedSpeculation* fs = new (fs_size) FailedSpeculation(speculation, speculation_len); + if (fs == NULL) { + // no memory -> ignore failed speculation + return false; + } + + guarantee(is_aligned(fs, sizeof(FailedSpeculation*)), "FailedSpeculation objects must be pointer aligned"); + guarantee_failed_speculations_alive(nm, failed_speculations_address); + + FailedSpeculation** cursor = failed_speculations_address; + do { + if (*cursor == NULL) { + FailedSpeculation* old_fs = Atomic::cmpxchg(fs, cursor, (FailedSpeculation*) NULL); + if (old_fs == NULL) { + // Successfully appended fs to end of the list + return true; + } + cursor = old_fs->next_adr(); + } else { + cursor = (*cursor)->next_adr(); + } + } while (true); +} + +void FailedSpeculation::free_failed_speculations(FailedSpeculation** failed_speculations_address) { + assert(failed_speculations_address != NULL, "must be"); + FailedSpeculation* fs = *failed_speculations_address; + while (fs != NULL) { + FailedSpeculation* next = fs->next(); + delete fs; + fs = next; + } + + // Write an unaligned value to failed_speculations_address to denote + // that it is no longer a valid pointer. This is allows for the check + // in add_failed_speculation against adding to a freed failed + // speculations list. + long* head = (long*) failed_speculations_address; + (*head) = (*head) | 0x1; +} +#endif // INCLUDE_JVMCI + int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) { #if INCLUDE_JVMCI if (ProfileTraps) { @@ -1227,6 +1307,7 @@ #if INCLUDE_JVMCI _jvmci_ir_size = 0; + _failed_speculations = NULL; #endif #if INCLUDE_RTM_OPT diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/oops/methodData.hpp --- a/src/hotspot/share/oops/methodData.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/oops/methodData.hpp Wed May 01 12:31:29 2019 -0700 @@ -1949,6 +1949,42 @@ }; +#if INCLUDE_JVMCI +// Encapsulates an encoded speculation reason. These are linked together in +// a list that is atomically appended to during deoptimization. Entries are +// never removed from the list. +// @see jdk.vm.ci.hotspot.HotSpotSpeculationLog.HotSpotSpeculationEncoding +class FailedSpeculation: public CHeapObj { + private: + // The length of HotSpotSpeculationEncoding.toByteArray(). The data itself + // is an array embedded at the end of this object. + int _data_len; + + // Next entry in a linked list. + FailedSpeculation* _next; + + FailedSpeculation(address data, int data_len); + + FailedSpeculation** next_adr() { return &_next; } + + // Placement new operator for inlining the speculation data into + // the FailedSpeculation object. + void* operator new(size_t size, size_t fs_size) throw(); + + public: + char* data() { return (char*)(((address) this) + sizeof(FailedSpeculation)); } + int data_len() const { return _data_len; } + FailedSpeculation* next() const { return _next; } + + // Atomically appends a speculation from nm to the list whose head is at (*failed_speculations_address). + // Returns false if the FailedSpeculation object could not be allocated. + static bool add_failed_speculation(nmethod* nm, FailedSpeculation** failed_speculations_address, address speculation, int speculation_len); + + // Frees all entries in the linked list whose head is at (*failed_speculations_address). + static void free_failed_speculations(FailedSpeculation** failed_speculations_address); +}; +#endif + class MethodData : public Metadata { friend class VMStructs; friend class JVMCIVMStructs; @@ -2030,7 +2066,8 @@ #if INCLUDE_JVMCI // Support for HotSpotMethodData.setCompiledIRSize(int) - int _jvmci_ir_size; + int _jvmci_ir_size; + FailedSpeculation* _failed_speculations; #endif // Size of _data array in bytes. (Excludes header and extra_data fields.) @@ -2191,6 +2228,12 @@ InvocationCounter* invocation_counter() { return &_invocation_counter; } InvocationCounter* backedge_counter() { return &_backedge_counter; } +#if INCLUDE_JVMCI + FailedSpeculation** get_failed_speculations_address() { + return &_failed_speculations; + } +#endif + #if INCLUDE_RTM_OPT int rtm_state() const { return _rtm_state; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/opto/chaitin.cpp --- a/src/hotspot/share/opto/chaitin.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/opto/chaitin.cpp Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2084,9 +2084,7 @@ // Dump a register name into a buffer. Be intelligent if we get called // before allocation is complete. char *PhaseChaitin::dump_register( const Node *n, char *buf ) const { - if( this == NULL ) { // Not got anything? - sprintf(buf,"N%d",n->_idx); // Then use Node index - } else if( _node_regs ) { + if( _node_regs ) { // Post allocation, use direct mappings, no LRG info available print_reg( get_reg_first(n), this, buf ); } else { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/prims/jni.cpp --- a/src/hotspot/share/prims/jni.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/prims/jni.cpp Wed May 01 12:31:29 2019 -0700 @@ -88,10 +88,6 @@ #include "utilities/histogram.hpp" #include "utilities/macros.hpp" #include "utilities/vmError.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmciCompiler.hpp" -#include "jvmci/jvmciRuntime.hpp" -#endif static jint CurrentVersion = JNI_VERSION_10; @@ -1318,14 +1314,15 @@ THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str); } + Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); + // Throw a NoSuchMethodError exception if we have an instance of a // primitive java.lang.Class if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(clazz))) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str); + ResourceMark rm; + THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); } - Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); - // Make sure class is linked and initialized before handing id's out to // Method*s. klass->initialize(CHECK_NULL); @@ -1346,7 +1343,8 @@ } } if (m == NULL || (m->is_static() != is_static)) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str); + ResourceMark rm; + THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); } return m->jmethod_id(); } @@ -2014,22 +2012,26 @@ jfieldID ret = 0; DT_RETURN_MARK(GetFieldID, jfieldID, (const jfieldID&)ret); + Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); + // The class should have been loaded (we have an instance of the class // passed in) so the field and signature should already be in the symbol // table. If they're not there, the field doesn't exist. TempNewSymbol fieldname = SymbolTable::probe(name, (int)strlen(name)); TempNewSymbol signame = SymbolTable::probe(sig, (int)strlen(sig)); if (fieldname == NULL || signame == NULL) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); + ResourceMark rm; + THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); } - Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); + // Make sure class is initialized before handing id's out to fields k->initialize(CHECK_NULL); fieldDescriptor fd; if (!k->is_instance_klass() || !InstanceKlass::cast(k)->find_field(fieldname, signame, false, &fd)) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); + ResourceMark rm; + THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); } // A jfieldID for a non-static field is simply the offset of the field within the instanceOop diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/prims/jvmtiTagMap.cpp --- a/src/hotspot/share/prims/jvmtiTagMap.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp Wed May 01 12:31:29 2019 -0700 @@ -62,6 +62,9 @@ #if INCLUDE_ZGC #include "gc/z/zGlobals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif // JvmtiTagHashmapEntry // @@ -3034,6 +3037,17 @@ // exceptions) will be visible. blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); Universe::oops_do(&blk); + if (blk.stopped()) { + return false; + } + +#if INCLUDE_JVMCI + blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); + JVMCI::oops_do(&blk); + if (blk.stopped()) { + return false; + } +#endif return true; } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/prims/nativeLookup.hpp --- a/src/hotspot/share/prims/nativeLookup.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/prims/nativeLookup.hpp Wed May 01 12:31:29 2019 -0700 @@ -33,11 +33,6 @@ class NativeLookup : AllStatic { private: - // JNI name computation - static char* pure_jni_name(const methodHandle& method); - static char* long_jni_name(const methodHandle& method); - static char* critical_jni_name(const methodHandle& method); - // Style specific lookup static address lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, bool os_style, bool& in_base_library, TRAPS); static address lookup_critical_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, bool os_style); @@ -45,6 +40,11 @@ static address lookup_entry(const methodHandle& method, bool& in_base_library, TRAPS); static address lookup_entry_prefixed(const methodHandle& method, bool& in_base_library, TRAPS); public: + // JNI name computation + static char* pure_jni_name(const methodHandle& method); + static char* long_jni_name(const methodHandle& method); + static char* critical_jni_name(const methodHandle& method); + // Lookup native function. May throw UnsatisfiedLinkError. static address lookup(const methodHandle& method, bool& in_base_library, TRAPS); static address lookup_critical_entry(const methodHandle& method); diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/arguments.cpp --- a/src/hotspot/share/runtime/arguments.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/arguments.cpp Wed May 01 12:31:29 2019 -0700 @@ -57,9 +57,6 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #include "utilities/stringUtils.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmciRuntime.hpp" -#endif #if INCLUDE_JFR #include "jfr/jfr.hpp" #endif diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/deoptimization.cpp --- a/src/hotspot/share/runtime/deoptimization.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/deoptimization.cpp Wed May 01 12:31:29 2019 -0700 @@ -63,11 +63,6 @@ #include "utilities/preserveException.hpp" #include "utilities/xmlstream.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmciRuntime.hpp" -#include "jvmci/jvmciJavaClasses.hpp" -#endif - bool DeoptimizationMarker::_is_active = false; @@ -1520,33 +1515,11 @@ methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); #if INCLUDE_JVMCI - long speculation = thread->pending_failed_speculation(); - if (nm->is_compiled_by_jvmci()) { - if (speculation != 0) { - oop speculation_log = nm->as_nmethod()->speculation_log(); - if (speculation_log != NULL) { - if (TraceDeoptimization || TraceUncollectedSpeculations) { - if (HotSpotSpeculationLog::lastFailed(speculation_log) != 0) { - tty->print_cr("A speculation that was not collected by the compiler is being overwritten"); - } - } - if (TraceDeoptimization) { - tty->print_cr("Saving speculation to speculation log"); - } - HotSpotSpeculationLog::set_lastFailed(speculation_log, speculation); - } else { - if (TraceDeoptimization) { - tty->print_cr("Speculation present but no speculation log"); - } - } - thread->set_pending_failed_speculation(0); - } else { - if (TraceDeoptimization) { - tty->print_cr("No speculation"); - } - } + jlong speculation = thread->pending_failed_speculation(); + if (nm->is_compiled_by_jvmci() && nm->is_nmethod()) { // Exclude AOTed methods + nm->as_nmethod()->update_speculation(thread); } else { - assert(speculation == 0, "There should not be a speculation for method compiled by non-JVMCI compilers"); + assert(speculation == 0, "There should not be a speculation for methods compiled by non-JVMCI compilers"); } if (trap_bci == SynchronizationEntryBCI) { @@ -1595,6 +1568,11 @@ xtty->begin_head("uncommon_trap thread='" UINTX_FORMAT "' %s", os::current_thread_id(), format_trap_request(buf, sizeof(buf), trap_request)); +#if INCLUDE_JVMCI + if (speculation != 0) { + xtty->print(" speculation='" JLONG_FORMAT "'", speculation); + } +#endif nm->log_identity(xtty); } Symbol* class_name = NULL; @@ -1640,7 +1618,7 @@ tty->print(" compiler=%s compile_id=%d", nm->compiler_name(), nm->compile_id()); #if INCLUDE_JVMCI if (nm->is_nmethod()) { - char* installed_code_name = nm->as_nmethod()->jvmci_installed_code_name(buf, sizeof(buf)); + const char* installed_code_name = nm->as_nmethod()->jvmci_name(); if (installed_code_name != NULL) { tty->print(" (JVMCI: installed code name=%s) ", installed_code_name); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/frame.cpp --- a/src/hotspot/share/runtime/frame.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/frame.cpp Wed May 01 12:31:29 2019 -0700 @@ -629,7 +629,7 @@ #if INCLUDE_JVMCI if (cm->is_nmethod()) { nmethod* nm = cm->as_nmethod(); - char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); + const char* jvmciName = nm->jvmci_name(); if (jvmciName != NULL) { st->print(" (%s)", jvmciName); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/init.cpp --- a/src/hotspot/share/runtime/init.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/init.cpp Wed May 01 12:31:29 2019 -0700 @@ -27,6 +27,9 @@ #include "classfile/symbolTable.hpp" #include "code/icBuffer.hpp" #include "gc/shared/collectedHeap.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmci.hpp" +#endif #include "interpreter/bytecodes.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" @@ -140,6 +143,11 @@ if (!compileBroker_init()) { return JNI_EINVAL; } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + JVMCI::initialize_globals(); + } +#endif if (!universe_post_init()) { return JNI_ERR; diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/java.cpp --- a/src/hotspot/share/runtime/java.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/java.cpp Wed May 01 12:31:29 2019 -0700 @@ -36,8 +36,7 @@ #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrThreadId.hpp" #if INCLUDE_JVMCI -#include "jvmci/jvmciCompiler.hpp" -#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmci.hpp" #endif #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -439,15 +438,7 @@ } #if INCLUDE_JVMCI - // We are not using CATCH here because we want the exit to continue normally. - Thread* THREAD = thread; - JVMCIRuntime::shutdown(THREAD); - if (HAS_PENDING_EXCEPTION) { - HandleMark hm(THREAD); - Handle exception(THREAD, PENDING_EXCEPTION); - CLEAR_PENDING_EXCEPTION; - java_lang_Throwable::java_printStackTrace(exception, THREAD); - } + JVMCI::shutdown(); #endif // Hang forever on exit if we're reporting an error. diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/javaCalls.cpp --- a/src/hotspot/share/runtime/javaCalls.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/javaCalls.cpp Wed May 01 12:31:29 2019 -0700 @@ -44,10 +44,6 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" -#if INCLUDE_JVMCI -#include "jvmci/jvmciJavaClasses.hpp" -#include "jvmci/jvmciRuntime.hpp" -#endif // ----------------------------------------------------- // Implementation of JavaCallWrapper diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/mutexLocker.cpp --- a/src/hotspot/share/runtime/mutexLocker.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/mutexLocker.cpp Wed May 01 12:31:29 2019 -0700 @@ -157,6 +157,13 @@ Mutex* CDSClassFileStream_lock = NULL; #endif +#if INCLUDE_JVMCI +Monitor* JVMCI_lock = NULL; +Mutex* JVMCIGlobalAlloc_lock = NULL; +Mutex* JVMCIGlobalActive_lock = NULL; +#endif + + #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; static int _num_mutex; @@ -348,6 +355,12 @@ #if INCLUDE_CDS && INCLUDE_JVMTI def(CDSClassFileStream_lock , PaddedMutex , max_nonleaf, false, Monitor::_safepoint_check_always); #endif + +#if INCLUDE_JVMCI + def(JVMCI_lock , PaddedMonitor, nonleaf+2, true, Monitor::_safepoint_check_always); + def(JVMCIGlobalAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never); + def(JVMCIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never); +#endif } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/mutexLocker.hpp --- a/src/hotspot/share/runtime/mutexLocker.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/mutexLocker.hpp Wed May 01 12:31:29 2019 -0700 @@ -155,6 +155,12 @@ extern Monitor* CodeHeapStateAnalytics_lock; // lock print functions against concurrent analyze functions. // Only used locally in PrintCodeCacheLayout processing. +#if INCLUDE_JVMCI +extern Monitor* JVMCI_lock; // Monitor to control initialization of JVMCI +extern Mutex* JVMCIGlobalAlloc_lock; // JVMCI global storage allocate list lock +extern Mutex* JVMCIGlobalActive_lock; // JVMCI global storage active list lock +#endif + // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not // an object lock, and the two do not interoperate. Do not use Mutex-based diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/thread.cpp Wed May 01 12:31:29 2019 -0700 @@ -117,9 +117,8 @@ #include "utilities/singleWriterSynchronizer.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JVMCI -#include "jvmci/jvmciCompiler.hpp" -#include "jvmci/jvmciRuntime.hpp" -#include "logging/logHandle.hpp" +#include "jvmci/jvmci.hpp" +#include "jvmci/jvmciEnv.hpp" #endif #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" @@ -1576,16 +1575,17 @@ return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); } -void JavaThread::collect_counters(typeArrayOop array) { +void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) { if (JVMCICounterSize > 0) { JavaThreadIteratorWithHandle jtiwh; - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, _jvmci_old_thread_counters[i]); + int len = jvmci_env->get_length(array); + for (int i = 0; i < len; i++) { + jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]); } for (; JavaThread *tp = jtiwh.next(); ) { if (jvmci_counters_include(tp)) { - for (int i = 0; i < array->length(); i++) { - array->long_at_put(i, array->long_at(i) + tp->_jvmci_counters[i]); + for (int i = 0; i < len; i++) { + jvmci_env->put_long_at(array, i, jvmci_env->get_long_at(array, i) + tp->_jvmci_counters[i]); } } } @@ -3922,10 +3922,8 @@ bool force_JVMCI_intialization = false; if (EnableJVMCI) { // Initialize JVMCI eagerly when it is explicitly requested. - // Or when JVMCIPrintProperties is enabled. - // The JVMCI Java initialization code will read this flag and - // do the printing if it's set. - force_JVMCI_intialization = EagerJVMCI || JVMCIPrintProperties; + // Or when JVMCILibDumpJNIConfig or JVMCIPrintProperties is enabled. + force_JVMCI_intialization = EagerJVMCI || JVMCIPrintProperties || JVMCILibDumpJNIConfig; if (!force_JVMCI_intialization) { // 8145270: Force initialization of JVMCI runtime otherwise requests for blocking @@ -3974,7 +3972,7 @@ #if INCLUDE_JVMCI if (force_JVMCI_intialization) { - JVMCIRuntime::force_initialization(CHECK_JNI_ERR); + JVMCI::initialize_compiler(CHECK_JNI_ERR); CompileBroker::compilation_init_phase2(); } #endif @@ -4274,7 +4272,7 @@ JavaValue result(T_VOID); JavaCalls::call_static(&result, shutdown_klass, - vmSymbols::shutdown_method_name(), + vmSymbols::shutdown_name(), vmSymbols::void_method_signature(), THREAD); } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/thread.hpp --- a/src/hotspot/share/runtime/thread.hpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/thread.hpp Wed May 01 12:31:29 2019 -0700 @@ -88,6 +88,9 @@ class ICRefillVerifier; class IdealGraphPrinter; +class JVMCIEnv; +class JVMCIPrimitiveArray; + class Metadata; class ResourceArea; @@ -1132,7 +1135,7 @@ // An id of a speculation that JVMCI compiled code can use to further describe and // uniquely identify the speculative optimization guarded by the uncommon trap - long _pending_failed_speculation; + jlong _pending_failed_speculation; // These fields are mutually exclusive in terms of live ranges. union { @@ -1149,7 +1152,7 @@ public: static jlong* _jvmci_old_thread_counters; - static void collect_counters(typeArrayOop array); + static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array); private: #endif // INCLUDE_JVMCI @@ -1532,11 +1535,11 @@ #if INCLUDE_JVMCI int pending_deoptimization() const { return _pending_deoptimization; } - long pending_failed_speculation() const { return _pending_failed_speculation; } + jlong pending_failed_speculation() const { return _pending_failed_speculation; } bool has_pending_monitorenter() const { return _pending_monitorenter; } void set_pending_monitorenter(bool b) { _pending_monitorenter = b; } void set_pending_deoptimization(int reason) { _pending_deoptimization = reason; } - void set_pending_failed_speculation(long failed_speculation) { _pending_failed_speculation = failed_speculation; } + void set_pending_failed_speculation(jlong failed_speculation) { _pending_failed_speculation = failed_speculation; } void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; } void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; } void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; } diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/tieredThresholdPolicy.cpp --- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Wed May 01 12:31:29 2019 -0700 @@ -34,7 +34,7 @@ #include "code/scopeDesc.hpp" #include "oops/method.inline.hpp" #if INCLUDE_JVMCI -#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmci.hpp" #endif #ifdef TIERED diff -r 0bda2308eded -r ad45b3802d4e src/hotspot/share/runtime/vmOperations.cpp --- a/src/hotspot/share/runtime/vmOperations.cpp Wed May 01 12:41:26 2019 -0400 +++ b/src/hotspot/share/runtime/vmOperations.cpp Wed May 01 12:31:29 2019 -0700 @@ -435,7 +435,20 @@ if (thr!=thr_cur && thr->thread_state() == _thread_in_native) { num_active++; if (thr->is_Compiler_thread()) { +#if INCLUDE_JVMCI + CompilerThread* ct = (CompilerThread*) thr; + if (ct->compiler() == NULL || !ct->compiler()->is_jvmci() || !UseJVMCINativeLibrary) { + num_active_compiler_thread++; + } else { + // When using a compiler in a JVMCI shared library, it's possible + // for one compiler thread to grab a lock in the shared library, + // enter HotSpot and go to sleep on the shutdown safepoint. Another + // JVMCI shared library compiler thread can then attempt to grab the + // lock and thus never make progress. + } +#else num_active_compiler_thread++; +#endif } } } diff -r 0bda2308eded -r ad45b3802d4e src/java.base/share/classes/module-info.java --- a/src/java.base/share/classes/module-info.java Wed May 01 12:41:26 2019 -0400 +++ b/src/java.base/share/classes/module-info.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,6 +214,7 @@ java.sql, java.sql.rowset, jdk.dynalink, + jdk.internal.vm.ci, jdk.scripting.nashorn, jdk.unsupported; exports jdk.internal.vm to diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,7 +191,9 @@ public abstract PlatformKind getLargestStorableKind(RegisterCategory category); /** - * Return the {@link PlatformKind} that is used to store values of a given {@link JavaKind}. + * Gets the {@link PlatformKind} that is used to store values of a given {@link JavaKind}. + * + * @return {@code null} if there no deterministic {@link PlatformKind} for {@code javaKind} */ public abstract PlatformKind getPlatformKind(JavaKind javaKind); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,11 @@ @Override public int hashCode() { - return getBCI(); + int hc = method.hashCode() * 31 + bci; + if (caller != null) { + hc = (hc * 31) + caller.hashCode(); + } + return hc; } /** diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,8 @@ * created. * @return a reference to the ready-to-run code * @throws BailoutException if the code installation failed + * @throws IllegalArgumentException if {@code installedCode != null} and this object does not + * support a predefined {@link InstalledCode} object */ default InstalledCode addCode(ResolvedJavaMethod method, CompiledCode compiledCode, SpeculationLog log, InstalledCode installedCode) { return installCode(method, compiledCode, installedCode, log, false); @@ -58,6 +60,8 @@ * @param compiledCode the compiled code to be added * @return a reference to the ready-to-run code * @throws BailoutException if the code installation failed + * @throws IllegalArgumentException if {@code installedCode != null} and this object does not + * support a predefined {@link InstalledCode} object */ default InstalledCode setDefaultCode(ResolvedJavaMethod method, CompiledCode compiledCode) { return installCode(method, compiledCode, null, null, true); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,14 +52,14 @@ /** * @return the address of entity representing this installed code. */ - public final long getAddress() { + public long getAddress() { return address; } /** * @return the address of the normal entry point of the installed code. */ - public final long getEntryPoint() { + public long getEntryPoint() { return entryPoint; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,5 +27,12 @@ */ public final class InvalidInstalledCodeException extends Exception { + public InvalidInstalledCodeException() { + } + + public InvalidInstalledCodeException(String message) { + super(message); + } + private static final long serialVersionUID = -3540232440794244844L; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/InitTimer.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/InitTimer.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/InitTimer.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ import java.util.concurrent.atomic.AtomicInteger; +import jdk.vm.ci.services.Services; + /** * A facility for timing a step in the runtime initialization sequence. This is independent from all * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the @@ -58,21 +60,32 @@ } public static InitTimer timer(String name) { - return ENABLED ? new InitTimer(name) : null; + return isEnabled() ? new InitTimer(name) : null; } public static InitTimer timer(String name, Object suffix) { - return ENABLED ? new InitTimer(name + suffix) : null; + return isEnabled() ? new InitTimer(name + suffix) : null; } /** - * Specifies if initialization timing is enabled. Note: This property cannot use + * Determines if initialization timing is enabled. Note: This property cannot use * {@code HotSpotJVMCIRuntime.Option} since that class is not visible from this package. */ - private static final boolean ENABLED = Boolean.getBoolean("jvmci.InitTimer"); + private static boolean isEnabled() { + if (enabledPropertyValue == null) { + enabledPropertyValue = Boolean.parseBoolean(Services.getSavedProperty("jvmci.InitTimer")); + nesting = new AtomicInteger(); + } + return enabledPropertyValue; + } - public static final AtomicInteger nesting = ENABLED ? new AtomicInteger() : null; - public static final String SPACES = " "; + /** + * Cache for value of {@code jvmci.InitTimer} system property. + */ + @NativeImageReinitialize private static Boolean enabledPropertyValue; + + private static AtomicInteger nesting; + private static final String SPACES = " "; /** * Used to assert the invariant that all related initialization happens on the same thread. diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/NativeImageReinitialize.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/NativeImageReinitialize.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/NativeImageReinitialize.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ import java.lang.annotation.Target; /** - * Denotes a field that should have the default value for its type when building a native image. + * Denotes a field that should have the default value for its type in an ahead of time image. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.services.Services; /** * Used to access native configuration details. @@ -36,7 +37,7 @@ super(config); } - final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux"); + final boolean linuxOs = Services.getSavedProperty("os.name", "").startsWith("Linux"); final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; +import jdk.vm.ci.services.Services; /** * Used to access AMD64 specific native configuration details. @@ -34,7 +35,7 @@ super(config); } - final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + final boolean windowsOs = Services.getSavedProperty("os.name", "").startsWith("Windows"); final boolean useCountLeadingZerosInstruction = getFlag("UseCountLeadingZerosInstruction", Boolean.class); final boolean useCountTrailingZerosInstruction = getFlag("UseCountTrailingZerosInstruction", Boolean.class); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; + +import jdk.vm.ci.common.NativeImageReinitialize; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * A cleaner tracks a referent object and includes some {@linkplain #doCleanup() cleanup code} that + * is run some time after the referent object has become weakly-reachable. + * + * This is like {@link sun.misc.Cleaner} but with weak semantics instead of phantom. Objects + * referenced by this might be referenced by {@link ResolvedJavaType} which is kept alive by a + * {@link WeakReference} so we need equivalent reference strength. + */ +abstract class Cleaner extends WeakReference { + + /** + * Head of linked list of cleaners. + */ + @NativeImageReinitialize private static Cleaner first; + + /** + * Linked list pointers. + */ + private Cleaner next = null; + private Cleaner prev = null; + + Cleaner(Object referent) { + super(referent, queue); + add(this); + } + + private static synchronized Cleaner add(Cleaner cl) { + if (first != null) { + clean(); + } + if (first != null) { + cl.next = first; + first.prev = cl; + } + first = cl; + return cl; + } + + /** + * Removes {@code cl} from the linked list of cleaners. + */ + private static synchronized void remove(Cleaner cl) { + // If already removed, do nothing + if (cl.next == cl) { + return; + } + + // Update list + if (first == cl) { + if (cl.next != null) { + first = cl.next; + } else { + first = cl.prev; + } + } + if (cl.next != null) { + cl.next.prev = cl.prev; + } + if (cl.prev != null) { + cl.prev.next = cl.next; + } + + // Indicate removal by pointing the cleaner to itself + cl.next = cl; + cl.prev = cl; + } + + /** + * Performs the cleanup action now that this object's referent has become weakly reachable. + */ + abstract void doCleanup(); + + /** + * Remove the cleaners whose referents have become weakly reachable. + */ + static void clean() { + Cleaner c = (Cleaner) queue.poll(); + while (c != null) { + remove(c); + c.doCleanup(); + c = (Cleaner) queue.poll(); + } + } + + /** + * The {@link ReferenceQueue} to which {@link Cleaner}s are enqueued once their referents' + * become unreachable. + */ + private static final ReferenceQueue queue = new ReferenceQueue<>(); +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,10 @@ import jdk.vm.ci.code.stack.InspectedFrameVisitor; import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -51,17 +55,60 @@ */ private static native void registerNatives(); - static { - initialize(); - } + /** + * These values mirror the equivalent values from {@link Unsafe} but are approriate for the JVM + * being compiled against. + */ + // Checkstyle: stop + final int ARRAY_BOOLEAN_BASE_OFFSET; + final int ARRAY_BYTE_BASE_OFFSET; + final int ARRAY_SHORT_BASE_OFFSET; + final int ARRAY_CHAR_BASE_OFFSET; + final int ARRAY_INT_BASE_OFFSET; + final int ARRAY_LONG_BASE_OFFSET; + final int ARRAY_FLOAT_BASE_OFFSET; + final int ARRAY_DOUBLE_BASE_OFFSET; + final int ARRAY_OBJECT_BASE_OFFSET; + final int ARRAY_BOOLEAN_INDEX_SCALE; + final int ARRAY_BYTE_INDEX_SCALE; + final int ARRAY_SHORT_INDEX_SCALE; + final int ARRAY_CHAR_INDEX_SCALE; + final int ARRAY_INT_INDEX_SCALE; + final int ARRAY_LONG_INDEX_SCALE; + final int ARRAY_FLOAT_INDEX_SCALE; + final int ARRAY_DOUBLE_INDEX_SCALE; + final int ARRAY_OBJECT_INDEX_SCALE; + // Checkstyle: resume @SuppressWarnings("try") - private static void initialize() { + CompilerToVM() { try (InitTimer t = timer("CompilerToVM.registerNatives")) { registerNatives(); + ARRAY_BOOLEAN_BASE_OFFSET = arrayBaseOffset(JavaKind.Boolean); + ARRAY_BYTE_BASE_OFFSET = arrayBaseOffset(JavaKind.Byte); + ARRAY_SHORT_BASE_OFFSET = arrayBaseOffset(JavaKind.Short); + ARRAY_CHAR_BASE_OFFSET = arrayBaseOffset(JavaKind.Char); + ARRAY_INT_BASE_OFFSET = arrayBaseOffset(JavaKind.Int); + ARRAY_LONG_BASE_OFFSET = arrayBaseOffset(JavaKind.Long); + ARRAY_FLOAT_BASE_OFFSET = arrayBaseOffset(JavaKind.Float); + ARRAY_DOUBLE_BASE_OFFSET = arrayBaseOffset(JavaKind.Double); + ARRAY_OBJECT_BASE_OFFSET = arrayBaseOffset(JavaKind.Object); + ARRAY_BOOLEAN_INDEX_SCALE = arrayIndexScale(JavaKind.Boolean); + ARRAY_BYTE_INDEX_SCALE = arrayIndexScale(JavaKind.Byte); + ARRAY_SHORT_INDEX_SCALE = arrayIndexScale(JavaKind.Short); + ARRAY_CHAR_INDEX_SCALE = arrayIndexScale(JavaKind.Char); + ARRAY_INT_INDEX_SCALE = arrayIndexScale(JavaKind.Int); + ARRAY_LONG_INDEX_SCALE = arrayIndexScale(JavaKind.Long); + ARRAY_FLOAT_INDEX_SCALE = arrayIndexScale(JavaKind.Float); + ARRAY_DOUBLE_INDEX_SCALE = arrayIndexScale(JavaKind.Double); + ARRAY_OBJECT_INDEX_SCALE = arrayIndexScale(JavaKind.Object); } } + native int arrayBaseOffset(JavaKind kind); + + native int arrayIndexScale(JavaKind kind); + /** * Gets the {@link CompilerToVM} instance associated with the singleton * {@link HotSpotJVMCIRuntime} instance. @@ -152,13 +199,16 @@ * Converts a name to a type. * * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format - * @param accessingClass the context of resolution (must not be null) + * @param accessingClass the context of resolution. A value of {@code null} implies that the + * class should be resolved with the class loader. * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will * either return a {@link ResolvedJavaType} or throw an exception * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false} * @throws ClassNotFoundException if {@code resolve == true} and the resolution failed */ - native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve) throws ClassNotFoundException; + native HotSpotResolvedJavaType lookupType(String name, HotSpotResolvedObjectTypeImpl accessingClass, boolean resolve) throws ClassNotFoundException; + + native HotSpotResolvedJavaType lookupClass(Class javaClass); /** * Resolves the entry at index {@code cpi} in {@code constantPool} to an object. @@ -167,7 +217,7 @@ * entry types: {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError}, * {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}. */ - native Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi); + native HotSpotObjectConstantImpl resolveConstantInPool(HotSpotConstantPool constantPool, int cpi); /** * Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the @@ -176,7 +226,7 @@ * The behavior of this method is undefined if {@code cpi} does not denote a * {@code JVM_CONSTANT_String} entry. */ - native Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi); + native HotSpotObjectConstantImpl resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi); /** * Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in @@ -318,7 +368,7 @@ * Gets the appendix object (if any) associated with the entry at index {@code cpi} in * {@code constantPool}. */ - native Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi); + native HotSpotObjectConstantImpl lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi); /** * Installs the result of a compilation into the code cache. @@ -335,7 +385,7 @@ * @throws JVMCIError if there is something wrong with the compiled code or the associated * metadata. */ - native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, HotSpotSpeculationLog speculationLog); + native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, long failedSpeculationsAddress, byte[] speculations); /** * Generates the VM metadata for some compiled code and copies them into {@code metaData}. This @@ -433,10 +483,10 @@ /** * Executes some {@code installedCode} with arguments {@code args}. * - * @return the result of executing {@code installedCode} - * @throws InvalidInstalledCodeException if {@code installedCode} has been invalidated + * @return the result of executing {@code nmethodMirror} + * @throws InvalidInstalledCodeException if {@code nmethodMirror} has been invalidated */ - native Object executeInstalledCode(Object[] args, InstalledCode installedCode) throws InvalidInstalledCodeException; + native Object executeHotSpotNmethod(Object[] args, HotSpotNmethod nmethodMirror) throws InvalidInstalledCodeException; /** * Gets the line number table for {@code method}. The line number table is encoded as (bci, @@ -472,6 +522,19 @@ native long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method); /** + * Reads an object pointer within a VM data structure. That is, any {@link VMField} whose + * {@link VMField#type type} is {@code "oop"} (e.g., + * {@code Klass::_java_mirror}, {@code JavaThread::_threadObj}). + * + * Note that {@link Unsafe#getObject(Object, long)} cannot be used for this since it does a + * {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data + * structures are (currently) always uncompressed. + * + * @param address address of an oop field within a VM data structure + */ + native HotSpotObjectConstantImpl readUncompressedOop(long address); + + /** * Sets flags on {@code method} indicating that it should never be inlined or compiled by the * VM. */ @@ -484,10 +547,12 @@ native void reprofile(HotSpotResolvedJavaMethodImpl method); /** - * Invalidates {@code installedCode} such that {@link InvalidInstalledCodeException} will be - * raised the next time {@code installedCode} is executed. + * Invalidates {@code nmethodMirror} such that {@link InvalidInstalledCodeException} will be + * raised the next time {@code nmethodMirror} is {@linkplain #executeHotSpotNmethod executed}. + * The {@code nmethod} associated with {@code nmethodMirror} is also made non-entrant and any + * current activations of the {@code nmethod} are deoptimized. */ - native void invalidateInstalledCode(InstalledCode installedCode); + native void invalidateHotSpotNmethod(HotSpotNmethod nmethodMirror); /** * Collects the current values of all JVMCI benchmark counters, summed up over all threads. @@ -572,7 +637,7 @@ * @param displacement * @return null or the resolved method for this location */ - native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, long displacement); + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(HotSpotObjectConstantImpl base, long displacement); /** * Gets the {@code ConstantPool*} associated with {@code object} and returns a @@ -586,7 +651,7 @@ * @throws IllegalArgumentException if {@code object} is neither a * {@link HotSpotResolvedJavaMethodImpl} nor a {@link HotSpotResolvedObjectTypeImpl} */ - native HotSpotConstantPool getConstantPool(Object object); + native HotSpotConstantPool getConstantPool(MetaspaceObject object); /** * Read a HotSpot Klass* value from the memory location described by {@code base} plus @@ -604,7 +669,19 @@ * @param compressed true if the location contains a compressed Klass* * @return null or the resolved method for this location */ - native HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, long displacement, boolean compressed); + private native HotSpotResolvedObjectTypeImpl getResolvedJavaType0(Object base, long displacement, boolean compressed); + + HotSpotResolvedObjectTypeImpl getResolvedJavaType(MetaspaceObject base, long displacement, boolean compressed) { + return getResolvedJavaType0(base, displacement, compressed); + } + + HotSpotResolvedObjectTypeImpl getResolvedJavaType(HotSpotObjectConstantImpl base, long displacement, boolean compressed) { + return getResolvedJavaType0(base, displacement, compressed); + } + + HotSpotResolvedObjectTypeImpl getResolvedJavaType(long displacement, boolean compressed) { + return getResolvedJavaType0(null, displacement, compressed); + } /** * Return the size of the HotSpot ProfileData* pointed at by {@code position}. If @@ -641,7 +718,7 @@ * Invokes non-public method {@code java.lang.invoke.LambdaForm.compileToBytecode()} on * {@code lambdaForm} (which must be a {@code java.lang.invoke.LambdaForm} instance). */ - native void compileToBytecode(Object lambdaForm); + native void compileToBytecode(HotSpotObjectConstantImpl lambdaForm); /** * Gets the value of the VM flag named {@code name}. @@ -660,6 +737,164 @@ native HotSpotResolvedObjectTypeImpl getHostClass(HotSpotResolvedObjectTypeImpl type); /** + * Gets the object at the address {@code oopAddress}. + * + * @param oopAddress a valid {@code oopDesc**} value + */ + native Object getObjectAtAddress(long oopAddress); + + /** + * @see ResolvedJavaType#getInterfaces() + */ + native HotSpotResolvedObjectTypeImpl[] getInterfaces(HotSpotResolvedObjectTypeImpl type); + + /** + * @see ResolvedJavaType#getComponentType() + */ + native HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl type); + + /** + * Forces initialization of {@code type}. + */ + native void ensureInitialized(HotSpotResolvedObjectTypeImpl type); + + /** + * Checks if {@code object} is a String and is an interned string value. + */ + native boolean isInternedString(HotSpotObjectConstantImpl object); + + /** + * Gets the {@linkplain System#identityHashCode(Object) identity} has code for the object + * represented by this constant. + */ + native int getIdentityHashCode(HotSpotObjectConstantImpl object); + + /** + * Converts a constant object representing a boxed primitive into a boxed primitive. + */ + native Object unboxPrimitive(HotSpotObjectConstantImpl object); + + /** + * Converts a boxed primitive into a JavaConstant representing the same value. + */ + native HotSpotObjectConstantImpl boxPrimitive(Object source); + + /** + * Gets the {@link ResolvedJavaMethod}s for all the constructors of the type {@code holder}. + */ + native ResolvedJavaMethod[] getDeclaredConstructors(HotSpotResolvedObjectTypeImpl holder); + + /** + * Gets the {@link ResolvedJavaMethod}s for all the non-constructor methods of the type + * {@code holder}. + */ + native ResolvedJavaMethod[] getDeclaredMethods(HotSpotResolvedObjectTypeImpl holder); + + /** + * Reads the current value of a static field. + */ + native JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl resolvedObjectType, HotSpotResolvedJavaField field, boolean isVolatile); + + /** + * Reads the current value of an instance field. + */ + native JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile); + + /** + * @see ResolvedJavaType#isInstance(JavaConstant) + */ + native boolean isInstance(HotSpotResolvedObjectTypeImpl holder, HotSpotObjectConstantImpl object); + + /** + * @see ResolvedJavaType#isAssignableFrom(ResolvedJavaType) + */ + native boolean isAssignableFrom(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedObjectTypeImpl otherType); + + /** + * @see ConstantReflectionProvider#asJavaType(Constant) + */ + native HotSpotResolvedJavaType asJavaType(HotSpotObjectConstantImpl object); + + /** + * Converts a String constant into a String. + */ + native String asString(HotSpotObjectConstantImpl object); + + /** + * Compares the contents of {@code xHandle} and {@code yHandle} for pointer equality. + */ + native boolean equals(HotSpotObjectConstantImpl x, long xHandle, HotSpotObjectConstantImpl y, long yHandle); + + /** + * Gets a {@link JavaConstant} wrapping the {@link java.lang.Class} mirror for {@code type}. + */ + native HotSpotObjectConstantImpl getJavaMirror(HotSpotResolvedJavaType type); + + /** + * Returns the length of the array if {@code object} represents an array or -1 otherwise. + */ + native int getArrayLength(HotSpotObjectConstantImpl object); + + /** + * Reads the element at {@code index} if {@code object} is an array. Elements of an object array + * are returned as {@link JavaConstant}s and primitives are returned as boxed values. The value + * {@code null} is returned if the {@code index} is out of range or object is not an array. + */ + native Object readArrayElement(HotSpotObjectConstantImpl object, int index); + + /** + * Reads a byte sized value from {@code displacement} in {@code object}. + */ + native byte getByte(HotSpotObjectConstantImpl object, long displacement); + + /** + * Reads a short sized value from {@code displacement} in {@code object}. + */ + native short getShort(HotSpotObjectConstantImpl object, long displacement); + + /** + * Reads an int sized value from {@code displacement} in {@code object}. + */ + native int getInt(HotSpotObjectConstantImpl object, long displacement); + + /** + * Reads a long sized value from {@code displacement} in {@code object}. + */ + native long getLong(HotSpotObjectConstantImpl object, long displacement); + + /** + * Reads a Java object from {@code displacement} in {@code object}. + */ + native HotSpotObjectConstantImpl getObject(HotSpotObjectConstantImpl object, long displacement); + + /** + * @see HotSpotJVMCIRuntime#registerNativeMethods + */ + native long[] registerNativeMethods(Class clazz); + + /** + * @see HotSpotJVMCIRuntime#translate(Object) + */ + native long translate(Object obj); + + /** + * @see HotSpotJVMCIRuntime#unhand(Class, long) + */ + native Object unhand(long handle); + + /** + * Updates {@code address} and {@code entryPoint} fields of {@code nmethodMirror} based on the + * current state of the {@code nmethod} identified by {@code address} and + * {@code nmethodMirror.compileId} in the code cache. + */ + native void updateHotSpotNmethod(HotSpotNmethod nmethodMirror); + + /** + * @see InstalledCode#getCode() + */ + native byte[] getCode(HotSpotInstalledCode code); + + /** * Gets a {@link Executable} corresponding to {@code method}. */ native Executable asReflectionExecutable(HotSpotResolvedJavaMethodImpl method); @@ -671,4 +906,45 @@ * @param fieldIndex the {@code fieldDescriptor::index()} denoting the field */ native Field asReflectionField(HotSpotResolvedObjectTypeImpl holder, int fieldIndex); + + /** + * @see HotSpotJVMCIRuntime#getIntrinsificationTrustPredicate(Class...) + */ + native boolean isTrustedForIntrinsics(HotSpotResolvedObjectTypeImpl type); + + /** + * Releases the resources backing the global JNI {@code handle}. This is equivalent to the + * {@code DeleteGlobalRef} JNI function. + */ + native void deleteGlobalHandle(long handle); + + /** + * Gets the failed speculations pointed to by {@code *failedSpeculationsAddress}. + * + * @param currentFailures the known failures at {@code failedSpeculationsAddress} + * @return the list of failed speculations with each entry being a single speculation in the + * format emitted by {@link HotSpotSpeculationEncoding#toByteArray()} + */ + native byte[][] getFailedSpeculations(long failedSpeculationsAddress, byte[][] currentFailures); + + /** + * Gets the address of the {@code MethodData::_failed_speculations} field in the + * {@code MethodData} associated with {@code method}. This will create and install the + * {@code MethodData} if it didn't already exist. + */ + native long getFailedSpeculationsAddress(HotSpotResolvedJavaMethodImpl method); + + /** + * Frees the failed speculations pointed to by {@code *failedSpeculationsAddress}. + */ + native void releaseFailedSpeculations(long failedSpeculationsAddress); + + /** + * Adds a speculation to the failed speculations pointed to by + * {@code *failedSpeculationsAddress}. + * + * @return {@code false} if the speculation could not be appended to the list + */ + native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation); + } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.JavaConstant; + +final class DirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl { + + static JavaConstant forObject(Object object, boolean compressed) { + if (object == null) { + return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER; + } else { + return new DirectHotSpotObjectConstantImpl(object, compressed); + } + } + + static HotSpotObjectConstantImpl forNonNullObject(Object object, boolean compressed) { + if (object == null) { + throw new NullPointerException(); + } + return new DirectHotSpotObjectConstantImpl(object, compressed); + } + + private DirectHotSpotObjectConstantImpl(Object object, boolean compressed) { + super(compressed); + assert object != null; + this.object = object; + } + + final Object object; + + @Override + public JavaConstant compress() { + assert !compressed; + return new DirectHotSpotObjectConstantImpl(object, true); + } + + @Override + public JavaConstant uncompress() { + assert compressed; + return new DirectHotSpotObjectConstantImpl(object, false); + } + + @Override + public int getIdentityHashCode() { + return System.identityHashCode(object); + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +/** + * This class manages a set of {@code jobject} and {@code jmetadata} handles whose lifetimes are + * dependent on associated {@link IndirectHotSpotObjectConstantImpl} and + * {@link MetaspaceHandleObject} wrapper objects respectively. + * + * The general theory of operation is that all wrappers are created by calling into the VM which + * calls back out to actually create the wrapper instance. During the call the VM keeps the object + * or metadata reference alive through the use of handles. Once the call completes the wrapper + * object is registered here and will be scanned during metadata scanning. The weakness of the + * reference to the wrapper object allows the handles to be reclaimed when they are no longer used. + */ +final class HandleCleaner extends Cleaner { + + /** + * A {@code jmetadata} or {@code jobject} handle. + */ + private final long handle; + + /** + * Specifies if {@link #handle} is a {@code jobject} or {@code jmetadata}. + */ + private final boolean isJObject; + + private HandleCleaner(Object wrapper, long handle, boolean isJObject) { + super(wrapper); + this.handle = handle; + this.isJObject = isJObject; + } + + /** + * Releases the resource associated with {@code this.handle}. + */ + @Override + void doCleanup() { + if (isJObject) { + // The sentinel value used to denote a free handle is + // an object on the HotSpot heap so we call into the + // VM to set the target of an object handle to this value. + CompilerToVM.compilerToVM().deleteGlobalHandle(handle); + } else { + // Setting the target of a jmetadata handle to 0 enables + // the handle to be reused. See MetadataHandleBlock in + // jvmciRuntime.cpp for more info. + long value = UNSAFE.getLong(null, handle); + UNSAFE.compareAndSetLong(null, handle, value, 0); + } + } + + /** + * Registers a cleaner for {@code handle}. The cleaner will release the handle some time after + * {@code wrapper} is detected as unreachable by the garbage collector. + */ + @SuppressWarnings("unused") + static void create(Object wrapper, long handle) { + assert wrapper instanceof IndirectHotSpotObjectConstantImpl || wrapper instanceof MetaspaceHandleObject; + new HandleCleaner(wrapper, handle, wrapper instanceof IndirectHotSpotObjectConstantImpl); + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ package jdk.vm.ci.hotspot; import java.util.Map; +import java.util.Objects; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodeFrame; @@ -102,25 +103,42 @@ @Override public InstalledCode installCode(ResolvedJavaMethod method, CompiledCode compiledCode, InstalledCode installedCode, SpeculationLog log, boolean isDefault) { InstalledCode resultInstalledCode; - if (installedCode == null) { - if (method == null) { - // Must be a stub - resultInstalledCode = new HotSpotRuntimeStub(((HotSpotCompiledCode) compiledCode).getName()); - } else { - resultInstalledCode = new HotSpotNmethod((HotSpotResolvedJavaMethod) method, ((HotSpotCompiledCode) compiledCode).getName(), isDefault); - } + if (installedCode != null) { + throw new IllegalArgumentException("InstalledCode argument must be null"); + } + HotSpotCompiledCode hsCompiledCode = (HotSpotCompiledCode) compiledCode; + String name = hsCompiledCode.getName(); + HotSpotCompiledNmethod hsCompiledNmethod = null; + if (method == null) { + // Must be a stub + resultInstalledCode = new HotSpotRuntimeStub(name); } else { - resultInstalledCode = installedCode; + hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode; + HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method; + resultInstalledCode = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id); } - HotSpotSpeculationLog speculationLog = (log != null && log.hasSpeculations()) ? (HotSpotSpeculationLog) log : null; + HotSpotSpeculationLog speculationLog = null; + if (log != null) { + if (log.hasSpeculations()) { + speculationLog = (HotSpotSpeculationLog) log; + } + } - int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, speculationLog); + byte[] speculations; + long failedSpeculationsAddress; + if (speculationLog != null) { + speculations = speculationLog.getFlattenedSpeculations(true); + failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress(); + } else { + speculations = new byte[0]; + failedSpeculationsAddress = 0L; + } + int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, failedSpeculationsAddress, speculations); if (result != config.codeInstallResultOk) { String resultDesc = config.getCodeInstallResultDescription(result); - if (compiledCode instanceof HotSpotCompiledNmethod) { - HotSpotCompiledNmethod compiledNmethod = (HotSpotCompiledNmethod) compiledCode; - String msg = compiledNmethod.getInstallationFailureMessage(); + if (hsCompiledNmethod != null) { + String msg = hsCompiledNmethod.getInstallationFailureMessage(); if (msg != null) { msg = String.format("Code installation failed: %s%n%s", resultDesc, msg); } else { @@ -139,7 +157,11 @@ @Override public void invalidateInstalledCode(InstalledCode installedCode) { - runtime.getCompilerToVM().invalidateInstalledCode(installedCode); + if (installedCode instanceof HotSpotNmethod) { + runtime.getCompilerToVM().invalidateHotSpotNmethod((HotSpotNmethod) installedCode); + } else { + throw new IllegalArgumentException("Cannot invalidate a " + Objects.requireNonNull(installedCode).getClass().getName()); + } } @Override diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,14 @@ * the address of a {@code JVMCIEnv} object that provides native context for a compilation. */ public class HotSpotCompilationRequest extends CompilationRequest { - private final long jvmciEnv; + /** + * Address of the native {@code JVMCICompileState} associated with the request. + */ + private final long compileState; + + /** + * An identifier for the request. + */ private final int id; /** @@ -39,10 +46,10 @@ * @param method the method to be compiled * @param entryBCI the bytecode index (BCI) at which to start compiling where -1 denotes the * method's entry point - * @param jvmciEnv address of a native {@code JVMCIEnv} object or 0L + * @param compileState address of a native {@code JVMCICompileState} object or 0L */ - public HotSpotCompilationRequest(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv) { - this(method, entryBCI, jvmciEnv, method.allocateCompileId(entryBCI)); + public HotSpotCompilationRequest(HotSpotResolvedJavaMethod method, int entryBCI, long compileState) { + this(method, entryBCI, compileState, method.allocateCompileId(entryBCI)); } /** @@ -51,12 +58,12 @@ * @param method the method to be compiled * @param entryBCI the bytecode index (BCI) at which to start compiling where -1 denotes the * method's entry point - * @param jvmciEnv address of a native {@code JVMCIEnv} object or 0L + * @param compileState address of a native {@code JVMCICompileState} object or 0L * @param id an identifier for the request */ - public HotSpotCompilationRequest(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + public HotSpotCompilationRequest(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) { super(method, entryBCI); - this.jvmciEnv = jvmciEnv; + this.compileState = compileState; this.id = id; } @@ -66,10 +73,12 @@ } /** - * Gets the address of the native {@code JVMCIEnv} object or 0L if no such object exists. + * Gets the address of the native {@code JVMCICompileState} or 0L if no such object exists. This + * method should really be named {@code getCompileState} but must remain as is for API + * stability. */ public long getJvmciEnv() { - return jvmciEnv; + return compileState; } /** @@ -78,5 +87,4 @@ public int getId() { return id; } - } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,9 +42,9 @@ protected final int id; /** - * Address of a native {@code JVMCIEnv} object or 0L if no such object exists. + * Address of a native {@code JVMCICompileState} object or 0L if no such object exists. */ - protected final long jvmciEnv; + protected final long compileState; protected final boolean hasUnsafeAccess; @@ -56,12 +56,12 @@ public HotSpotCompiledNmethod(String name, byte[] targetCode, int targetCodeSize, Site[] sites, Assumption[] assumptions, ResolvedJavaMethod[] methods, Comment[] comments, byte[] dataSection, int dataSectionAlignment, DataPatch[] dataSectionPatches, boolean isImmutablePIC, int totalFrameSize, StackSlot deoptRescueSlot, HotSpotResolvedJavaMethod method, int entryBCI, - int id, long jvmciEnv, boolean hasUnsafeAccess) { + int id, long compileState, boolean hasUnsafeAccess) { super(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC, totalFrameSize, deoptRescueSlot); this.method = method; this.entryBCI = entryBCI; this.id = id; - this.jvmciEnv = jvmciEnv; + this.compileState = compileState; this.hasUnsafeAccess = hasUnsafeAccess; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,8 @@ import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import java.lang.invoke.MethodHandle; - import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaField; @@ -45,7 +44,7 @@ /** * Implementation of {@link ConstantPool} for HotSpot. */ -public final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject { +public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleObject { /** * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. @@ -97,76 +96,86 @@ } } - /** - * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and - * internal ones. - */ - private enum JVM_CONSTANT { - // @formatter:off - Utf8(config().jvmConstantUtf8), - Integer(config().jvmConstantInteger), - Long(config().jvmConstantLong), - Float(config().jvmConstantFloat), - Double(config().jvmConstantDouble), - Class(config().jvmConstantClass), - UnresolvedClass(config().jvmConstantUnresolvedClass), - UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), - String(config().jvmConstantString), - Fieldref(config().jvmConstantFieldref), - MethodRef(config().jvmConstantMethodref), - InterfaceMethodref(config().jvmConstantInterfaceMethodref), - NameAndType(config().jvmConstantNameAndType), - MethodHandle(config().jvmConstantMethodHandle), - MethodHandleInError(config().jvmConstantMethodHandleInError), - MethodType(config().jvmConstantMethodType), - MethodTypeInError(config().jvmConstantMethodTypeInError), - InvokeDynamic(config().jvmConstantInvokeDynamic); - // @formatter:on + static final class JvmConstant { + private final int tag; + private final String name; - private final int tag; - - private static final int ExternalMax = config().jvmConstantExternalMax; - private static final int InternalMin = config().jvmConstantInternalMin; - private static final int InternalMax = config().jvmConstantInternalMax; - - JVM_CONSTANT(int tag) { + JvmConstant(int tag, String name) { this.tag = tag; + this.name = name; } - /** - * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy - * initialization. - */ - static class TagValueMap { - private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; + @Override + public String toString() { + return name; + } + } + + /** + * {@code JVM_CONSTANT} constants used in the VM including both public and internal ones. + */ + static final class JvmConstants { + + private final HotSpotVMConfig c = config(); + private final int externalMax = c.jvmConstantExternalMax; + private final int internalMax = c.jvmConstantInternalMax; + private final int internalMin = c.jvmConstantInternalMin; + private final JvmConstant[] table = new JvmConstant[externalMax + 1 + (internalMax - internalMin) + 1]; - static { - assert InternalMin > ExternalMax; - for (JVM_CONSTANT e : values()) { - table[indexOf(e.tag)] = e; + final JvmConstant jvmUtf8 = add(new JvmConstant(c.jvmConstantUtf8, "Utf8")); + final JvmConstant jvmInteger = add(new JvmConstant(c.jvmConstantInteger, "Integer")); + final JvmConstant jvmLong = add(new JvmConstant(c.jvmConstantLong, "Long")); + final JvmConstant jvmFloat = add(new JvmConstant(c.jvmConstantFloat, "Float")); + final JvmConstant jvmDouble = add(new JvmConstant(c.jvmConstantDouble, "Double")); + final JvmConstant jvmClass = add(new JvmConstant(c.jvmConstantClass, "Class")); + final JvmConstant jvmUnresolvedClass = add(new JvmConstant(c.jvmConstantUnresolvedClass, "UnresolvedClass")); + final JvmConstant jvmUnresolvedClassInError = add(new JvmConstant(c.jvmConstantUnresolvedClassInError, "UnresolvedClassInError")); + final JvmConstant jvmString = add(new JvmConstant(c.jvmConstantString, "String")); + final JvmConstant jvmFieldref = add(new JvmConstant(c.jvmConstantFieldref, "Fieldref")); + final JvmConstant jvmMethodref = add(new JvmConstant(c.jvmConstantMethodref, "Methodref")); + final JvmConstant jvmInterfaceMethodref = add(new JvmConstant(c.jvmConstantInterfaceMethodref, "InterfaceMethodref")); + final JvmConstant jvmNameAndType = add(new JvmConstant(c.jvmConstantNameAndType, "NameAndType")); + final JvmConstant jvmMethodHandle = add(new JvmConstant(c.jvmConstantMethodHandle, "MethodHandle")); + final JvmConstant jvmMethodHandleInError = add(new JvmConstant(c.jvmConstantMethodHandleInError, "MethodHandleInError")); + final JvmConstant jvmMethodType = add(new JvmConstant(c.jvmConstantMethodType, "MethodType")); + final JvmConstant jvmMethodTypeInError = add(new JvmConstant(c.jvmConstantMethodTypeInError, "MethodTypeInError")); + final JvmConstant jvmInvokeDynamic = add(new JvmConstant(c.jvmConstantInvokeDynamic, "InvokeDynamic")); + + private JvmConstant add(JvmConstant constant) { + table[indexOf(constant.tag)] = constant; + return constant; + } + + private int indexOf(int tag) { + if (tag >= internalMin) { + return tag - internalMin + externalMax + 1; + } else { + assert tag <= externalMax; + } + return tag; + } + + JvmConstant get(int tag) { + JvmConstant res = table[indexOf(tag)]; + if (res != null) { + return res; + } + throw new JVMCIError("Unknown JvmConstant tag %s", tag); + } + + @NativeImageReinitialize private static volatile JvmConstants instance; + + static JvmConstants instance() { + JvmConstants result = instance; + if (result == null) { + synchronized (JvmConstants.class) { + result = instance; + if (result == null) { + instance = result = new JvmConstants(); + } } } - - private static int indexOf(int tag) { - if (tag >= InternalMin) { - return tag - InternalMin + ExternalMax + 1; - } else { - assert tag <= ExternalMax; - } - return tag; - } - - static JVM_CONSTANT get(int tag) { - JVM_CONSTANT res = table[indexOf(tag)]; - if (res != null) { - return res; - } - throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); - } - } - - public static JVM_CONSTANT getEnum(int tag) { - return TagValueMap.get(tag); + return result; } } @@ -182,15 +191,18 @@ } /** - * Reference to the C++ ConstantPool object. + * Handle to the {@code ConstantPool} VM object. The handle is in + * {@code JVMCI::_metadata_handles}. */ - private final long metaspaceConstantPool; + private final long metadataHandle; + private volatile LookupTypeCacheElement lastLookupType; + private final JvmConstants constants; /** * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that * the ConstantPool is kept alive for the duration of this call and the - * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * {@link HotSpotJVMCIRuntime} keeps it alive after that. * * Called from the VM. * @@ -198,14 +210,15 @@ * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} */ @SuppressWarnings("unused") + @VMEntryPoint private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { - HotSpotConstantPool cp = new HotSpotConstantPool(metaspaceConstantPool); - runtime().metaAccessContext.add(cp); - return cp; + return new HotSpotConstantPool(metaspaceConstantPool); } - private HotSpotConstantPool(long metaspaceConstantPool) { - this.metaspaceConstantPool = metaspaceConstantPool; + private HotSpotConstantPool(long metadataHandle) { + this.metadataHandle = metadataHandle; + this.constants = JvmConstants.instance(); + HandleCleaner.create(this, metadataHandle); } /** @@ -271,12 +284,12 @@ } long getMetaspaceConstantPool() { - return metaspaceConstantPool; + return getMetaspacePointer(); } @Override - public long getMetaspacePointer() { - return getMetaspaceConstantPool(); + public long getMetadataHandle() { + return metadataHandle; } /** @@ -285,7 +298,7 @@ * @param index constant pool index * @return constant pool tag */ - private JVM_CONSTANT getTagAt(int index) { + private JvmConstant getTagAt(int index) { assert checkBounds(index); HotSpotVMConfig config = config(); final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); @@ -293,7 +306,7 @@ if (tag == 0) { return null; } - return JVM_CONSTANT.getEnum(tag); + return constants.get(tag); } /** @@ -315,7 +328,7 @@ * @return integer constant pool entry at index */ private int getIntAt(int index) { - assert checkTag(index, JVM_CONSTANT.Integer); + assert checkTag(index, constants.jvmInteger); int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); } @@ -327,7 +340,7 @@ * @return long constant pool entry */ private long getLongAt(int index) { - assert checkTag(index, JVM_CONSTANT.Long); + assert checkTag(index, constants.jvmLong); int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + offset); } @@ -339,7 +352,7 @@ * @return float constant pool entry */ private float getFloatAt(int index) { - assert checkTag(index, JVM_CONSTANT.Float); + assert checkTag(index, constants.jvmFloat); int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + offset); } @@ -351,7 +364,7 @@ * @return float constant pool entry */ private double getDoubleAt(int index) { - assert checkTag(index, JVM_CONSTANT.Double); + assert checkTag(index, constants.jvmDouble); int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + offset); } @@ -363,7 +376,7 @@ * @return {@code JVM_CONSTANT_NameAndType} constant pool entry */ private int getNameAndTypeAt(int index) { - assert checkTag(index, JVM_CONSTANT.NameAndType); + assert checkTag(index, constants.jvmNameAndType); int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); } @@ -470,22 +483,23 @@ * @param tag expected tag * @throws AssertionError if the check fails */ - private boolean checkTag(int index, JVM_CONSTANT tag) { - final JVM_CONSTANT tagAt = getTagAt(index); + private boolean checkTag(int index, JvmConstant tag) { + final JvmConstant tagAt = getTagAt(index); assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; return true; } /** - * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, - * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * Asserts that the constant pool tag at index {@code index} is a + * {@link JvmConstants#jvmFieldref}, or a {@link JvmConstants#jvmMethodref}, or a + * {@link JvmConstants#jvmInterfaceMethodref}. * * @param index constant pool index * @throws AssertionError if the check fails */ private boolean checkTagIsFieldOrMethod(int index) { - final JVM_CONSTANT tagAt = getTagAt(index); - assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; + final JvmConstant tagAt = getTagAt(index); + assert tagAt == constants.jvmFieldref || tagAt == constants.jvmMethodref || tagAt == constants.jvmInterfaceMethodref : tagAt; return true; } @@ -505,35 +519,33 @@ @Override public Object lookupConstant(int cpi) { assert cpi != 0; - final JVM_CONSTANT tag = getTagAt(cpi); - switch (tag) { - case Integer: + final JvmConstant tag = getTagAt(cpi); + switch (tag.name) { + case "Integer": return JavaConstant.forInt(getIntAt(cpi)); - case Long: + case "Long": return JavaConstant.forLong(getLongAt(cpi)); - case Float: + case "Float": return JavaConstant.forFloat(getFloatAt(cpi)); - case Double: + case "Double": return JavaConstant.forDouble(getDoubleAt(cpi)); - case Class: - case UnresolvedClass: - case UnresolvedClassInError: + case "Class": + case "UnresolvedClass": + case "UnresolvedClassInError": final int opcode = -1; // opcode is not used return lookupType(cpi, opcode); - case String: + case "String": /* * Normally, we would expect a String here, but unsafe anonymous classes can have * "pseudo strings" (arbitrary live objects) patched into a String entry. Such * entries do not have a symbol in the constant pool slot. */ - Object string = compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); - return HotSpotObjectConstantImpl.forObject(string); - case MethodHandle: - case MethodHandleInError: - case MethodType: - case MethodTypeInError: - Object obj = compilerToVM().resolveConstantInPool(this, cpi); - return HotSpotObjectConstantImpl.forObject(obj); + return compilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); + case "MethodHandle": + case "MethodHandleInError": + case "MethodType": + case "MethodTypeInError": + return compilerToVM().resolveConstantInPool(this, cpi); default: throw new JVMCIError("Unknown constant pool tag %s", tag); } @@ -541,7 +553,7 @@ @Override public String lookupUtf8(int cpi) { - assert checkTag(cpi, JVM_CONSTANT.Utf8); + assert checkTag(cpi, constants.jvmUtf8); return compilerToVM().getSymbol(getEntryAt(cpi)); } @@ -554,12 +566,7 @@ public JavaConstant lookupAppendix(int cpi, int opcode) { assert Bytecodes.isInvoke(opcode); final int index = rawIndexToConstantPoolCacheIndex(cpi, opcode); - Object appendix = compilerToVM().lookupAppendixInPool(this, index); - if (appendix == null) { - return null; - } else { - return HotSpotObjectConstantImpl.forObject(appendix); - } + return compilerToVM().lookupAppendixInPool(this, index); } /** @@ -587,7 +594,7 @@ String name = getNameOf(index); HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); if (opcode == Bytecodes.INVOKEDYNAMIC) { - HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); + HotSpotResolvedObjectType holder = runtime().getMethodHandleClass(); return new UnresolvedJavaMethod(name, signature, holder); } else { final int klassIndex = getKlassRefIndexAt(index); @@ -709,40 +716,37 @@ throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); } - final JVM_CONSTANT tag = getTagAt(index); + final JvmConstant tag = getTagAt(index); if (tag == null) { - assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; + assert getTagAt(index - 1) == constants.jvmDouble || getTagAt(index - 1) == constants.jvmLong; return; } - switch (tag) { - case MethodRef: - case Fieldref: - case InterfaceMethodref: + switch (tag.name) { + case "Methodref": + case "Fieldref": + case "InterfaceMethodref": index = getUncachedKlassRefIndexAt(index); // Read the tag only once because it could change between multiple reads. - final JVM_CONSTANT klassTag = getTagAt(index); - assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; + final JvmConstant klassTag = getTagAt(index); + assert klassTag == constants.jvmClass || klassTag == constants.jvmUnresolvedClass || klassTag == constants.jvmUnresolvedClassInError : klassTag; // fall through - case Class: - case UnresolvedClass: - case UnresolvedClassInError: + case "Class": + case "UnresolvedClass": + case "UnresolvedClassInError": final HotSpotResolvedObjectTypeImpl type = compilerToVM().resolveTypeInPool(this, index); - if (initialize) { - Class klass = type.mirror(); - if (!klass.isPrimitive() && !klass.isArray()) { - UNSAFE.ensureClassInitialized(klass); - } + if (initialize && !type.isPrimitive() && !type.isArray()) { + type.ensureInitialized(); } - if (tag == JVM_CONSTANT.MethodRef) { + if (tag == constants.jvmMethodref) { if (Bytecodes.isInvokeHandleAlias(opcode) && isSignaturePolymorphicHolder(type)) { final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); - assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), constants.jvmMethodref); compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); } } break; - case InvokeDynamic: + case "InvokeDynamic": if (isInvokedynamicIndex(cpi)) { compilerToVM().resolveInvokeDynamicInPool(this, cpi); } @@ -788,7 +792,7 @@ public boolean isResolvedDynamicInvoke(int cpi, int opcode) { if (Bytecodes.isInvokeHandleAlias(opcode)) { final int methodRefCacheIndex = rawIndexToConstantPoolCacheIndex(cpi, opcode); - assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), constants.jvmMethodref); int op = compilerToVM().isResolvedInvokeHandleInPool(this, methodRefCacheIndex); return op == opcode; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,19 @@ package jdk.vm.ci.hotspot; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; /** * Represents a constant that was retrieved from a constant pool. Used to keep track of the constant * pool slot for the constant. */ -public final class HotSpotConstantPoolObject extends HotSpotObjectConstantImpl { +public final class HotSpotConstantPoolObject implements JavaConstant { - static JavaConstant forObject(HotSpotResolvedObjectType type, int cpi, Object object) { + public static JavaConstant forObject(HotSpotResolvedObjectType type, int cpi, JavaConstant object) { return new HotSpotConstantPoolObject(type, cpi, object); } - public static JavaConstant forObject(HotSpotResolvedObjectType type, int cpi, JavaConstant object) { - return forObject(type, cpi, ((HotSpotObjectConstantImpl) object).object()); - } - + private final JavaConstant constant; private final HotSpotResolvedObjectType type; private final int cpi; @@ -49,24 +47,72 @@ return cpi; } - HotSpotConstantPoolObject(HotSpotResolvedObjectType type, int cpi, Object object) { - super(object, false); + HotSpotConstantPoolObject(HotSpotResolvedObjectType type, int cpi, JavaConstant constant) { this.type = type; this.cpi = cpi; + this.constant = constant; } @Override public boolean equals(Object o) { if (o instanceof HotSpotConstantPoolObject) { - if (super.equals(o)) { - HotSpotConstantPoolObject other = (HotSpotConstantPoolObject) o; - return type.equals(other.type) && cpi == other.cpi; - } + HotSpotConstantPoolObject other = (HotSpotConstantPoolObject) o; + return type.equals(other.type) && cpi == other.cpi && constant.equals(other.constant); } return false; } @Override + public int hashCode() { + return constant.hashCode() + cpi + type.hashCode(); + } + + @Override + public JavaKind getJavaKind() { + return constant.getJavaKind(); + } + + @Override + public boolean isNull() { + return constant.isNull(); + } + + @Override + public boolean isDefaultForKind() { + return constant.isDefaultForKind(); + } + + @Override + public Object asBoxedPrimitive() { + return constant.asBoxedPrimitive(); + } + + @Override + public int asInt() { + return constant.asInt(); + } + + @Override + public boolean asBoolean() { + return constant.asBoolean(); + } + + @Override + public long asLong() { + return constant.asLong(); + } + + @Override + public float asFloat() { + return constant.asFloat(); + } + + @Override + public double asDouble() { + return 0; + } + + @Override public String toValueString() { return getCpType().getName() + getCpi(); } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,6 @@ */ package jdk.vm.ci.hotspot; -import java.lang.reflect.Array; import java.util.Objects; import jdk.vm.ci.common.JVMCIError; @@ -65,7 +64,7 @@ if (x == y) { return true; } else if (x instanceof HotSpotObjectConstantImpl) { - return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object(); + return y instanceof HotSpotObjectConstantImpl && x.equals(y); } else { return Objects.equals(x, y); } @@ -77,11 +76,8 @@ return null; } - Object arrayObject = ((HotSpotObjectConstantImpl) array).object(); - if (!arrayObject.getClass().isArray()) { - return null; - } - return Array.getLength(arrayObject); + HotSpotObjectConstantImpl arrayObject = ((HotSpotObjectConstantImpl) array); + return runtime.getReflection().getLength(arrayObject); } @Override @@ -89,18 +85,8 @@ if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) { return null; } - Object a = ((HotSpotObjectConstantImpl) array).object(); - - if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) { - return null; - } - - if (a instanceof Object[]) { - Object element = ((Object[]) a)[index]; - return HotSpotObjectConstantImpl.forObject(element); - } else { - return JavaConstant.forBoxedPrimitive(Array.get(a, index)); - } + HotSpotObjectConstantImpl arrayObject = ((HotSpotObjectConstantImpl) array); + return runtime.getReflection().readArrayElement(arrayObject, index); } /** @@ -135,7 +121,7 @@ if (source == null || !source.getJavaKind().isPrimitive() || !isBoxCached(source)) { return null; } - return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive()); + return runtime.getReflection().boxPrimitive(source); } @Override @@ -146,28 +132,25 @@ if (source.isNull()) { return null; } - return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object()); + return runtime.getReflection().unboxPrimitive((HotSpotObjectConstantImpl) source); } @Override public JavaConstant forString(String value) { - return HotSpotObjectConstantImpl.forObject(value); + return runtime.getReflection().forObject(value); } public JavaConstant forObject(Object value) { - return HotSpotObjectConstantImpl.forObject(value); + return runtime.getReflection().forObject(value); } @Override public ResolvedJavaType asJavaType(Constant constant) { - if (constant instanceof HotSpotObjectConstant) { - Object obj = ((HotSpotObjectConstantImpl) constant).object(); - if (obj instanceof Class) { - return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class) obj); - } + if (constant instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) constant).asJavaType(); } if (constant instanceof HotSpotMetaspaceConstant) { - MetaspaceWrapperObject obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant); + MetaspaceObject obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant); if (obj instanceof HotSpotResolvedObjectTypeImpl) { return (ResolvedJavaType) obj; } @@ -179,15 +162,15 @@ public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; if (hotspotField.isStatic()) { - HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); + HotSpotResolvedObjectTypeImpl holder = (HotSpotResolvedObjectTypeImpl) hotspotField.getDeclaringClass(); if (holder.isInitialized()) { - return memoryAccess.readFieldValue(hotspotField, holder.mirror(), field.isVolatile()); + return holder.readFieldValue(hotspotField, field.isVolatile()); } } else { - if (receiver.isNonNull()) { - Object object = ((HotSpotObjectConstantImpl) receiver).object(); + if (receiver.isNonNull() && receiver instanceof HotSpotObjectConstantImpl) { + HotSpotObjectConstantImpl object = ((HotSpotObjectConstantImpl) receiver); if (hotspotField.isInObject(receiver)) { - return memoryAccess.readFieldValue(hotspotField, object, field.isVolatile()); + return object.readFieldValue(hotspotField, field.isVolatile()); } } } @@ -196,7 +179,7 @@ @Override public JavaConstant asJavaClass(ResolvedJavaType type) { - return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedJavaType) type).mirror()); + return ((HotSpotResolvedJavaType) type).getJavaMirror(); } @Override diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,28 +22,28 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import jdk.internal.misc.Unsafe; import jdk.vm.ci.code.InstalledCode; /** - * Implementation of {@link InstalledCode} for HotSpot. + * Implementation of {@link InstalledCode} for HotSpot representing a {@code CodeBlob}. The address + * of the {@code CodeBlob} is stored in {@link InstalledCode#address}. */ public abstract class HotSpotInstalledCode extends InstalledCode { /** - * Total size of the code blob. + * Total size of the code blob (i.e. {@code CodeBlob::size()}). */ @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int size; /** - * Start address of the code. + * Start address of the code (i.e. {@code CodeBlob::code_begin()}). */ @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private long codeStart; /** - * Size of the code. + * Size of the code (i.e. {@code CodeBlob::code_size()}). */ @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int codeSize; @@ -52,7 +52,7 @@ } /** - * @return the total size of this code blob + * Gets the value of {@code CodeBlob::size()}. */ public int getSize() { return size; @@ -61,22 +61,25 @@ @Override public abstract String toString(); + /** + * Gets the value of {@code CodeBlob::code_begin()} if {@linkplain #isValid() valid}, 0 + * otherwise. + */ @Override public long getStart() { return codeStart; } + /** + * Gets the value of {@code CodeBlob::code_size()} if {@linkplain #isValid() valid}, 0 + * otherwise. + */ public long getCodeSize() { return codeSize; } @Override public byte[] getCode() { - if (!isValid()) { - return null; - } - byte[] code = new byte[codeSize]; - UNSAFE.copyMemory(null, codeStart, code, Unsafe.ARRAY_BYTE_BASE_OFFSET, codeSize); - return code; + return compilerToVM().getCode(this); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Executable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.HashMap; + +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Implementation of {@link HotSpotJVMCIReflection} in terms of standard JDK reflection API. This is + * only available when running in the HotSpot heap. + */ +final class HotSpotJDKReflection extends HotSpotJVMCIReflection { + + @Override + Object resolveObject(HotSpotObjectConstantImpl object) { + if (object == null) { + return null; + } + return ((DirectHotSpotObjectConstantImpl) object).object; + } + + @Override + boolean isInstance(HotSpotResolvedObjectTypeImpl holder, HotSpotObjectConstantImpl obj) { + Class javaMirror = getMirror(holder); + Object value = resolveObject(obj); + return javaMirror.isInstance(value); + } + + @Override + boolean isAssignableFrom(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedObjectTypeImpl otherType) { + Class javaMirror = getMirror(holder); + return javaMirror.isAssignableFrom(getMirror(otherType)); + + } + + @Override + Annotation[] getAnnotations(HotSpotResolvedObjectTypeImpl holder) { + Class javaMirror = getMirror(holder); + return javaMirror.getAnnotations(); + } + + @Override + Annotation[] getDeclaredAnnotations(HotSpotResolvedObjectTypeImpl holder) { + Class javaMirror = getMirror(holder); + return javaMirror.getDeclaredAnnotations(); + } + + @Override + T getAnnotation(HotSpotResolvedObjectTypeImpl holder, Class annotationClass) { + Class javaMirror = getMirror(holder); + return javaMirror.getAnnotation(annotationClass); + } + + @Override + boolean isLocalClass(HotSpotResolvedObjectTypeImpl holder) { + Class javaMirror = getMirror(holder); + return javaMirror.isLocalClass(); + } + + @Override + boolean isMemberClass(HotSpotResolvedObjectTypeImpl holder) { + Class javaMirror = getMirror(holder); + return javaMirror.isMemberClass(); + } + + @Override + HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder) { + Class javaMirror = getMirror(holder); + return (HotSpotResolvedObjectType) runtime().fromClass(javaMirror.getEnclosingClass()); + } + + @Override + JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile) { + Class javaMirror = getMirror(holder); + return readFieldValue(field, javaMirror, isVolatile); + } + + @Override + JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile) { + Object value = resolveObject(object); + return readFieldValue(field, value, isVolatile); + } + + @Override + boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) { + return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed(); + } + + @Override + JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType holder) { + return holder.mirror; + } + + @Override + ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { + java.lang.reflect.Parameter[] javaParameters = getMethod(javaMethod).getParameters(); + ResolvedJavaMethod.Parameter[] res = new ResolvedJavaMethod.Parameter[javaParameters.length]; + for (int i = 0; i < res.length; i++) { + java.lang.reflect.Parameter src = javaParameters[i]; + String paramName = src.isNamePresent() ? src.getName() : null; + res[i] = new ResolvedJavaMethod.Parameter(paramName, src.getModifiers(), javaMethod, i); + } + return res; + } + + @Override + Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + return getMethod(javaMethod).getParameterAnnotations(); + } + + @Override + Type[] getGenericParameterTypes(HotSpotResolvedJavaMethodImpl javaMethod) { + return getMethod(javaMethod).getGenericParameterTypes(); + } + + @Override + Annotation[] getFieldAnnotations(HotSpotResolvedJavaFieldImpl javaField) { + return getField(javaField).getAnnotations(); + } + + @Override + Annotation[] getMethodAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + return getMethod(javaMethod).getAnnotations(); + } + + @Override + Annotation[] getMethodDeclaredAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + return getMethod(javaMethod).getDeclaredAnnotations(); + } + + @Override + Annotation[] getFieldDeclaredAnnotations(HotSpotResolvedJavaFieldImpl javaField) { + return getField(javaField).getDeclaredAnnotations(); + } + + @Override + T getMethodAnnotation(HotSpotResolvedJavaMethodImpl javaMethod, Class annotationClass) { + return getMethod(javaMethod).getAnnotation(annotationClass); + } + + @Override + T getFieldAnnotation(HotSpotResolvedJavaFieldImpl javaField, Class annotationClass) { + return getField(javaField).getAnnotation(annotationClass); + } + + @Override + HotSpotResolvedObjectTypeImpl getType(HotSpotObjectConstantImpl object) { + Object value = resolveObject(object); + Class theClass = value.getClass(); + return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(theClass); + } + + @Override + String asString(HotSpotObjectConstantImpl object) { + Object value = resolveObject(object); + if (value instanceof String) { + return (String) value; + } + return null; + } + + @Override + ResolvedJavaType asJavaType(HotSpotObjectConstantImpl object) { + Object value = resolveObject(object); + if (value instanceof Class) { + Class javaClass = (Class) value; + return runtime().fromClass(javaClass); + } + if (value instanceof ResolvedJavaType) { + return (ResolvedJavaType) value; + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + T asObject(HotSpotObjectConstantImpl object, Class type) { + Object value = resolveObject(object); + if (type.isInstance(value)) { + return (T) value; + } + return null; + } + + @Override + Object asObject(HotSpotObjectConstantImpl object, HotSpotResolvedJavaType type) { + Object value = resolveObject(object); + if (getMirror(type).isInstance(value)) { + return value; + } + return null; + } + + @Override + String formatString(HotSpotObjectConstantImpl object) { + return JavaKind.Object.format(resolveObject(object)); + } + + @Override + Integer getLength(HotSpotObjectConstantImpl arrayObject) { + Object object = resolveObject(arrayObject); + if (object.getClass().isArray()) { + return Array.getLength(object); + } + return null; + } + + @Override + JavaConstant readArrayElement(HotSpotObjectConstantImpl arrayObject, int index) { + Object a = resolveObject(arrayObject); + if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) { + return null; + } + if (a instanceof Object[]) { + Object element = ((Object[]) a)[index]; + return forObject(element); + } else { + if (a instanceof int[]) { + return JavaConstant.forInt(((int[]) a)[index]); + } else if (a instanceof char[]) { + return JavaConstant.forChar(((char[]) a)[index]); + } else if (a instanceof byte[]) { + return JavaConstant.forByte(((byte[]) a)[index]); + } else if (a instanceof long[]) { + return JavaConstant.forLong(((long[]) a)[index]); + } else if (a instanceof short[]) { + return JavaConstant.forShort(((short[]) a)[index]); + } else if (a instanceof float[]) { + return JavaConstant.forFloat(((float[]) a)[index]); + } else if (a instanceof double[]) { + return JavaConstant.forDouble(((double[]) a)[index]); + } else if (a instanceof boolean[]) { + return JavaConstant.forBoolean(((boolean[]) a)[index]); + } else { + throw new JVMCIError("Should not reach here"); + } + } + } + + @Override + JavaConstant unboxPrimitive(HotSpotObjectConstantImpl source) { + return JavaConstant.forBoxedPrimitive(resolveObject(source)); + } + + @Override + JavaConstant forObject(Object value) { + if (value == null) { + return JavaConstant.NULL_POINTER; + } + return forNonNullObject(value); + } + + private static HotSpotObjectConstantImpl forNonNullObject(Object value) { + return DirectHotSpotObjectConstantImpl.forNonNullObject(value, false); + } + + @Override + JavaConstant boxPrimitive(JavaConstant source) { + return forNonNullObject(source.asBoxedPrimitive()); + } + + @Override + int getInt(HotSpotObjectConstantImpl object, long displacement) { + return UNSAFE.getInt((resolveObject(object)), displacement); + } + + @Override + byte getByte(HotSpotObjectConstantImpl object, long displacement) { + return UNSAFE.getByte(resolveObject(object), displacement); + } + + @Override + short getShort(HotSpotObjectConstantImpl object, long displacement) { + return UNSAFE.getShort(resolveObject(object), displacement); + } + + @Override + long getLong(HotSpotObjectConstantImpl object, long displacement) { + return UNSAFE.getLong(resolveObject(object), displacement); + } + + @Override + void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type) { + checkRead(kind, displacement, type, resolveObject(constant)); + } + + /** + * Offset of injected {@code java.lang.Class::oop_size} field. No need to make {@code volatile} + * as initialization is idempotent. + */ + private long oopSizeOffset; + + private static int computeOopSizeOffset(HotSpotJVMCIRuntime runtime) { + MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess(); + ResolvedJavaType staticType = metaAccess.lookupJavaType(Class.class); + for (ResolvedJavaField f : staticType.getInstanceFields(false)) { + if (f.getName().equals("oop_size")) { + int offset = f.getOffset(); + assert offset != 0 : "not expecting offset of java.lang.Class::oop_size to be 0"; + return offset; + } + } + throw new JVMCIError("Could not find injected java.lang.Class::oop_size field"); + } + + long oopSizeOffset() { + if (oopSizeOffset == 0) { + oopSizeOffset = computeOopSizeOffset(runtime()); + } + return oopSizeOffset; + } + + private boolean checkRead(JavaKind kind, long displacement, HotSpotResolvedObjectType type, Object object) { + if (type.isArray()) { + ResolvedJavaType componentType = type.getComponentType(); + JavaKind componentKind = componentType.getJavaKind(); + final int headerSize = runtime().getArrayBaseOffset(componentKind); + int sizeOfElement = runtime().getArrayIndexScale(componentKind); + int length = Array.getLength(object); + long arrayEnd = headerSize + (sizeOfElement * length); + boolean aligned = ((displacement - headerSize) % sizeOfElement) == 0; + if (displacement < 0 || displacement > (arrayEnd - sizeOfElement) || (kind == JavaKind.Object && !aligned)) { + int index = (int) ((displacement - headerSize) / sizeOfElement); + throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind + + " at offset " + displacement + " (index ~ " + index + ") in " + + type.toJavaName() + " object of length " + length); + } + } else if (kind != JavaKind.Object) { + long size; + if (object instanceof Class) { + int wordSize = runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize; + size = UNSAFE.getInt(object, oopSizeOffset()) * wordSize; + } else { + size = Math.abs(type.instanceSize()); + } + int bytesToRead = kind.getByteCount(); + if (displacement + bytesToRead > size || displacement < 0) { + throw new IllegalArgumentException("Unsafe access: reading " + bytesToRead + " bytes at offset " + displacement + " in " + + type.toJavaName() + " object of size " + size); + } + } else { + ResolvedJavaField field = null; + if (object instanceof Class) { + // Read of a static field + HotSpotResolvedJavaType hotSpotResolvedJavaType = runtime().fromClass((Class) object); + if (hotSpotResolvedJavaType instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) hotSpotResolvedJavaType; + field = staticFieldsHolder.findStaticFieldWithOffset(displacement, JavaKind.Object); + } + } + if (field == null) { + field = type.findInstanceFieldWithOffset(displacement, JavaKind.Object); + } + if (field == null) { + throw new IllegalArgumentException("Unsafe object access: field not found for read of kind Object" + + " at offset " + displacement + " in " + type.toJavaName() + " object"); + } + if (field.getJavaKind() != JavaKind.Object) { + throw new IllegalArgumentException("Unsafe object access: field " + field.format("%H.%n:%T") + " not of expected kind Object" + + " at offset " + displacement + " in " + type.toJavaName() + " object"); + } + } + return true; + } + + JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean isVolatile) { + assert obj != null; + assert !field.isStatic() || obj instanceof Class; + long displacement = field.getOffset(); + + assert checkRead(field.getJavaKind(), displacement, + (HotSpotResolvedObjectType) runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(field.isStatic() ? (Class) obj : obj.getClass()), + obj); + JavaKind kind = field.getJavaKind(); + switch (kind) { + case Boolean: + return JavaConstant.forBoolean(isVolatile ? UNSAFE.getBooleanVolatile(obj, displacement) : UNSAFE.getBoolean(obj, displacement)); + case Byte: + return JavaConstant.forByte(isVolatile ? UNSAFE.getByteVolatile(obj, displacement) : UNSAFE.getByte(obj, displacement)); + case Char: + return JavaConstant.forChar(isVolatile ? UNSAFE.getCharVolatile(obj, displacement) : UNSAFE.getChar(obj, displacement)); + case Short: + return JavaConstant.forShort(isVolatile ? UNSAFE.getShortVolatile(obj, displacement) : UNSAFE.getShort(obj, displacement)); + case Int: + return JavaConstant.forInt(isVolatile ? UNSAFE.getIntVolatile(obj, displacement) : UNSAFE.getInt(obj, displacement)); + case Long: + return JavaConstant.forLong(isVolatile ? UNSAFE.getLongVolatile(obj, displacement) : UNSAFE.getLong(obj, displacement)); + case Float: + return JavaConstant.forFloat(isVolatile ? UNSAFE.getFloatVolatile(obj, displacement) : UNSAFE.getFloat(obj, displacement)); + case Double: + return JavaConstant.forDouble(isVolatile ? UNSAFE.getDoubleVolatile(obj, displacement) : UNSAFE.getDouble(obj, displacement)); + case Object: + return forObject(isVolatile ? UNSAFE.getReferenceVolatile(obj, displacement) : UNSAFE.getReference(obj, displacement)); + default: + throw new IllegalArgumentException("Unsupported kind: " + kind); + + } + } + + /** + * Gets a {@link Method} object corresponding to {@code method}. This method guarantees the same + * {@link Method} object is returned if called twice on the same {@code method} value. + */ + private static Executable getMethod(HotSpotResolvedJavaMethodImpl method) { + assert !method.isClassInitializer() : method; + if (method.toJavaCache == null) { + synchronized (method) { + if (method.toJavaCache == null) { + method.toJavaCache = compilerToVM().asReflectionExecutable(method); + } + } + } + return method.toJavaCache; + } + + /** + * Gets a {@link Field} object corresponding to {@code field}. This method guarantees the same + * {@link Field} object is returned if called twice on the same {@code field} value. This is + * required to ensure the results of {@link HotSpotResolvedJavaFieldImpl#getAnnotations()} and + * {@link HotSpotResolvedJavaFieldImpl#getAnnotation(Class)} are stable (i.e., for a given field + * {@code f} and annotation class {@code a}, the same object is returned for each call to + * {@code f.getAnnotation(a)}). + */ + private static Field getField(HotSpotResolvedJavaFieldImpl field) { + HotSpotResolvedObjectTypeImpl declaringClass = field.getDeclaringClass(); + synchronized (declaringClass) { + HashMap cache = declaringClass.reflectionFieldCache; + if (cache == null) { + cache = new HashMap<>(); + declaringClass.reflectionFieldCache = cache; + } + Field reflect = cache.get(field); + if (reflect == null) { + reflect = compilerToVM().asReflectionField(field.getDeclaringClass(), field.getIndex()); + cache.put(field, reflect); + } + return reflect; + } + } + + Class getMirror(HotSpotResolvedObjectTypeImpl holder) { + return (Class) resolveObject((HotSpotObjectConstantImpl) holder.getJavaMirror()); + } + + Class getMirror(HotSpotResolvedJavaType type) { + assert type != null; + if (type instanceof HotSpotResolvedPrimitiveType) { + return (Class) resolveObject(((HotSpotResolvedPrimitiveType) type).mirror); + } else { + return getMirror((HotSpotResolvedObjectTypeImpl) type); + } + } +} + diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,12 @@ */ package jdk.vm.ci.hotspot; +import java.util.List; import java.util.Set; import jdk.vm.ci.code.CompilationRequest; import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; import jdk.vm.ci.runtime.JVMCICompiler; import jdk.vm.ci.runtime.JVMCICompilerFactory; @@ -33,6 +35,8 @@ import jdk.vm.ci.services.JVMCIPermission; import jdk.vm.ci.services.JVMCIServiceLocator; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; + final class HotSpotJVMCICompilerConfig { /** @@ -61,7 +65,7 @@ /** * Factory of the selected system compiler. */ - private static JVMCICompilerFactory compilerFactory; + @NativeImageReinitialize private static JVMCICompilerFactory compilerFactory; /** * Gets the selected system compiler factory. @@ -78,7 +82,7 @@ if (compilerName.isEmpty() || compilerName.equals("null")) { factory = new DummyCompilerFactory(); } else { - for (JVMCICompilerFactory f : JVMCIServiceLocator.getProviders(JVMCICompilerFactory.class)) { + for (JVMCICompilerFactory f : getJVMCICompilerFactories()) { if (f.getCompilerName().equals(compilerName)) { factory = f; } @@ -89,7 +93,7 @@ } } else { // Auto select a single available compiler - for (JVMCICompilerFactory f : JVMCIServiceLocator.getProviders(JVMCICompilerFactory.class)) { + for (JVMCICompilerFactory f : getJVMCICompilerFactories()) { if (factory == null) { openJVMCITo(f.getClass().getModule()); factory = f; @@ -113,15 +117,21 @@ * Opens all JVMCI packages to {@code otherModule}. */ private static void openJVMCITo(Module otherModule) { - Module jvmci = HotSpotJVMCICompilerConfig.class.getModule(); - if (jvmci != otherModule) { - Set packages = jvmci.getPackages(); - for (String pkg : packages) { - boolean opened = jvmci.isOpen(pkg, otherModule); - if (!opened) { - jvmci.addOpens(pkg, otherModule); + if (!IS_IN_NATIVE_IMAGE) { + Module jvmci = HotSpotJVMCICompilerConfig.class.getModule(); + if (jvmci != otherModule) { + Set packages = jvmci.getPackages(); + for (String pkg : packages) { + boolean opened = jvmci.isOpen(pkg, otherModule); + if (!opened) { + jvmci.addOpens(pkg, otherModule); + } } } } } + + private static List getJVMCICompilerFactories() { + return JVMCIServiceLocator.getProviders(JVMCICompilerFactory.class); + } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java Wed May 01 12:41:26 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.hotspot; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.Arrays; -import java.util.Iterator; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * This class manages the set of metadata roots that must be scanned during garbage collection. - * Because of class redefinition Method* and ConstantPool* can be freed if they don't appear to be - * in use so they must be tracked when there are live references to them from Java. - * - * The general theory of operation is that all {@link MetaspaceWrapperObject}s are created by - * calling into the VM which calls back out to actually create the wrapper instance. During the call - * the VM keeps the metadata reference alive through the use of metadata handles. Once the call - * completes the wrapper object is registered here and will be scanned during metadata scanning. The - * weakness of the reference to the wrapper object allows them to be reclaimed when they are no - * longer used. - * - */ -class HotSpotJVMCIMetaAccessContext { - - /** - * The set of currently live contexts used for tracking of live metadata. Examined from the VM - * during garbage collection. - */ - private static WeakReference[] allContexts = new WeakReference[0]; - - /** - * This is a chunked list of metadata roots. It can be read from VM native code so it's been - * marked volatile to ensure the order of updates are respected. - */ - private volatile Object[] metadataRoots; - - private ChunkedList> list = new ChunkedList<>(); - - /** - * The number of weak references freed since the last time the list was shrunk. - */ - private int freed; - - /** - * The {@link ReferenceQueue} tracking the weak references created by this context. - */ - private final ReferenceQueue queue = new ReferenceQueue<>(); - - static synchronized void add(HotSpotJVMCIMetaAccessContext context) { - for (int i = 0; i < allContexts.length; i++) { - if (allContexts[i] == null || allContexts[i].get() == null) { - allContexts[i] = new WeakReference<>(context); - return; - } - } - int index = allContexts.length; - allContexts = Arrays.copyOf(allContexts, index + 2); - allContexts[index] = new WeakReference<>(context); - } - - HotSpotJVMCIMetaAccessContext() { - add(this); - } - - /** - * Periodically trim the list of tracked metadata. A new list is created to replace the old to - * avoid concurrent scanning issues. - */ - private void clean() { - Reference ref = queue.poll(); - if (ref == null) { - return; - } - while (ref != null) { - freed++; - ref = queue.poll(); - } - if (freed > list.size() / 2) { - ChunkedList> newList = new ChunkedList<>(); - for (WeakReference element : list) { - /* - * The referent could become null anywhere in here but it doesn't matter. It will - * get cleaned up next time. - */ - if (element != null && element.get() != null) { - newList.add(element); - } - } - list = newList; - metadataRoots = list.getHead(); - freed = 0; - } - } - - /** - * Add a {@link MetaspaceWrapperObject} to tracked by the GC. It's assumed that the caller is - * responsible for keeping the reference alive for the duration of the call. Once registration - * is complete then the VM will ensure it's kept alive. - * - * @param metaspaceObject - */ - - public synchronized void add(MetaspaceWrapperObject metaspaceObject) { - clean(); - list.add(new WeakReference<>(metaspaceObject, queue)); - if (list.getHead() != metadataRoots) { - /* - * The list enlarged so update the head. - */ - metadataRoots = list.getHead(); - } - assert isRegistered(metaspaceObject); - } - - protected ResolvedJavaType createClass(Class javaClass) { - if (javaClass.isPrimitive()) { - JavaKind kind = JavaKind.fromJavaClass(javaClass); - return new HotSpotResolvedPrimitiveType(kind); - } else { - return new HotSpotResolvedObjectTypeImpl(javaClass, this); - } - } - - private final ClassValue> resolvedJavaType = new ClassValue<>() { - @Override - protected WeakReference computeValue(Class type) { - return new WeakReference<>(createClass(type)); - } - }; - - /** - * Gets the JVMCI mirror for a {@link Class} object. - * - * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} - */ - public ResolvedJavaType fromClass(Class javaClass) { - ResolvedJavaType javaType = null; - while (javaType == null) { - WeakReference type = resolvedJavaType.get(javaClass); - javaType = type.get(); - if (javaType == null) { - /* - * If the referent has become null, clear out the current value and let computeValue - * above create a new value. Reload the value in a loop because in theory the - * WeakReference referent can be reclaimed at any point. - */ - resolvedJavaType.remove(javaClass); - } - } - return javaType; - } - - /** - * A very simple append only chunked list implementation. - */ - static class ChunkedList implements Iterable { - private static final int CHUNK_SIZE = 32; - - private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1; - - private Object[] head; - private int index; - private int size; - - ChunkedList() { - head = new Object[CHUNK_SIZE]; - index = 0; - } - - void add(T element) { - if (index == NEXT_CHUNK_INDEX) { - Object[] newHead = new Object[CHUNK_SIZE]; - newHead[index] = head; - head = newHead; - index = 0; - } - head[index++] = element; - size++; - } - - Object[] getHead() { - return head; - } - - @Override - public Iterator iterator() { - return new ChunkIterator<>(); - } - - int size() { - return size; - } - - class ChunkIterator implements Iterator { - - ChunkIterator() { - currentChunk = head; - currentIndex = -1; - next = findNext(); - } - - Object[] currentChunk; - int currentIndex; - V next; - - @SuppressWarnings("unchecked") - V findNext() { - V result; - do { - currentIndex++; - if (currentIndex == NEXT_CHUNK_INDEX) { - currentChunk = (Object[]) currentChunk[currentIndex]; - currentIndex = 0; - if (currentChunk == null) { - return null; - } - } - result = (V) currentChunk[currentIndex]; - } while (result == null); - return result; - } - - @Override - public boolean hasNext() { - return next != null; - } - - @Override - public V next() { - V result = next; - next = findNext(); - return result; - } - - } - - } - - synchronized boolean isRegistered(MetaspaceWrapperObject wrapper) { - for (WeakReference m : list) { - if (m != null && m.get() == wrapper) { - return true; - } - } - return false; - } -} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Reflection interface for reflecting on the internals of HotSpot JVMCI types and objects. + */ +abstract class HotSpotJVMCIReflection { + + abstract boolean isInstance(HotSpotResolvedObjectTypeImpl holder, HotSpotObjectConstantImpl obj); + + abstract boolean isAssignableFrom(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedObjectTypeImpl otherType); + + abstract Annotation[] getAnnotations(HotSpotResolvedObjectTypeImpl holder); + + abstract Annotation[] getDeclaredAnnotations(HotSpotResolvedObjectTypeImpl holder); + + abstract T getAnnotation(HotSpotResolvedObjectTypeImpl holder, Class annotationClass); + + abstract boolean isLocalClass(HotSpotResolvedObjectTypeImpl holder); + + abstract boolean isMemberClass(HotSpotResolvedObjectTypeImpl holder); + + abstract HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder); + + abstract JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile); + + abstract JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile); + + abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that); + + abstract JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType hotSpotResolvedJavaType); + + abstract ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod); + + abstract Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod); + + abstract Type[] getGenericParameterTypes(HotSpotResolvedJavaMethodImpl javaMethod); + + abstract Annotation[] getFieldAnnotations(HotSpotResolvedJavaFieldImpl javaMethod); + + abstract Annotation[] getMethodAnnotations(HotSpotResolvedJavaMethodImpl javaField); + + abstract Annotation[] getMethodDeclaredAnnotations(HotSpotResolvedJavaMethodImpl javaMethod); + + abstract Annotation[] getFieldDeclaredAnnotations(HotSpotResolvedJavaFieldImpl javaMethod); + + abstract T getMethodAnnotation(HotSpotResolvedJavaMethodImpl javaMethod, Class annotationClass); + + abstract HotSpotResolvedObjectTypeImpl getType(HotSpotObjectConstantImpl object); + + abstract String asString(HotSpotObjectConstantImpl object); + + /** + * Given a {@link java.lang.Class} instance, return the corresponding ResolvedJavaType. + */ + abstract ResolvedJavaType asJavaType(HotSpotObjectConstantImpl object); + + abstract T asObject(HotSpotObjectConstantImpl object, Class type); + + abstract Object asObject(HotSpotObjectConstantImpl object, HotSpotResolvedJavaType type); + + abstract String formatString(HotSpotObjectConstantImpl object); + + abstract Integer getLength(HotSpotObjectConstantImpl arrayObject); + + abstract JavaConstant readArrayElement(HotSpotObjectConstantImpl arrayObject, int index); + + abstract JavaConstant unboxPrimitive(HotSpotObjectConstantImpl source); + + abstract JavaConstant forObject(Object value); + + abstract JavaConstant boxPrimitive(JavaConstant source); + + abstract int getInt(HotSpotObjectConstantImpl object, long displacement); + + abstract byte getByte(HotSpotObjectConstantImpl object, long displacement); + + abstract short getShort(HotSpotObjectConstantImpl object, long displacement); + + abstract long getLong(HotSpotObjectConstantImpl object, long displacement); + + abstract void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type); + + abstract T getFieldAnnotation(HotSpotResolvedJavaFieldImpl javaField, Class annotationClass); + + /** + * Resolves {@code objectHandle} to a raw object if possible. + * + * @throws HotSpotJVMCIUnsupportedOperationError if {@code objectHandle} refers to an object in + * another heap + */ + abstract Object resolveObject(HotSpotObjectConstantImpl objectHandle); +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Wed May 01 12:31:29 2019 -0700 @@ -23,11 +23,22 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.common.InitTimer.timer; +import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None; +import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; +import java.io.Serializable; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandle; import java.lang.module.ModuleDescriptor.Requires; +import java.lang.ref.WeakReference; + +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -35,11 +46,11 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; -import java.util.Set; +import java.util.TreeMap; import java.util.function.Predicate; -import jdk.internal.misc.VM; import jdk.internal.misc.Unsafe; + import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.CompilationRequestResult; import jdk.vm.ci.code.CompiledCode; @@ -57,44 +68,144 @@ import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.runtime.JVMCIRuntime; import jdk.vm.ci.services.JVMCIServiceLocator; - -import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None; +import jdk.vm.ci.services.Services; /** * HotSpot implementation of a JVMCI runtime. - * - * The initialization of this class is very fragile since it's initialized both through - * {@link JVMCI#initialize()} or through calling {@link HotSpotJVMCIRuntime#runtime()} and - * {@link HotSpotJVMCIRuntime#runtime()} is also called by {@link JVMCI#initialize()}. So this class - * can't have a static initializer and any required initialization must be done as part of - * {@link #runtime()}. This allows the initialization to funnel back through - * {@link JVMCI#initialize()} without deadlocking. */ public final class HotSpotJVMCIRuntime implements JVMCIRuntime { - @SuppressWarnings("try") - static class DelayedInit { - private static final HotSpotJVMCIRuntime instance; + /** + * Singleton instance lazily initialized via double-checked locking. + */ + @NativeImageReinitialize private static volatile HotSpotJVMCIRuntime instance; + + private HotSpotResolvedObjectTypeImpl javaLangObject; + private HotSpotResolvedObjectTypeImpl javaLangInvokeMethodHandle; + private HotSpotResolvedObjectTypeImpl constantCallSiteType; + private HotSpotResolvedObjectTypeImpl callSiteType; + private HotSpotResolvedObjectTypeImpl javaLangString; + private HotSpotResolvedObjectTypeImpl javaLangClass; + private HotSpotResolvedObjectTypeImpl throwableType; + private HotSpotResolvedObjectTypeImpl serializableType; + private HotSpotResolvedObjectTypeImpl cloneableType; + private HotSpotResolvedObjectTypeImpl enumType; - static { - try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { - instance = new HotSpotJVMCIRuntime(); + HotSpotResolvedObjectTypeImpl getJavaLangObject() { + if (javaLangObject == null) { + javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class); + } + return javaLangObject; + } + + HotSpotResolvedObjectTypeImpl getJavaLangString() { + if (javaLangString == null) { + javaLangString = (HotSpotResolvedObjectTypeImpl) fromClass(String.class); + } + return javaLangString; + } + + HotSpotResolvedObjectTypeImpl getJavaLangClass() { + if (javaLangClass == null) { + javaLangClass = (HotSpotResolvedObjectTypeImpl) fromClass(Class.class); + } + return javaLangClass; + } - // Can only do eager initialization of the JVMCI compiler - // once the singleton instance is available. - if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { - instance.getCompiler(); - } - } + HotSpotResolvedObjectTypeImpl getJavaLangCloneable() { + if (cloneableType == null) { + cloneableType = (HotSpotResolvedObjectTypeImpl) fromClass(Cloneable.class); + } + return cloneableType; + } + + HotSpotResolvedObjectTypeImpl getJavaLangSerializable() { + if (serializableType == null) { + serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class); + } + return serializableType; + } + + HotSpotResolvedObjectTypeImpl getJavaLangThrowable() { + if (throwableType == null) { + throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class); } + return throwableType; + } + + HotSpotResolvedObjectTypeImpl getJavaLangEnum() { + if (enumType == null) { + enumType = (HotSpotResolvedObjectTypeImpl) fromClass(Enum.class); + } + return enumType; + } + + HotSpotResolvedObjectTypeImpl getConstantCallSite() { + if (constantCallSiteType == null) { + constantCallSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(ConstantCallSite.class); + } + return constantCallSiteType; + } + + HotSpotResolvedObjectTypeImpl getCallSite() { + if (callSiteType == null) { + callSiteType = (HotSpotResolvedObjectTypeImpl) fromClass(CallSite.class); + } + return callSiteType; + } + + HotSpotResolvedObjectType getMethodHandleClass() { + if (javaLangInvokeMethodHandle == null) { + javaLangInvokeMethodHandle = (HotSpotResolvedObjectTypeImpl) fromClass(MethodHandle.class); + } + return javaLangInvokeMethodHandle; } /** * Gets the singleton {@link HotSpotJVMCIRuntime} object. */ + @VMEntryPoint + @SuppressWarnings("try") public static HotSpotJVMCIRuntime runtime() { - JVMCI.initialize(); - return DelayedInit.instance; + HotSpotJVMCIRuntime result = instance; + if (result == null) { + // Synchronize on JVMCI.class to avoid deadlock + // between the two JVMCI initialization paths: + // HotSpotJVMCIRuntime.runtime() and JVMCI.getRuntime(). + synchronized (JVMCI.class) { + result = instance; + if (result == null) { + try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { + instance = result = new HotSpotJVMCIRuntime(); + + // Can only do eager initialization of the JVMCI compiler + // once the singleton instance is available. + if (instance.config.getFlag("EagerJVMCI", Boolean.class)) { + instance.getCompiler(); + } + } + // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is + // initialized. + JVMCI.getRuntime(); + } + } + } + return result; + } + + @VMEntryPoint + static Throwable decodeThrowable(String encodedThrowable) throws Throwable { + return TranslatedException.decodeThrowable(encodedThrowable); + } + + @VMEntryPoint + static String encodeThrowable(Throwable throwable) throws Throwable { + return TranslatedException.encodeThrowable(throwable); + } + + @VMEntryPoint + static String callToString(Object o) { + return o.toString(); } /** @@ -103,17 +214,17 @@ public enum Option { // @formatter:off Compiler(String.class, null, "Selects the system compiler. This must match the getCompilerName() value returned " + - "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " + - "An empty string or the value \"null\" selects a compiler " + - "that will raise an exception upon receiving a compilation request."), + "by a jdk.vm.ci.runtime.JVMCICompilerFactory provider. " + + "An empty string or the value \"null\" selects a compiler " + + "that will raise an exception upon receiving a compilation request."), // Note: The following one is not used (see InitTimer.ENABLED). It is added here // so that -XX:+JVMCIPrintProperties shows the option. InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), TraceMethodDataFilter(String.class, null, - "Enables tracing of profiling info when read by JVMCI.", - "Empty value: trace all methods", - "Non-empty value: trace methods whose fully qualified name contains the value."), + "Enables tracing of profiling info when read by JVMCI.", + "Empty value: trace all methods", + "Non-empty value: trace methods whose fully qualified name contains the value."), UseProfilingInformation(Boolean.class, true, ""); // @formatter:on @@ -123,12 +234,12 @@ private static final String JVMCI_OPTION_PROPERTY_PREFIX = "jvmci."; /** - * Marker for uninitialized flags. + * Sentinel for value initialized to {@code null} since {@code null} means uninitialized. */ - private static final String UNINITIALIZED = "UNINITIALIZED"; + private static final String NULL_VALUE = "NULL"; private final Class type; - private Object value; + @NativeImageReinitialize private Object value; private final Object defaultValue; private boolean isDefault; private final String[] helpLines; @@ -136,17 +247,16 @@ Option(Class type, Object defaultValue, String... helpLines) { assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name(); this.type = type; - this.value = UNINITIALIZED; this.defaultValue = defaultValue; this.helpLines = helpLines; } @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum") private Object getValue() { - if (value == UNINITIALIZED) { - String propertyValue = VM.getSavedProperty(getPropertyName()); + if (value == null) { + String propertyValue = Services.getSavedProperty(getPropertyName()); if (propertyValue == null) { - this.value = defaultValue; + this.value = defaultValue == null ? NULL_VALUE : defaultValue; this.isDefault = true; } else { if (type == Boolean.class) { @@ -158,10 +268,8 @@ } this.isDefault = false; } - // Saved properties should not be interned - let's be sure - assert value != UNINITIALIZED; } - return value; + return value == NULL_VALUE ? null : value; } /** @@ -224,8 +332,10 @@ } } - static HotSpotJVMCIBackendFactory findFactory(String architecture) { - for (HotSpotJVMCIBackendFactory factory : ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader())) { + private static HotSpotJVMCIBackendFactory findFactory(String architecture) { + Iterable factories = getHotSpotJVMCIBackendFactories(); +assert factories != null : "sanity"; + for (HotSpotJVMCIBackendFactory factory : factories) { if (factory.getArchitecture().equalsIgnoreCase(architecture)) { return factory; } @@ -234,6 +344,23 @@ throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); } + private static volatile List cachedHotSpotJVMCIBackendFactories; + + @SuppressFBWarnings(value = "LI_LAZY_INIT_UPDATE_STATIC", justification = "not sure about this") + private static Iterable getHotSpotJVMCIBackendFactories() { + if (IS_IN_NATIVE_IMAGE || cachedHotSpotJVMCIBackendFactories != null) { + return cachedHotSpotJVMCIBackendFactories; + } + Iterable result = ServiceLoader.load(HotSpotJVMCIBackendFactory.class, ClassLoader.getSystemClassLoader()); + if (IS_BUILDING_NATIVE_IMAGE) { + cachedHotSpotJVMCIBackendFactories = new ArrayList<>(); + for (HotSpotJVMCIBackendFactory factory : result) { + cachedHotSpotJVMCIBackendFactories.add(factory); + } + } + return result; + } + /** * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. */ @@ -241,22 +368,32 @@ return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind; } - final CompilerToVM compilerToVm; + protected final CompilerToVM compilerToVm; protected final HotSpotVMConfigStore configStore; - private final HotSpotVMConfig config; + protected final HotSpotVMConfig config; private final JVMCIBackend hostBackend; private final JVMCICompilerFactory compilerFactory; private final HotSpotJVMCICompilerFactory hsCompilerFactory; private volatile JVMCICompiler compiler; - final HotSpotJVMCIMetaAccessContext metaAccessContext; + protected final HotSpotJVMCIReflection reflection; + + @NativeImageReinitialize private volatile boolean creatingCompiler; + + /** + * Cache for speeding up {@link #fromClass(Class)}. + */ + @NativeImageReinitialize private volatile ClassValue> resolvedJavaType; + + @NativeImageReinitialize private HashMap> resolvedJavaTypes; /** * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can * be read from the VM. */ - @SuppressWarnings("unused") @NativeImageReinitialize private Module[] excludeFromJVMCICompilation; + @SuppressWarnings("unused")// + @NativeImageReinitialize private Module[] excludeFromJVMCICompilation; private final Map, JVMCIBackend> backends = new HashMap<>(); @@ -283,6 +420,16 @@ config = new HotSpotVMConfig(configStore); } + reflection = IS_IN_NATIVE_IMAGE ? new SharedLibraryJVMCIReflection() : new HotSpotJDKReflection(); + + PrintStream vmLogStream = null; + if (IS_IN_NATIVE_IMAGE) { + // Redirect System.out and System.err to HotSpot's TTY stream + vmLogStream = new PrintStream(getLogStream()); + System.setOut(vmLogStream); + System.setErr(vmLogStream); + } + String hostArchitecture = config.getHostArchitectureName(); HotSpotJVMCIBackendFactory factory; @@ -294,8 +441,6 @@ hostBackend = registerBackend(factory.createJVMCIBackend(this, null)); } - metaAccessContext = new HotSpotJVMCIMetaAccessContext(); - compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); if (compilerFactory instanceof HotSpotJVMCICompilerFactory) { hsCompilerFactory = (HotSpotJVMCICompilerFactory) compilerFactory; @@ -310,15 +455,89 @@ } if (config.getFlag("JVMCIPrintProperties", Boolean.class)) { - PrintStream out = new PrintStream(getLogStream()); - Option.printProperties(out); - compilerFactory.printProperties(out); + if (vmLogStream == null) { + vmLogStream = new PrintStream(getLogStream()); + } + Option.printProperties(vmLogStream); + compilerFactory.printProperties(vmLogStream); System.exit(0); } if (Option.PrintConfig.getBoolean()) { - configStore.printConfig(); + printConfig(configStore, compilerToVm); + } + } + + HotSpotResolvedJavaType createClass(Class javaClass) { + if (javaClass.isPrimitive()) { + return HotSpotResolvedPrimitiveType.forKind(JavaKind.fromJavaClass(javaClass)); + } + if (IS_IN_NATIVE_IMAGE) { + try { + return compilerToVm.lookupType(javaClass.getName().replace('.', '/'), null, true); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } + } + return compilerToVm.lookupClass(javaClass); + } + + private HotSpotResolvedJavaType fromClass0(Class javaClass) { + if (resolvedJavaType == null) { + synchronized (this) { + if (resolvedJavaType == null) { + resolvedJavaType = new ClassValue>() { + @Override + protected WeakReference computeValue(Class type) { + return new WeakReference<>(createClass(type)); + } + }; + } + } } + HotSpotResolvedJavaType javaType = null; + while (javaType == null) { + WeakReference type = resolvedJavaType.get(javaClass); + javaType = type.get(); + if (javaType == null) { + /* + * If the referent has become null, clear out the current value and let computeValue + * above create a new value. Reload the value in a loop because in theory the + * WeakReference referent can be reclaimed at any point. + */ + resolvedJavaType.remove(javaClass); + } + } + return javaType; + } + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + HotSpotResolvedJavaType fromClass(Class javaClass) { + if (javaClass == null) { + return null; + } + return fromClass0(javaClass); + } + + synchronized HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) { + if (resolvedJavaTypes == null) { + resolvedJavaTypes = new HashMap<>(); + } + assert klassPointer != 0; + WeakReference klassReference = resolvedJavaTypes.get(klassPointer); + HotSpotResolvedObjectTypeImpl javaType = null; + if (klassReference != null) { + javaType = (HotSpotResolvedObjectTypeImpl) klassReference.get(); + } + if (javaType == null) { + javaType = new HotSpotResolvedObjectTypeImpl(klassPointer, signature); + resolvedJavaTypes.put(klassPointer, new WeakReference<>(javaType)); + } + return javaType; } private JVMCIBackend registerBackend(JVMCIBackend backend) { @@ -328,24 +547,21 @@ return backend; } - ResolvedJavaType fromClass(Class javaClass) { - return metaAccessContext.fromClass(javaClass); - } - public HotSpotVMConfigStore getConfigStore() { return configStore; } - HotSpotVMConfig getConfig() { + public HotSpotVMConfig getConfig() { return config; } - CompilerToVM getCompilerToVM() { + public CompilerToVM getCompilerToVM() { return compilerToVm; } - // Non-volatile since multi-initialization is harmless - private Predicate intrinsificationTrustPredicate; + HotSpotJVMCIReflection getReflection() { + return reflection; + } /** * Gets a predicate that determines if a given type can be considered trusted for the purpose of @@ -355,47 +571,17 @@ * compiler. */ public Predicate getIntrinsificationTrustPredicate(Class... compilerLeafClasses) { - if (intrinsificationTrustPredicate == null) { - intrinsificationTrustPredicate = new Predicate<>() { - @Override - public boolean test(ResolvedJavaType type) { - if (type instanceof HotSpotResolvedJavaType) { - Class mirror = getMirror(type); - Module module = mirror.getModule(); - return getTrustedModules().contains(module); - } else { - return false; - } + return new Predicate() { + @Override + public boolean test(ResolvedJavaType type) { + if (type instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl hsType = (HotSpotResolvedObjectTypeImpl) type; + return compilerToVm.isTrustedForIntrinsics(hsType); + } else { + return false; } - - private volatile Set trustedModules; - - private Set getTrustedModules() { - Set modules = trustedModules; - if (modules == null) { - modules = new HashSet<>(); - for (Class compilerConfiguration : compilerLeafClasses) { - Module compilerConfigurationModule = compilerConfiguration.getModule(); - if (compilerConfigurationModule.getDescriptor().isAutomatic()) { - throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module", - compilerConfigurationModule.getName(), compilerConfiguration.getClass().getName())); - } - modules.add(compilerConfigurationModule); - for (Requires require : compilerConfigurationModule.getDescriptor().requires()) { - for (Module module : compilerConfigurationModule.getLayer().modules()) { - if (module.getName().equals(require.name())) { - modules.add(module); - } - } - } - } - trustedModules = modules; - } - return modules; - } - }; - } - return intrinsificationTrustPredicate; + } + }; } /** @@ -406,9 +592,11 @@ * does not support mapping {@link ResolvedJavaType} instances to {@link Class} * instances */ - @SuppressWarnings("static-method") public Class getMirror(ResolvedJavaType type) { - return ((HotSpotResolvedJavaType) type).mirror(); + if (type instanceof HotSpotResolvedJavaType && reflection instanceof HotSpotJDKReflection) { + return ((HotSpotJDKReflection) reflection).getMirror((HotSpotResolvedJavaType) type); + } + return null; } @Override @@ -416,7 +604,10 @@ if (compiler == null) { synchronized (this) { if (compiler == null) { + assert !creatingCompiler : "recursive compiler creation"; + creatingCompiler = true; compiler = compilerFactory.createCompiler(this); + creatingCompiler = false; } } } @@ -438,19 +629,23 @@ */ public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); + return lookupTypeInternal(name, accessingType, resolve); + } + + JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { // If the name represents a primitive type we can short-circuit the lookup. if (name.length() == 1) { JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); - return fromClass(kind.toJavaClass()); + return HotSpotResolvedPrimitiveType.forKind(kind); } // Resolve non-primitive types in the VM. HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; try { - final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + final HotSpotResolvedJavaType klass = compilerToVm.lookupType(name, hsAccessingType, resolve); if (klass == null) { - assert resolve == false; + assert resolve == false : name; return UnresolvedJavaType.create(name); } return klass; @@ -474,12 +669,9 @@ return Collections.unmodifiableMap(backends); } - /** - * Called from the VM. - */ - @SuppressWarnings({"unused"}) - private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { - CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, jvmciEnv, id)); + @VMEntryPoint + private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) { + CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, compileState, id)); assert result != null : "compileMethod must always return something"; HotSpotCompilationRequestResult hsResult; if (result instanceof HotSpotCompilationRequestResult) { @@ -500,11 +692,13 @@ /** * Shuts down the runtime. - * - * Called from the VM. */ - @SuppressWarnings({"unused"}) + @VMEntryPoint private void shutdown() throws Exception { + // Cleaners are normally only processed when a new Cleaner is + // instantiated so process all remaining cleaners now. + Cleaner.clean(); + for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { vmEventListener.notifyShutdown(); } @@ -512,10 +706,8 @@ /** * Notify on completion of a bootstrap. - * - * Called from the VM. */ - @SuppressWarnings({"unused"}) + @VMEntryPoint private void bootstrapFinished() throws Exception { for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { vmEventListener.notifyBootstrapFinished(); @@ -535,6 +727,41 @@ } } + @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!") + private static void printConfigLine(CompilerToVM vm, String format, Object... args) { + String line = String.format(format, args); + byte[] lineBytes = line.getBytes(); + vm.writeDebugOutput(lineBytes, 0, lineBytes.length); + vm.flushDebugOutput(); + } + + private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) { + TreeMap fields = new TreeMap<>(store.getFields()); + for (VMField field : fields.values()) { + if (!field.isStatic()) { + printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset); + } else { + String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value); + printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address); + } + } + TreeMap flags = new TreeMap<>(store.getFlags()); + for (VMFlag flag : flags.values()) { + printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value); + } + TreeMap addresses = new TreeMap<>(store.getAddresses()); + for (Map.Entry e : addresses.entrySet()) { + printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); + } + TreeMap constants = new TreeMap<>(store.getConstants()); + for (Map.Entry e : constants.entrySet()) { + printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue()); + } + for (VMIntrinsicMethod e : store.getIntrinsics()) { + printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor); + } + } + /** * Gets an output stream that writes to HotSpot's {@code tty} stream. */ @@ -577,27 +804,26 @@ * * @return the offset in bytes */ - @SuppressWarnings("static-method") public int getArrayBaseOffset(JavaKind kind) { switch (kind) { case Boolean: - return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + return compilerToVm.ARRAY_BOOLEAN_BASE_OFFSET; case Byte: - return Unsafe.ARRAY_BYTE_BASE_OFFSET; + return compilerToVm.ARRAY_BYTE_BASE_OFFSET; case Char: - return Unsafe.ARRAY_CHAR_BASE_OFFSET; + return compilerToVm.ARRAY_CHAR_BASE_OFFSET; case Short: - return Unsafe.ARRAY_SHORT_BASE_OFFSET; + return compilerToVm.ARRAY_SHORT_BASE_OFFSET; case Int: - return Unsafe.ARRAY_INT_BASE_OFFSET; + return compilerToVm.ARRAY_INT_BASE_OFFSET; case Long: - return Unsafe.ARRAY_LONG_BASE_OFFSET; + return compilerToVm.ARRAY_LONG_BASE_OFFSET; case Float: - return Unsafe.ARRAY_FLOAT_BASE_OFFSET; + return compilerToVm.ARRAY_FLOAT_BASE_OFFSET; case Double: - return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + return compilerToVm.ARRAY_DOUBLE_BASE_OFFSET; case Object: - return Unsafe.ARRAY_OBJECT_BASE_OFFSET; + return compilerToVm.ARRAY_OBJECT_BASE_OFFSET; default: throw new JVMCIError("%s", kind); } @@ -609,27 +835,26 @@ * * @return the scale in order to convert the index into a byte offset */ - @SuppressWarnings("static-method") public int getArrayIndexScale(JavaKind kind) { switch (kind) { case Boolean: - return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + return compilerToVm.ARRAY_BOOLEAN_INDEX_SCALE; case Byte: - return Unsafe.ARRAY_BYTE_INDEX_SCALE; + return compilerToVm.ARRAY_BYTE_INDEX_SCALE; case Char: - return Unsafe.ARRAY_CHAR_INDEX_SCALE; + return compilerToVm.ARRAY_CHAR_INDEX_SCALE; case Short: - return Unsafe.ARRAY_SHORT_INDEX_SCALE; + return compilerToVm.ARRAY_SHORT_INDEX_SCALE; case Int: - return Unsafe.ARRAY_INT_INDEX_SCALE; + return compilerToVm.ARRAY_INT_INDEX_SCALE; case Long: - return Unsafe.ARRAY_LONG_INDEX_SCALE; + return compilerToVm.ARRAY_LONG_INDEX_SCALE; case Float: - return Unsafe.ARRAY_FLOAT_INDEX_SCALE; + return compilerToVm.ARRAY_FLOAT_INDEX_SCALE; case Double: - return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + return compilerToVm.ARRAY_DOUBLE_INDEX_SCALE; case Object: - return Unsafe.ARRAY_OBJECT_INDEX_SCALE; + return compilerToVm.ARRAY_OBJECT_INDEX_SCALE; default: throw new JVMCIError("%s", kind); @@ -637,10 +862,10 @@ } /** - * Links each native method in {@code clazz} to an implementation in the JVMCI SVM library. + * Links each native method in {@code clazz} to an implementation in the JVMCI shared library. *

* A use case for this is a JVMCI compiler implementation that offers an API to Java code - * executing in HotSpot to exercise functionality (mostly) in the JVMCI SVM library. For + * executing in HotSpot to exercise functionality (mostly) in the JVMCI shared library. For * example: * *

@@ -665,28 +890,73 @@
      * }
      * 
* - * The implementation of the native {@code JCompile.compile0} method would be in the SVM library - * that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} implementation - * will be exported as the following JNI-compliant symbol: + * The implementation of the native {@code JCompile.compile0} method would be in the JVMCI + * shared library that contains the bulk of the JVMCI compiler. The {@code JCompile.compile0} + * implementation will be exported as the following JNI-compatible symbol: * *
      * Java_com_jcompile_JCompile_compile0
      * 
* - * How the JVMCI compiler SVM library is built is outside the scope of this document. + * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names" + * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#creating_the_vm" + * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#invocation_api_functions" * - * @see "https://docs.oracle.com/javase/10/docs/specs/jni/design.html#resolving-native-method-names" * + * @return an array of 4 longs where the first value is the {@code JavaVM*} value representing + * the Java VM in the JVMCI shared library, and the remaining values are the first 3 + * pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface}) * @throws NullPointerException if {@code clazz == null} - * @throws IllegalArgumentException if the current execution context is SVM or if {@code clazz} - * is {@link Class#isPrimitive()} - * @throws UnsatisfiedLinkError if the JVMCI SVM library is not available, a native method in - * {@code clazz} is already linked or the SVM JVMCI library does not contain a - * JNI-compliant symbol for a native method in {@code clazz} + * @throws IllegalArgumentException if the current execution context is the JVMCI shared library + * or if {@code clazz} is {@link Class#isPrimitive()} + * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in + * {@code clazz} is already linked or the JVMCI shared library does not contain a + * JNI-compatible symbol for a native method in {@code clazz} */ - @SuppressWarnings({"static-method", "unused"}) - public void registerNativeMethods(Class clazz) { - throw new UnsatisfiedLinkError("SVM library is not available"); + public long[] registerNativeMethods(Class clazz) { + return compilerToVm.registerNativeMethods(clazz); + } + + /** + * Creates or retrieves an object in the peer runtime that mirrors {@code obj}. The types whose + * objects can be translated are: + *
    + *
  • {@link HotSpotResolvedJavaMethodImpl},
  • + *
  • {@link HotSpotResolvedObjectTypeImpl},
  • + *
  • {@link HotSpotResolvedPrimitiveType},
  • + *
  • {@link IndirectHotSpotObjectConstantImpl},
  • + *
  • {@link DirectHotSpotObjectConstantImpl} and
  • + *
  • {@link HotSpotNmethod}
  • + *
+ * + * This mechanism can be used to pass and return values between the HotSpot and JVMCI shared + * library runtimes. In the receiving runtime, the value can be converted back to an object with + * {@link #unhand(Class, long)}. + * + * @param obj an object for which an equivalent instance in the peer runtime is requested + * @return a JNI global reference to the mirror of {@code obj} in the peer runtime + * @throws IllegalArgumentException if {@code obj} is not of a translatable type + * + * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" + */ + public long translate(Object obj) { + return compilerToVm.translate(obj); + } + + /** + * Dereferences and returns the object referred to by the JNI global reference {@code handle}. + * The global reference is deleted prior to returning. Any further use of {@code handle} is + * invalid. + * + * @param handle a JNI global reference to an object in the current runtime + * @return the object referred to by {@code handle} + * @throws ClassCastException if the returned object cannot be case to {@code type} + * + * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references" + * + */ + public T unhand(Class type, long handle) { + return type.cast(compilerToVm.unhand(handle)); } /** diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.services.Services; + +/** + * Indicates a path in HotSpot JVMCI related code that is unsupported in the current execution + * environment. For example, certain operations are not supported by JVMCI code running in an ahead + * of time compiled {@linkplain Services#IS_IN_NATIVE_IMAGE native image}. This usually reflects + * functionality only needed in non-native image execution that would require a more complex + * implementation to support in a native image. + * + * An example of such functionality is {@link ResolvedJavaType#isLocal()}. This can be conveniently + * implemented when JVMCI is running on the HotSpot heap as we can obtain the {@link Class} mirror + * for the {@link ResolvedJavaType} and call {@link Class#isLocalClass()}. In a native image, there + * is no {@link Class} mirror available in the native image heap so implementing this would involve + * a call into VM native code that in turn would make an upcall into Java code executing on the + * HotSpot heap. We have opted to defer implementing functionality such as this until there's a + * demonstrated need for it. + */ +public class HotSpotJVMCIUnsupportedOperationError extends Error { + + public HotSpotJVMCIUnsupportedOperationError(String reason) { + super(reason); + } + + public HotSpotJVMCIUnsupportedOperationError(String reason, Throwable cause) { + super(reason, cause); + } + + private static final long serialVersionUID = 7782431672678016392L; + +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,19 +22,14 @@ */ package jdk.vm.ci.hotspot; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; -import java.lang.reflect.Array; - -import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MemoryAccessProvider; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaType; /** * HotSpot implementation of {@link MemoryAccessProvider}. @@ -55,89 +50,34 @@ * @return {@code null} if {@code base} does not box an object otherwise the object boxed in * {@code base} */ - private Object asObject(Constant base, JavaKind kind, long displacement) { + private static HotSpotObjectConstantImpl asObject(Constant base, JavaKind kind, long displacement) { if (base instanceof HotSpotObjectConstantImpl) { HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base; HotSpotResolvedObjectType type = constant.getType(); - Object object = constant.object(); - checkRead(kind, displacement, type, object, runtime.getHostJVMCIBackend().getMetaAccess()); - return object; + runtime().reflection.checkRead(constant, kind, displacement, type); + return constant; } return null; } - /** - * Offset of injected {@code java.lang.Class::oop_size} field. No need to make {@code volatile} - * as initialization is idempotent. - */ - private long oopSizeOffset; - - private static int computeOopSizeOffset(HotSpotJVMCIRuntime runtime) { - MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess(); - ResolvedJavaType staticType = metaAccess.lookupJavaType(Class.class); - for (ResolvedJavaField f : staticType.getInstanceFields(false)) { - if (f.getName().equals("oop_size")) { - int offset = ((HotSpotResolvedJavaField) f).getOffset(); - assert offset != 0 : "not expecting offset of java.lang.Class::oop_size to be 0"; - return offset; + private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { + if (base instanceof HotSpotMetaspaceConstant) { + MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().javaMirrorOffset) { + // Klass::_java_mirror is valid for all Klass* values + return true; + } + } else { + throw new IllegalArgumentException(String.valueOf(metaspaceObject)); } } - throw new JVMCIError("Could not find injected java.lang.Class::oop_size field"); - } - - private boolean checkRead(JavaKind kind, long displacement, HotSpotResolvedObjectType type, Object object, MetaAccessProvider metaAccess) { - if (type.isArray()) { - ResolvedJavaType componentType = type.getComponentType(); - JavaKind componentKind = componentType.getJavaKind(); - final int headerSize = metaAccess.getArrayBaseOffset(componentKind); - int sizeOfElement = metaAccess.getArrayIndexScale(componentKind); - int length = Array.getLength(object); - long arrayEnd = headerSize + (sizeOfElement * length); - boolean aligned = ((displacement - headerSize) % sizeOfElement) == 0; - if (displacement < 0 || displacement > (arrayEnd - sizeOfElement) || (kind == JavaKind.Object && !aligned)) { - int index = (int) ((displacement - headerSize) / sizeOfElement); - throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind + - " at offset " + displacement + " (index ~ " + index + ") in " + - type.toJavaName() + " object of length " + length); - } - } else if (kind != JavaKind.Object) { - long size; - if (object instanceof Class) { - if (oopSizeOffset == 0) { - oopSizeOffset = computeOopSizeOffset(runtime); - } - int wordSize = runtime.getHostJVMCIBackend().getCodeCache().getTarget().wordSize; - size = UNSAFE.getInt(object, oopSizeOffset) * wordSize; - } else { - size = Math.abs(type.instanceSize()); - } - int bytesToRead = kind.getByteCount(); - if (displacement + bytesToRead > size || displacement < 0) { - throw new IllegalArgumentException("Unsafe access: reading " + bytesToRead + " bytes at offset " + displacement + " in " + - type.toJavaName() + " object of size " + size); - } - } else { - ResolvedJavaField field = type.findInstanceFieldWithOffset(displacement, JavaKind.Object); - if (field == null && object instanceof Class) { - // Read of a static field - HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) metaAccess.lookupJavaType((Class) object); - field = staticFieldsHolder.findStaticFieldWithOffset(displacement, JavaKind.Object); - } - if (field == null) { - throw new IllegalArgumentException("Unsafe object access: field not found for read of kind Object" + - " at offset " + displacement + " in " + type.toJavaName() + " object"); - } - if (field.getJavaKind() != JavaKind.Object) { - throw new IllegalArgumentException("Unsafe object access: field " + field.format("%H.%n:%T") + " not of expected kind Object" + - " at offset " + displacement + " in " + type.toJavaName() + " object"); - } - } - return true; + return false; } private static long asRawPointer(Constant base) { if (base instanceof HotSpotMetaspaceConstantImpl) { - MetaspaceWrapperObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + MetaspaceObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); return meta.getMetaspacePointer(); } else if (base instanceof PrimitiveConstant) { PrimitiveConstant prim = (PrimitiveConstant) base; @@ -148,18 +88,18 @@ throw new IllegalArgumentException(String.valueOf(base)); } - private long readRawValue(Constant baseConstant, long displacement, JavaKind kind, int bits) { - Object base = asObject(baseConstant, kind, displacement); + private static long readRawValue(Constant baseConstant, long displacement, JavaKind kind, int bits) { + HotSpotObjectConstantImpl base = asObject(baseConstant, kind, displacement); if (base != null) { switch (bits) { case Byte.SIZE: - return UNSAFE.getByte(base, displacement); + return runtime().reflection.getByte(base, displacement); case Short.SIZE: - return UNSAFE.getShort(base, displacement); + return runtime().reflection.getShort(base, displacement); case Integer.SIZE: - return UNSAFE.getInt(base, displacement); + return runtime().reflection.getInt(base, displacement); case Long.SIZE: - return UNSAFE.getLong(base, displacement); + return runtime().reflection.getLong(base, displacement); default: throw new IllegalArgumentException(String.valueOf(bits)); } @@ -180,63 +120,33 @@ } } - private boolean verifyReadRawObject(Object expected, Constant base, long displacement) { + private boolean verifyReadRawObject(JavaConstant expected, Constant base, long displacement) { if (base instanceof HotSpotMetaspaceConstant) { - MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { - if (displacement == runtime.getConfig().classMirrorHandleOffset) { - assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); + if (displacement == runtime.getConfig().javaMirrorOffset) { + HotSpotResolvedObjectTypeImpl type = (HotSpotResolvedObjectTypeImpl) metaspaceObject; + assert expected.equals(type.getJavaMirror()); } } } return true; } - private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { + private JavaConstant readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { long displacement = initialDisplacement; - Object ret; - Object base = asObject(baseConstant, JavaKind.Object, displacement); + JavaConstant ret; + HotSpotObjectConstantImpl base = asObject(baseConstant, JavaKind.Object, displacement); if (base == null) { assert !compressed; displacement += asRawPointer(baseConstant); - ret = UNSAFE.getUncompressedObject(displacement); + ret = runtime.getCompilerToVM().readUncompressedOop(displacement); assert verifyReadRawObject(ret, baseConstant, initialDisplacement); } else { assert runtime.getConfig().useCompressedOops == compressed; - ret = UNSAFE.getReference(base, displacement); + ret = runtime.getCompilerToVM().getObject(base, displacement); } - return ret; - } - - JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean isVolatile) { - assert obj != null; - assert !field.isStatic() || obj instanceof Class; - long displacement = field.getOffset(); - assert checkRead(field.getJavaKind(), displacement, (HotSpotResolvedObjectType) runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(obj.getClass()), obj, - runtime.getHostJVMCIBackend().getMetaAccess()); - JavaKind kind = field.getJavaKind(); - switch (kind) { - case Boolean: - return JavaConstant.forBoolean(isVolatile ? UNSAFE.getBooleanVolatile(obj, displacement) : UNSAFE.getBoolean(obj, displacement)); - case Byte: - return JavaConstant.forByte(isVolatile ? UNSAFE.getByteVolatile(obj, displacement) : UNSAFE.getByte(obj, displacement)); - case Char: - return JavaConstant.forChar(isVolatile ? UNSAFE.getCharVolatile(obj, displacement) : UNSAFE.getChar(obj, displacement)); - case Short: - return JavaConstant.forShort(isVolatile ? UNSAFE.getShortVolatile(obj, displacement) : UNSAFE.getShort(obj, displacement)); - case Int: - return JavaConstant.forInt(isVolatile ? UNSAFE.getIntVolatile(obj, displacement) : UNSAFE.getInt(obj, displacement)); - case Long: - return JavaConstant.forLong(isVolatile ? UNSAFE.getLongVolatile(obj, displacement) : UNSAFE.getLong(obj, displacement)); - case Float: - return JavaConstant.forFloat(isVolatile ? UNSAFE.getFloatVolatile(obj, displacement) : UNSAFE.getFloat(obj, displacement)); - case Double: - return JavaConstant.forDouble(isVolatile ? UNSAFE.getDoubleVolatile(obj, displacement) : UNSAFE.getDouble(obj, displacement)); - case Object: - return HotSpotObjectConstantImpl.forObject(isVolatile ? UNSAFE.getReferenceVolatile(obj, displacement) : UNSAFE.getReference(obj, displacement)); - default: - throw new IllegalArgumentException("Unsupported kind: " + kind); - } + return ret == null ? JavaConstant.NULL_POINTER : ret; } @Override @@ -271,34 +181,35 @@ @Override public JavaConstant readObjectConstant(Constant base, long displacement) { if (base instanceof HotSpotObjectConstantImpl) { - Object o = readRawObject(base, displacement, runtime.getConfig().useCompressedOops); - return HotSpotObjectConstantImpl.forObject(o); + return readRawObject(base, displacement, runtime.getConfig().useCompressedOops); + } + if (!isValidObjectFieldDisplacement(base, displacement)) { + return null; } - if (base instanceof HotSpotMetaspaceConstant) { - MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); - if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { - if (displacement == runtime.getConfig().classMirrorHandleOffset) { - // Klass::_java_mirror is valid for all Klass* values - return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror()); - } - } else { - throw new IllegalArgumentException(String.valueOf(metaspaceObject)); - } + if (base instanceof HotSpotMetaspaceConstant && + displacement == runtime.getConfig().javaMirrorOffset) { + MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).getJavaMirror(); } - return null; + return readRawObject(base, displacement, false); } @Override public JavaConstant readNarrowOopConstant(Constant base, long displacement) { - return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true); + JavaConstant res = readRawObject(base, displacement, true); + return JavaConstant.NULL_POINTER.equals(res) ? HotSpotCompressedNullConstant.COMPRESSED_NULL : ((HotSpotObjectConstant) res).compress(); } private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); - Object baseObject = (base instanceof HotSpotMetaspaceConstantImpl) ? ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType() : ((HotSpotObjectConstantImpl) base).object(); - return runtime.getCompilerToVM().getResolvedJavaType(baseObject, displacement, compressed); + if (base instanceof HotSpotMetaspaceConstantImpl) { + return runtime.getCompilerToVM().getResolvedJavaType((HotSpotResolvedObjectTypeImpl) ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType(), displacement, compressed); + } else { + return runtime.getCompilerToVM().getResolvedJavaType(((HotSpotObjectConstantImpl) base), displacement, compressed); + } } + @Override public Constant readKlassPointerConstant(Constant base, long displacement) { HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); @@ -320,8 +231,7 @@ @Override public Constant readMethodPointerConstant(Constant base, long displacement) { assert (base instanceof HotSpotObjectConstantImpl); - Object baseObject = ((HotSpotObjectConstantImpl) base).object(); - HotSpotResolvedJavaMethodImpl method = runtime.getCompilerToVM().getResolvedJavaMethod(baseObject, displacement); + HotSpotResolvedJavaMethodImpl method = runtime.getCompilerToVM().getResolvedJavaMethod((HotSpotObjectConstantImpl) base, displacement); return HotSpotMetaspaceConstantImpl.forMetaspaceObject(method, false); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,6 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.fromObjectClass; -import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; - -import java.lang.reflect.Array; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -43,6 +39,8 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.SpeculationLog.NoSpeculationReason; +import jdk.vm.ci.meta.SpeculationLog.Speculation; // JaCoCo Exclude @@ -87,20 +85,19 @@ public ResolvedJavaField lookupJavaField(Field reflectionField) { Class fieldHolder = reflectionField.getDeclaringClass(); - HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder); + HotSpotResolvedJavaType holder = runtime.fromClass(fieldHolder); + assert holder != null : fieldHolder; + ResolvedJavaField[] fields; if (Modifier.isStatic(reflectionField.getModifiers())) { - final long offset = UNSAFE.staticFieldOffset(reflectionField); - for (ResolvedJavaField field : holder.getStaticFields()) { - if (offset == ((HotSpotResolvedJavaField) field).getOffset()) { - return field; - } - } + fields = holder.getStaticFields(); } else { - final long offset = UNSAFE.objectFieldOffset(reflectionField); - for (ResolvedJavaField field : holder.getInstanceFields(false)) { - if (offset == ((HotSpotResolvedJavaField) field).getOffset()) { - return field; - } + fields = holder.getInstanceFields(false); + } + ResolvedJavaType fieldType = lookupJavaType(reflectionField.getType()); + for (ResolvedJavaField field : fields) { + if (reflectionField.getName().equals(field.getName()) && field.getType().equals(fieldType)) { + assert Modifier.isStatic(reflectionField.getModifiers()) == field.isStatic(); + return field; } } @@ -147,19 +144,21 @@ } @Override - public JavaConstant encodeSpeculation(SpeculationLog.Speculation speculation) { - if (speculation.getReason() instanceof SpeculationLog.NoSpeculationReason) { + public JavaConstant encodeSpeculation(Speculation speculation) { + if (speculation.getReason() instanceof NoSpeculationReason) { return JavaConstant.LONG_0; } return ((HotSpotSpeculationLog.HotSpotSpeculation) speculation).getEncoding(); } @Override - public SpeculationLog.Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog) { + public Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog) { if (constant.equals(JavaConstant.LONG_0)) { return SpeculationLog.NO_SPECULATION; } - assert speculationLog != null : "Must have a speculation log"; + if (speculationLog == null) { + throw new IllegalArgumentException("A speculation log is required to decode the speculation denoted by " + constant); + } return speculationLog.lookupSpeculation(constant); } @@ -303,11 +302,11 @@ return 0; } else { if (lookupJavaType.isArray()) { - int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object()); + int length = runtime.getHostJVMCIBackend().getConstantReflection().readArrayLength(constant); ResolvedJavaType elementType = lookupJavaType.getComponentType(); JavaKind elementKind = elementType.getJavaKind(); - final int headerSize = getArrayBaseOffset(elementKind); - int sizeOfElement = getArrayIndexScale(elementKind); + final int headerSize = runtime.getArrayBaseOffset(elementKind); + int sizeOfElement = runtime.getArrayIndexScale(elementKind); int log2ElementSize = CodeUtil.log2(sizeOfElement); return computeArrayAllocationSize(length, headerSize, log2ElementSize); } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,18 +29,18 @@ final class HotSpotMetaspaceConstantImpl implements HotSpotMetaspaceConstant, VMConstant { - static HotSpotMetaspaceConstantImpl forMetaspaceObject(MetaspaceWrapperObject metaspaceObject, boolean compressed) { + static HotSpotMetaspaceConstantImpl forMetaspaceObject(MetaspaceObject metaspaceObject, boolean compressed) { return new HotSpotMetaspaceConstantImpl(metaspaceObject, compressed); } - static MetaspaceWrapperObject getMetaspaceObject(Constant constant) { + static MetaspaceObject getMetaspaceObject(Constant constant) { return ((HotSpotMetaspaceConstantImpl) constant).metaspaceObject; } - private final MetaspaceWrapperObject metaspaceObject; + private final MetaspaceObject metaspaceObject; private final boolean compressed; - private HotSpotMetaspaceConstantImpl(MetaspaceWrapperObject metaspaceObject, boolean compressed) { + private HotSpotMetaspaceConstantImpl(MetaspaceObject metaspaceObject, boolean compressed) { this.metaspaceObject = metaspaceObject; this.compressed = compressed; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,8 +78,4 @@ String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString(); formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width)); } - - public JavaMethod asJavaMethod() { - return this; - } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Arrays; +import jdk.vm.ci.common.NativeImageReinitialize; import jdk.internal.misc.Unsafe; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaMethodProfile; @@ -45,26 +46,139 @@ */ final class HotSpotMethodData { - static final HotSpotVMConfig config = config(); - static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(config, config.dataLayoutNoTag, TriState.FALSE); - static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(config, config.dataLayoutNoTag, TriState.UNKNOWN); + /** + * VM state that can be reset when building an AOT image. + */ + static final class VMState { + final HotSpotVMConfig config = config(); + final HotSpotMethodDataAccessor noDataNoExceptionAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.FALSE); + final HotSpotMethodDataAccessor noDataExceptionPossiblyNotRecordedAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.UNKNOWN); + final int noDataSize = cellIndexToOffset(0); + final int bitDataSize = cellIndexToOffset(0); + final int bitDataNullSeenFlag = 1 << config.bitDataNullSeenFlag; + final int counterDataSize = cellIndexToOffset(1); + final int counterDataCountOffset = cellIndexToOffset(config.methodDataCountOffset); + final int jumpDataSize = cellIndexToOffset(2); + final int takenCountOffset = cellIndexToOffset(config.jumpDataTakenOffset); + final int takenDisplacementOffset = cellIndexToOffset(config.jumpDataDisplacementOffset); + final int typeDataRowSize = cellsToBytes(config.receiverTypeDataReceiverTypeRowCellCount); + + final int nonprofiledCountOffset = cellIndexToOffset(config.receiverTypeDataNonprofiledCountOffset); + final int typeDataFirstTypeOffset = cellIndexToOffset(config.receiverTypeDataReceiver0Offset); + final int typeDataFirstTypeCountOffset = cellIndexToOffset(config.receiverTypeDataCount0Offset); + + final int typeCheckDataSize = cellIndexToOffset(2) + typeDataRowSize * config.typeProfileWidth; + final int virtualCallDataSize = cellIndexToOffset(2) + typeDataRowSize * (config.typeProfileWidth + config.methodProfileWidth); + final int virtualCallDataFirstMethodOffset = typeDataFirstTypeOffset + typeDataRowSize * config.typeProfileWidth; + final int virtualCallDataFirstMethodCountOffset = typeDataFirstTypeCountOffset + typeDataRowSize * config.typeProfileWidth; + + final int retDataRowSize = cellsToBytes(3); + final int retDataSize = cellIndexToOffset(1) + retDataRowSize * config.bciProfileWidth; + + final int branchDataSize = cellIndexToOffset(3); + final int notTakenCountOffset = cellIndexToOffset(config.branchDataNotTakenOffset); + + final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset); + final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset); + + final int multiBranchDataSize = cellIndexToOffset(1); + final int multiBranchDataRowSizeInCells = config.multiBranchDataPerCaseCellCount; + final int multiBranchDataRowSize = cellsToBytes(multiBranchDataRowSizeInCells); + final int multiBranchDataFirstCountOffset = arrayDataStartOffset + cellsToBytes(0); + final int multiBranchDataFirstDisplacementOffset = arrayDataStartOffset + cellsToBytes(1); + + final int argInfoDataSize = cellIndexToOffset(1); + + // sorted by tag + // @formatter:off + final HotSpotMethodDataAccessor[] profileDataAccessors = { + null, + new BitData(this, config.dataLayoutBitDataTag), + new CounterData(this, config.dataLayoutCounterDataTag), + new JumpData(this, config.dataLayoutJumpDataTag), + new ReceiverTypeData(this, config.dataLayoutReceiverTypeDataTag), + new VirtualCallData(this, config.dataLayoutVirtualCallDataTag), + new RetData(this, config.dataLayoutRetDataTag), + new BranchData(this, config.dataLayoutBranchDataTag), + new MultiBranchData(this, config.dataLayoutMultiBranchDataTag), + new ArgInfoData(this, config.dataLayoutArgInfoDataTag), + new UnknownProfileData(this, config.dataLayoutCallTypeDataTag), + new VirtualCallTypeData(this, config.dataLayoutVirtualCallTypeDataTag), + new UnknownProfileData(this, config.dataLayoutParametersTypeDataTag), + new UnknownProfileData(this, config.dataLayoutSpeculativeTrapDataTag), + }; + // @formatter:on + + private boolean checkAccessorTags() { + int expectedTag = 0; + for (HotSpotMethodDataAccessor accessor : profileDataAccessors) { + if (expectedTag == 0) { + assert accessor == null; + } else { + assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor; + } + expectedTag++; + } + return true; + } + + private VMState() { + assert checkAccessorTags(); + } + + private static int truncateLongToInt(long value) { + return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; + } + + private int computeFullOffset(int position, int offsetInBytes) { + return config.methodDataOopDataOffset + position + offsetInBytes; + } + + private int cellIndexToOffset(int cells) { + return config.dataLayoutHeaderSize + cellsToBytes(cells); + } + + private int cellsToBytes(int cells) { + return cells * config.dataLayoutCellSize; + } + + /** + * Singleton instance lazily initialized via double-checked locking. + */ + @NativeImageReinitialize private static volatile VMState instance; + + static VMState instance() { + VMState result = instance; + if (result == null) { + synchronized (VMState.class) { + result = instance; + if (result == null) { + instance = result = new VMState(); + } + } + } + return result; + } + } /** * Reference to the C++ MethodData object. */ final long metaspaceMethodData; private final HotSpotResolvedJavaMethodImpl method; + private final VMState state; HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) { this.metaspaceMethodData = metaspaceMethodData; this.method = method; + this.state = VMState.instance(); } /** * @return value of the MethodData::_data_size field */ private int normalDataSize() { - return UNSAFE.getInt(metaspaceMethodData + config.methodDataDataSize); + return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataDataSize); } /** @@ -74,8 +188,8 @@ * @return size of extra data records */ private int extraDataSize() { - final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); - final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + config.methodDataSize); + final int extraDataBase = state.config.methodDataOopDataOffset + normalDataSize(); + final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + state.config.methodDataSize); return extraDataLimit - extraDataBase; } @@ -98,25 +212,25 @@ public int getDeoptimizationCount(DeoptimizationReason reason) { HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); int reasonIndex = metaAccess.convertDeoptReason(reason); - return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; + return UNSAFE.getByte(metaspaceMethodData + state.config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; } public int getOSRDeoptimizationCount(DeoptimizationReason reason) { HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); int reasonIndex = metaAccess.convertDeoptReason(reason); - return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; + return UNSAFE.getByte(metaspaceMethodData + state.config.methodDataOopTrapHistoryOffset + state.config.deoptReasonOSROffset + reasonIndex) & 0xFF; } public int getDecompileCount() { - return UNSAFE.getInt(metaspaceMethodData + config.methodDataDecompiles); + return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataDecompiles); } public int getOverflowRecompileCount() { - return UNSAFE.getInt(metaspaceMethodData + config.methodDataOverflowRecompiles); + return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataOverflowRecompiles); } public int getOverflowTrapCount() { - return UNSAFE.getInt(metaspaceMethodData + config.methodDataOverflowTraps); + return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataOverflowTraps); } public HotSpotMethodDataAccessor getNormalData(int position) { @@ -140,27 +254,27 @@ public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { if (exceptionPossiblyNotRecorded) { - return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; + return VMState.instance().noDataExceptionPossiblyNotRecordedAccessor; } else { - return NO_DATA_NO_EXCEPTION_ACCESSOR; + return VMState.instance().noDataNoExceptionAccessor; } } private HotSpotMethodDataAccessor getData(int position) { assert position >= 0 : "out of bounds"; - final int tag = HotSpotMethodDataAccessor.readTag(config, this, position); - HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag]; + final int tag = HotSpotMethodDataAccessor.readTag(state.config, this, position); + HotSpotMethodDataAccessor accessor = state.profileDataAccessors[tag]; assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; return accessor; } int readUnsignedByte(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; } int readUnsignedShort(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; } @@ -169,13 +283,13 @@ * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. */ private long readUnsignedInt(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; } private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { long value = readUnsignedInt(position, offsetInBytes); - return truncateLongToInt(value); + return VMState.truncateLongToInt(value); } /** @@ -183,34 +297,18 @@ * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. */ private int readInt(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes); } private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); return compilerToVM().getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes); } private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { - long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); - return compilerToVM().getResolvedJavaType(null, metaspaceMethodData + fullOffsetInBytes, false); - } - - private static int truncateLongToInt(long value) { - return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; - } - - private static int computeFullOffset(int position, int offsetInBytes) { - return config.methodDataOopDataOffset + position + offsetInBytes; - } - - private static int cellIndexToOffset(int cells) { - return config.dataLayoutHeaderSize + cellsToBytes(cells); - } - - private static int cellsToBytes(int cells) { - return cells * config.dataLayoutCellSize; + long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); + return compilerToVM().getResolvedJavaType(metaspaceMethodData + fullOffsetInBytes, false); } /** @@ -263,14 +361,12 @@ return sb.toString(); } - static final int NO_DATA_SIZE = cellIndexToOffset(0); - static class NoMethodData extends HotSpotMethodDataAccessor { private final TriState exceptionSeen; - protected NoMethodData(HotSpotVMConfig config, int tag, TriState exceptionSeen) { - super(config, tag, NO_DATA_SIZE); + protected NoMethodData(VMState state, int tag, TriState exceptionSeen) { + super(state, tag, state.noDataSize); this.exceptionSeen = exceptionSeen; } @@ -290,22 +386,19 @@ } } - static final int BIT_DATA_SIZE = cellIndexToOffset(0); - static final int BIT_DATA_NULL_SEEN_FLAG = 1 << config.bitDataNullSeenFlag; - static class BitData extends HotSpotMethodDataAccessor { - private BitData(HotSpotVMConfig config, int tag) { - super(config, tag, BIT_DATA_SIZE); + private BitData(VMState state, int tag) { + super(state, tag, state.bitDataSize); } - protected BitData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected BitData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override public TriState getNullSeen(HotSpotMethodData data, int position) { - return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); + return TriState.get((getFlags(data, position) & state.bitDataNullSeenFlag) != 0); } @Override @@ -314,17 +407,14 @@ } } - static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); - static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(config.methodDataCountOffset); - static class CounterData extends BitData { - CounterData(HotSpotVMConfig config, int tag) { - super(config, tag, COUNTER_DATA_SIZE); + CounterData(VMState state, int tag) { + super(state, tag, state.counterDataSize); } - protected CounterData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected CounterData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override @@ -333,7 +423,7 @@ } protected int getCounterValue(HotSpotMethodData data, int position) { - return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); + return data.readUnsignedIntAsSignedInt(position, state.counterDataCountOffset); } @Override @@ -342,18 +432,14 @@ } } - static final int JUMP_DATA_SIZE = cellIndexToOffset(2); - static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(config.jumpDataTakenOffset); - static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(config.jumpDataDisplacementOffset); - static class JumpData extends HotSpotMethodDataAccessor { - JumpData(HotSpotVMConfig config, int tag) { - super(config, tag, JUMP_DATA_SIZE); + JumpData(VMState state, int tag) { + super(state, tag, state.jumpDataSize); } - protected JumpData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected JumpData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override @@ -363,11 +449,11 @@ @Override public int getExecutionCount(HotSpotMethodData data, int position) { - return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); + return data.readUnsignedIntAsSignedInt(position, state.takenCountOffset); } public int getTakenDisplacement(HotSpotMethodData data, int position) { - return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); + return data.readInt(position, state.takenDisplacementOffset); } @Override @@ -390,16 +476,10 @@ } } - static final int TYPE_DATA_ROW_SIZE = cellsToBytes(config.receiverTypeDataReceiverTypeRowCellCount); - - static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(config.receiverTypeDataNonprofiledCountOffset); - static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(config.receiverTypeDataReceiver0Offset); - static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(config.receiverTypeDataCount0Offset); - abstract static class AbstractTypeData extends CounterData { - protected AbstractTypeData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected AbstractTypeData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override @@ -446,7 +526,7 @@ protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); public int getNonprofiledCount(HotSpotMethodData data, int position) { - return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset); } private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile profile) { @@ -470,12 +550,12 @@ return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); } - private static int getTypeOffset(int row) { - return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; + private int getTypeOffset(int row) { + return state.typeDataFirstTypeOffset + row * state.typeDataRowSize; } - protected static int getTypeCountOffset(int row) { - return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + protected int getTypeCountOffset(int row) { + return state.typeDataFirstTypeCountOffset + row * state.typeDataRowSize; } @Override @@ -493,16 +573,14 @@ } } - static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; - static class ReceiverTypeData extends AbstractTypeData { - ReceiverTypeData(HotSpotVMConfig config, int tag) { - super(config, tag, TYPE_CHECK_DATA_SIZE); + ReceiverTypeData(VMState state, int tag) { + super(state, tag, state.typeCheckDataSize); } - protected ReceiverTypeData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected ReceiverTypeData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override @@ -516,18 +594,14 @@ } } - static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); - static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; - static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; - static class VirtualCallData extends ReceiverTypeData { - VirtualCallData(HotSpotVMConfig config, int tag) { - super(config, tag, VIRTUAL_CALL_DATA_SIZE); + VirtualCallData(VMState state, int tag) { + super(state, tag, state.virtualCallDataSize); } - protected VirtualCallData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + protected VirtualCallData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override @@ -540,7 +614,7 @@ } total += getCounterValue(data, position); - return truncateLongToInt(total); + return VMState.truncateLongToInt(total); } @Override @@ -548,8 +622,8 @@ return getCounterValue(data, position); } - private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { - return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + private long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset); } @Override @@ -610,12 +684,12 @@ return new JavaMethodProfile(notRecordedMethodProbability, pmethods); } - private static int getMethodOffset(int row) { - return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; + private int getMethodOffset(int row) { + return state.virtualCallDataFirstMethodOffset + row * state.typeDataRowSize; } - private static int getMethodCountOffset(int row) { - return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + private int getMethodCountOffset(int row) { + return state.virtualCallDataFirstMethodCountOffset + row * state.typeDataRowSize; } @Override @@ -632,8 +706,8 @@ static class VirtualCallTypeData extends VirtualCallData { - VirtualCallTypeData(HotSpotVMConfig config, int tag) { - super(config, tag, 0); + VirtualCallTypeData(VMState state, int tag) { + super(state, tag, 0); } @Override @@ -643,29 +717,23 @@ } } - static final int RET_DATA_ROW_SIZE = cellsToBytes(3); - static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; - static class RetData extends CounterData { - RetData(HotSpotVMConfig config, int tag) { - super(config, tag, RET_DATA_SIZE); + RetData(VMState state, int tag) { + super(state, tag, state.retDataSize); } } - static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); - static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(config.branchDataNotTakenOffset); - static class BranchData extends JumpData { - BranchData(HotSpotVMConfig config, int tag) { - super(config, tag, BRANCH_DATA_SIZE); + BranchData(VMState state, int tag) { + super(state, tag, state.branchDataSize); } @Override public double getBranchTakenProbability(HotSpotMethodData data, int position) { - long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); - long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + long takenCount = data.readUnsignedInt(position, state.takenCountOffset); + long notTakenCount = data.readUnsignedInt(position, state.notTakenCountOffset); long total = takenCount + notTakenCount; return total <= 0 ? -1 : takenCount / (double) total; @@ -673,35 +741,32 @@ @Override public int getExecutionCount(HotSpotMethodData data, int position) { - long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); - return truncateLongToInt(count); + long count = data.readUnsignedInt(position, state.takenCountOffset) + data.readUnsignedInt(position, state.notTakenCountOffset); + return VMState.truncateLongToInt(count); } @Override public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { - long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); - long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); + long taken = data.readUnsignedInt(pos, state.takenCountOffset); + long notTaken = data.readUnsignedInt(pos, state.notTakenCountOffset); double takenProbability = getBranchTakenProbability(data, pos); return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); } } - static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(config.arrayDataArrayLenOffset); - static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(config.arrayDataArrayStartOffset); - static class ArrayData extends HotSpotMethodDataAccessor { - ArrayData(HotSpotVMConfig config, int tag, int staticSize) { - super(config, tag, staticSize); + ArrayData(VMState state, int tag, int staticSize) { + super(state, tag, staticSize); } @Override protected int getDynamicSize(HotSpotMethodData data, int position) { - return cellsToBytes(getLength(data, position)); + return state.cellsToBytes(getLength(data, position)); } - protected static int getLength(HotSpotMethodData data, int position) { - return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); + protected int getLength(HotSpotMethodData data, int position) { + return data.readInt(position, state.arrayDataLengthOffset); } @Override @@ -710,25 +775,19 @@ } } - static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); - static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = config.multiBranchDataPerCaseCellCount; - static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); - static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); - static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); - static class MultiBranchData extends ArrayData { - MultiBranchData(HotSpotVMConfig config, int tag) { - super(config, tag, MULTI_BRANCH_DATA_SIZE); + MultiBranchData(VMState state, int tag) { + super(state, tag, state.multiBranchDataSize); } @Override public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { int arrayLength = getLength(data, position); assert arrayLength > 0 : "switch must have at least the default case"; - assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; - int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + int length = arrayLength / state.multiBranchDataRowSizeInCells; long totalCount = 0; double[] result = new double[length]; @@ -753,7 +812,7 @@ } } - private static long readCount(HotSpotMethodData data, int position, int i) { + private long readCount(HotSpotMethodData data, int position, int i) { int offset; long count; offset = getCountOffset(i); @@ -765,29 +824,29 @@ public int getExecutionCount(HotSpotMethodData data, int position) { int arrayLength = getLength(data, position); assert arrayLength > 0 : "switch must have at least the default case"; - assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; - int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + int length = arrayLength / state.multiBranchDataRowSizeInCells; long totalCount = 0; for (int i = 0; i < length; i++) { int offset = getCountOffset(i); totalCount += data.readUnsignedInt(position, offset); } - return truncateLongToInt(totalCount); + return VMState.truncateLongToInt(totalCount); } - private static int getCountOffset(int index) { - return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + private int getCountOffset(int index) { + return state.multiBranchDataFirstCountOffset + index * state.multiBranchDataRowSize; } - private static int getDisplacementOffset(int index) { - return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + private int getDisplacementOffset(int index) { + return state.multiBranchDataFirstDisplacementOffset + index * state.multiBranchDataRowSize; } @Override public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { - int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + int entries = getLength(data, pos) / state.multiBranchDataRowSizeInCells; sb.append(format("entries(%d)", entries)); for (int i = 0; i < entries; i++) { sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); @@ -796,18 +855,16 @@ } } - static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); - static class ArgInfoData extends ArrayData { - ArgInfoData(HotSpotVMConfig config, int tag) { - super(config, tag, ARG_INFO_DATA_SIZE); + ArgInfoData(VMState state, int tag) { + super(state, tag, state.argInfoDataSize); } } static class UnknownProfileData extends HotSpotMethodDataAccessor { - UnknownProfileData(HotSpotVMConfig config, int tag) { - super(config, tag, 0); + UnknownProfileData(VMState state, int tag) { + super(state, tag, 0); } @Override @@ -824,47 +881,10 @@ } public void setCompiledIRSize(int size) { - UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); + UNSAFE.putInt(metaspaceMethodData + state.config.methodDataIRSizeOffset, size); } public int getCompiledIRSize() { - return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); + return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataIRSizeOffset); } - - // sorted by tag - // @formatter:off - static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { - null, - new BitData(config, config.dataLayoutBitDataTag), - new CounterData(config, config.dataLayoutCounterDataTag), - new JumpData(config, config.dataLayoutJumpDataTag), - new ReceiverTypeData(config, config.dataLayoutReceiverTypeDataTag), - new VirtualCallData(config, config.dataLayoutVirtualCallDataTag), - new RetData(config, config.dataLayoutRetDataTag), - new BranchData(config, config.dataLayoutBranchDataTag), - new MultiBranchData(config, config.dataLayoutMultiBranchDataTag), - new ArgInfoData(config, config.dataLayoutArgInfoDataTag), - new UnknownProfileData(config, config.dataLayoutCallTypeDataTag), - new VirtualCallTypeData(config, config.dataLayoutVirtualCallTypeDataTag), - new UnknownProfileData(config, config.dataLayoutParametersTypeDataTag), - new UnknownProfileData(config, config.dataLayoutSpeculativeTrapDataTag), - }; - - private static boolean checkAccessorTags() { - int expectedTag = 0; - for (HotSpotMethodDataAccessor accessor : PROFILE_DATA_ACCESSORS) { - if (expectedTag == 0) { - assert accessor == null; - } else { - assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor; - } - expectedTag++; - } - return true; - } - - static { - assert checkAccessorTags(); - } - // @formatter:on } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,10 +36,12 @@ final int tag; final int staticSize; + final HotSpotMethodData.VMState state; final HotSpotVMConfig config; - protected HotSpotMethodDataAccessor(HotSpotVMConfig config, int tag, int staticSize) { - this.config = config; + protected HotSpotMethodDataAccessor(HotSpotMethodData.VMState state, int tag, int staticSize) { + this.state = state; + this.config = state.config; this.tag = tag; this.staticSize = staticSize; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,10 @@ import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import java.lang.invoke.MethodHandle; -import java.util.Objects; import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.common.NativeImageReinitialize; +import jdk.vm.ci.hotspot.HotSpotMethodData.VMState; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MethodHandleAccessProvider; @@ -45,15 +46,16 @@ } /** - * Lazy initialization to break class initialization cycle. Field and method lookup is only - * possible after the {@link HotSpotJVMCIRuntime} is fully initialized. + * Lazy initialized reflection on {@link MethodHandle} internals. Field and method lookup is + * only possible after the {@link HotSpotJVMCIRuntime} is fully initialized. */ - static class LazyInitialization { - static final ResolvedJavaType lambdaFormType; - static final ResolvedJavaField methodHandleFormField; - static final ResolvedJavaField lambdaFormVmentryField; - static final ResolvedJavaField methodField; - static final HotSpotResolvedJavaField vmtargetField; + static final class Internals { + final ResolvedJavaType lambdaFormType; + final ResolvedJavaField methodHandleFormField; + final ResolvedJavaField lambdaFormVmentryField; + final HotSpotResolvedJavaField callSiteTargetField; + final ResolvedJavaField methodField; + final HotSpotResolvedJavaField vmtargetField; /** * Search for an instance field with the given name in a class. @@ -71,34 +73,53 @@ return field; } } - throw new NoSuchFieldError(fieldType.getName() + " " + declaringType + "." + fieldName); + throw new NoSuchFieldError(declaringType + "." + fieldName); } - private static ResolvedJavaType resolveType(Class c) { - return runtime().fromClass(c); - } - - private static ResolvedJavaType resolveType(String className) throws ClassNotFoundException { - return resolveType(Class.forName(className)); + private static ResolvedJavaType resolveType(String className) { + return (ResolvedJavaType) runtime().lookupTypeInternal(className, null, true); } - static { + private Internals() { try { - ResolvedJavaType methodHandleType = resolveType(MethodHandle.class); - ResolvedJavaType memberNameType = resolveType("java.lang.invoke.MemberName"); - lambdaFormType = resolveType("java.lang.invoke.LambdaForm"); + ResolvedJavaType methodHandleType = resolveType("Ljava/lang/invoke/MethodHandle;"); + ResolvedJavaType memberNameType = resolveType("Ljava/lang/invoke/MemberName;"); + lambdaFormType = resolveType("Ljava/lang/invoke/LambdaForm;"); methodHandleFormField = findFieldInClass(methodHandleType, "form", lambdaFormType); lambdaFormVmentryField = findFieldInClass(lambdaFormType, "vmentry", memberNameType); - ResolvedJavaType methodType = resolveType("java.lang.invoke.ResolvedMethodName"); + + ResolvedJavaType methodType = resolveType("Ljava/lang/invoke/ResolvedMethodName;"); methodField = findFieldInClass(memberNameType, "method", methodType); - vmtargetField = (HotSpotResolvedJavaField) findFieldInClass(methodType, "vmtarget", resolveType(HotSpotJVMCIRuntime.getHostWordKind().toJavaClass())); + vmtargetField = (HotSpotResolvedJavaField) findFieldInClass(methodType, "vmtarget", resolveType(Character.toString(HotSpotJVMCIRuntime.getHostWordKind().getTypeChar()))); + ResolvedJavaType callSiteType = resolveType("Ljava/lang/invoke/CallSite;"); + callSiteTargetField = (HotSpotResolvedJavaField) findFieldInClass(callSiteType, "target", methodHandleType); } catch (Throwable ex) { throw new JVMCIError(ex); } } + + /** + * Singleton instance lazily initialized via double-checked locking. + */ + @NativeImageReinitialize private static volatile Internals instance; + + static Internals instance() { + Internals result = instance; + if (result == null) { + synchronized (VMState.class) { + result = instance; + if (result == null) { + instance = result = new Internals(); + } + } + } + return result; + } + } + @Override public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) { int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId(); @@ -131,19 +152,19 @@ } /* Load non-public field: LambdaForm MethodHandle.form */ - JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle); + Internals internals = Internals.instance(); + JavaConstant lambdaForm = constantReflection.readFieldValue(internals.methodHandleFormField, methodHandle); if (lambdaForm == null || lambdaForm.isNull()) { return null; } - JavaConstant memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); + JavaConstant memberName = constantReflection.readFieldValue(internals.lambdaFormVmentryField, lambdaForm); if (memberName.isNull() && forceBytecodeGeneration) { - Object lf = ((HotSpotObjectConstant) lambdaForm).asObject(LazyInitialization.lambdaFormType); - compilerToVM().compileToBytecode(Objects.requireNonNull(lf)); - memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); + compilerToVM().compileToBytecode((HotSpotObjectConstantImpl) lambdaForm); + memberName = constantReflection.readFieldValue(internals.lambdaFormVmentryField, lambdaForm); assert memberName.isNonNull(); } - JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName); + JavaConstant method = constantReflection.readFieldValue(internals.methodField, memberName); return getTargetMethod(method); } @@ -152,7 +173,7 @@ if (memberName.isNull()) { return null; } - JavaConstant method = constantReflection.readFieldValue(LazyInitialization.methodField, memberName); + JavaConstant method = constantReflection.readFieldValue(Internals.instance().methodField, memberName); return getTargetMethod(method); } @@ -165,8 +186,7 @@ throw new IllegalArgumentException("unexpected type for memberName"); } - Object object = ((HotSpotObjectConstantImpl) method).object(); /* Read the ResolvedJavaMethod from the injected field MemberName.method.vmtarget */ - return compilerToVM().getResolvedJavaMethod(object, LazyInitialization.vmtargetField.getOffset()); + return compilerToVM().getResolvedJavaMethod((HotSpotObjectConstantImpl) method, Internals.instance().vmtargetField.getOffset()); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package jdk.vm.ci.hotspot; import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; + import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.InvalidInstalledCodeException; import jdk.vm.ci.meta.JavaKind; @@ -30,56 +32,104 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; /** - * Implementation of {@link InstalledCode} for code installed as an nmethod. - * - * When a {@link HotSpotNmethod} dies, it triggers unloading of the nmethod unless - * {@link #isDefault() == true}. + * Implementation of {@link InstalledCode} for code installed as an {@code nmethod}. The address of + * the {@code nmethod} is stored in {@link InstalledCode#address} and the value of + * {@code nmethod::verified_entry_point()} is in {@link InstalledCode#entryPoint}. */ public class HotSpotNmethod extends HotSpotInstalledCode { /** - * This (indirect) Method* reference is safe since class redefinition preserves all methods - * associated with nmethods in the code cache. + * This (indirect) {@code Method*} reference is safe since class redefinition preserves all + * methods associated with nmethods in the code cache. */ - private final HotSpotResolvedJavaMethod method; + private final HotSpotResolvedJavaMethodImpl method; + /** + * Specifies whether the {@code nmethod} associated with this object is the code executed by + * default HotSpot linkage when a normal Java call to {@link #method} is made. That is, does + * {@code this.method.metadataHandle->_code} == {@code this.address}. If not, then the + * {@code nmethod} can only be invoked via a reference to this object. An example of this is the + * trampoline mechanism used by Truffle: https://goo.gl/LX88rZ. + */ private final boolean isDefault; - public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault) { + /** + * Determines whether this object is in the oops table of the nmethod. + *

+ * If this object is in the oops table, the VM uses the oops table entry to update this object's + * {@link #address} and {@link #entryPoint} fields when the state of the nmethod changes. The + * nmethod will be unloadable when this object dies. + *

+ * Otherwise, the nmethod's unloadability is not changed when this object dies. + */ + boolean inOopsTable() { + return compileIdSnapshot != 0; + } + + /** + * If this field is 0, this object is in the oops table of the nmethod. Otherwise, the value of + * the field records the nmethod's compile identifier. This value is used to confirm an entry in + * the code cache retrieved by {@link #address} is indeed the nmethod represented by this + * object. + * + * @see #inOopsTable + */ + private final long compileIdSnapshot; + + HotSpotNmethod(HotSpotResolvedJavaMethodImpl method, String name, boolean isDefault, long compileId) { super(name); this.method = method; this.isDefault = isDefault; + boolean inOopsTable = !IS_IN_NATIVE_IMAGE && !isDefault; + this.compileIdSnapshot = inOopsTable ? 0L : compileId; + assert inOopsTable || compileId != 0L : this; } /** * Determines if the nmethod associated with this object is the compiled entry point for - * {@link #getMethod()}. If {@code false}, then the nmethod is unloaded when the VM determines - * this object has died. + * {@link #getMethod()}. */ public boolean isDefault() { return isDefault; } + @Override + public boolean isValid() { + if (compileIdSnapshot != 0L) { + compilerToVM().updateHotSpotNmethod(this); + } + return super.isValid(); + } + public ResolvedJavaMethod getMethod() { return method; } @Override public void invalidate() { - compilerToVM().invalidateInstalledCode(this); + compilerToVM().invalidateHotSpotNmethod(this); + } + + @Override + public long getAddress() { + if (compileIdSnapshot != 0L) { + compilerToVM().updateHotSpotNmethod(this); + } + return super.getAddress(); + } + + @Override + public long getEntryPoint() { + if (compileIdSnapshot != 0L) { + return 0; + } + return super.getEntryPoint(); } @Override public String toString() { - return String.format("InstalledNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name); - } - - protected boolean checkThreeObjectArgs() { - assert method.getSignature().getParameterCount(!method.isStatic()) == 3; - assert method.getSignature().getParameterKind(0) == JavaKind.Object; - assert method.getSignature().getParameterKind(1) == JavaKind.Object; - assert !method.isStatic() || method.getSignature().getParameterKind(2) == JavaKind.Object; - return true; + return String.format("HotSpotNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s, inOopsTable=%s]", + method, getAddress(), isDefault, name, inOopsTable()); } private boolean checkArgs(Object... args) { @@ -98,8 +148,11 @@ @Override public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + if (IS_IN_NATIVE_IMAGE) { + throw new HotSpotJVMCIUnsupportedOperationError("Cannot execute nmethod via mirror in native image"); + } assert checkArgs(args); - return compilerToVM().executeInstalledCode(args, this); + return compilerToVM().executeHotSpotNmethod(args, this); } @Override diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,14 +22,9 @@ */ package jdk.vm.ci.hotspot; -import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.fromObjectClass; - -import java.lang.invoke.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import jdk.vm.ci.meta.Assumptions; -import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; @@ -38,45 +33,12 @@ * Represents a constant non-{@code null} object reference, within the compiler and across the * compiler/runtime interface. */ -class HotSpotObjectConstantImpl implements HotSpotObjectConstant { - - static JavaConstant forObject(Object object) { - return forObject(object, false); - } - - static JavaConstant forObject(Object object, boolean compressed) { - if (object == null) { - return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER; - } else { - return new HotSpotObjectConstantImpl(object, compressed); - } - } +abstract class HotSpotObjectConstantImpl implements HotSpotObjectConstant { - public static JavaConstant forBoxedValue(JavaKind kind, Object value) { - if (kind == JavaKind.Object) { - return HotSpotObjectConstantImpl.forObject(value); - } else { - return JavaConstant.forBoxedPrimitive(value); - } - } + protected final boolean compressed; - static Object asBoxedValue(Constant constant) { - if (JavaConstant.isNull(constant)) { - return null; - } else if (constant instanceof HotSpotObjectConstantImpl) { - return ((HotSpotObjectConstantImpl) constant).object; - } else { - return ((JavaConstant) constant).asBoxedPrimitive(); - } - } - - private final Object object; - private final boolean compressed; - - protected HotSpotObjectConstantImpl(Object object, boolean compressed) { - this.object = object; + HotSpotObjectConstantImpl(boolean compressed) { this.compressed = compressed; - assert object != null; } @Override @@ -84,82 +46,54 @@ return JavaKind.Object; } - /** - * Package-private accessor for the object represented by this constant. - */ - Object object() { - return object; - } - @Override public boolean isCompressed() { return compressed; } @Override - public JavaConstant compress() { - assert !compressed; - return new HotSpotObjectConstantImpl(object, true); - } + public abstract JavaConstant compress(); @Override - public JavaConstant uncompress() { - assert compressed; - return new HotSpotObjectConstantImpl(object, false); - } + public abstract JavaConstant uncompress(); @Override public HotSpotResolvedObjectType getType() { - return fromObjectClass(object.getClass()); + return runtime().reflection.getType(this); } @Override - public int getIdentityHashCode() { - return System.identityHashCode(object); - } + public abstract int getIdentityHashCode(); @Override public JavaConstant getCallSiteTarget(Assumptions assumptions) { - if (object instanceof CallSite) { - CallSite callSite = (CallSite) object; - MethodHandle target = callSite.getTarget(); - JavaConstant targetConstant = HotSpotObjectConstantImpl.forObject(target); - if (!(callSite instanceof ConstantCallSite)) { + if (runtime().getCallSite().isInstance(this)) { + HotSpotObjectConstantImpl target = (HotSpotObjectConstantImpl) runtime().getHostJVMCIBackend().getConstantReflection().readFieldValue( + HotSpotMethodHandleAccessProvider.Internals.instance().callSiteTargetField, this); + if (!runtime().getConstantCallSite().isInstance(this)) { if (assumptions == null) { return null; } - assumptions.record(new Assumptions.CallSiteTargetValue(this, targetConstant)); + assumptions.record(new Assumptions.CallSiteTargetValue(this, target)); } - - return targetConstant; + return target; } return null; } @Override - @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want") public boolean isInternedString() { - if (object instanceof String) { - String s = (String) object; - return s.intern() == s; - } - return false; + return runtime().compilerToVm.isInternedString(this); } @Override public T asObject(Class type) { - if (type.isInstance(object)) { - return type.cast(object); - } - return null; + return runtime().reflection.asObject(this, type); } @Override public Object asObject(ResolvedJavaType type) { - if (type.isInstance(this)) { - return object; - } - return null; + return runtime().reflection.asObject(this, (HotSpotResolvedJavaType) type); } @Override @@ -203,32 +137,40 @@ } @Override - public int hashCode() { - return System.identityHashCode(object); - } - - @Override public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof HotSpotObjectConstantImpl) { HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o; - return object == other.object && compressed == other.compressed; + return runtime().reflection.equals(this, other); } return false; } @Override + public int hashCode() { + return getIdentityHashCode(); + } + + @Override public String toValueString() { - if (object instanceof String) { - return "\"" + (String) object + "\""; + if (runtime().getJavaLangString().isInstance(this)) { + return "\"" + runtime().reflection.asString(this) + "\""; } else { - return JavaKind.Object.format(object); + return runtime().reflection.formatString(this); } } @Override public String toString() { - return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + JavaKind.Object.format(object) + "]"; + return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + runtime().reflection.formatString(this) + "]"; + } + + public JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) { + return runtime().reflection.readFieldValue(this, field, isVolatile); + } + + public ResolvedJavaType asJavaType() { + return runtime().reflection.asJavaType(this); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,15 +22,14 @@ */ package jdk.vm.ci.hotspot; -import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; -import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; -import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmFieldModifiers; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; +import static jdk.internal.misc.Unsafe.ADDRESS_SIZE; import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.util.HashMap; + +import jdk.internal.vm.annotation.Stable; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; @@ -44,7 +43,15 @@ private final HotSpotResolvedObjectTypeImpl holder; private JavaType type; + + /** + * Value of {@code fieldDescriptor::access_flags()}. + */ private final int offset; + + /** + * Value of {@code fieldDescriptor::index()}. + */ private final short index; /** @@ -68,7 +75,7 @@ if (this == obj) { return true; } - if (obj instanceof HotSpotResolvedJavaField) { + if (obj instanceof HotSpotResolvedJavaFieldImpl) { HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; if (that.offset != this.offset || that.isStatic() != this.isStatic()) { return false; @@ -86,7 +93,7 @@ @Override public int getModifiers() { - return modifiers & jvmFieldModifiers(); + return modifiers & HotSpotModifiers.jvmFieldModifiers(); } @Override @@ -101,12 +108,12 @@ * {@code object}'s class */ @Override - public boolean isInObject(JavaConstant constant) { + public boolean isInObject(JavaConstant object) { if (isStatic()) { return false; } - Object object = ((HotSpotObjectConstantImpl) constant).object(); - return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); + HotSpotObjectConstant constant = (HotSpotObjectConstant) object; + return getDeclaringClass().isAssignableFrom(constant.getType()); } @Override @@ -127,12 +134,13 @@ if (currentType instanceof UnresolvedJavaType) { // Don't allow unresolved types to hang around forever UnresolvedJavaType unresolvedType = (UnresolvedJavaType) currentType; - ResolvedJavaType resolved = holder.lookupType(unresolvedType, false); - if (resolved != null) { + JavaType resolved = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedType.getName(), holder, false); + if (resolved instanceof ResolvedJavaType) { type = resolved; } } return type; + } @Override @@ -140,9 +148,17 @@ return offset; } + /** + * Gets the value of this field's index (i.e. {@code fieldDescriptor::index()} in the encoded + * fields of the declaring class. + */ + int getIndex() { + return index; + } + @Override public String toString() { - return format("HotSpotField<%H.%n %t:") + offset + ">"; + return format("HotSpotResolvedJavaFieldImpl<%H.%n %t:") + offset + ">"; } @Override @@ -151,9 +167,9 @@ } /** - * Checks if this field has the {@code Stable} annotation. + * Checks if this field has the {@link Stable} annotation. * - * @return true if field has {@code Stable} annotation, false otherwise + * @return true if field has {@link Stable} annotation, false otherwise */ @Override public boolean isStable() { @@ -180,7 +196,7 @@ if (!hasAnnotations()) { return new Annotation[0]; } - return toJava().getAnnotations(); + return runtime().reflection.getFieldAnnotations(this); } @Override @@ -188,7 +204,7 @@ if (!hasAnnotations()) { return new Annotation[0]; } - return toJava().getDeclaredAnnotations(); + return runtime().reflection.getFieldDeclaredAnnotations(this); } @Override @@ -196,29 +212,6 @@ if (!hasAnnotations()) { return null; } - return toJava().getAnnotation(annotationClass); - } - - /** - * Gets a {@link Field} object corresponding to this object. This method always returns the same - * {@link Field} object for a given {@link HotSpotResolvedJavaFieldImpl}. This ensures - * {@link #getDeclaredAnnotations()}, {@link #getAnnotations()} and - * {@link #getAnnotation(Class)} are stable with respect to the identity of the - * {@link Annotation} objects they return. - */ - private Field toJava() { - synchronized (holder) { - HashMap cache = holder.reflectionFieldCache; - if (cache == null) { - cache = new HashMap<>(); - holder.reflectionFieldCache = cache; - } - Field reflect = cache.get(this); - if (reflect == null) { - reflect = compilerToVM().asReflectionField(holder, index); - cache.put(this, reflect); - } - return reflect; - } + return runtime().reflection.getFieldAnnotation(this, annotationClass); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,8 +35,6 @@ import java.lang.reflect.Executable; import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; @@ -58,23 +56,24 @@ /** * Implementation of {@link JavaMethod} for resolved HotSpot methods. */ -final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, MetaspaceWrapperObject { +final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, MetaspaceHandleObject { /** - * Reference to metaspace Method object. + * Handle to the metaspace {@code Method} object. The handle is in + * {@code JVMCI::_metadata_handles}. */ - private final long metaspaceMethod; + private final long metadataHandle; private final HotSpotResolvedObjectTypeImpl holder; private final HotSpotConstantPool constantPool; - private final HotSpotSignature signature; + final HotSpotSignature signature; private HotSpotMethodData methodData; private byte[] code; /** - * Cache for {@link #toJava()}. + * Cache for {@link HotSpotJDKReflection#getMethod}. */ - private volatile Executable toJavaCache; + volatile Executable toJavaCache; /** * Only 30% of {@link HotSpotResolvedJavaMethodImpl}s have their name accessed so compute it @@ -85,35 +84,40 @@ /** * Gets the holder of a HotSpot metaspace method native object. * - * @param metaspaceMethod a metaspace Method object + * @param metaspaceHandle a handle to a metaspace Method object * @return the {@link ResolvedJavaType} corresponding to the holder of the * {@code metaspaceMethod} */ - private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { + private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceHandle) { HotSpotVMConfig config = config(); + long metaspaceMethod = UNSAFE.getLong(metaspaceHandle); + assert metaspaceMethod != 0 : metaspaceHandle; final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); - return compilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); + HotSpotResolvedObjectTypeImpl result = compilerToVM().getResolvedJavaType(metaspaceConstantPool + config.constantPoolHolderOffset, false); + assert result != null; + return result; } /** * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the - * Method* is kept alive for the duration of this call and the - * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. - * + * Method* is kept alive for the duration of this call and the {@link HotSpotJVMCIRuntime} keeps + * it alive after that. + *

* Called from the VM. * - * @param metaspaceMethod a metaspace Method object + * @param metaspaceHandle a handle to metaspace Method object * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} */ @SuppressWarnings("unused") - private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { - HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); - return holder.createMethod(metaspaceMethod); + @VMEntryPoint + private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceHandle) { + HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceHandle); + return holder.createMethod(metaspaceHandle); } - HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { - this.metaspaceMethod = metaspaceMethod; + HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceHandle) { + this.metadataHandle = metaspaceHandle; this.holder = holder; HotSpotVMConfig config = config(); @@ -133,6 +137,7 @@ final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); + HandleCleaner.create(this, metaspaceHandle); } /** @@ -144,8 +149,7 @@ * @return pointer to this method's ConstMethod */ private long getConstMethod() { - assert metaspaceMethod != 0; - return UNSAFE.getAddress(metaspaceMethod + config().methodConstMethodOffset); + return UNSAFE.getAddress(getMetaspaceMethod() + config().methodConstMethodOffset); } @Override @@ -164,14 +168,14 @@ } if (obj instanceof HotSpotResolvedJavaMethodImpl) { HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; - return that.metaspaceMethod == metaspaceMethod; + return that.getMetaspaceMethod() == getMetaspaceMethod(); } return false; } @Override public int hashCode() { - return (int) metaspaceMethod; + return (int) getMetaspaceMethod(); } /** @@ -180,7 +184,7 @@ * @return flags of this method */ private int getFlags() { - return UNSAFE.getShort(metaspaceMethod + config().methodFlagsOffset); + return UNSAFE.getShort(getMetaspaceMethod() + config().methodFlagsOffset); } /** @@ -204,9 +208,17 @@ return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); } + long getMetaspaceMethod() { + long metaspacePointer = getMetaspacePointer(); + if (metaspacePointer == 0) { + throw new NullPointerException("Method* is null"); + } + return metaspacePointer; + } + @Override - public long getMetaspacePointer() { - return metaspaceMethod; + public long getMetadataHandle() { + return metadataHandle; } @Override @@ -219,7 +231,7 @@ * modifiers as well as the HotSpot internal modifiers. */ public int getAllModifiers() { - return UNSAFE.getInt(metaspaceMethod + config().methodAccessFlagsOffset); + return UNSAFE.getInt(getMetaspaceMethod() + config().methodAccessFlagsOffset); } @Override @@ -277,7 +289,7 @@ // Check for Throwable which catches everything. if (catchType instanceof HotSpotResolvedObjectTypeImpl) { HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; - if (resolvedType.mirror() == Throwable.class) { + if (resolvedType.equals(runtime().getJavaLangThrowable())) { catchTypeIndex = 0; catchType = null; } @@ -424,7 +436,7 @@ */ private long getCompiledCode() { HotSpotVMConfig config = config(); - return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); + return UNSAFE.getAddress(getMetaspaceMethod() + config.methodCodeOffset); } /** @@ -455,7 +467,7 @@ ProfilingInfo info; if (Option.UseProfilingInformation.getBoolean() && methodData == null) { - long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset); + long metaspaceMethodData = UNSAFE.getAddress(getMetaspaceMethod() + config().methodDataOffset); if (metaspaceMethodData != 0) { methodData = new HotSpotMethodData(metaspaceMethodData, this); String methodDataFilter = Option.TraceMethodDataFilter.getString(); @@ -490,14 +502,7 @@ if (signature.getParameterCount(false) == 0) { return new ResolvedJavaMethod.Parameter[0]; } - java.lang.reflect.Parameter[] javaParameters = toJava().getParameters(); - Parameter[] res = new Parameter[javaParameters.length]; - for (int i = 0; i < res.length; i++) { - java.lang.reflect.Parameter src = javaParameters[i]; - String paramName = src.isNamePresent() ? src.getName() : null; - res[i] = new Parameter(paramName, src.getModifiers(), this, i); - } - return res; + return runtime().reflection.getParameters(this); } @Override @@ -505,7 +510,7 @@ if ((getConstMethodFlags() & config().constMethodHasParameterAnnotations) == 0) { return new Annotation[signature.getParameterCount(false)][0]; } - return toJava().getParameterAnnotations(); + return runtime().reflection.getParameterAnnotations(this); } @Override @@ -513,7 +518,7 @@ if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { return new Annotation[0]; } - return toJava().getAnnotations(); + return runtime().reflection.getMethodAnnotations(this); } @Override @@ -521,7 +526,7 @@ if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { return new Annotation[0]; } - return toJava().getDeclaredAnnotations(); + return runtime().reflection.getMethodDeclaredAnnotations(this); } @Override @@ -529,7 +534,7 @@ if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { return null; } - return toJava().getAnnotation(annotationClass); + return runtime().reflection.getMethodAnnotation(this, annotationClass); } @Override @@ -559,19 +564,7 @@ if (isClassInitializer()) { return new Type[0]; } - return toJava().getGenericParameterTypes(); - } - - private Executable toJava() { - if (toJavaCache == null) { - assert !isClassInitializer() : this; - synchronized (this) { - if (toJavaCache == null) { - toJavaCache = compilerToVM().asReflectionExecutable(this); - } - } - } - return toJavaCache; + return runtime().reflection.getGenericParameterTypes(this); } @Override @@ -698,7 +691,7 @@ private int getVtableIndex() { assert !holder.isInterface(); HotSpotVMConfig config = config(); - int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); + int result = UNSAFE.getInt(getMetaspaceMethod() + config.methodVtableIndexOffset); assert result >= config.nonvirtualVtableIndex : "must be linked"; return result; } @@ -708,40 +701,16 @@ return compilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); } - /** - * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type - * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is - * never moves and b) we never read from it. - *

- * One implication is that we will preserve {@link SpeculationLog}s for methods that have been - * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot - * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods - * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). - */ - private static final ClassValue> SpeculationLogs = new ClassValue<>() { - @Override - protected Map computeValue(java.lang.Class type) { - return new HashMap<>(4); - } - }; - @Override public SpeculationLog getSpeculationLog() { - Map map = SpeculationLogs.get(holder.mirror()); - synchronized (map) { - SpeculationLog log = map.get(this.metaspaceMethod); - if (log == null) { - log = new HotSpotSpeculationLog(); - map.put(metaspaceMethod, log); - } - return log; - } + long address = compilerToVM().getFailedSpeculationsAddress(this); + return new HotSpotSpeculationLog(address); } @Override public int intrinsicId() { HotSpotVMConfig config = config(); - return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset); + return UNSAFE.getChar(getMetaspaceMethod() + config.methodIntrinsicIdOffset); } @Override diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ package jdk.vm.ci.hotspot; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaType; public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { @@ -30,20 +31,13 @@ super(name); } - abstract Class mirror(); - @Override - public final boolean equals(Object obj) { - if (!(obj instanceof HotSpotResolvedJavaType)) { - return false; - } - HotSpotResolvedJavaType that = (HotSpotResolvedJavaType) obj; - return this.mirror().equals(that.mirror()); - } + public abstract boolean equals(Object obj); @Override public final int hashCode() { return getName().hashCode(); } + abstract JavaConstant getJavaMirror(); } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,7 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.ByteOrder; import java.util.HashMap; @@ -56,9 +53,11 @@ import jdk.vm.ci.meta.UnresolvedJavaType; /** - * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. This class is not + * an {@link MetaspaceHandleObject} because it doesn't have to be scanned for GC. It's liveness is + * maintained by a reference to the {@link Class} instance. */ -final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceWrapperObject { +final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceObject { private static final HotSpotResolvedJavaField[] NO_FIELDS = new HotSpotResolvedJavaField[0]; private static final int METHOD_CACHE_ARRAY_CAPACITY = 8; @@ -66,94 +65,71 @@ /** * The Java class this type represents. */ - private final Class javaClass; + private final long metadataPointer; + private HotSpotResolvedJavaMethodImpl[] methodCacheArray; private HashMap methodCacheHashMap; - private HotSpotResolvedJavaField[] instanceFields; - private HotSpotResolvedObjectTypeImpl[] interfaces; + private volatile HotSpotResolvedJavaField[] instanceFields; + private volatile HotSpotResolvedObjectTypeImpl[] interfaces; private HotSpotConstantPool constantPool; - final HotSpotJVMCIMetaAccessContext context; private HotSpotResolvedObjectType arrayOfType; + private final JavaConstant mirror; + private HotSpotResolvedObjectTypeImpl superClass; /** - * Managed exclusively by {@link HotSpotResolvedJavaFieldImpl#toJava}. + * Managed exclusively by {@link HotSpotJDKReflection#getField}. */ HashMap reflectionFieldCache; - /** - * Gets the JVMCI mirror for a {@link Class} object. - * - * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} - */ - static HotSpotResolvedObjectTypeImpl fromObjectClass(Class javaClass) { - return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); + static HotSpotResolvedObjectTypeImpl getJavaLangObject() { + return runtime().getJavaLangObject(); } /** - * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the - * underlying Klass*, it is used instead of the raw Klass*. + * Gets the JVMCI mirror from a HotSpot type. * * Called from the VM. * - * @param javaClass a {@link Class} object + * @param klassPointer a native pointer to the Klass* * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} */ @SuppressWarnings("unused") - private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class javaClass) { - return fromObjectClass(javaClass); + @VMEntryPoint + private static HotSpotResolvedObjectTypeImpl fromMetaspace(long klassPointer, String signature) { + return runtime().fromMetaspace(klassPointer, signature); } /** * Creates the JVMCI mirror for a {@link Class} object. * - *

* NOTE: Creating an instance of this class does not install the mirror for the - * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} - * instead. + * {@link Class} type. {@link #fromMetaspace} instead. *

* - * @param javaClass the Class to create the mirror for - * @param context + * @param metadataPointer the Klass* to create the mirror for */ - HotSpotResolvedObjectTypeImpl(Class javaClass, HotSpotJVMCIMetaAccessContext context) { - super(getSignatureName(javaClass)); - this.javaClass = javaClass; - this.context = context; + HotSpotResolvedObjectTypeImpl(long metadataPointer, String name) { + super(name); + this.metadataPointer = metadataPointer; + this.mirror = runtime().compilerToVm.getJavaMirror(this); + assert metadataPointer != 0; assert getName().charAt(0) != '[' || isArray() : getName(); } /** - * Returns the name of this type as it would appear in a signature. - */ - private static String getSignatureName(Class javaClass) { - if (javaClass.isArray()) { - return javaClass.getName().replace('.', '/'); - } - return "L" + javaClass.getName().replace('.', '/') + ";"; - } - - /** * Gets the metaspace Klass for this type. */ long getMetaspaceKlass() { - if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { - return UNSAFE.getLong(javaClass, config().klassOffset); + long metaspacePointer = getMetaspacePointer(); + if (metaspacePointer == 0) { + throw new NullPointerException("Klass* is null"); } - return UNSAFE.getInt(javaClass, config().klassOffset) & 0xFFFFFFFFL; + return metaspacePointer; } @Override public long getMetaspacePointer() { - return getMetaspaceKlass(); - } - - /** - * The Klass* for this object is kept alive by the direct reference to {@link #javaClass} so no - * extra work is required. - */ - @Override - public boolean isRegistered() { - return true; + return metadataPointer; } @Override @@ -173,15 +149,18 @@ @Override public HotSpotResolvedObjectType getArrayClass() { if (arrayOfType == null) { - arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); + try { + arrayOfType = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + getName(), this, true); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } } return arrayOfType; } @Override public ResolvedJavaType getComponentType() { - Class javaComponentType = mirror().getComponentType(); - return javaComponentType == null ? null : runtime().fromClass(javaComponentType); + return runtime().compilerToVm.getComponentType(this); } @Override @@ -279,19 +258,35 @@ @Override public HotSpotResolvedObjectTypeImpl getSuperclass() { - Class javaSuperclass = mirror().getSuperclass(); - return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); + if (isInterface()) { + return null; + } + HotSpotResolvedObjectTypeImpl javaLangObject = runtime().getJavaLangObject(); + if (this.equals(javaLangObject)) { + return null; + } + if (isArray()) { + return javaLangObject; + } + + // Cache result of native call + if (superClass == null) { + superClass = compilerToVM().getResolvedJavaType(this, config().superOffset, false); + } + return superClass; } @Override public HotSpotResolvedObjectTypeImpl[] getInterfaces() { if (interfaces == null) { - Class[] javaInterfaces = mirror().getInterfaces(); - HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; - for (int i = 0; i < javaInterfaces.length; i++) { - result[i] = fromObjectClass(javaInterfaces[i]); + if (isArray()) { + HotSpotResolvedObjectTypeImpl[] types = new HotSpotResolvedObjectTypeImpl[2]; + types[0] = runtime().getJavaLangCloneable(); + types[1] = runtime().getJavaLangSerializable(); + this.interfaces = types; + } else { + interfaces = runtime().compilerToVm.getInterfaces(this); } - interfaces = result; } return interfaces; } @@ -308,13 +303,14 @@ public HotSpotResolvedObjectTypeImpl getSupertype() { if (isArray()) { ResolvedJavaType componentType = getComponentType(); - if (mirror() == Object[].class || componentType.isPrimitive()) { - return fromObjectClass(Object.class); + if (componentType.equals(getJavaLangObject()) || componentType.isPrimitive()) { + return getJavaLangObject(); } - return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); + HotSpotResolvedObjectTypeImpl supertype = ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype(); + return (HotSpotResolvedObjectTypeImpl) supertype.getArrayClass(); } if (isInterface()) { - return fromObjectClass(Object.class); + return getJavaLangObject(); } return getSuperclass(); } @@ -354,18 +350,14 @@ } @Override - public boolean isPrimitive() { - return false; - } - - @Override public boolean isArray() { - return mirror().isArray(); + return layoutHelper() < config().klassLayoutHelperNeutralValue; } @Override public boolean isEnum() { - return mirror().isEnum(); + HotSpotResolvedObjectTypeImpl superclass = getSuperclass(); + return superclass != null && superclass.equals(runtime().getJavaLangEnum()); } @Override @@ -392,7 +384,7 @@ @Override public void initialize() { if (!isInitialized()) { - UNSAFE.ensureClassInitialized(mirror()); + runtime().compilerToVm.ensureInitialized(this); assert isInitialized(); } } @@ -400,7 +392,7 @@ @Override public boolean isInstance(JavaConstant obj) { if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { - return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); + return runtime().reflection.isInstance(this, (HotSpotObjectConstantImpl) obj); } return false; } @@ -412,7 +404,7 @@ @Override public boolean isInterface() { - return mirror().isInterface(); + return (getAccessFlags() & config().jvmAccInterface) != 0; } @Override @@ -420,7 +412,7 @@ assert other != null; if (other instanceof HotSpotResolvedObjectTypeImpl) { HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; - return mirror().isAssignableFrom(otherType.mirror()); + return runtime().reflection.isAssignableFrom(this, otherType); } return false; } @@ -435,7 +427,7 @@ @Override public boolean isJavaLangObject() { - return javaClass.equals(Object.class); + return getName().equals("Ljava/lang/Object;"); } @Override @@ -501,6 +493,7 @@ @Override public int layoutHelper() { HotSpotVMConfig config = config(); + assert getMetaspaceKlass() != 0 : getName(); return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); } @@ -509,7 +502,8 @@ return compilerToVM().getFingerprint(getMetaspaceKlass()); } - synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { + synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceHandle) { + long metaspaceMethod = UNSAFE.getLong(metaspaceHandle); // Maintain cache as array. if (methodCacheArray == null) { methodCacheArray = new HotSpotResolvedJavaMethodImpl[METHOD_CACHE_ARRAY_CAPACITY]; @@ -519,11 +513,10 @@ for (; i < methodCacheArray.length; ++i) { HotSpotResolvedJavaMethodImpl curMethod = methodCacheArray[i]; if (curMethod == null) { - HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); + HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceHandle); methodCacheArray[i] = newMethod; - context.add(newMethod); return newMethod; - } else if (curMethod.getMetaspacePointer() == metaspaceMethod) { + } else if (curMethod.getMetaspaceMethod() == metaspaceMethod) { return curMethod; } } @@ -535,9 +528,8 @@ HotSpotResolvedJavaMethodImpl lookupResult = methodCacheHashMap.get(metaspaceMethod); if (lookupResult == null) { - HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); + HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceHandle); methodCacheHashMap.put(metaspaceMethod, newMethod); - context.add(lookupResult); return newMethod; } else { return lookupResult; @@ -599,6 +591,27 @@ return new FieldInfo(index); } + public void ensureInitialized() { + runtime().compilerToVm.ensureInitialized(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof HotSpotResolvedObjectTypeImpl)) { + return false; + } + HotSpotResolvedObjectTypeImpl that = (HotSpotResolvedObjectTypeImpl) obj; + return getMetaspaceKlass() == that.getMetaspaceKlass(); + } + + @Override + JavaConstant getJavaMirror() { + return mirror; + } + /** * This class represents the field information for one field contained in the fields array of an * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. @@ -782,11 +795,6 @@ } @Override - public Class mirror() { - return javaClass; - } - - @Override public String getSourceFileName() { HotSpotVMConfig config = config(); final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); @@ -798,17 +806,17 @@ @Override public Annotation[] getAnnotations() { - return mirror().getAnnotations(); + return runtime().reflection.getAnnotations(this); } @Override public Annotation[] getDeclaredAnnotations() { - return mirror().getDeclaredAnnotations(); + return runtime().reflection.getDeclaredAnnotations(this); } @Override public T getAnnotation(Class annotationClass) { - return mirror().getAnnotation(annotationClass); + return runtime().reflection.getAnnotation(this, annotationClass); } /** @@ -828,12 +836,17 @@ } if (elementType.getName().startsWith("Ljava/")) { // Classes in a java.* package can only be defined by the - // boot or platform class loader. + // boot class loader. This is enforced by ClassLoader.preDefineClass() + assert hasSameClassLoader(runtime().getJavaLangObject()); return true; } - ClassLoader thisCl = mirror().getClassLoader(); - ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); - return thisCl == accessingClassCl; + HotSpotResolvedObjectTypeImpl otherMirror = ((HotSpotResolvedObjectTypeImpl) accessingClass); + return hasSameClassLoader(otherMirror); + } + + private boolean hasSameClassLoader(HotSpotResolvedObjectTypeImpl otherMirror) { + return UnsafeAccess.UNSAFE.getAddress(getMetaspaceKlass() + config().classLoaderDataOffset) == UnsafeAccess.UNSAFE.getAddress( + otherMirror.getMetaspaceKlass() + config().classLoaderDataOffset); } @Override @@ -887,16 +900,15 @@ private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) { for (ResolvedJavaField field : declaredFields) { - HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; - long resolvedFieldOffset = resolvedField.getOffset(); + long resolvedFieldOffset = field.getOffset(); // @formatter:off - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && - expectedEntryKind.isPrimitive() && - !expectedEntryKind.equals(JavaKind.Void) && - resolvedField.getJavaKind().isPrimitive()) { + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && + expectedEntryKind.isPrimitive() && + !expectedEntryKind.equals(JavaKind.Void) && + field.getJavaKind().isPrimitive()) { resolvedFieldOffset += - resolvedField.getJavaKind().getByteCount() - - Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); + field.getJavaKind().getByteCount() - + Math.min(field.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); } if (resolvedFieldOffset == offset) { return field; @@ -908,40 +920,27 @@ @Override public boolean isLocal() { - return mirror().isLocalClass(); + return runtime().reflection.isLocalClass(this); } @Override public boolean isMember() { - return mirror().isMemberClass(); + return runtime().reflection.isMemberClass(this); } @Override - public HotSpotResolvedObjectTypeImpl getEnclosingType() { - final Class encl = mirror().getEnclosingClass(); - return encl == null ? null : fromObjectClass(encl); + public HotSpotResolvedObjectType getEnclosingType() { + return runtime().reflection.getEnclosingClass(this); } @Override public ResolvedJavaMethod[] getDeclaredConstructors() { - Constructor[] constructors = mirror().getDeclaredConstructors(); - ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; - for (int i = 0; i < constructors.length; i++) { - result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); - assert result[i].isConstructor(); - } - return result; + return runtime().compilerToVm.getDeclaredConstructors(this); } @Override public ResolvedJavaMethod[] getDeclaredMethods() { - Method[] methods = mirror().getDeclaredMethods(); - ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; - for (int i = 0; i < methods.length; i++) { - result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); - assert !result[i].isConstructor(); - } - return result; + return runtime().compilerToVm.getDeclaredMethods(this); } @Override @@ -986,6 +985,10 @@ return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0; } + JavaConstant readFieldValue(HotSpotResolvedJavaField field, boolean isVolatile) { + return runtime().reflection.readFieldValue(this, field, isVolatile); + } + private int getMiscFlags() { return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset); } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,13 @@ package jdk.vm.ci.hotspot; import static java.util.Objects.requireNonNull; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import java.lang.annotation.Annotation; -import java.lang.reflect.Array; import java.lang.reflect.Modifier; import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.common.NativeImageReinitialize; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; @@ -42,22 +43,38 @@ */ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType { - private final JavaKind kind; + @NativeImageReinitialize static HotSpotResolvedPrimitiveType[] primitives; + + private JavaKind kind; + private HotSpotResolvedObjectType arrayClass; + HotSpotObjectConstantImpl mirror; /** * Creates the JVMCI mirror for a primitive {@link JavaKind}. * - *

- * NOTE: Creating an instance of this class does not install the mirror for the - * {@link Class} type. Use {@link HotSpotJVMCIRuntime#fromClass(Class)} instead. - *

- * * @param kind the Kind to create the mirror for */ - HotSpotResolvedPrimitiveType(JavaKind kind) { + private HotSpotResolvedPrimitiveType(JavaKind kind, HotSpotObjectConstantImpl mirror) { super(String.valueOf(kind.getTypeChar())); + this.mirror = mirror; this.kind = kind; - assert mirror().isPrimitive() : mirror() + " not a primitive type"; + } + + static HotSpotResolvedPrimitiveType forKind(JavaKind kind) { + HotSpotResolvedPrimitiveType primitive = primitives[kind.getBasicType()]; + assert primitive != null : kind; + return primitive; + } + + @VMEntryPoint + static HotSpotResolvedPrimitiveType fromMetaspace(HotSpotObjectConstantImpl mirror, char typeChar) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(typeChar); + if (primitives == null) { + primitives = new HotSpotResolvedPrimitiveType[JavaKind.Void.getBasicType() + 1]; + } + HotSpotResolvedPrimitiveType result = new HotSpotResolvedPrimitiveType(kind, mirror); + primitives[kind.getBasicType()] = result; + return result; } @Override @@ -70,8 +87,14 @@ if (kind == JavaKind.Void) { return null; } - Class javaArrayMirror = Array.newInstance(mirror(), 0).getClass(); - return HotSpotResolvedObjectTypeImpl.fromObjectClass(javaArrayMirror); + if (arrayClass == null) { + try { + arrayClass = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + kind.getTypeChar(), null, true); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } + } + return arrayClass; } @Override @@ -241,11 +264,6 @@ } @Override - Class mirror() { - return kind.toJavaClass(); - } - - @Override public boolean isLocal() { return false; } @@ -279,4 +297,18 @@ public boolean isCloneableWithAllocation() { return false; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof HotSpotResolvedPrimitiveType)) { + return false; + } + HotSpotResolvedPrimitiveType that = (HotSpotResolvedPrimitiveType) obj; + return that.kind == kind; + } + + @Override + JavaConstant getJavaMirror() { + return runtime().reflection.getJavaMirror(this); + } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,9 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; /** - * Implementation of {@link InstalledCode} for code installed as a RuntimeStub. + * Implementation of {@link InstalledCode} for code installed as a {@code RuntimeStub}. The address + * of the {@code RuntimeStub} is stored in {@link InstalledCode#address} and the value of + * {@code RuntimeStub::entry_point()} is in {@link InstalledCode#entryPoint}. */ public class HotSpotRuntimeStub extends HotSpotInstalledCode { diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,15 +168,17 @@ type = (ResolvedJavaType) result; parameterTypes[index] = type; } else { + assert result != null; return result; } } + assert type != null; return type; } @Override public String toMethodDescriptor() { - assert originalString.equals(Signature.super.toMethodDescriptor()); + assert originalString.equals(Signature.super.toMethodDescriptor()) : originalString + " != " + Signature.super.toMethodDescriptor(); return originalString; } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding; + +/** + * Implements a {@link SpeculationReasonEncoding} that {@linkplain #getByteArray() produces} a byte + * array. Data is added via a {@link DataOutputStream}. When producing the final byte array, if the + * total length of data exceeds the length of a SHA-1 digest, then a SHA-1 digest of the data is + * produced instead. + */ +final class HotSpotSpeculationEncoding extends ByteArrayOutputStream implements SpeculationReasonEncoding { + + private DataOutputStream dos = new DataOutputStream(this); + private byte[] result; + + HotSpotSpeculationEncoding() { + super(SHA1_LENGTH); + } + + private void checkOpen() { + if (result != null) { + throw new IllegalArgumentException("Cannot update closed speculation encoding"); + } + } + + private static final int NULL_METHOD = -1; + private static final int NULL_TYPE = -2; + private static final int NULL_STRING = -3; + + @Override + public void addByte(int value) { + checkOpen(); + try { + dos.writeByte(value); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public void addShort(int value) { + checkOpen(); + try { + dos.writeShort(value); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public void addMethod(ResolvedJavaMethod method) { + if (!addNull(method, NULL_METHOD)) { + checkOpen(); + if (method instanceof HotSpotResolvedJavaMethodImpl) { + try { + dos.writeLong(((HotSpotResolvedJavaMethodImpl) method).getMetaspaceMethod()); + } catch (IOException e) { + throw new InternalError(e); + } + } else { + throw new IllegalArgumentException("Cannot encode unsupported type " + method.getClass().getName() + ": " + method.format("%H.%n(%p)")); + } + } + } + + @Override + public void addType(ResolvedJavaType type) { + if (!addNull(type, NULL_TYPE)) { + checkOpen(); + if (type instanceof HotSpotResolvedObjectTypeImpl) { + try { + dos.writeLong(((HotSpotResolvedObjectTypeImpl) type).getMetaspaceKlass()); + } catch (IOException e) { + throw new InternalError(e); + } + } else { + throw new IllegalArgumentException("Cannot encode unsupported type " + type.getClass().getName() + ": " + type.toClassName()); + } + } + } + + @Override + public void addString(String value) { + if (!addNull(value, NULL_STRING)) { + checkOpen(); + try { + dos.writeChars(value); + } catch (IOException e) { + throw new InternalError(e); + } + } + } + + @Override + public void addInt(int value) { + checkOpen(); + try { + dos.writeInt(value); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public void addLong(long value) { + checkOpen(); + try { + dos.writeLong(value); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private boolean addNull(Object o, int nullValue) { + if (o == null) { + addInt(nullValue); + return true; + } + return false; + } + + /** + * Prototype SHA1 digest that is cloned before use. + */ + private static final MessageDigest SHA1 = getSHA1(); + private static final int SHA1_LENGTH = SHA1.getDigestLength(); + + private static MessageDigest getSHA1() { + try { + MessageDigest sha1 = MessageDigest.getInstance("SHA-1"); + sha1.clone(); + return sha1; + } catch (CloneNotSupportedException | NoSuchAlgorithmException e) { + // Should never happen given that SHA-1 is mandated in a + // compliant Java platform implementation. + throw new JVMCIError("Expect a cloneable implementation of a SHA-1 message digest to be available", e); + } + } + + /** + * Gets the final encoded byte array and closes this encoding such that any further attempts to + * update it result in an {@link IllegalArgumentException}. + */ + byte[] getByteArray() { + if (result == null) { + if (count > SHA1_LENGTH) { + try { + MessageDigest md = (MessageDigest) SHA1.clone(); + md.update(buf, 0, count); + result = md.digest(); + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + } else { + if (buf.length == count) { + // No need to copy the byte array + return buf; + } + result = Arrays.copyOf(buf, count); + } + dos = null; + } + return result; + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,98 +22,340 @@ */ package jdk.vm.ci.hotspot; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Formatter; +import java.util.List; + +import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.SpeculationLog; +/** + * Implements a {@link SpeculationLog} that can be used to: + *
    + *
  • Query failed speculations recorded in a native linked list of {@code FailedSpeculation}s (see + * methodData.hpp).
  • + *
  • Make speculations during compilation and record them in compiled code. This must only be done + * on compilation-local {@link HotSpotSpeculationLog} objects.
  • + *
+ * + * The choice of constructor determines whether the native failed speculations list is + * {@linkplain #managesFailedSpeculations() managed} by a {@link HotSpotSpeculationLog} object. + */ public class HotSpotSpeculationLog implements SpeculationLog { + + private static final byte[] NO_FLATTENED_SPECULATIONS = {}; + + /** + * Creates a speculation log that manages a failed speculation list. That is, when this object + * dies, the native resources of the list are freed. + * + * @see #managesFailedSpeculations() + * @see #getFailedSpeculationsAddress() + */ + public HotSpotSpeculationLog() { + managesFailedSpeculations = true; + } + + /** + * Creates a speculation log that reads from an externally managed failed speculation list. That + * is, the lifetime of the list is independent of this object. + * + * @param failedSpeculationsAddress an address in native memory at which the pointer to the + * externally managed sailed speculation list resides + */ + public HotSpotSpeculationLog(long failedSpeculationsAddress) { + if (failedSpeculationsAddress == 0) { + throw new IllegalArgumentException("failedSpeculationsAddress cannot be 0"); + } + this.failedSpeculationsAddress = failedSpeculationsAddress; + managesFailedSpeculations = false; + } + + /** + * Gets the address of the pointer to the native failed speculations list. + * + * @see #managesFailedSpeculations() + */ + public long getFailedSpeculationsAddress() { + if (managesFailedSpeculations) { + synchronized (this) { + if (failedSpeculationsAddress == 0L) { + failedSpeculationsAddress = UnsafeAccess.UNSAFE.allocateMemory(HotSpotJVMCIRuntime.getHostWordKind().getByteCount()); + UnsafeAccess.UNSAFE.putAddress(failedSpeculationsAddress, 0L); + LogCleaner c = new LogCleaner(this, failedSpeculationsAddress); + assert c.address == failedSpeculationsAddress; + } + } + } + return failedSpeculationsAddress; + } + + /** + * Adds {@code speculation} to the native list of failed speculations. To update this object's + * view of the failed speculations, {@link #collectFailedSpeculations()} must be called after + * this method returns. + * + * This method exists primarily for testing purposes. Speculations are normally only added to + * the list by HotSpot during deoptimization. + * + * @return {@code false} if the speculation could not be appended to the list + */ + public boolean addFailedSpeculation(Speculation speculation) { + return compilerToVM().addFailedSpeculation(getFailedSpeculationsAddress(), ((HotSpotSpeculation) speculation).encoding); + } + + /** + * Returns {@code true} if the value returned by {@link #getFailedSpeculationsAddress()} is only + * valid only as long as this object is alive, {@code false} otherwise. + */ + public boolean managesFailedSpeculations() { + return managesFailedSpeculations; + } + public static final class HotSpotSpeculation extends Speculation { - private JavaConstant encoding; - HotSpotSpeculation(SpeculationReason reason, JavaConstant encoding) { + /** + * A speculation id is a long encoding an offset (high 32 bits) and a length (low 32 bts). + * Combined, the index and length denote where the {@linkplain #encoding encoded + * speculation} is in a {@linkplain HotSpotSpeculationLog#getFlattenedSpeculations + * flattened} speculations array. + */ + private final JavaConstant id; + + private final byte[] encoding; + + HotSpotSpeculation(SpeculationReason reason, JavaConstant id, byte[] encoding) { super(reason); + this.id = id; this.encoding = encoding; } public JavaConstant getEncoding() { - return encoding; + return id; + } + + @Override + public String toString() { + long indexAndLength = id.asLong(); + int index = decodeIndex(indexAndLength); + int length = decodeLength(indexAndLength); + return String.format("{0x%016x[index: %d, len: %d, hash: 0x%x]: %s}", indexAndLength, index, length, Arrays.hashCode(encoding), getReason()); } } - /** Written by the C++ code that performs deoptimization. */ - private volatile long lastFailed; + /** + * Address of a pointer to a set of failed speculations. The address is recorded in the nmethod + * compiled with this speculation log such that when it fails a speculation, the speculation is + * added to the list. + */ + private long failedSpeculationsAddress; + + private final boolean managesFailedSpeculations; - /** All speculations that have caused a deoptimization. */ - private Set failedSpeculations; + /** + * The list of failed speculations read from native memory via + * {@link CompilerToVM#getFailedSpeculations}. + */ + private byte[][] failedSpeculations; - /** Strong references to all reasons embedded in the current nmethod. */ - private HashMap speculations; - - private long currentSpeculationID; + /** + * Speculations made during the compilation associated with this log. + */ + private List speculations; + private List speculationReasons; @Override - public synchronized void collectFailedSpeculations() { - if (lastFailed != 0) { - if (failedSpeculations == null) { - failedSpeculations = new HashSet<>(2); - } - if (speculations != null) { - SpeculationReason lastFailedSpeculation = lookupSpeculation(this.lastFailed); - if (lastFailedSpeculation != null) { - failedSpeculations.add(lastFailedSpeculation); - } - lastFailed = 0; - speculations = null; - } + public void collectFailedSpeculations() { + if (failedSpeculationsAddress != 0 && UnsafeAccess.UNSAFE.getLong(failedSpeculationsAddress) != 0) { + failedSpeculations = compilerToVM().getFailedSpeculations(failedSpeculationsAddress, failedSpeculations); + assert failedSpeculations.getClass() == byte[][].class; } } - private SpeculationReason lookupSpeculation(long value) { - for (Map.Entry entry : speculations.entrySet()) { - if (value == entry.getValue().asLong()) { - return entry.getKey(); + byte[] getFlattenedSpeculations(boolean validate) { + if (speculations == null) { + return NO_FLATTENED_SPECULATIONS; + } + if (validate) { + int newFailuresStart = failedSpeculations == null ? 0 : failedSpeculations.length; + collectFailedSpeculations(); + if (failedSpeculations != null && failedSpeculations.length != newFailuresStart) { + for (SpeculationReason reason : speculationReasons) { + byte[] encoding = encode(reason); + // Only check against new failures + if (contains(failedSpeculations, newFailuresStart, encoding)) { + throw new BailoutException(false, "Speculation failed: " + reason); + } + } } } - return null; + int size = 0; + for (byte[] s : speculations) { + size += s.length; + } + byte[] result = new byte[size]; + size = 0; + for (byte[] s : speculations) { + System.arraycopy(s, 0, result, size, s.length); + size += s.length; + } + return result; } @Override - public synchronized boolean maySpeculate(SpeculationReason reason) { - if (failedSpeculations != null && failedSpeculations.contains(reason)) { - return false; + public boolean maySpeculate(SpeculationReason reason) { + if (failedSpeculations == null) { + collectFailedSpeculations(); + } + if (failedSpeculations != null && failedSpeculations.length != 0) { + byte[] encoding = encode(reason); + return !contains(failedSpeculations, 0, encoding); } return true; } - @Override - public synchronized Speculation speculate(SpeculationReason reason) { - if (speculations == null) { - speculations = new HashMap<>(); + /** + * @return {@code true} if {@code needle} is in {@code haystack[fromIndex..haystack.length-1]} + */ + private static boolean contains(byte[][] haystack, int fromIndex, byte[] needle) { + for (int i = fromIndex; i < haystack.length; i++) { + byte[] fs = haystack[i]; + + if (Arrays.equals(fs, needle)) { + return true; + } } - JavaConstant id = speculations.get(reason); - if (id == null) { - id = JavaConstant.forLong(++currentSpeculationID); - speculations.put(reason, id); + return false; + } + + private static long encodeIndexAndLength(int index, int length) { + return ((long) index) << 32 | length; + } + + private static int decodeIndex(long indexAndLength) { + return (int) (indexAndLength >>> 32); + } + + private static int decodeLength(long indexAndLength) { + return (int) indexAndLength & 0xFFFFFFFF; + } + + @Override + public Speculation speculate(SpeculationReason reason) { + byte[] encoding = encode(reason); + JavaConstant id; + if (speculations == null) { + speculations = new ArrayList<>(); + speculationReasons = new ArrayList<>(); + id = JavaConstant.forLong(encodeIndexAndLength(0, encoding.length)); + speculations.add(encoding); + speculationReasons.add(reason); + } else { + id = null; + int flattenedIndex = 0; + for (byte[] fs : speculations) { + if (Arrays.equals(fs, encoding)) { + id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, fs.length)); + break; + } + flattenedIndex += fs.length; + } + if (id == null) { + id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, encoding.length)); + speculations.add(encoding); + speculationReasons.add(reason); + } } - return new HotSpotSpeculation(reason, id); + + return new HotSpotSpeculation(reason, id, encoding); + } + + private static byte[] encode(SpeculationReason reason) { + HotSpotSpeculationEncoding encoding = (HotSpotSpeculationEncoding) reason.encode(HotSpotSpeculationEncoding::new); + byte[] result = encoding == null ? null : encoding.getByteArray(); + if (result == null) { + throw new IllegalArgumentException(HotSpotSpeculationLog.class.getName() + " expects " + reason.getClass().getName() + ".encode() to return a non-empty encoding"); + } + return result; + } + + @Override + public boolean hasSpeculations() { + return speculations != null; } @Override - public synchronized boolean hasSpeculations() { - return speculations != null && !speculations.isEmpty(); + public Speculation lookupSpeculation(JavaConstant constant) { + if (constant.isDefaultForKind()) { + return NO_SPECULATION; + } + int flattenedIndex = decodeIndex(constant.asLong()); + int index = 0; + for (byte[] s : speculations) { + if (flattenedIndex == 0) { + SpeculationReason reason = speculationReasons.get(index); + return new HotSpotSpeculation(reason, constant, s); + } + index++; + flattenedIndex -= s.length; + } + throw new IllegalArgumentException("Unknown encoded speculation: " + constant); } @Override - public synchronized Speculation lookupSpeculation(JavaConstant constant) { - if (constant.isDefaultForKind()) { - return NO_SPECULATION; + public String toString() { + Formatter buf = new Formatter(); + buf.format("{managed:%s, failedSpeculationsAddress:0x%x, failedSpeculations:[", managesFailedSpeculations, failedSpeculationsAddress); + + String sep = ""; + if (failedSpeculations != null) { + for (int i = 0; i < failedSpeculations.length; i++) { + buf.format("%s{len:%d, hash:0x%x}", sep, failedSpeculations[i].length, Arrays.hashCode(failedSpeculations[i])); + sep = ", "; + } + } + + buf.format("], speculations:["); + + int size = 0; + if (speculations != null) { + sep = ""; + for (int i = 0; i < speculations.size(); i++) { + byte[] s = speculations.get(i); + size += s.length; + buf.format("%s{len:%d, hash:0x%x, reason:{%s}}", sep, s.length, Arrays.hashCode(s), speculationReasons.get(i)); + sep = ", "; + } } - SpeculationReason reason = lookupSpeculation(constant.asLong()); - assert reason != null : "Speculation should have been registered"; - return new HotSpotSpeculation(reason, constant); + buf.format("], len:%d, hash:0x%x}", size, Arrays.hashCode(getFlattenedSpeculations(false))); + return buf.toString(); + } + + /** + * Frees the native memory resources associated with {@link HotSpotSpeculationLog}s once they + * become reclaimable. + */ + private static final class LogCleaner extends Cleaner { + + LogCleaner(HotSpotSpeculationLog referent, long address) { + super(referent); + this.address = address; + } + + @Override + void doCleanup() { + long pointer = UnsafeAccess.UNSAFE.getAddress(address); + if (pointer != 0) { + compilerToVM().releaseFailedSpeculations(address); + } + UnsafeAccess.UNSAFE.freeMemory(address); + } + + final long address; } } + diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; +import jdk.vm.ci.services.Services; import jdk.internal.misc.Unsafe; /** @@ -52,7 +53,7 @@ * {@linkplain HotSpotJVMCIBackendFactory backend}. */ String getHostArchitectureName() { - String arch = System.getProperty("os.arch"); + String arch = Services.getSavedProperty("os.arch"); switch (arch) { case "x86_64": return "amd64"; @@ -70,16 +71,21 @@ final int objectAlignment = getFlag("ObjectAlignmentInBytes", Integer.class); + final int hubOffset = getFieldOffset("oopDesc::_metadata._klass", Integer.class, "Klass*"); + final int prototypeMarkWordOffset = getFieldOffset("Klass::_prototype_header", Integer.class, "markOop"); final int subklassOffset = getFieldOffset("Klass::_subklass", Integer.class, "Klass*"); + final int superOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*"); final int nextSiblingOffset = getFieldOffset("Klass::_next_sibling", Integer.class, "Klass*"); final int superCheckOffsetOffset = getFieldOffset("Klass::_super_check_offset", Integer.class, "juint"); final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*"); + final int classLoaderDataOffset = getFieldOffset("Klass::_class_loader_data", Integer.class, "ClassLoaderData*"); + /** * The offset of the _java_mirror field (of type {@link Class}) in a Klass. */ - final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); + final int javaMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); @@ -131,6 +137,7 @@ final int jvmAccBridge = getConstant("JVM_ACC_BRIDGE", Integer.class); final int jvmAccVarargs = getConstant("JVM_ACC_VARARGS", Integer.class); final int jvmAccEnum = getConstant("JVM_ACC_ENUM", Integer.class); + final int jvmAccInterface = getConstant("JVM_ACC_INTERFACE", Integer.class); // This is only valid on AMD64. final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, osArch.equals("amd64") ? null : 0); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,9 @@ */ package jdk.vm.ci.hotspot; +import java.util.Set; +import java.util.stream.Collectors; + import jdk.vm.ci.common.JVMCIError; /** @@ -50,8 +53,8 @@ if (notPresent != null) { return notPresent; } - store.printConfig(); - throw new JVMCIError("expected VM symbol not found in " + store + ": " + name); + throw missingEntry("address", name, store.vmFlags.keySet()); + } return entry; } @@ -82,8 +85,7 @@ if (notPresent != null) { return notPresent; } - store.printConfig(); - throw new JVMCIError("expected VM constant not found in " + store + ": " + name); + throw missingEntry("constant", name, store.vmConstants.keySet()); } return type.cast(convertValue(name, type, c, null)); } @@ -112,15 +114,23 @@ * @throws JVMCIError if the field is static or not present and {@code notPresent} is null */ public T getFieldOffset(String name, Class type, String cppType, T notPresent) { - assert type == Integer.class || type == Long.class; - VMField entry = getField(name, cppType, notPresent == null); - if (entry == null) { - return notPresent; - } - if (entry.address != 0) { - throw new JVMCIError("cannot get offset of static field " + name); - } - return type.cast(convertValue(name, type, entry.offset, cppType)); + return getFieldOffset0(name, type, notPresent, cppType, null); + } + + /** + * Gets the offset of a non-static C++ field. + * + * @param name fully qualified name of the field + * @param type the boxed type to which the offset value will be converted (must be + * {@link Integer} or {@link Long}) + * @param notPresent if non-null and the field is not present then this value is returned + * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is + * returned in element 0 of this array + * @return the offset in bytes of the requested field + * @throws JVMCIError if the field is static or not present and {@code notPresent} is null + */ + public T getFieldOffset(String name, Class type, T notPresent, String[] outCppType) { + return getFieldOffset0(name, type, notPresent, null, outCppType); } /** @@ -134,7 +144,7 @@ * @throws JVMCIError if the field is static or not present */ public T getFieldOffset(String name, Class type, String cppType) { - return getFieldOffset(name, type, cppType, null); + return getFieldOffset0(name, type, null, cppType, null); } /** @@ -147,7 +157,22 @@ * @throws JVMCIError if the field is static or not present */ public T getFieldOffset(String name, Class type) { - return getFieldOffset(name, type, null, null); + return getFieldOffset0(name, type, null, null, null); + } + + private T getFieldOffset0(String name, Class type, T notPresent, String inCppType, String[] outCppType) { + assert type == Integer.class || type == Long.class; + VMField entry = getField(name, inCppType, notPresent == null); + if (entry == null) { + return notPresent; + } + if (entry.address != 0) { + throw new JVMCIError("cannot get offset of static field " + name); + } + if (outCppType != null) { + outCppType[0] = entry.type; + } + return type.cast(convertValue(name, type, entry.offset, inCppType)); } /** @@ -160,14 +185,21 @@ * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null */ public long getFieldAddress(String name, String cppType, Long notPresent) { - VMField entry = getField(name, cppType, notPresent == null); - if (entry == null) { - return notPresent; - } - if (entry.address == 0) { - throw new JVMCIError(name + " is not a static field"); - } - return entry.address; + return getFieldAddress0(name, notPresent, cppType, null); + } + + /** + * Gets the address of a static C++ field. + * + * @param name fully qualified name of the field + * @param notPresent if non-null and the field is not present then this value is returned + * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is + * returned in element 0 of this array + * @return the address of the requested field + * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null + */ + public long getFieldAddress(String name, Long notPresent, String[] outCppType) { + return getFieldAddress0(name, notPresent, null, outCppType); } /** @@ -179,7 +211,21 @@ * @throws JVMCIError if the field is not static or not present */ public long getFieldAddress(String name, String cppType) { - return getFieldAddress(name, cppType, null); + return getFieldAddress0(name, null, cppType, null); + } + + private long getFieldAddress0(String name, Long notPresent, String inCppType, String[] outCppType) { + VMField entry = getField(name, inCppType, notPresent == null); + if (entry == null) { + return notPresent; + } + if (entry.address == 0) { + throw new JVMCIError(name + " is not a static field"); + } + if (outCppType != null) { + outCppType[0] = entry.type; + } + return entry.address; } /** @@ -193,14 +239,7 @@ * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null */ public T getFieldValue(String name, Class type, String cppType, T notPresent) { - VMField entry = getField(name, cppType, notPresent == null); - if (entry == null) { - return notPresent; - } - if (entry.value == null) { - throw new JVMCIError(name + " is not a static field"); - } - return type.cast(convertValue(name, type, entry.value, cppType)); + return getFieldValue0(name, type, notPresent, cppType, null); } /** @@ -213,7 +252,22 @@ * @throws JVMCIError if the field is not static or not present */ public T getFieldValue(String name, Class type, String cppType) { - return getFieldValue(name, type, cppType, null); + return getFieldValue0(name, type, null, cppType, null); + } + + /** + * Gets the value of a static C++ field. + * + * @param name fully qualified name of the field + * @param type the boxed type to which the constant value will be converted + * @param notPresent if non-null and the field is not present then this value is returned + * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is + * returned in element 0 of this array + * @return the value of the requested field + * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null + */ + public T getFieldValue(String name, Class type, T notPresent, String[] outCppType) { + return getFieldValue0(name, type, notPresent, null, outCppType); } /** @@ -225,7 +279,21 @@ * @throws JVMCIError if the field is not static or not present */ public T getFieldValue(String name, Class type) { - return getFieldValue(name, type, null, null); + return getFieldValue0(name, type, null, null, null); + } + + private T getFieldValue0(String name, Class type, T notPresent, String inCppType, String[] outCppType) { + VMField entry = getField(name, inCppType, notPresent == null); + if (entry == null) { + return notPresent; + } + if (entry.value == null) { + throw new JVMCIError(name + " is not a static field "); + } + if (outCppType != null) { + outCppType[0] = entry.type; + } + return type.cast(convertValue(name, type, entry.value, inCppType)); } /** @@ -243,8 +311,7 @@ if (!required) { return null; } - store.printConfig(); - throw new JVMCIError("expected VM field not found in " + store + ": " + name); + throw missingEntry("field", name, store.vmFields.keySet()); } // Make sure the native type is still the type we expect. @@ -288,8 +355,7 @@ if (notPresent != null) { return notPresent; } - store.printConfig(); - throw new JVMCIError("expected VM flag not found in " + store + ": " + name); + throw missingEntry("flag", name, store.vmFlags.keySet()); } else { cppType = null; } @@ -300,6 +366,11 @@ return type.cast(convertValue(name, type, value, cppType)); } + private JVMCIError missingEntry(String category, String name, Set keys) { + throw new JVMCIError("expected VM %s not found in %s: %s%nAvailable values:%n %s", category, store, name, + keys.stream().sorted().collect(Collectors.joining(System.lineSeparator() + " "))); + } + private static Object convertValue(String name, Class toType, Object value, String cppType) throws JVMCIError { if (toType == Boolean.class) { if (value instanceof String) { diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +import jdk.vm.ci.meta.JavaConstant; + +final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl { + /** + * An object handle in {@code JVMCI::_jvmci_handles}. + */ + final long objectHandle; + private int hashCode; + + final IndirectHotSpotObjectConstantImpl base; + + @VMEntryPoint + private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister) { + super(compressed); + assert objectHandle != 0 && UnsafeAccess.UNSAFE.getLong(objectHandle) != 0; + this.objectHandle = objectHandle; + this.base = null; + if (!skipRegister) { + HandleCleaner.create(this, objectHandle); + } + } + + private IndirectHotSpotObjectConstantImpl(IndirectHotSpotObjectConstantImpl base, boolean compressed) { + super(compressed); + // This is a variant of an original object that only varies in compress vs uncompressed. + // Instead of creating a new handle, reference that object and objectHandle. + this.objectHandle = base.objectHandle; + // There should only be on level of indirection to the base object. + assert base.base == null || base.base.base == null; + this.base = base.base != null ? base.base : base; + } + + @Override + public JavaConstant compress() { + assert !compressed; + return new IndirectHotSpotObjectConstantImpl(this, true); + } + + @Override + public JavaConstant uncompress() { + assert compressed; + return new IndirectHotSpotObjectConstantImpl(this, false); + } + + @Override + public int getIdentityHashCode() { + int hash = hashCode; + if (hash == 0) { + hash = runtime().compilerToVm.getIdentityHashCode(this); + if (hash == 0) { + hash = 31; + } + hashCode = hash; + } + return hash; + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceHandleObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceHandleObject.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * A tag interface indicating that this type is a handledized wrapper around a HotSpot metaspace + * object that requires GC interaction to keep alive. + * + * It would preferable if this were the base class containing the pointer but that would require + * mixins since most of the wrapper types have complex supertype hierarchies. + */ +interface MetaspaceHandleObject extends MetaspaceObject { + + long getMetadataHandle(); + + @Override + default long getMetaspacePointer() { + return UnsafeAccess.UNSAFE.getLong(getMetadataHandle()); + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceObject.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * The marker interface for an object which wraps HotSpot Metadata. + */ +interface MetaspaceObject { + long getMetaspacePointer(); +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java Wed May 01 12:41:26 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.vm.ci.hotspot; - -/** - * A tag interface indicating that this type is a wrapper around a HotSpot metaspace object that - * requires GC interaction to keep alive. - * - * It would preferable if this were the base class containing the pointer but that would require - * mixins since most of the wrapper types have complex supertype hierarchies. - */ -interface MetaspaceWrapperObject { - - long getMetaspacePointer(); - - /** - * Check if this object is properly registered for metadata tracking. All classes which - * implement this interface must be registered with the - * {@link HotSpotJVMCIMetaAccessContext#add} unless they are kept alive through other means. - * Currently the only type which doesn't require explicit registration is - * {@link HotSpotResolvedObjectTypeImpl} since it's kept alive by references to the - * {@link Class}. - * - * @return true if this object is properly registered for meta data tracking. - */ - default boolean isRegistered() { - return HotSpotJVMCIRuntime.runtime().metaAccessContext.isRegistered(this); - } -} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; +import java.lang.reflect.Type; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Implementation of {@link HotSpotJVMCIReflection} when running in a JVMCI shared library. + */ +class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection { + + @Override + Object resolveObject(HotSpotObjectConstantImpl objectHandle) { + throw new HotSpotJVMCIUnsupportedOperationError("cannot resolve handle in a JVMCI shared library to a raw object: " + objectHandle); + } + + @Override + boolean isInstance(HotSpotResolvedObjectTypeImpl holder, HotSpotObjectConstantImpl obj) { + if (obj instanceof DirectHotSpotObjectConstantImpl) { + ResolvedJavaType type = getType(obj); + return holder.isAssignableFrom(type); + } + return runtime().compilerToVm.isInstance(holder, obj); + } + + @Override + boolean isAssignableFrom(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedObjectTypeImpl otherType) { + return runtime().compilerToVm.isAssignableFrom(holder, otherType); + } + + @Override + boolean isLocalClass(HotSpotResolvedObjectTypeImpl holder) { + throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.isLocalClass()"); + } + + @Override + boolean isMemberClass(HotSpotResolvedObjectTypeImpl holder) { + throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.isMemberClass()"); + } + + @Override + HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder) { + throw new HotSpotJVMCIUnsupportedOperationError("requires a call Class.getEnclosingClass()"); + } + + @Override + JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile) { + JavaConstant javaConstant = runtime().compilerToVm.readFieldValue(holder, field, isVolatile); + if (javaConstant == null) { + return JavaConstant.NULL_POINTER; + } + return javaConstant; + } + + @Override + JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + // cannot read fields from objects due to lack of + // general reflection support in native image + return null; + } + JavaConstant javaConstant = runtime().compilerToVm.readFieldValue(object, field, isVolatile); + if (javaConstant == null) { + return JavaConstant.NULL_POINTER; + } + return javaConstant; + } + + @Override + boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) { + if (x == y) { + return true; + } + if (x.compressed != y.compressed) { + return false; + } + if (x instanceof DirectHotSpotObjectConstantImpl && y instanceof DirectHotSpotObjectConstantImpl) { + DirectHotSpotObjectConstantImpl xd = (DirectHotSpotObjectConstantImpl) x; + DirectHotSpotObjectConstantImpl yd = (DirectHotSpotObjectConstantImpl) y; + return (xd.object == yd.object); + } + if (x instanceof DirectHotSpotObjectConstantImpl || y instanceof DirectHotSpotObjectConstantImpl) { + // Mixing of constant types is always inequal + return false; + } + IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x; + IndirectHotSpotObjectConstantImpl indirectY = (IndirectHotSpotObjectConstantImpl) y; + return runtime().compilerToVm.equals(x, indirectX.objectHandle, y, indirectY.objectHandle); + } + + @Override + JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType hotSpotResolvedPrimitiveType) { + return runtime().compilerToVm.getJavaMirror(hotSpotResolvedPrimitiveType); + } + + @Override + ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { + // ResolvedJavaMethod.getParameters allows a return value of null + return null; + } + + // Substituted by Target_jdk_vm_ci_hotspot_SharedLibraryJVMCIReflection + static Annotation[] getClassAnnotations(String className) { + throw new InternalError("missing substitution: " + className); + } + + // Substituted by Target_jdk_vm_ci_hotspot_SharedLibraryJVMCIReflection + static Annotation[][] getParameterAnnotations(String className, String methodName) { + throw new InternalError("missing substitution: " + className + " " + methodName); + } + + @Override + Annotation[] getAnnotations(HotSpotResolvedObjectTypeImpl holder) { + return getClassAnnotations(holder.getName()); + } + + @Override + Annotation[] getDeclaredAnnotations(HotSpotResolvedObjectTypeImpl holder) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + T getAnnotation(HotSpotResolvedObjectTypeImpl holder, Class annotationClass) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + return getParameterAnnotations(javaMethod.getDeclaringClass().getName(), javaMethod.getName()); + } + + @Override + Type[] getGenericParameterTypes(HotSpotResolvedJavaMethodImpl javaMethod) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + Annotation[] getFieldAnnotations(HotSpotResolvedJavaFieldImpl javaField) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + Annotation[] getMethodAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + return getMethodAnnotationsInternal(javaMethod); + } + + @Override + T getMethodAnnotation(HotSpotResolvedJavaMethodImpl javaMethod, Class annotationClass) { + Annotation[] methodAnnotations = getMethodAnnotations(javaMethod); + if (methodAnnotations != null) { + for (Annotation ann : methodAnnotations) { + if (annotationClass.isInstance(ann)) { + return annotationClass.cast(ann); + } + } + } + return null; + } + + // Substituted by Target_jdk_vm_ci_hotspot_SharedLibraryJVMCIReflection + @SuppressWarnings("unused") + private static Annotation[] getMethodAnnotationsInternal(ResolvedJavaMethod javaMethod) { + throw new InternalError("missing substitution"); + } + + @Override + Annotation[] getMethodDeclaredAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + Annotation[] getFieldDeclaredAnnotations(HotSpotResolvedJavaFieldImpl javaMethod) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + T getFieldAnnotation(HotSpotResolvedJavaFieldImpl javaField, Class annotationClass) { + throw new HotSpotJVMCIUnsupportedOperationError("unimplemented"); + } + + @Override + HotSpotResolvedObjectTypeImpl getType(HotSpotObjectConstantImpl object) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + Class theClass = ((DirectHotSpotObjectConstantImpl) object).object.getClass(); + try { + String name = theClass.getName().replace('.', '/'); + HotSpotResolvedObjectTypeImpl type = (HotSpotResolvedObjectTypeImpl) runtime().compilerToVm.lookupType(name, null, true); + if (type == null) { + throw new InternalError(name); + } + return type; + } catch (ClassNotFoundException e) { + throw new InternalError(e); + } + } + return runtime().compilerToVm.getResolvedJavaType(object, runtime().getConfig().hubOffset, false); + } + + @Override + String asString(HotSpotObjectConstantImpl object) { + if (object instanceof IndirectHotSpotObjectConstantImpl) { + return runtime().compilerToVm.asString(object); + } + Object value = ((DirectHotSpotObjectConstantImpl) object).object; + if (value instanceof String) { + return (String) value; + } + return null; + } + + @Override + ResolvedJavaType asJavaType(HotSpotObjectConstantImpl object) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object; + if (direct.object instanceof Class) { + Class javaClass = (Class) direct.object; + return runtime().fromClass(javaClass); + } + if (direct.object instanceof ResolvedJavaType) { + return (ResolvedJavaType) convertUnknownValue(direct.object); + } + return null; + } + return runtime().compilerToVm.asJavaType(object); + } + + // Substituted by Target_jdk_vm_ci_hotspot_SharedLibraryJVMCIReflection + static Object convertUnknownValue(Object object) { + return object; + } + + @SuppressWarnings("unchecked") + @Override + T asObject(HotSpotObjectConstantImpl object, Class type) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + Object theObject = ((DirectHotSpotObjectConstantImpl) object).object; + if (type.isInstance(theObject)) { + return (T) convertUnknownValue(type.cast(theObject)); + } + } + return null; + } + + @Override + Object asObject(HotSpotObjectConstantImpl object, HotSpotResolvedJavaType type) { + throw new HotSpotJVMCIUnsupportedOperationError("cannot resolve a shared library JVMCI object handle to a " + + "raw object as it may be in another runtime"); + } + + @Override + String formatString(HotSpotObjectConstantImpl object) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object; + return "CompilerObject<" + direct.object.getClass().getName() + ">"; + } + return "Instance<" + object.getType().toJavaName() + ">"; + } + + @Override + Integer getLength(HotSpotObjectConstantImpl object) { + if (object instanceof DirectHotSpotObjectConstantImpl) { + DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object; + if (direct.object.getClass().isArray()) { + return Array.getLength(direct.object); + } + return null; + } + int length = runtime().compilerToVm.getArrayLength(object); + if (length >= 0) { + return length; + } + return null; + } + + @Override + JavaConstant readArrayElement(HotSpotObjectConstantImpl arrayObject, int index) { + Object result = runtime().compilerToVm.readArrayElement(arrayObject, index); + if (result == null) { + return null; + } + if (result instanceof JavaConstant) { + return (JavaConstant) result; + } + JavaConstant constant = JavaConstant.forBoxedPrimitive(result); + if (constant == null) { + throw new InternalError("Unexpected value " + result); + } + return constant; + } + + @Override + JavaConstant forObject(Object value) { + return DirectHotSpotObjectConstantImpl.forObject(value, false); + } + + @Override + JavaConstant unboxPrimitive(HotSpotObjectConstantImpl source) { + Object box = runtime().compilerToVm.unboxPrimitive(source); + return JavaConstant.forBoxedPrimitive(box); + } + + @Override + JavaConstant boxPrimitive(JavaConstant source) { + return runtime().compilerToVm.boxPrimitive(source.asBoxedPrimitive()); + } + + @Override + int getInt(HotSpotObjectConstantImpl object, long displacement) { + return runtime().compilerToVm.getInt(object, displacement); + } + + @Override + byte getByte(HotSpotObjectConstantImpl object, long displacement) { + return runtime().compilerToVm.getByte(object, displacement); + } + + @Override + short getShort(HotSpotObjectConstantImpl object, long displacement) { + return runtime().compilerToVm.getShort(object, displacement); + } + + @Override + long getLong(HotSpotObjectConstantImpl object, long displacement) { + return runtime().compilerToVm.getLong(object, displacement); + } + + @Override + void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type) { + + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.util.Arrays; +import java.util.Formatter; +import java.util.Objects; + +/** + * Support for translating exceptions between different runtime heaps. + */ +@SuppressWarnings("serial") +final class TranslatedException extends Exception { + + private TranslatedException(String message) { + super(message); + } + + private TranslatedException(String message, Throwable cause) { + super(message, cause); + } + + /** + * No need to record an initial stack trace since it will be manually overwritten. + */ + @SuppressWarnings("sync-override") + @Override + public Throwable fillInStackTrace() { + return this; + } + + @Override + public String toString() { + return getMessage(); + } + + private static TranslatedException create(String className, String message) { + if (className.equals(TranslatedException.class.getName())) { + // Chop the class name when boxing another TranslatedException + return new TranslatedException(message); + } + if (message == null) { + return new TranslatedException(className); + } + return new TranslatedException(className + ": " + message); + } + + private static String encodedString(String value) { + return Objects.toString(value, "").replace('|', '_'); + } + + /** + * Encodes {@code throwable} including its stack and causes as a string. The encoding format of + * a single exception with its cause is: + * + *
+     *  '|'  '|'  '|' [ '|'  '|'  '|'  '|' ]*
+     * 
+ * + * Each cause is appended after the exception is it the cause of. + */ + @VMEntryPoint + static String encodeThrowable(Throwable throwable) throws Throwable { + try { + Formatter enc = new Formatter(); + Throwable current = throwable; + do { + enc.format("%s|%s|", current.getClass().getName(), encodedString(current.getMessage())); + StackTraceElement[] stackTrace = current.getStackTrace(); + if (stackTrace == null) { + stackTrace = new StackTraceElement[0]; + } + enc.format("%d|", stackTrace.length); + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement frame = stackTrace[i]; + if (frame != null) { + enc.format("%s|%s|%s|%d|", frame.getClassName(), frame.getMethodName(), + encodedString(frame.getFileName()), frame.getLineNumber()); + } + } + current = current.getCause(); + } while (current != null); + return enc.toString(); + } catch (Throwable e) { + try { + return e.getClass().getName() + "|" + encodedString(e.getMessage()) + "|0|"; + } catch (Throwable e2) { + return "java.lang.Throwable|too many errors during encoding|0|"; + } + } + } + + /** + * Gets the stack of the current thread without the frames between this call and the one just + * below the frame of the first method in {@link CompilerToVM}. The chopped frames are specific + * to the implementation of {@link HotSpotJVMCIRuntime#decodeThrowable(String)}. + */ + private static StackTraceElement[] getStackTraceSuffix() { + StackTraceElement[] stack = new Exception().getStackTrace(); + for (int i = 0; i < stack.length; i++) { + StackTraceElement e = stack[i]; + if (e.getClassName().equals(CompilerToVM.class.getName())) { + return Arrays.copyOfRange(stack, i, stack.length); + } + } + // This should never happen but since we're in exception handling + // code, just return a safe value instead raising a nested exception. + return new StackTraceElement[0]; + } + + /** + * Decodes {@code encodedThrowable} into a {@link TranslatedException}. + * + * @param encodedThrowable an encoded exception in the format specified by + * {@link #encodeThrowable} + */ + @VMEntryPoint + static Throwable decodeThrowable(String encodedThrowable) { + try { + int i = 0; + String[] parts = encodedThrowable.split("\\|"); + Throwable parent = null; + Throwable result = null; + while (i != parts.length) { + String exceptionClassName = parts[i++]; + String exceptionMessage = parts[i++]; + Throwable throwable = create(exceptionClassName, exceptionMessage); + int stackTraceDepth = Integer.parseInt(parts[i++]); + + StackTraceElement[] suffix = parent == null ? new StackTraceElement[0] : getStackTraceSuffix(); + StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length]; + for (int j = 0; j < stackTraceDepth; j++) { + String className = parts[i++]; + String methodName = parts[i++]; + String fileName = parts[i++]; + int lineNumber = Integer.parseInt(parts[i++]); + if (fileName.isEmpty()) { + fileName = null; + } + stackTrace[j] = new StackTraceElement(className, methodName, fileName, lineNumber); + } + System.arraycopy(suffix, 0, stackTrace, stackTraceDepth, suffix.length); + throwable.setStackTrace(stackTrace); + if (parent != null) { + parent.initCause(throwable); + } else { + result = throwable; + } + parent = throwable; + } + return result; + } catch (Throwable t) { + return new TranslatedException("Error decoding exception: " + encodedThrowable, t); + } + } +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +/** + * Marker interface for methods which are called from the JVM. + */ +@interface VMEntryPoint { + /** + * An optional comment describing the caller. + */ + String value() default ""; +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMField.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMField.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMField.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,19 +63,20 @@ } /** - * Creates a description of a field. + * Creates a description of a non-static field. */ - VMField(String name, String type, long address, Object value) { + @VMEntryPoint + VMField(String name, String type, long offset, long address, Object value) { this.name = name; this.type = type; - this.offset = 0; + this.offset = offset; this.address = address; this.value = value; } @Override public String toString() { - String val = value == null ? "null" : String.format("0x%x", value); + String val = value == null ? "null" : (type.contains("*") ? String.format("0x%x", value) : String.format("%s", value)); return String.format("Field[name=%s, type=%s, offset=%d, address=0x%x, value=%s]", name, type, offset, address, val); } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMFlag.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMFlag.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMFlag.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ */ public final Object value; + @VMEntryPoint VMFlag(String name, String type, Object value) { this.name = name; this.type = type; diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMIntrinsicMethod.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMIntrinsicMethod.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMIntrinsicMethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,6 +54,7 @@ */ public final int id; + @VMEntryPoint VMIntrinsicMethod(String declaringClass, String name, String descriptor, int id) { this.declaringClass = declaringClass; this.name = name; diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ package jdk.vm.ci.meta; +import java.lang.reflect.Modifier; import java.util.ArrayList; import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; @@ -146,7 +147,7 @@ public ProfiledType(ResolvedJavaType type, double probability) { super(type, probability); - assert type.isArray() || type.isConcrete() : type; + assert type.isArray() || type.isConcrete() : type + " " + Modifier.toString(type.getModifiers()); } /** diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,14 +102,25 @@ */ JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId); + /** + * Gets a constant that denotes {@code speculation}. The constant can passed to the + * deoptimization handler (e.g., through a thread local) to indicate a failed speculation. + */ JavaConstant encodeSpeculation(Speculation speculation); + /** + * Decodes {@code constant} back to a {@link Speculation} object. + * + * @throws IllegalArgumentException if {@code constant} can only be decoded through a + * {@link SpeculationLog} and {@code speculationLog} does not contain the + * speculation denoted by {@code constant} + */ + Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog); + DeoptimizationReason decodeDeoptReason(JavaConstant constant); DeoptimizationAction decodeDeoptAction(JavaConstant constant); - Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog); - int decodeDebugId(JavaConstant constant); int getArrayBaseOffset(JavaKind elementKind); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,10 @@ assert kind.isPrimitive() || kind == JavaKind.Illegal; } + static PrimitiveConstant forTypeChar(char kind, long i) { + return JavaConstant.forIntegerKind(JavaKind.fromPrimitiveOrVoidTypeChar(kind), i); + } + @Override public JavaKind getJavaKind() { return kind; diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; @@ -39,7 +38,8 @@ /** * Returns the bytecode of this method, if the method has code. The returned byte array does not * contain breakpoints or non-Java bytecodes. This may return null if the - * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}. + * {@linkplain #getDeclaringClass() declaring class} is not + * {@linkplain ResolvedJavaType#isLinked() linked}. * * The contained constant pool indices may not be the ones found in the original class file but * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}). @@ -439,13 +439,15 @@ } /** - * Checks whether the method has bytecodes associated with it. Methods without bytecodes are - * either abstract or native methods. + * Checks whether the method has bytecodes associated with it. Note that even if this method + * returns {@code true}, {@link #getCode} can return {@code null} if + * {@linkplain #getDeclaringClass() declaring class} is not + * {@linkplain ResolvedJavaType#isLinked() linked}. * - * @return whether the definition of this method is Java bytecodes + * @return {@code this.getCodeSize() != 0} */ default boolean hasBytecodes() { - return isConcrete() && !isNative(); + return getCodeSize() != 0; } /** @@ -464,16 +466,11 @@ return getDeclaringClass().isJavaLangObject() && getName().equals(""); } + /** + * Gets a speculation log that can be used when compiling this method to make new speculations + * and query previously failed speculations. The implementation may return a new + * {@link SpeculationLog} object each time this method is called so its the caller's + * responsibility to ensure the same speculation log is used throughout a compilation. + */ SpeculationLog getSpeculationLog(); - - /** - * - * @param object - * @param args - * @throws InvocationTargetException - * @throws IllegalAccessException - */ - default JavaConstant invoke(JavaConstant object, JavaConstant... args) throws InvocationTargetException, IllegalAccessException { - throw new InternalError("unimplemented"); - } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,19 +22,72 @@ */ package jdk.vm.ci.meta; +import java.util.Map; +import java.util.function.Supplier; + /** - * Manages unique deoptimization reasons. Reasons are embedded in compiled code and can be - * invalidated at run time. Subsequent compilations then should not speculate again on such - * invalidated reasons to avoid repeated deoptimization. - * - * All methods of this interface are called by the compiler. There is no need for API to register - * failed speculations during deoptimization, since every VM has different needs there. + * Manages unique {@link SpeculationReason} objects that denote why a deoptimization occurred. + * Reasons are embedded in compiled code for a method. If the compiled code deoptimizes at a + * position associated with a {@link SpeculationReason}, the reason is added to a set of failed + * speculations associated with the method. A subsequent compilation of the method can query the + * failed speculations via a {@link SpeculationLog} to avoid making a speculation based on + * invalidated reasons. This avoids repeated deoptimizations. */ public interface SpeculationLog { /** - * Marker interface for speculation objects that can be added to the speculation log. + * The specific attributes of a speculation that a compiler uses to denote a speculation in a + * compiled method. Typical attributes of a speculation are a bytecode position, type + * information about a variable being speculated on and an enum denoting the type of operation + * to which the speculation applies. A {@link SpeculationReason} is used as a key in a + * {@link Map} and so it must implement {@link Object#equals(Object)} and + * {@link Object#hashCode()} in terms of its attributes. + * + * A JVMCI implementation may serialize speculations for storage off heap (e.g. in native memory + * associated with an nmethod). For this reason, the attributes of a {@link SpeculationReason} + * are restricted to those supported by the {@code add...} methods of + * {@link SpeculationReasonEncoding}. */ public interface SpeculationReason { + + /** + * Encodes the attributes of this reason using a {@link SpeculationReasonEncoding}. For + * efficiency, a {@link SpeculationReason} implementation should cache the returned value + * and return it for all subsequent calls to this method. This also underlines the + * requirement that the encoding for a specific reason instance should be stable. + * + * @param encodingSupplier source of a {@link SpeculationReasonEncoding} + * @return a {@link SpeculationReasonEncoding} that encodes all the attributes that uniquely + * identify this reason + */ + default SpeculationReasonEncoding encode(Supplier encodingSupplier) { + return null; + } + } + + /** + * Provides a facility for encoding the attributes of a {@link SpeculationReason}. The encoding + * format is determined by the implementation of this interface. + */ + public interface SpeculationReasonEncoding { + void addByte(int value); + + void addShort(int value); + + void addInt(int value); + + void addLong(long value); + + void addMethod(ResolvedJavaMethod method); + + void addType(ResolvedJavaType type); + + void addString(String value); + + default void addField(ResolvedJavaField field) { + addType(field.getDeclaringClass()); + addInt(field.getModifiers()); + addInt(field.getOffset()); + } } /** @@ -44,7 +97,7 @@ } class Speculation { - private SpeculationReason reason; + private final SpeculationReason reason; public Speculation(SpeculationReason reason) { this.reason = reason; @@ -77,7 +130,8 @@ Speculation NO_SPECULATION = new Speculation(new NoSpeculationReason()); /** - * Must be called before compilation, i.e., before a compiler calls {@link #maySpeculate}. + * Updates the set of failed speculations recorded in this log. This must be called before + * compilation. */ void collectFailedSpeculations(); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,40 +24,57 @@ import java.util.Formatter; +import jdk.vm.ci.common.NativeImageReinitialize; +import jdk.vm.ci.services.Services; + public class JVMCI { - private static final JVMCIRuntime runtime; + /** + * Singleton instance lazily initialized via double-checked locking. + */ + @NativeImageReinitialize private static volatile JVMCIRuntime runtime; - private static native JVMCIRuntime initializeRuntime(); + @NativeImageReinitialize private static boolean initializing; public static void initialize() { // force static initializer } + private static native JVMCIRuntime initializeRuntime(); + /** * Gets the singleton {@link JVMCIRuntime} instance available to the application. * * @throws UnsupportedOperationException if JVMCI is not supported */ public static JVMCIRuntime getRuntime() { - if (runtime == null) { - String javaHome = System.getProperty("java.home"); - String vmName = System.getProperty("java.vm.name"); - Formatter errorMessage = new Formatter(); - errorMessage.format("The VM does not support the JVMCI API.%n"); - errorMessage.format("Currently used Java home directory is %s.%n", javaHome); - errorMessage.format("Currently used VM configuration is: %s", vmName); - throw new UnsupportedOperationException(errorMessage.toString()); + JVMCIRuntime result = runtime; + if (result == null) { + synchronized (JVMCI.class) { + result = runtime; + if (result == null) { + if (initializing) { + // In recursive call from HotSpotJVMCIRuntime.runtime + // so no need to re-enter initializeRuntime below. This + // path is only entered if JVMCI initialization starts + // with JVMCI.getRuntime(). + return null; + } + initializing = true; + try { + runtime = result = initializeRuntime(); + } catch (UnsatisfiedLinkError e) { + String javaHome = Services.getSavedProperty("java.home"); + String vmName = Services.getSavedProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not support the JVMCI API.%n"); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + } + } } - return runtime; - } - - static { - JVMCIRuntime rt = null; - try { - rt = initializeRuntime(); - } catch (UnsatisfiedLinkError e) { - } - runtime = rt; + return result; } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/.checkstyle_checks.xml --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/.checkstyle_checks.xml Wed May 01 12:41:26 2019 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java Wed May 01 12:31:29 2019 -0700 @@ -22,6 +22,9 @@ */ package jdk.vm.ci.services; +import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; + import java.util.ArrayList; import java.util.List; import java.util.ServiceLoader; @@ -68,6 +71,26 @@ */ protected abstract S getProvider(Class service); + private static volatile List cachedLocators; + + private static Iterable getJVMCIServiceLocators() { + Iterable result = cachedLocators; + if (result != null) { + return result; + } + result = ServiceLoader.load(JVMCIServiceLocator.class, ClassLoader.getSystemClassLoader()); + if (IS_BUILDING_NATIVE_IMAGE) { + ArrayList l = new ArrayList<>(); + for (JVMCIServiceLocator locator: result) { + l.add(locator); + } + l.trimToSize(); + cachedLocators = l; + return l; + } + return result; + } + /** * Gets the providers of the service defined by {@code service} by querying the available * {@link JVMCIServiceLocator} providers. @@ -82,7 +105,7 @@ sm.checkPermission(new JVMCIPermission()); } List providers = new ArrayList<>(); - for (JVMCIServiceLocator access : ServiceLoader.load(JVMCIServiceLocator.class, ClassLoader.getSystemClassLoader())) { + for (JVMCIServiceLocator access : getJVMCIServiceLocators()) { S provider = access.getProvider(service); if (provider != null) { providers.add(provider); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,10 +22,23 @@ */ package jdk.vm.ci.services; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; import java.util.Set; import jdk.internal.misc.VM; +import jdk.internal.reflect.Reflection; /** * Provides utilities needed by JVMCI clients. @@ -36,35 +49,32 @@ // processors while building JDK 9 so use of API added in JDK 9 is made via reflection. /** - * Guards code that should be run when building a native image but should be excluded from - * (being compiled into) the image. Such code must be directly guarded by an {@code if} + * Guards code that should be run when building an JVMCI shared library but should be excluded + * from (being compiled into) the library. Such code must be directly guarded by an {@code if} * statement on this field - the guard cannot be behind a method call. */ - public static final boolean IS_BUILDING_NATIVE_IMAGE; + public static final boolean IS_BUILDING_NATIVE_IMAGE = Boolean.parseBoolean(VM.getSavedProperty("jdk.vm.ci.services.aot")); /** - * Guards code that should only be run in native image. Such code must be directly guarded by an - * {@code if} statement on this field - the guard cannot be behind a method call. + * Guards code that should only be run in a JVMCI shared library. Such code must be directly + * guarded by an {@code if} statement on this field - the guard cannot be behind a method call. * - * The value of this field seen during analysis and compilation of an SVM image must be - * {@code true}. + * The value of this field in a JVMCI shared library runtime must be {@code true}. */ public static final boolean IS_IN_NATIVE_IMAGE; - static { /* - * Prevents javac from constant folding use of this field. It is set to true in the SVM - * image via substitution during image building. + * Prevents javac from constant folding use of this field. It is set to true by the process + * that builds the shared library. */ IS_IN_NATIVE_IMAGE = false; - IS_BUILDING_NATIVE_IMAGE = false; } private Services() { } - static final Map SAVED_PROPERTIES = VM.getSavedProperties(); - static final boolean JVMCI_ENABLED = Boolean.parseBoolean(SAVED_PROPERTIES.get("jdk.internal.vm.ci.enabled")); + private static volatile Map savedProperties = VM.getSavedProperties(); + static final boolean JVMCI_ENABLED = Boolean.parseBoolean(savedProperties.get("jdk.internal.vm.ci.enabled")); /** * Checks that JVMCI is enabled in the VM and throws an error if it isn't. @@ -84,7 +94,21 @@ if (sm != null) { sm.checkPermission(new JVMCIPermission()); } - return SAVED_PROPERTIES; + return savedProperties; + } + + /** + * Helper method equivalent to {@link #getSavedProperties()}{@code .getOrDefault(name, def)}. + */ + public static String getSavedProperty(String name, String def) { + return Services.getSavedProperties().getOrDefault(name, def); + } + + /** + * Helper method equivalent to {@link #getSavedProperties()}{@code .get(name)}. + */ + public static String getSavedProperty(String name) { + return Services.getSavedProperties().get(name); } /** @@ -99,6 +123,83 @@ } } + private static boolean jvmciEnabled = true; + + /** + * When {@code -XX:-UseJVMCIClassLoader} is in use, JVMCI classes are loaded via the boot class + * loader. When {@code null} is the second argument to + * {@link ServiceLoader#load(Class, ClassLoader)}, service lookup will use the system class + * loader and thus find application classes which violates the API of {@link #load} and + * {@link #loadSingle}. To avoid this, a class loader that simply delegates to the boot class + * loader is used. + */ + static class LazyBootClassPath { + static final ClassLoader bootClassPath = new ClassLoader(null) { + }; + } + + private static ClassLoader findBootClassLoaderChild(ClassLoader start) { + ClassLoader cl = start; + while (cl.getParent() != null) { + cl = cl.getParent(); + } + return cl; + } + + private static final Map, List> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; + + @SuppressWarnings("unchecked") + private static Iterable load0(Class service) { + if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) { + List list = servicesCache.get(service); + if (list != null) { + return (Iterable) list; + } + if (IS_IN_NATIVE_IMAGE) { + throw new InternalError(String.format("No %s providers found when building native image", service.getName())); + } + } + + Iterable providers = Collections.emptyList(); + if (jvmciEnabled) { + ClassLoader cl = null; + try { + cl = getJVMCIClassLoader(); + if (cl == null) { + cl = LazyBootClassPath.bootClassPath; + // JVMCI classes are loaded via the boot class loader. + // If we use null as the second argument to ServiceLoader.load, + // service loading will use the system class loader + // and find classes on the application class path. Since we + // don't want this, we use a loader that is as close to the + // boot class loader as possible (since it is impossible + // to force service loading to use only the boot class loader). + cl = findBootClassLoaderChild(ClassLoader.getSystemClassLoader()); + } + providers = ServiceLoader.load(service, cl); + } catch (UnsatisfiedLinkError e) { + jvmciEnabled = false; + } catch (InternalError e) { + if (e.getMessage().equals("JVMCI is not enabled")) { + jvmciEnabled = false; + } else { + throw e; + } + } + } + if (IS_BUILDING_NATIVE_IMAGE) { + synchronized (servicesCache) { + ArrayList providersList = new ArrayList<>(); + for (S provider : providers) { + providersList.add(provider); + } + servicesCache.put(service, providersList); + providers = providersList; + } + } + return providers; + } + /** * Opens all JVMCI packages to {@code otherModule}. */ @@ -114,4 +215,123 @@ } } } + + /** + * Gets an {@link Iterable} of the JVMCI providers available for a given service. + * + * @throws SecurityException if a security manager is present and it denies + * {@link RuntimePermission}("jvmci") + */ + public static Iterable load(Class service) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new JVMCIPermission()); + } + return load0(service); + } + + /** + * Gets the JVMCI provider for a given service for which at most one provider must be available. + * + * @param service the service whose provider is being requested + * @param required specifies if an {@link InternalError} should be thrown if no provider of + * {@code service} is available + * @throws SecurityException if a security manager is present and it denies + * {@link RuntimePermission}("jvmci") + */ + public static S loadSingle(Class service, boolean required) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new JVMCIPermission()); + } + Iterable providers = load0(service); + + S singleProvider = null; + for (S provider : providers) { + if (singleProvider != null) { + throw new InternalError(String.format("Multiple %s providers found: %s, %s", service.getName(), singleProvider.getClass().getName(), provider.getClass().getName())); + } + singleProvider = provider; + } + if (singleProvider == null && required) { + String javaHome = Services.getSavedProperty("java.home"); + String vmName = Services.getSavedProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not expose required service %s.%n", service.getName()); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return singleProvider; + } + + static { + Reflection.registerMethodsToFilter(Services.class, Set.of("getJVMCIClassLoader")); + } + + /** + * Gets the JVMCI class loader. + * + * @throws InternalError with the {@linkplain Throwable#getMessage() message} + * {@code "JVMCI is not enabled"} iff JVMCI is not enabled + */ + private static ClassLoader getJVMCIClassLoader() { + if (IS_IN_NATIVE_IMAGE) { + return null; + } + return ClassLoader.getSystemClassLoader(); + } + + /** + * Serializes the {@linkplain #getSavedProperties() saved system properties} to a byte array for + * the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial + * properties in the JVMCI shared library. + */ + @VMEntryPoint + private static byte[] serializeSavedProperties() throws IOException { + if (IS_IN_NATIVE_IMAGE) { + throw new InternalError("Can only serialize saved properties in HotSpot runtime"); + } + Map props = Services.getSavedProperties(); + + // Compute size of output on the assumption that + // all system properties have ASCII names and values + int estimate = 4; + for (Map.Entry e : props.entrySet()) { + String name = e.getKey(); + String value = e.getValue(); + estimate += (2 + (name.length())) + (2 + (value.length())); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate); + DataOutputStream out = new DataOutputStream(baos); + out.writeInt(props.size()); + for (Map.Entry e : props.entrySet()) { + String name = e.getKey(); + String value = e.getValue(); + out.writeUTF(name); + out.writeUTF(value); + } + return baos.toByteArray(); + } + + /** + * Initialized the {@linkplain #getSavedProperties() saved system properties} in the JVMCI + * shared library from the {@linkplain #serializeSavedProperties() serialized saved properties} + * in the HotSpot runtime. + */ + @VMEntryPoint + private static void initializeSavedProperties(byte[] serializedProperties) throws IOException { + if (!IS_IN_NATIVE_IMAGE) { + throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime"); + } + DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties)); + Map props = new HashMap<>(in.readInt()); + while (in.available() != 0) { + String name = in.readUTF(); + String value = in.readUTF(); + props.put(name, value); + } + savedProperties = Collections.unmodifiableMap(props); + } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/VMEntryPoint.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/VMEntryPoint.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.services; + +/** + * Marker interface for methods which are called from the JVM. + */ +@interface VMEntryPoint { + /** + * An optional comment describing the caller. + */ + String value() default ""; +} diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -313,7 +313,7 @@ case Double: return SPARCKind.DOUBLE; default: - throw new IllegalArgumentException("Unknown JavaKind: " + javaKind); + return null; } } diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java Wed May 01 12:31:29 2019 -0700 @@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot.amd64; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs; import org.graalvm.compiler.api.replacements.Snippet; @@ -66,7 +67,7 @@ @Override public void initialize(OptionValues options, Iterable factories, HotSpotProviders providers, GraalHotSpotVMConfig config) { convertSnippets = new AMD64ConvertSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); - profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue(options) && !JavaVersionUtil.Java8OrEarlier + profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue(options) && !JavaVersionUtil.Java8OrEarlier && GeneratePIC.getValue(options) ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget()) : null; mathSnippets = new AMD64X87MathSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed May 01 12:31:29 2019 -0700 @@ -26,6 +26,7 @@ import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs; import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace; import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; @@ -227,7 +228,7 @@ stringToBytesSnippets = new StringToBytesSnippets.Templates(options, factories, providers, target); hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target); resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target); - if (!JavaVersionUtil.Java8OrEarlier) { + if (!JavaVersionUtil.Java8OrEarlier && GeneratePIC.getValue(options)) { profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target); } objectCloneSnippets = new ObjectCloneSnippets.Templates(options, factories, providers, target); diff -r 0bda2308eded -r ad45b3802d4e src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java Wed May 01 12:41:26 2019 -0400 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,22 +29,38 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; +import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.SpeculationLog.SpeculationReason; +import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding; import jdk.vm.ci.runtime.JVMCI; import jdk.vm.ci.services.JVMCIPermission; import jdk.vm.ci.services.Services; +import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; +import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; + /** - * JDK 9+ version of {@link GraalServices}. + * JDK 13+ version of {@link GraalServices}. */ public final class GraalServices { + private static final Map, List> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; + private GraalServices() { } @@ -54,8 +70,37 @@ * @throws SecurityException if on JDK8 and a security manager is present and it denies * {@link JVMCIPermission} */ + @SuppressWarnings("unchecked") public static Iterable load(Class service) { - Iterable iterable = ServiceLoader.load(service); + if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) { + List list = servicesCache.get(service); + if (list != null) { + return (Iterable) list; + } + if (IS_IN_NATIVE_IMAGE) { + throw new InternalError(String.format("No %s providers found when building native image", service.getName())); + } + } + + Iterable providers = load0(service); + + if (IS_BUILDING_NATIVE_IMAGE) { + synchronized (servicesCache) { + ArrayList providersList = new ArrayList<>(); + for (S provider : providers) { + providersList.add(provider); + } + providers = providersList; + servicesCache.put(service, providersList); + return providers; + } + } + + return providers; + } + + protected static Iterable load0(Class service) { + Iterable iterable = ServiceLoader.load(service, GraalServices.class.getClassLoader()); return new Iterable<>() { @Override public Iterator iterator() { @@ -90,6 +135,8 @@ * @param other all JVMCI packages will be opened to the module defining this class */ static void openJVMCITo(Class other) { + if (IS_IN_NATIVE_IMAGE) return; + Module jvmciModule = JVMCI_MODULE; Module otherModule = other.getModule(); if (jvmciModule != otherModule) { @@ -98,7 +145,7 @@ // JVMCI initialization opens all JVMCI packages // to Graal which is a prerequisite for Graal to // open JVMCI packages to other modules. - JVMCI.initialize(); + JVMCI.getRuntime(); jvmciModule.addOpens(pkg, otherModule); } @@ -179,6 +226,7 @@ final int groupId; final String groupName; final Object[] context; + private SpeculationReasonEncoding encoding; DirectSpeculationReason(int groupId, String groupName, Object[] context) { this.groupId = groupId; @@ -204,6 +252,123 @@ public String toString() { return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context)); } + + @Override + public SpeculationReasonEncoding encode(Supplier encodingSupplier) { + if (encoding == null) { + encoding = encodingSupplier.get(); + encoding.addInt(groupId); + for (Object o : context) { + if (o == null) { + encoding.addInt(0); + } else { + addNonNullObject(encoding, o); + } + } + } + return encoding; + } + + static void addNonNullObject(SpeculationReasonEncoding encoding, Object o) { + Class c = o.getClass(); + if (c == String.class) { + encoding.addString((String) o); + } else if (c == Byte.class) { + encoding.addByte((Byte) o); + } else if (c == Short.class) { + encoding.addShort((Short) o); + } else if (c == Character.class) { + encoding.addShort((Character) o); + } else if (c == Integer.class) { + encoding.addInt((Integer) o); + } else if (c == Long.class) { + encoding.addLong((Long) o); + } else if (c == Float.class) { + encoding.addInt(Float.floatToRawIntBits((Float) o)); + } else if (c == Double.class) { + encoding.addLong(Double.doubleToRawLongBits((Double) o)); + } else if (o instanceof Enum) { + encoding.addInt(((Enum) o).ordinal()); + } else if (o instanceof ResolvedJavaMethod) { + encoding.addMethod((ResolvedJavaMethod) o); + } else if (o instanceof ResolvedJavaType) { + encoding.addType((ResolvedJavaType) o); + } else if (o instanceof ResolvedJavaField) { + encoding.addField((ResolvedJavaField) o); + } else if (o instanceof SpeculationContextObject) { + SpeculationContextObject sco = (SpeculationContextObject) o; + // These are compiler objects which all have the same class + // loader so the class name uniquely identifies the class. + encoding.addString(o.getClass().getName()); + sco.accept(new EncodingAdapter(encoding)); + } else if (o.getClass() == BytecodePosition.class) { + BytecodePosition p = (BytecodePosition) o; + while (p != null) { + encoding.addInt(p.getBCI()); + encoding.addMethod(p.getMethod()); + p = p.getCaller(); + } + } else { + throw new IllegalArgumentException("Unsupported type for encoding: " + c.getName()); + } + } + } + + static class EncodingAdapter implements SpeculationContextObject.Visitor { + private final SpeculationReasonEncoding encoding; + + EncodingAdapter(SpeculationReasonEncoding encoding) { + this.encoding = encoding; + } + + @Override + public void visitBoolean(boolean v) { + encoding.addByte(v ? 1 : 0); + } + + @Override + public void visitByte(byte v) { + encoding.addByte(v); + } + + @Override + public void visitChar(char v) { + encoding.addShort(v); + } + + @Override + public void visitShort(short v) { + encoding.addInt(v); + } + + @Override + public void visitInt(int v) { + encoding.addInt(v); + } + + @Override + public void visitLong(long v) { + encoding.addLong(v); + } + + @Override + public void visitFloat(float v) { + encoding.addInt(Float.floatToRawIntBits(v)); + } + + @Override + public void visitDouble(double v) { + encoding.addLong(Double.doubleToRawLongBits(v)); + } + + @Override + public void visitObject(Object v) { + if (v == null) { + encoding.addInt(0); + } else { + DirectSpeculationReason.addNonNullObject(encoding, v); + } + } } static SpeculationReason createSpeculationReason(int groupId, String groupName, Object... context) { diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/SecurityRestrictionsTest.java --- a/test/hotspot/jtreg/compiler/jvmci/SecurityRestrictionsTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/SecurityRestrictionsTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ NO_JVMCI { @Override public Class getExpectedException() { - return InternalError.class; + return Error.class; } }, ALL_PERM { @@ -172,12 +172,8 @@ } }; Utils.runAndCheckException(() -> { - try { - // CompilerToVM:: provokes CompilerToVM:: - Class.forName("jdk.vm.ci.hotspot.CompilerToVMHelper"); - } catch (ClassNotFoundException e) { - throw new Error("TESTBUG : " + e, e); - } + // CompilerToVM:: provokes CompilerToVM:: + Class.forName("jdk.vm.ci.hotspot.CompilerToVMHelper"); }, exceptionCheck); } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java --- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,10 @@ import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.code.stack.InspectedFrameVisitor; import jdk.vm.ci.meta.ConstantPool; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.runtime.JVMCI; import java.lang.reflect.Executable; /** @@ -36,6 +39,7 @@ */ public class CompilerToVMHelper { public static final CompilerToVM CTVM = new CompilerToVM(); + private static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); public static byte[] getBytecode(HotSpotResolvedJavaMethod method) { return CTVM.getBytecode((HotSpotResolvedJavaMethodImpl)method); @@ -80,8 +84,12 @@ } public static HotSpotResolvedObjectType lookupType(String name, - Class accessingClass, boolean resolve) throws ClassNotFoundException { - return CTVM.lookupType(name, accessingClass, resolve); + Class accessClass, boolean resolve) throws ClassNotFoundException { + if (accessClass == null) { + throw new NullPointerException(); + } + HotSpotResolvedObjectTypeImpl accessingClass = (HotSpotResolvedObjectTypeImpl) metaAccess.lookupJavaType(accessClass); + return (HotSpotResolvedObjectType) CTVM.lookupType(name, accessingClass, resolve); } public static HotSpotResolvedObjectType lookupTypeHelper(String name, @@ -94,11 +102,13 @@ } public static Object resolveConstantInPool(ConstantPool constantPool, int cpi) { - return CTVM.resolveConstantInPool((HotSpotConstantPool) constantPool, cpi); + DirectHotSpotObjectConstantImpl obj = (DirectHotSpotObjectConstantImpl) CTVM.resolveConstantInPool((HotSpotConstantPool) constantPool, cpi); + return obj.object; } public static Object resolvePossiblyCachedConstantInPool(ConstantPool constantPool, int cpi) { - return CTVM.resolvePossiblyCachedConstantInPool((HotSpotConstantPool) constantPool, cpi); + DirectHotSpotObjectConstantImpl obj = (DirectHotSpotObjectConstantImpl) CTVM.resolvePossiblyCachedConstantInPool((HotSpotConstantPool) constantPool, cpi); + return obj.object; } public static int lookupNameAndTypeRefIndexInPool(ConstantPool constantPool, int cpi) { @@ -158,7 +168,16 @@ public static int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, HotSpotSpeculationLog speculationLog) { - return CTVM.installCode(target, compiledCode, code, speculationLog); + byte[] speculations; + long failedSpeculationsAddress; + if (speculationLog != null) { + speculations = speculationLog.getFlattenedSpeculations(true); + failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress(); + } else { + speculations = new byte[0]; + failedSpeculationsAddress = 0L; + } + return CTVM.installCode(target, compiledCode, code, failedSpeculationsAddress, speculations); } public static int getMetadata(TargetDescription target, @@ -208,9 +227,9 @@ return CTVM.getStackTraceElement((HotSpotResolvedJavaMethodImpl)method, bci); } - public static Object executeInstalledCode(Object[] args, - InstalledCode installedCode) throws InvalidInstalledCodeException { - return CTVM.executeInstalledCode(args, installedCode); + public static Object executeHotSpotNmethod(Object[] args, + HotSpotNmethod nmethodMirror) throws InvalidInstalledCodeException { + return CTVM.executeHotSpotNmethod(args, nmethodMirror); } public static long[] getLineNumberTable(HotSpotResolvedJavaMethod method) { @@ -233,8 +252,8 @@ CTVM.reprofile((HotSpotResolvedJavaMethodImpl)method); } - public static void invalidateInstalledCode(InstalledCode installedCode) { - CTVM.invalidateInstalledCode(installedCode); + public static void invalidateHotSpotNmethod(HotSpotNmethod nmethodMirror) { + CTVM.invalidateHotSpotNmethod(nmethodMirror); } public static long[] collectCounters() { @@ -289,33 +308,33 @@ CTVM.flushDebugOutput(); } - public static HotSpotResolvedJavaMethod getResolvedJavaMethod(Object base, + public static HotSpotResolvedJavaMethod getResolvedJavaMethod(HotSpotObjectConstantImpl base, long displacement) { return CTVM.getResolvedJavaMethod(base, displacement); } - public static HotSpotConstantPool getConstantPool(Object object) { + public static HotSpotConstantPool getConstantPool(MetaspaceObject object) { return CTVM.getConstantPool(object); } - public static HotSpotResolvedObjectType getResolvedJavaType(Object base, + public static HotSpotResolvedObjectType getResolvedJavaType(MetaspaceObject base, long displacement, boolean compressed) { return CTVM.getResolvedJavaType(base, displacement, compressed); } public static long getMetaspacePointer(Object o) { - return ((MetaspaceWrapperObject) o).getMetaspacePointer(); + return ((MetaspaceObject) o).getMetaspacePointer(); } public static Class CompilerToVMClass() { return CompilerToVM.class; } - public static Class getMirror(HotSpotResolvedObjectType type) { - return ((HotSpotResolvedJavaType) type).mirror(); + public static JavaConstant getJavaMirror(HotSpotResolvedObjectType type) { + return ((HotSpotResolvedJavaType) type).getJavaMirror(); } public static HotSpotResolvedObjectType fromObjectClass(Class theClass) { - return HotSpotResolvedObjectTypeImpl.fromObjectClass(theClass); + return (HotSpotResolvedObjectType) metaAccess.lookupJavaType(theClass); } } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/PublicMetaspaceWrapperObject.java --- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/PublicMetaspaceWrapperObject.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/PublicMetaspaceWrapperObject.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,4 +26,4 @@ /** * A public available version of MetaspaceWrapperObject interface. */ -public interface PublicMetaspaceWrapperObject extends MetaspaceWrapperObject { } +public interface PublicMetaspaceWrapperObject extends MetaspaceHandleObject { } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ private void checkNull() { Utils.runAndCheckException( - () -> CompilerToVMHelper.disassembleCodeBlob(null), + () -> { CompilerToVMHelper.disassembleCodeBlob(null); }, NullPointerException.class); } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @requires vm.jvmci * @library /test/lib / * @library ../common/patches + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetConstantPoolTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetConstantPoolTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetConstantPoolTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @requires vm.jvmci * @library /test/lib / * @library ../common/patches + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @requires vm.jvmci * @library / /test/lib * @library ../common/patches + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc:+open * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:+open * diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @requires vm.jvmci * @library / /test/lib * @library ../common/patches + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.meta diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @requires vm.jvmci * @library /test/lib / * @library ../common/patches + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ * @bug 8136421 * @requires vm.jvmci * @library /test/lib / + * @ignore Not supported JVMCI API * @modules java.base/jdk.internal.misc:open * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot:open * jdk.internal.vm.ci/jdk.vm.ci.runtime diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java --- a/test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,9 @@ import jdk.vm.ci.code.site.Site; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; +import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PlatformKind; @@ -50,7 +52,7 @@ protected final MetaAccessProvider metaAccess; protected final HotSpotConstantReflectionProvider constantReflection; - protected final ResolvedJavaMethod dummyMethod; + protected final HotSpotResolvedJavaMethod dummyMethod; public static void dummyMethod() { } @@ -69,12 +71,13 @@ Assert.fail(); } - dummyMethod = metaAccess.lookupJavaMethod(method); + dummyMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); } protected void installEmptyCode(Site[] sites, Assumption[] assumptions, Comment[] comments, int dataSectionAlignment, DataPatch[] dataSectionPatches, StackSlot deoptRescueSlot) { - HotSpotCompiledCode code = new HotSpotCompiledCode("dummyMethod", new byte[0], 0, sites, assumptions, new ResolvedJavaMethod[]{dummyMethod}, comments, new byte[8], dataSectionAlignment, - dataSectionPatches, false, 0, deoptRescueSlot); + HotSpotCompiledCode code = new HotSpotCompiledNmethod("dummyMethod", new byte[0], 0, sites, assumptions, new ResolvedJavaMethod[]{dummyMethod}, comments, new byte[8], dataSectionAlignment, + dataSectionPatches, false, 0, deoptRescueSlot, + dummyMethod, 0, 1, 0L, false); codeCache.addCode(dummyMethod, code, null, null); } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,7 @@ import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; +import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.HotSpotVMEventListener; @@ -118,10 +119,11 @@ } HotSpotResolvedJavaMethod method = CTVMUtilities .getResolvedMethod(SimpleClass.class, testMethod); - HotSpotCompiledCode compiledCode = new HotSpotCompiledCode(METHOD_NAME, + HotSpotCompiledCode compiledCode = new HotSpotCompiledNmethod(METHOD_NAME, new byte[0], 0, new Site[0], new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], - 16, new DataPatch[0], false, 0, null); + 16, new DataPatch[0], false, 0, null, + method, 0, 1, 0L, false); codeCache.installCode(method, compiledCode, /* installedCode = */ null, /* speculationLog = */ null, /* isDefault = */ false); Asserts.assertEQ(gotInstallNotification, 1, diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciShutdownEventListener.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ public static void main(String args[]) { try { HotSpotJVMCIRuntime.runtime(); // let's trigger that lazy jvmci init - } catch (InternalError e) { + } catch (Error e) { System.out.println(GOT_INTERNAL_ERROR); } } diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotSpeculationLog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotSpeculationLog.java Wed May 01 12:31:29 2019 -0700 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot.test; + +import java.util.function.Supplier; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +import jdk.vm.ci.hotspot.HotSpotSpeculationLog; +import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding; + +public class TestHotSpotSpeculationLog { + + static final class DummyReason implements SpeculationLog.SpeculationReason { + + final String name; + private SpeculationReasonEncoding cachedEncoding; + + DummyReason(String name) { + this.name = name; + } + + @Override + public SpeculationReasonEncoding encode(Supplier encodingSupplier) { + SpeculationReasonEncoding encoding = cachedEncoding; + if (encoding == null) { + encoding = encodingSupplier.get(); + encoding.addString(name); + } + cachedEncoding = encoding; + return encoding; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DummyReason) { + DummyReason that = (DummyReason) obj; + return this.name.equals(that.name); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } + } + + @Test + public synchronized void testFailedSpeculations() { + HotSpotSpeculationLog log = new HotSpotSpeculationLog(); + DummyReason reason1 = new DummyReason("dummy1"); + DummyReason reason2 = new DummyReason("dummy2"); + Assert.assertTrue(log.maySpeculate(reason1)); + Assert.assertTrue(log.maySpeculate(reason2)); + + SpeculationLog.Speculation s1 = log.speculate(reason1); + SpeculationLog.Speculation s2 = log.speculate(reason2); + + boolean added = log.addFailedSpeculation(s1); + Assume.assumeTrue(added); + log.collectFailedSpeculations(); + Assert.assertFalse(log.maySpeculate(reason1)); + Assert.assertTrue(log.maySpeculate(reason2)); + + added = log.addFailedSpeculation(s2); + Assume.assumeTrue(added); + log.collectFailedSpeculations(); + Assume.assumeTrue(added); + Assert.assertFalse(log.maySpeculate(reason1)); + Assert.assertFalse(log.toString(), log.maySpeculate(reason2)); + } +} diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @requires vm.jvmci * @library ../../../../../ + * @ignore Not supported JVMCI API * @modules jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.runtime * java.base/jdk.internal.misc diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @requires vm.jvmci * @library ../../../../../ + * @ignore Not supported JVMCI API * @modules jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.runtime * java.base/jdk.internal.misc diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java Wed May 01 12:31:29 2019 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,24 +24,107 @@ */ package jdk.vm.ci.runtime.test; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.function.Supplier; + import org.junit.Assert; import org.junit.Test; +import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding; +import jdk.vm.ci.runtime.JVMCI; public class TestSpeculationLog extends MethodUniverse { - static class Dummy implements SpeculationLog.SpeculationReason { + static final class Dummy implements SpeculationLog.SpeculationReason { + + final int[] ints = {Integer.MIN_VALUE, -42, -1, 0, 1, 42, Integer.MAX_VALUE}; + final long[] longs = {Long.MIN_VALUE, -42, -1, 0, 1, 42, Long.MAX_VALUE}; + final String[] strings = {null, "non-empty string", ""}; + final Collection methods = new ArrayList<>(MethodUniverse.methods.values()).subList(0, 10); + final Collection constructors = new ArrayList<>(MethodUniverse.constructors.values()).subList(0, 10); + final Collection types = new ArrayList<>(TypeUniverse.javaTypes).subList(0, 10); + + private final boolean useCache; + private SpeculationReasonEncoding cachedEncoding; + + Dummy(boolean useCache) { + this.useCache = useCache; + } + @Override + public SpeculationReasonEncoding encode(Supplier encodingSupplier) { + SpeculationReasonEncoding encoding = cachedEncoding; + if (encoding == null) { + encoding = encodingSupplier.get(); + for (int i : ints) { + encoding.addInt(i); + } + for (long l : longs) { + encoding.addLong(l); + } + for (String s : strings) { + encoding.addString(s); + } + for (ResolvedJavaMethod m : methods) { + encoding.addMethod(m); + } + for (ResolvedJavaMethod c : constructors) { + encoding.addMethod(c); + } + for (ResolvedJavaType t : types) { + encoding.addType(t); + } + encoding.addMethod(null); + encoding.addType(null); + } + if (useCache) { + cachedEncoding = encoding; + } + return encoding; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Dummy) { + Dummy that = (Dummy) obj; + return Arrays.equals(this.ints, that.ints) && + Arrays.equals(this.longs, that.longs) && + Arrays.equals(this.strings, that.strings) && + this.methods.equals(that.methods) && + this.constructors.equals(that.constructors) && + this.types.equals(that.types); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return 31 * Arrays.hashCode(ints) ^ + Arrays.hashCode(longs) ^ + Arrays.hashCode(strings) ^ + methods.hashCode() ^ + constructors.hashCode() ^ + types.hashCode(); + } } @Test - public void testSpeculationIdentity() { - Dummy spec = new Dummy(); - SpeculationLog log = methods.entrySet().iterator().next().getValue().getSpeculationLog(); - SpeculationLog.Speculation s1 = log.speculate(spec); - SpeculationLog.Speculation s2 = log.speculate(spec); + public synchronized void testSpeculationIdentity() { + CodeCacheProvider codeCache = JVMCI.getRuntime().getHostJVMCIBackend().getCodeCache(); + SpeculationLog log = codeCache.createSpeculationLog(); + Dummy spec1 = new Dummy(true); + Dummy spec2 = new Dummy(false); + Assert.assertTrue(log.maySpeculate(spec1)); + Assert.assertTrue(log.maySpeculate(spec2)); + SpeculationLog.Speculation s1 = log.speculate(spec1); + SpeculationLog.Speculation s2 = log.speculate(spec2); Assert.assertTrue("Speculation should maintain identity", s1.equals(s2)); JavaConstant e1 = metaAccess.encodeSpeculation(s1); JavaConstant e2 = metaAccess.encodeSpeculation(s2); diff -r 0bda2308eded -r ad45b3802d4e test/hotspot/jtreg/runtime/NMT/MallocSiteTypeChange.java --- a/test/hotspot/jtreg/runtime/NMT/MallocSiteTypeChange.java Wed May 01 12:41:26 2019 -0400 +++ b/test/hotspot/jtreg/runtime/NMT/MallocSiteTypeChange.java Wed May 01 12:31:29 2019 -0700 @@ -60,7 +60,7 @@ output.shouldContain("Baseline succeeded"); wb.NMTFree(addr); - addr = wb.NMTMallocWithPseudoStackAndType(2 * 1024, pc, 7 /* mtInternal */ ); + addr = wb.NMTMallocWithPseudoStackAndType(2 * 1024, pc, 8 /* mtInternal */ ); pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail.diff"}); output = new OutputAnalyzer(pb.start()); output.shouldContain("(malloc=0KB type=Test -4KB)");