| /* |
| * Copyright (c) 2011, 2022, 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_JVMCICODEINSTALLER_HPP |
| #define SHARE_JVMCI_JVMCICODEINSTALLER_HPP |
| |
| #include "classfile/classFileStream.hpp" |
| #include "code/debugInfoRec.hpp" |
| #include "code/exceptionHandlerTable.hpp" |
| #include "code/nativeInst.hpp" |
| #include "jvmci/jvmci.hpp" |
| #include "jvmci/jvmciEnv.hpp" |
| |
| // Object for decoding a serialized HotSpotCompiledCode object. |
| // Encoding is done by jdk.vm.ci.hotspot.HotSpotCompiledCodeStream. |
| class HotSpotCompiledCodeStream : public ResourceObj { |
| private: |
| class Chunk { |
| private: |
| Chunk* _next; |
| u4 _size; |
| |
| public: |
| u4 size() const { return _size; } |
| const u1* data() const { return ((const u1*)this) + HEADER; } |
| const u1* data_end() const { return data() + _size; } |
| Chunk* next() const { return _next; } |
| }; |
| |
| // Mirrors jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.HEADER |
| static const int HEADER = sizeof(Chunk*) + sizeof(u4); |
| |
| Chunk* _head; // First chunk in buffer |
| Chunk* _chunk; // Chunk currently being read |
| mutable const u1* _pos; // Read position in _chunk |
| const bool _with_type_info; |
| objArrayHandle _object_pool; // Pool for objects in Java heap (ignored if libjvmci) |
| JavaThread* _thread; // Current thread |
| |
| // Virtual objects in DebugInfo currently being decoded |
| GrowableArray<ScopeValue*>* _virtual_objects; |
| |
| // HotSpotCompiledCode.name or HotSpotCompiledNmethod.method |
| const char* _code_desc; |
| |
| #define checked_read(value, name, type) do { \ |
| if (_with_type_info) { check_data(sizeof(type), name); } \ |
| return (type) value; \ |
| } while (0) |
| |
| void before_read(u1 size); |
| |
| u1 get_u1() { before_read(1); u1 res = *_pos; _pos += 1; return res; } |
| u2 get_u2() { before_read(2); u2 res = *((u2*) _pos); _pos += 2; return res; } |
| u4 get_u4() { before_read(4); u4 res = *((u4*) _pos); _pos += 4; return res; } |
| u8 get_u8() { before_read(8); u8 res = *((u8*) _pos); _pos += 8; return res; } |
| |
| void check_data(u2 expect_size, const char *expect_name); |
| |
| public: |
| HotSpotCompiledCodeStream(JavaThread* thread, const u1* buffer, bool with_type_info, objArrayHandle& object_pool) : |
| _head((Chunk*) buffer), |
| _chunk((Chunk*) buffer), |
| _pos(_chunk->data()), |
| _with_type_info(with_type_info), |
| _object_pool(object_pool), |
| _thread(thread), |
| _virtual_objects(nullptr), |
| _code_desc("<unknown>") |
| {} |
| |
| // Dump complete buffer to `st`. |
| void dump_buffer(outputStream* st=tty) const; |
| |
| // Dump last `len` bytes of current buffer chunk to `st` |
| void dump_buffer_tail(int len, outputStream* st=tty) const; |
| |
| // Gets a string containing code_desc() followed by a hexdump |
| // of about 100 bytes in the stream up to the current read position. |
| const char* context() const; |
| |
| // Gets HotSpotCompiledCode.name or HotSpotCompiledNmethod.method.name_and_sig_as_C_string(). |
| const char* code_desc() const { return _code_desc; } |
| |
| void set_code_desc(const char* name, methodHandle& method) { |
| if (name != nullptr) { |
| _code_desc = name; |
| } else if (!method.is_null()) { |
| _code_desc = method->name_and_sig_as_C_string(); |
| } |
| } |
| |
| // Current read address. |
| address pos() const { return (address) _pos; } |
| |
| // Offset of current read position from start of buffer. |
| u4 offset() const; |
| |
| // Gets the number of remaining bytes in the stream. |
| bool available() const; |
| |
| oop get_oop(int id, JVMCI_TRAPS) const; |
| JavaThread* thread() const { return _thread; } |
| |
| void set_virtual_objects(GrowableArray<ScopeValue*>* objs) { _virtual_objects = objs; } |
| ScopeValue* virtual_object_at(int id, JVMCI_TRAPS) const; |
| |
| u1 read_u1(const char* name) { checked_read(get_u1(), name, u1); } |
| u2 read_u2(const char* name) { checked_read(get_u2(), name, u2); } |
| u4 read_u4(const char* name) { checked_read(get_u4(), name, u4); } |
| u8 read_u8(const char* name) { checked_read(get_u8(), name, u8); } |
| s2 read_s2(const char* name) { checked_read(get_u2(), name, s2); } |
| s4 read_s4(const char* name) { checked_read(get_u4(), name, s4); } |
| s8 read_s8(const char* name) { checked_read(get_u8(), name, s8); } |
| |
| bool read_bool(const char* name) { checked_read((get_u1() != 0), name, bool); } |
| Method* read_method(const char* name); |
| Klass* read_klass(const char* name); |
| const char* read_utf8(const char* name, JVMCI_TRAPS); |
| #undef checked_read |
| }; |
| |
| // Converts a HotSpotCompiledCode to a CodeBlob or an nmethod. |
| class CodeInstaller : public StackObj { |
| friend class JVMCIVMStructs; |
| private: |
| enum MarkId { |
| INVALID_MARK, |
| VERIFIED_ENTRY, |
| UNVERIFIED_ENTRY, |
| OSR_ENTRY, |
| EXCEPTION_HANDLER_ENTRY, |
| DEOPT_HANDLER_ENTRY, |
| FRAME_COMPLETE, |
| ENTRY_BARRIER_PATCH, |
| INVOKEINTERFACE, |
| INVOKEVIRTUAL, |
| INVOKESTATIC, |
| INVOKESPECIAL, |
| INLINE_INVOKE, |
| POLL_NEAR, |
| POLL_RETURN_NEAR, |
| POLL_FAR, |
| POLL_RETURN_FAR, |
| CARD_TABLE_ADDRESS, |
| CARD_TABLE_SHIFT, |
| HEAP_TOP_ADDRESS, |
| HEAP_END_ADDRESS, |
| NARROW_KLASS_BASE_ADDRESS, |
| NARROW_OOP_BASE_ADDRESS, |
| CRC_TABLE_ADDRESS, |
| LOG_OF_HEAP_REGION_GRAIN_BYTES, |
| INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED, |
| DEOPT_MH_HANDLER_ENTRY, |
| VERIFY_OOPS, |
| VERIFY_OOP_BITS, |
| VERIFY_OOP_MASK, |
| VERIFY_OOP_COUNT_ADDRESS, |
| INVOKE_INVALID = -1 |
| }; |
| |
| // Mirrors jdk.vm.ci.hotspot.HotSpotCompiledCodeStream.Tag |
| enum Tag { |
| ILLEGAL, |
| REGISTER_PRIMITIVE, |
| REGISTER_OOP, |
| REGISTER_NARROW_OOP, |
| STACK_SLOT_PRIMITIVE, |
| STACK_SLOT_OOP, |
| STACK_SLOT_NARROW_OOP, |
| VIRTUAL_OBJECT_ID, |
| VIRTUAL_OBJECT_ID2, |
| NULL_CONSTANT, |
| RAW_CONSTANT, |
| PRIMITIVE_0, |
| PRIMITIVE4, |
| PRIMITIVE8, |
| JOBJECT, |
| OBJECT_ID, |
| OBJECT_ID2, |
| |
| NO_FINALIZABLE_SUBCLASS, |
| CONCRETE_SUBTYPE, |
| LEAF_TYPE, |
| CONCRETE_METHOD, |
| CALLSITE_TARGET_VALUE, |
| |
| PATCH_OBJECT_ID, |
| PATCH_OBJECT_ID2, |
| PATCH_NARROW_OBJECT_ID, |
| PATCH_NARROW_OBJECT_ID2, |
| PATCH_JOBJECT, |
| PATCH_NARROW_JOBJECT, |
| PATCH_KLASS, |
| PATCH_NARROW_KLASS, |
| PATCH_METHOD, |
| PATCH_DATA_SECTION_REFERENCE, |
| |
| SITE_CALL, |
| SITE_FOREIGN_CALL, |
| SITE_FOREIGN_CALL_NO_DEBUG_INFO, |
| SITE_SAFEPOINT, |
| SITE_INFOPOINT, |
| SITE_IMPLICIT_EXCEPTION, |
| SITE_IMPLICIT_EXCEPTION_DISPATCH, |
| SITE_MARK, |
| SITE_DATA_PATCH, |
| SITE_EXCEPTION_HANDLER, |
| }; |
| |
| // Mirrors constants from jdk.vm.ci.code.BytecodeFrame. |
| enum BytecodeFrameBCI { |
| UNWIND_BCI = -1, |
| BEFORE_BCI = -2, |
| AFTER_BCI = -3, |
| AFTER_EXCEPTION_BCI = -4, |
| UNKNOWN_BCI = -5, |
| INVALID_FRAMESTATE_BCI = -6 |
| }; |
| |
| // Mirrors HotSpotCompiledCode flags from jdk.vm.ci.hotspot.HotSpotCompiledCodeStream. |
| enum HotSpotCompiledCodeFlags { |
| HCC_IS_NMETHOD = 0x01, |
| HCC_HAS_ASSUMPTIONS = 0x02, |
| HCC_HAS_METHODS = 0x04, |
| HCC_HAS_DEOPT_RESCUE_SLOT = 0x08, |
| HCC_HAS_COMMENTS = 0x10 |
| }; |
| |
| // Mirrors DebugInfo flags from jdk.vm.ci.hotspot.HotSpotCompiledCodeStream. |
| enum DebugInfoFlags { |
| DI_HAS_REFERENCE_MAP = 0x01, |
| DI_HAS_CALLEE_SAVE_INFO = 0x02, |
| DI_HAS_FRAMES = 0x04 |
| }; |
| |
| // Mirrors BytecodeFrame flags from jdk.vm.ci.hotspot.HotSpotCompiledCodeStream. |
| enum DebugInfoFrameFlags { |
| DIF_HAS_LOCALS = 0x01, |
| DIF_HAS_STACK = 0x02, |
| DIF_HAS_LOCKS = 0x04, |
| DIF_DURING_CALL = 0x08, |
| DIF_RETHROW_EXCEPTION = 0x10 |
| }; |
| |
| // Sentinel value in a DebugInfo stream denoting no register. |
| static const int NO_REGISTER = 0xFFFF; |
| |
| Arena _arena; |
| JVMCIEnv* _jvmci_env; |
| |
| jint _sites_count; |
| |
| CodeOffsets _offsets; |
| int _nmethod_entry_patch_offset; |
| |
| jint _code_size; |
| jint _total_frame_size; |
| jint _orig_pc_offset; |
| jint _parameter_count; |
| jint _constants_size; |
| |
| bool _has_monitors; |
| bool _has_wide_vector; |
| |
| MarkId _next_call_type; |
| address _invoke_mark_pc; |
| |
| CodeSection* _instructions; |
| CodeSection* _constants; |
| |
| OopRecorder* _oop_recorder; |
| DebugInformationRecorder* _debug_recorder; |
| Dependencies* _dependencies; |
| ExceptionHandlerTable _exception_handler_table; |
| ImplicitExceptionTable _implicit_exception_table; |
| bool _has_auto_box; |
| |
| static ConstantOopWriteValue* _oop_null_scope_value; |
| static ConstantIntValue* _int_m1_scope_value; |
| static ConstantIntValue* _int_0_scope_value; |
| static ConstantIntValue* _int_1_scope_value; |
| static ConstantIntValue* _int_2_scope_value; |
| static LocationValue* _illegal_value; |
| static MarkerValue* _virtual_byte_array_marker; |
| |
| jint pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCI_TRAPS); |
| void pd_patch_OopConstant(int pc_offset, Handle& obj, bool compressed, JVMCI_TRAPS); |
| void pd_patch_MetaspaceConstant(int pc_offset, HotSpotCompiledCodeStream* stream, u1 tag, 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, methodHandle& method, jint pc_offset, JVMCI_TRAPS); |
| void pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS); |
| |
| public: |
| |
| #ifndef PRODUCT |
| // Verifies the enum mirroring BCI constants in BytecodeFrame is in sync. |
| static void verify_bci_constants(JVMCIEnv* env); |
| #endif |
| |
| CodeInstaller(JVMCIEnv* jvmci_env) : |
| _arena(mtJVMCI), |
| _jvmci_env(jvmci_env), |
| _has_auto_box(false) {} |
| |
| JVMCI::CodeInstallResult install(JVMCICompiler* compiler, |
| jlong compiled_code_buffer, |
| bool with_type_info, |
| JVMCIObject compiled_code, |
| objArrayHandle object_pool, |
| 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, JVMCI_TRAPS); |
| static bool is_general_purpose_reg(VMReg hotspotRegister); |
| static ScopeValue* to_primitive_value(HotSpotCompiledCodeStream* stream, jlong raw, BasicType type, ScopeValue* &second, JVMCI_TRAPS); |
| |
| const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } |
| |
| // Gets the tag to be used with `read_oop()` corresponding to `patch_object_tag`. |
| static u1 as_read_oop_tag(HotSpotCompiledCodeStream* stream, u1 patch_object_tag, JVMCI_TRAPS); |
| |
| protected: |
| Handle read_oop(HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS); |
| |
| ScopeValue* get_scope_value(HotSpotCompiledCodeStream* stream, u1 tag, BasicType type, ScopeValue* &second, JVMCI_TRAPS); |
| |
| GrowableArray<ScopeValue*>* read_local_or_stack_values(HotSpotCompiledCodeStream* stream, u1 frame_flags, bool is_locals, JVMCI_TRAPS); |
| |
| void* record_metadata_reference(CodeSection* section, address dest, HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS); |
| #ifdef _LP64 |
| narrowKlass record_narrow_metadata_reference(CodeSection* section, address dest, HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS); |
| #endif |
| GrowableArray<MonitorValue*>* read_monitor_values(HotSpotCompiledCodeStream* stream, u1 frame_flags, JVMCI_TRAPS); |
| |
| // extract the fields of the HotSpotCompiledCode |
| void initialize_fields(HotSpotCompiledCodeStream* stream, u1 code_flags, methodHandle& method, CodeBuffer& buffer, JVMCI_TRAPS); |
| void initialize_dependencies(HotSpotCompiledCodeStream* stream, u1 code_flags, OopRecorder* oop_recorder, JVMCI_TRAPS); |
| |
| int estimate_stubs_size(HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| |
| // perform data and call relocation on the CodeBuffer |
| JVMCI::CodeInstallResult initialize_buffer(JVMCIObject compiled_code, CodeBuffer& buffer, HotSpotCompiledCodeStream* stream, u1 code_flags, JVMCI_TRAPS); |
| |
| void site_Safepoint(CodeBuffer& buffer, jint pc_offset, HotSpotCompiledCodeStream* stream, u1 tag, JVMCI_TRAPS); |
| void site_Infopoint(CodeBuffer& buffer, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| void site_Call(CodeBuffer& buffer, u1 tag, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| void site_DataPatch(CodeBuffer& buffer, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| void site_Mark(CodeBuffer& buffer, jint pc_offset, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| void site_ExceptionHandler(jint pc_offset, HotSpotCompiledCodeStream* stream); |
| |
| OopMap* create_oop_map(HotSpotCompiledCodeStream* stream, u1 debug_info_flags, JVMCI_TRAPS); |
| |
| VMReg getVMRegFromLocation(HotSpotCompiledCodeStream* stream, int total_frame_size, JVMCI_TRAPS); |
| |
| int map_jvmci_bci(int bci); |
| |
| void record_oop_patch(HotSpotCompiledCodeStream* stream, address dest, u1 read_tag, bool narrow, JVMCI_TRAPS); |
| |
| // full_info: if false, only BytecodePosition is in stream otherwise all DebugInfo is in stream |
| void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, bool is_mh_invoke, bool return_oop, JVMCI_TRAPS); |
| |
| void record_scope(jint pc_offset, HotSpotCompiledCodeStream* stream, u1 debug_info_flags, bool full_info, JVMCI_TRAPS) { |
| record_scope(pc_offset, stream, debug_info_flags, full_info, false /* is_mh_invoke */, false /* return_oop */, JVMCIENV); |
| } |
| void record_object_value(ObjectValue* sv, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| |
| void read_virtual_objects(HotSpotCompiledCodeStream* stream, JVMCI_TRAPS); |
| |
| int estimateStubSpace(int static_call_stubs); |
| }; |
| |
| #endif // SHARE_JVMCI_JVMCICODEINSTALLER_HPP |