| 1 | /* |
| 2 | * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | */ |
| 23 | |
| 24 | #ifndef SHARE_AOT_AOTCOMPILEDMETHOD_HPP |
| 25 | #define SHARE_AOT_AOTCOMPILEDMETHOD_HPP |
| 26 | |
| 27 | #include "code/codeCache.hpp" |
| 28 | #include "code/compiledIC.hpp" |
| 29 | #include "code/compiledMethod.hpp" |
| 30 | #include "code/pcDesc.hpp" |
| 31 | #include "code/relocInfo.hpp" |
| 32 | |
| 33 | class AOTCodeHeap; |
| 34 | |
| 35 | class aot_metadata { |
| 36 | private: |
| 37 | int _size; |
| 38 | int _code_size; |
| 39 | int _entry; |
| 40 | int _verified_entry; |
| 41 | int _exception_handler_offset; |
| 42 | int _deopt_handler_offset; |
| 43 | int _stubs_offset; |
| 44 | int _frame_size; |
| 45 | // location in frame (offset for sp) that deopt can store the original |
| 46 | // pc during a deopt. |
| 47 | int _orig_pc_offset; |
| 48 | int _unsafe_access; |
| 49 | |
| 50 | int _pc_desc_begin; |
| 51 | int _scopes_begin; |
| 52 | int _reloc_begin; |
| 53 | int _exception_table_begin; |
| 54 | int _nul_chk_table_begin; |
| 55 | int _oopmap_begin; |
| 56 | address at_offset(size_t offset) const { return ((address) this) + offset; } |
| 57 | public: |
| 58 | int code_size() const { return _code_size; } |
| 59 | int frame_size() const { return _frame_size / HeapWordSize; } |
| 60 | PcDesc *scopes_pcs_begin() const { return (PcDesc *) at_offset(_pc_desc_begin); } |
| 61 | PcDesc *scopes_pcs_end() const { return (PcDesc *) at_offset(_scopes_begin); } |
| 62 | address scopes_data_begin() const { return at_offset(_scopes_begin); } |
| 63 | address scopes_data_end() const { return at_offset(_reloc_begin); } |
| 64 | relocInfo* relocation_begin() const { return (relocInfo*) at_offset(_reloc_begin); } |
| 65 | relocInfo* relocation_end() const { return (relocInfo*) at_offset(_exception_table_begin); } |
| 66 | address handler_table_begin () const { return at_offset(_exception_table_begin); } |
| 67 | address handler_table_end() const { return at_offset(_nul_chk_table_begin); } |
| 68 | |
| 69 | address nul_chk_table_begin() const { return at_offset(_nul_chk_table_begin); } |
| 70 | address nul_chk_table_end() const { return at_offset(_oopmap_begin); } |
| 71 | |
| 72 | ImmutableOopMapSet* oopmap_set() const { return (ImmutableOopMapSet*) at_offset(_oopmap_begin); } |
| 73 | |
| 74 | address consts_begin() const { return at_offset(_size); } |
| 75 | address consts_end() const { return at_offset(_size); } |
| 76 | int stub_offset() const { return _stubs_offset; } |
| 77 | int entry_offset() const { return _entry; } |
| 78 | int verified_entry_offset() const { return _verified_entry; } |
| 79 | int exception_handler_offset() const { return _exception_handler_offset; } |
| 80 | int deopt_handler_offset() const { return _deopt_handler_offset; } |
| 81 | int orig_pc_offset() const { return _orig_pc_offset; } |
| 82 | |
| 83 | int handler_table_size() const { return handler_table_end() - handler_table_begin(); } |
| 84 | int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); } |
| 85 | bool has_unsafe_access() const { return _unsafe_access != 0; } |
| 86 | |
| 87 | }; |
| 88 | |
| 89 | /* |
| 90 | * Use this for AOTCompiledMethods since a lot of the fields in CodeBlob gets the same |
| 91 | * value when they come from AOT. code_begin == content_begin, etc... */ |
| 92 | class AOTCompiledMethodLayout : public CodeBlobLayout { |
| 93 | public: |
| 94 | AOTCompiledMethodLayout(address code_begin, address code_end, address relocation_begin, address relocation_end) : |
| 95 | CodeBlobLayout( |
| 96 | code_begin, // code_begin |
| 97 | code_end, // code_end |
| 98 | code_begin, // content_begin |
| 99 | code_end, // content_end |
| 100 | code_end, // data_end |
| 101 | relocation_begin, // relocation_begin |
| 102 | relocation_end |
| 103 | ) { |
| 104 | } |
| 105 | }; |
| 106 | |
| 107 | class AOTCompiledMethod : public CompiledMethod, public CHeapObj<mtCode> { |
| 108 | private: |
| 109 | address _code; |
| 110 | aot_metadata* _meta; |
| 111 | Metadata** _metadata_got; |
| 112 | jlong* _state_adr; // Address of cell to indicate aot method state (in_use or not_entrant) |
| 113 | AOTCodeHeap* _heap; // code heap which has this method |
| 114 | const char* _name; // For stub: "AOT Stub<name>" for stub, |
| 115 | // For nmethod: "<u2_size>Ljava/lang/ThreadGroup;<u2_size>addUnstarted<u2_size>()V" |
| 116 | const int _metadata_size; // size of _metadata_got |
| 117 | const int _aot_id; |
| 118 | const int _method_index; |
| 119 | oop _oop; // method()->method_holder()->klass_holder() |
| 120 | |
| 121 | address* orig_pc_addr(const frame* fr); |
| 122 | bool make_not_entrant_helper(int new_state); |
| 123 | |
| 124 | public: |
| 125 | using CHeapObj<mtCode>::operator new; |
| 126 | using CHeapObj<mtCode>::operator delete; |
| 127 | |
| 128 | int method_index() const { return _method_index; } |
| 129 | void set_oop(oop o) { _oop = o; } |
| 130 | |
| 131 | AOTCompiledMethod(address code, Method* method, aot_metadata* meta, address metadata_got, int metadata_size, jlong* state_adr, AOTCodeHeap* heap, const char* name, int method_index, int aot_id) : |
| 132 | CompiledMethod(method, name, compiler_jvmci, // AOT code is generated by JVMCI compiler |
| 133 | AOTCompiledMethodLayout(code, code + meta->code_size(), (address) meta->relocation_begin(), (address) meta->relocation_end()), |
| 134 | 0 /* frame_complete_offset */, meta->frame_size() /* frame_size */, meta->oopmap_set(), false /* caller_must_gc_arguments */), |
| 135 | _code(code), |
| 136 | _meta(meta), |
| 137 | _metadata_got((Metadata**) metadata_got), |
| 138 | _state_adr(state_adr), |
| 139 | _heap(heap), |
| 140 | _name(name), |
| 141 | _metadata_size(metadata_size), |
| 142 | _aot_id(aot_id), |
| 143 | _method_index(method_index) { |
| 144 | |
| 145 | _is_far_code = CodeCache::is_far_target(code) || |
| 146 | CodeCache::is_far_target(code + meta->code_size()); |
| 147 | _exception_cache = NULL; |
| 148 | |
| 149 | _scopes_data_begin = (address) _meta->scopes_data_begin(); |
| 150 | _deopt_handler_begin = (address) _code + _meta->deopt_handler_offset(); |
| 151 | _deopt_mh_handler_begin = (address) this; |
| 152 | |
| 153 | _pc_desc_container.reset_to(scopes_pcs_begin()); |
| 154 | |
| 155 | // Mark the AOTCompiledMethod as in_use |
| 156 | *_state_adr = nmethod::in_use; |
| 157 | set_has_unsafe_access(_meta->has_unsafe_access()); |
| 158 | _oop = NULL; |
| 159 | } |
| 160 | |
| 161 | virtual bool is_aot() const { return true; } |
| 162 | virtual bool is_runtime_stub() const { return is_aot_runtime_stub(); } |
| 163 | |
| 164 | virtual bool is_compiled() const { return !is_aot_runtime_stub(); } |
| 165 | |
| 166 | virtual bool is_locked_by_vm() const { return false; } |
| 167 | |
| 168 | int state() const { return *_state_adr; } |
| 169 | |
| 170 | // Non-virtual for speed |
| 171 | bool _is_alive() const { return state() < zombie; } |
| 172 | |
| 173 | virtual bool is_zombie() const { return state() == zombie; } |
| 174 | virtual bool is_unloaded() const { return state() == unloaded; } |
| 175 | virtual bool is_not_entrant() const { return state() == not_entrant || |
| 176 | state() == not_used; } |
| 177 | virtual bool is_alive() const { return _is_alive(); } |
| 178 | virtual bool is_in_use() const { return state() == in_use; } |
| 179 | |
| 180 | virtual bool is_unloading() { return false; } |
| 181 | |
| 182 | address exception_begin() const { return (address) _code + _meta->exception_handler_offset(); } |
| 183 | |
| 184 | virtual const char* name() const { return _name; } |
| 185 | |
| 186 | virtual int compile_id() const { return _aot_id; } |
| 187 | |
| 188 | void print_on(outputStream* st) const; |
| 189 | void print_on(outputStream* st, const char* msg) const; |
| 190 | void print() const; |
| 191 | |
| 192 | virtual void print_value_on(outputStream *stream) const; |
| 193 | virtual void (outputStream *stream, address block_begin) const { } |
| 194 | virtual void verify() {} |
| 195 | |
| 196 | virtual int comp_level() const { return CompLevel_aot; } |
| 197 | virtual address verified_entry_point() const { return _code + _meta->verified_entry_offset(); } |
| 198 | virtual void log_identity(xmlStream* stream) const; |
| 199 | virtual void log_state_change() const; |
| 200 | virtual bool make_entrant() NOT_TIERED({ ShouldNotReachHere(); return false; }); |
| 201 | virtual bool make_not_entrant() { return make_not_entrant_helper(not_entrant); } |
| 202 | virtual bool make_not_used() { return make_not_entrant_helper(not_used); } |
| 203 | virtual address entry_point() const { return _code + _meta->entry_offset(); } |
| 204 | virtual bool make_zombie() { ShouldNotReachHere(); return false; } |
| 205 | virtual bool is_osr_method() const { return false; } |
| 206 | virtual int osr_entry_bci() const { ShouldNotReachHere(); return -1; } |
| 207 | // AOT compiled methods do not get into zombie state |
| 208 | virtual bool can_convert_to_zombie() { return false; } |
| 209 | |
| 210 | virtual bool is_dependent_on_method(Method* dependee) { return true; } |
| 211 | |
| 212 | virtual void clear_inline_caches(); |
| 213 | |
| 214 | virtual void print_pcs() {} |
| 215 | |
| 216 | virtual address scopes_data_end() const { return _meta->scopes_data_end(); } |
| 217 | |
| 218 | virtual oop oop_at(int index) const; |
| 219 | virtual Metadata* metadata_at(int index) const; |
| 220 | |
| 221 | virtual PcDesc* scopes_pcs_begin() const { return _meta->scopes_pcs_begin(); } |
| 222 | virtual PcDesc* scopes_pcs_end() const { return _meta->scopes_pcs_end(); } |
| 223 | |
| 224 | virtual address handler_table_begin() const { return _meta->handler_table_begin(); } |
| 225 | virtual address handler_table_end() const { return _meta->handler_table_end(); } |
| 226 | |
| 227 | virtual address nul_chk_table_begin() const { return _meta->nul_chk_table_begin(); } |
| 228 | virtual address nul_chk_table_end() const { return _meta->nul_chk_table_end(); } |
| 229 | |
| 230 | virtual address consts_begin() const { return _meta->consts_begin(); } |
| 231 | virtual address consts_end() const { return _meta->consts_end(); } |
| 232 | |
| 233 | virtual address stub_begin() const { return code_begin() + _meta->stub_offset(); } |
| 234 | virtual address stub_end() const { return code_end(); } |
| 235 | |
| 236 | virtual oop* oop_addr_at(int index) const { ShouldNotReachHere(); return NULL; } |
| 237 | virtual Metadata** metadata_addr_at(int index) const { ShouldNotReachHere(); return NULL; } |
| 238 | |
| 239 | // Accessor/mutator for the original pc of a frame before a frame was deopted. |
| 240 | address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } |
| 241 | void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; } |
| 242 | |
| 243 | virtual void metadata_do(MetadataClosure* f); |
| 244 | |
| 245 | bool metadata_got_contains(Metadata **p) { |
| 246 | return p >= &_metadata_got[0] && p < &_metadata_got[_metadata_size]; |
| 247 | } |
| 248 | |
| 249 | Metadata** metadata_begin() const { return &_metadata_got[0] ; } |
| 250 | Metadata** metadata_end() const { return &_metadata_got[_metadata_size] ; } |
| 251 | const char* compile_kind() const { return "AOT" ; } |
| 252 | |
| 253 | int get_state() const { |
| 254 | return (int) (*_state_adr); |
| 255 | } |
| 256 | |
| 257 | // inlined and non-virtual for AOTCodeHeap::oops_do |
| 258 | void do_oops(OopClosure* f) { |
| 259 | assert(_is_alive(), "" ); |
| 260 | if (_oop != NULL) { |
| 261 | f->do_oop(&_oop); |
| 262 | } |
| 263 | #if 0 |
| 264 | metadata_oops_do(metadata_begin(), metadata_end(), f); |
| 265 | #endif |
| 266 | } |
| 267 | |
| 268 | virtual void do_unloading(bool unloading_occurred); |
| 269 | |
| 270 | protected: |
| 271 | // AOT compiled methods are not flushed |
| 272 | void flush() {}; |
| 273 | |
| 274 | NativeCallWrapper* call_wrapper_at(address call) const; |
| 275 | NativeCallWrapper* call_wrapper_before(address return_pc) const; |
| 276 | address call_instruction_address(address pc) const; |
| 277 | |
| 278 | CompiledStaticCall* compiledStaticCall_at(Relocation* call_site) const; |
| 279 | CompiledStaticCall* compiledStaticCall_at(address addr) const; |
| 280 | CompiledStaticCall* compiledStaticCall_before(address addr) const; |
| 281 | private: |
| 282 | bool is_aot_runtime_stub() const { return _method == NULL; } |
| 283 | }; |
| 284 | |
| 285 | class PltNativeCallWrapper: public NativeCallWrapper { |
| 286 | private: |
| 287 | NativePltCall* _call; |
| 288 | |
| 289 | public: |
| 290 | PltNativeCallWrapper(NativePltCall* call) : _call(call) {} |
| 291 | |
| 292 | virtual address destination() const { return _call->destination(); } |
| 293 | virtual address instruction_address() const { return _call->instruction_address(); } |
| 294 | virtual address next_instruction_address() const { return _call->next_instruction_address(); } |
| 295 | virtual address return_address() const { return _call->return_address(); } |
| 296 | virtual address get_resolve_call_stub(bool is_optimized) const { return _call->plt_resolve_call(); } |
| 297 | virtual void set_destination_mt_safe(address dest) { _call->set_destination_mt_safe(dest); } |
| 298 | virtual void set_to_interpreted(const methodHandle& method, CompiledICInfo& info); |
| 299 | virtual void verify() const { _call->verify(); } |
| 300 | virtual void verify_resolve_call(address dest) const; |
| 301 | |
| 302 | virtual bool is_call_to_interpreted(address dest) const { return (dest == _call->plt_c2i_stub()); } |
| 303 | // TODO: assume for now that patching of aot code (got cell) is safe. |
| 304 | virtual bool is_safe_for_patching() const { return true; } |
| 305 | |
| 306 | virtual NativeInstruction* get_load_instruction(virtual_call_Relocation* r) const; |
| 307 | |
| 308 | virtual void *get_data(NativeInstruction* instruction) const { |
| 309 | return (void*)((NativeLoadGot*) instruction)->data(); |
| 310 | } |
| 311 | |
| 312 | virtual void set_data(NativeInstruction* instruction, intptr_t data) { |
| 313 | ((NativeLoadGot*) instruction)->set_data(data); |
| 314 | } |
| 315 | }; |
| 316 | |
| 317 | #endif // SHARE_AOT_AOTCOMPILEDMETHOD_HPP |
| 318 | |