Tue, 29 Aug 2017 15:31:19 +0800
#6062 The disassembler is implemented by hsdis instead of disassembler_mips.cpp.
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. |
aoqi@0 | 8 | * |
aoqi@0 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 13 | * accompanied this code). |
aoqi@0 | 14 | * |
aoqi@0 | 15 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 18 | * |
aoqi@0 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 20 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 21 | * questions. |
aoqi@0 | 22 | * |
aoqi@0 | 23 | */ |
aoqi@0 | 24 | |
aoqi@0 | 25 | #ifndef SHARE_VM_COMPILER_OOPMAP_HPP |
aoqi@0 | 26 | #define SHARE_VM_COMPILER_OOPMAP_HPP |
aoqi@0 | 27 | |
aoqi@0 | 28 | #include "code/compressedStream.hpp" |
aoqi@0 | 29 | #include "code/vmreg.hpp" |
aoqi@0 | 30 | #include "memory/allocation.hpp" |
aoqi@0 | 31 | #include "utilities/growableArray.hpp" |
aoqi@0 | 32 | |
aoqi@0 | 33 | // Interface for generating the frame map for compiled code. A frame map |
aoqi@0 | 34 | // describes for a specific pc whether each register and frame stack slot is: |
aoqi@0 | 35 | // Oop - A GC root for current frame |
aoqi@0 | 36 | // Value - Live non-oop, non-float value: int, either half of double |
aoqi@0 | 37 | // Dead - Dead; can be Zapped for debugging |
aoqi@0 | 38 | // CalleeXX - Callee saved; also describes which caller register is saved |
aoqi@0 | 39 | // DerivedXX - A derived oop; original oop is described. |
aoqi@0 | 40 | // |
aoqi@0 | 41 | // OopMapValue describes a single OopMap entry |
aoqi@0 | 42 | |
aoqi@0 | 43 | class frame; |
aoqi@0 | 44 | class RegisterMap; |
aoqi@0 | 45 | class DerivedPointerEntry; |
aoqi@0 | 46 | |
aoqi@0 | 47 | class OopMapValue: public StackObj { |
aoqi@0 | 48 | friend class VMStructs; |
aoqi@0 | 49 | private: |
aoqi@0 | 50 | short _value; |
aoqi@0 | 51 | int value() const { return _value; } |
aoqi@0 | 52 | void set_value(int value) { _value = value; } |
aoqi@0 | 53 | short _content_reg; |
aoqi@0 | 54 | |
aoqi@0 | 55 | public: |
aoqi@0 | 56 | // Constants |
aoqi@0 | 57 | enum { type_bits = 5, |
aoqi@0 | 58 | register_bits = BitsPerShort - type_bits }; |
aoqi@0 | 59 | |
aoqi@0 | 60 | enum { type_shift = 0, |
aoqi@0 | 61 | register_shift = type_bits }; |
aoqi@0 | 62 | |
aoqi@0 | 63 | enum { type_mask = right_n_bits(type_bits), |
aoqi@0 | 64 | type_mask_in_place = type_mask << type_shift, |
aoqi@0 | 65 | register_mask = right_n_bits(register_bits), |
aoqi@0 | 66 | register_mask_in_place = register_mask << register_shift }; |
aoqi@0 | 67 | |
aoqi@0 | 68 | enum oop_types { // must fit in type_bits |
aoqi@0 | 69 | unused_value =0, // powers of 2, for masking OopMapStream |
aoqi@0 | 70 | oop_value = 1, |
aoqi@0 | 71 | value_value = 2, |
aoqi@0 | 72 | narrowoop_value = 4, |
aoqi@0 | 73 | callee_saved_value = 8, |
aoqi@0 | 74 | derived_oop_value= 16 }; |
aoqi@0 | 75 | |
aoqi@0 | 76 | // Constructors |
aoqi@0 | 77 | OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); } |
aoqi@0 | 78 | OopMapValue (VMReg reg, oop_types t) { set_reg_type(reg,t); } |
aoqi@0 | 79 | OopMapValue (VMReg reg, oop_types t, VMReg reg2) { set_reg_type(reg,t); set_content_reg(reg2); } |
aoqi@0 | 80 | OopMapValue (CompressedReadStream* stream) { read_from(stream); } |
aoqi@0 | 81 | |
aoqi@0 | 82 | // Archiving |
aoqi@0 | 83 | void write_on(CompressedWriteStream* stream) { |
aoqi@0 | 84 | stream->write_int(value()); |
aoqi@0 | 85 | if(is_callee_saved() || is_derived_oop()) { |
aoqi@0 | 86 | stream->write_int(content_reg()->value()); |
aoqi@0 | 87 | } |
aoqi@0 | 88 | } |
aoqi@0 | 89 | |
aoqi@0 | 90 | void read_from(CompressedReadStream* stream) { |
aoqi@0 | 91 | set_value(stream->read_int()); |
aoqi@0 | 92 | if(is_callee_saved() || is_derived_oop()) { |
aoqi@0 | 93 | set_content_reg(VMRegImpl::as_VMReg(stream->read_int(), true)); |
aoqi@0 | 94 | } |
aoqi@0 | 95 | } |
aoqi@0 | 96 | |
aoqi@0 | 97 | // Querying |
aoqi@0 | 98 | bool is_oop() { return mask_bits(value(), type_mask_in_place) == oop_value; } |
aoqi@0 | 99 | bool is_value() { return mask_bits(value(), type_mask_in_place) == value_value; } |
aoqi@0 | 100 | bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; } |
aoqi@0 | 101 | bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; } |
aoqi@0 | 102 | bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; } |
aoqi@0 | 103 | |
aoqi@0 | 104 | void set_oop() { set_value((value() & register_mask_in_place) | oop_value); } |
aoqi@0 | 105 | void set_value() { set_value((value() & register_mask_in_place) | value_value); } |
aoqi@0 | 106 | void set_narrowoop() { set_value((value() & register_mask_in_place) | narrowoop_value); } |
aoqi@0 | 107 | void set_callee_saved() { set_value((value() & register_mask_in_place) | callee_saved_value); } |
aoqi@0 | 108 | void set_derived_oop() { set_value((value() & register_mask_in_place) | derived_oop_value); } |
aoqi@0 | 109 | |
aoqi@0 | 110 | VMReg reg() const { return VMRegImpl::as_VMReg(mask_bits(value(), register_mask_in_place) >> register_shift); } |
aoqi@0 | 111 | oop_types type() const { return (oop_types)mask_bits(value(), type_mask_in_place); } |
aoqi@0 | 112 | |
aoqi@0 | 113 | static bool legal_vm_reg_name(VMReg p) { |
aoqi@0 | 114 | return (p->value() == (p->value() & register_mask)); |
aoqi@0 | 115 | } |
aoqi@0 | 116 | |
aoqi@0 | 117 | void set_reg_type(VMReg p, oop_types t) { |
aoqi@0 | 118 | set_value((p->value() << register_shift) | t); |
aoqi@0 | 119 | assert(reg() == p, "sanity check" ); |
aoqi@0 | 120 | assert(type() == t, "sanity check" ); |
aoqi@0 | 121 | } |
aoqi@0 | 122 | |
aoqi@0 | 123 | |
aoqi@0 | 124 | VMReg content_reg() const { return VMRegImpl::as_VMReg(_content_reg, true); } |
aoqi@0 | 125 | void set_content_reg(VMReg r) { _content_reg = r->value(); } |
aoqi@0 | 126 | |
aoqi@0 | 127 | // Physical location queries |
aoqi@0 | 128 | bool is_register_loc() { return reg()->is_reg(); } |
aoqi@0 | 129 | bool is_stack_loc() { return reg()->is_stack(); } |
aoqi@0 | 130 | |
aoqi@0 | 131 | // Returns offset from sp. |
aoqi@0 | 132 | int stack_offset() { |
aoqi@0 | 133 | assert(is_stack_loc(), "must be stack location"); |
aoqi@0 | 134 | return reg()->reg2stack(); |
aoqi@0 | 135 | } |
aoqi@0 | 136 | |
aoqi@0 | 137 | void print_on(outputStream* st) const; |
aoqi@0 | 138 | void print() const { print_on(tty); } |
aoqi@0 | 139 | }; |
aoqi@0 | 140 | |
aoqi@0 | 141 | |
aoqi@0 | 142 | class OopMap: public ResourceObj { |
aoqi@0 | 143 | friend class OopMapStream; |
aoqi@0 | 144 | friend class VMStructs; |
aoqi@0 | 145 | private: |
aoqi@0 | 146 | int _pc_offset; |
aoqi@0 | 147 | int _omv_count; |
aoqi@0 | 148 | int _omv_data_size; |
aoqi@0 | 149 | unsigned char* _omv_data; |
aoqi@0 | 150 | CompressedWriteStream* _write_stream; |
aoqi@0 | 151 | |
aoqi@0 | 152 | debug_only( OopMapValue::oop_types* _locs_used; int _locs_length;) |
aoqi@0 | 153 | |
aoqi@0 | 154 | // Accessors |
aoqi@0 | 155 | unsigned char* omv_data() const { return _omv_data; } |
aoqi@0 | 156 | void set_omv_data(unsigned char* value) { _omv_data = value; } |
aoqi@0 | 157 | int omv_data_size() const { return _omv_data_size; } |
aoqi@0 | 158 | void set_omv_data_size(int value) { _omv_data_size = value; } |
aoqi@0 | 159 | int omv_count() const { return _omv_count; } |
aoqi@0 | 160 | void set_omv_count(int value) { _omv_count = value; } |
aoqi@0 | 161 | void increment_count() { _omv_count++; } |
aoqi@0 | 162 | CompressedWriteStream* write_stream() const { return _write_stream; } |
aoqi@0 | 163 | void set_write_stream(CompressedWriteStream* value) { _write_stream = value; } |
aoqi@0 | 164 | |
aoqi@0 | 165 | private: |
aoqi@0 | 166 | enum DeepCopyToken { _deep_copy_token }; |
aoqi@0 | 167 | OopMap(DeepCopyToken, OopMap* source); // used only by deep_copy |
aoqi@0 | 168 | |
aoqi@0 | 169 | public: |
aoqi@0 | 170 | OopMap(int frame_size, int arg_count); |
aoqi@0 | 171 | |
aoqi@0 | 172 | // pc-offset handling |
aoqi@0 | 173 | int offset() const { return _pc_offset; } |
aoqi@0 | 174 | void set_offset(int o) { _pc_offset = o; } |
aoqi@0 | 175 | |
aoqi@0 | 176 | // Check to avoid double insertion |
aoqi@0 | 177 | debug_only(OopMapValue::oop_types locs_used( int indx ) { return _locs_used[indx]; }) |
aoqi@0 | 178 | |
aoqi@0 | 179 | // Construction |
aoqi@0 | 180 | // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd |
aoqi@0 | 181 | // slots to hold 4-byte values like ints and floats in the LP64 build. |
aoqi@0 | 182 | void set_oop ( VMReg local); |
aoqi@0 | 183 | void set_value( VMReg local); |
aoqi@0 | 184 | void set_narrowoop(VMReg local); |
aoqi@0 | 185 | void set_dead ( VMReg local); |
aoqi@0 | 186 | void set_callee_saved( VMReg local, VMReg caller_machine_register ); |
aoqi@0 | 187 | void set_derived_oop ( VMReg local, VMReg derived_from_local_register ); |
aoqi@0 | 188 | void set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional); |
aoqi@0 | 189 | |
aoqi@0 | 190 | int heap_size() const; |
aoqi@0 | 191 | void copy_to(address addr); |
aoqi@0 | 192 | OopMap* deep_copy(); |
aoqi@0 | 193 | |
aoqi@0 | 194 | bool has_derived_pointer() const PRODUCT_RETURN0; |
aoqi@0 | 195 | |
aoqi@0 | 196 | bool legal_vm_reg_name(VMReg local) { |
aoqi@0 | 197 | return OopMapValue::legal_vm_reg_name(local); |
aoqi@0 | 198 | } |
aoqi@0 | 199 | |
aoqi@0 | 200 | // Printing |
aoqi@0 | 201 | void print_on(outputStream* st) const; |
aoqi@0 | 202 | void print() const { print_on(tty); } |
aoqi@0 | 203 | }; |
aoqi@0 | 204 | |
aoqi@0 | 205 | |
aoqi@0 | 206 | class OopMapSet : public ResourceObj { |
aoqi@0 | 207 | friend class VMStructs; |
aoqi@0 | 208 | private: |
aoqi@0 | 209 | int _om_count; |
aoqi@0 | 210 | int _om_size; |
aoqi@0 | 211 | OopMap** _om_data; |
aoqi@0 | 212 | |
aoqi@0 | 213 | int om_count() const { return _om_count; } |
aoqi@0 | 214 | void set_om_count(int value) { _om_count = value; } |
aoqi@0 | 215 | void increment_count() { _om_count++; } |
aoqi@0 | 216 | int om_size() const { return _om_size; } |
aoqi@0 | 217 | void set_om_size(int value) { _om_size = value; } |
aoqi@0 | 218 | OopMap** om_data() const { return _om_data; } |
aoqi@0 | 219 | void set_om_data(OopMap** value) { _om_data = value; } |
aoqi@0 | 220 | void grow_om_data(); |
aoqi@0 | 221 | void set(int index,OopMap* value) { assert((index == 0) || ((index > 0) && (index < om_size())),"bad index"); _om_data[index] = value; } |
aoqi@0 | 222 | |
aoqi@0 | 223 | public: |
aoqi@0 | 224 | OopMapSet(); |
aoqi@0 | 225 | |
aoqi@0 | 226 | // returns the number of OopMaps in this OopMapSet |
aoqi@0 | 227 | int size() const { return _om_count; } |
aoqi@0 | 228 | // returns the OopMap at a given index |
aoqi@0 | 229 | OopMap* at(int index) const { assert((index >= 0) && (index <= om_count()),"bad index"); return _om_data[index]; } |
aoqi@0 | 230 | |
aoqi@0 | 231 | // Collect OopMaps. |
aoqi@0 | 232 | void add_gc_map(int pc, OopMap* map); |
aoqi@0 | 233 | |
aoqi@0 | 234 | // Returns the only oop map. Used for reconstructing |
aoqi@0 | 235 | // Adapter frames during deoptimization |
aoqi@0 | 236 | OopMap* singular_oop_map(); |
aoqi@0 | 237 | |
aoqi@0 | 238 | // returns OopMap in that is anchored to the pc |
aoqi@0 | 239 | OopMap* find_map_at_offset(int pc_offset) const; |
aoqi@0 | 240 | |
aoqi@0 | 241 | int heap_size() const; |
aoqi@0 | 242 | void copy_to(address addr); |
aoqi@0 | 243 | |
aoqi@0 | 244 | // Methods oops_do() and all_do() filter out NULL oops and |
aoqi@0 | 245 | // oop == Universe::narrow_oop_base() before passing oops |
aoqi@0 | 246 | // to closures. |
aoqi@0 | 247 | |
aoqi@0 | 248 | // Iterates through frame for a compiled method |
aoqi@0 | 249 | static void oops_do (const frame* fr, |
aoqi@0 | 250 | const RegisterMap* reg_map, OopClosure* f); |
aoqi@0 | 251 | static void update_register_map(const frame* fr, RegisterMap *reg_map); |
aoqi@0 | 252 | |
aoqi@0 | 253 | // Iterates through frame for a compiled method for dead ones and values, too |
aoqi@0 | 254 | static void all_do(const frame* fr, const RegisterMap* reg_map, |
aoqi@0 | 255 | OopClosure* oop_fn, |
aoqi@0 | 256 | void derived_oop_fn(oop* base, oop* derived), |
aoqi@0 | 257 | OopClosure* value_fn); |
aoqi@0 | 258 | |
aoqi@0 | 259 | // Printing |
aoqi@0 | 260 | void print_on(outputStream* st) const; |
aoqi@0 | 261 | void print() const { print_on(tty); } |
aoqi@0 | 262 | }; |
aoqi@0 | 263 | |
aoqi@0 | 264 | |
aoqi@0 | 265 | class OopMapStream : public StackObj { |
aoqi@0 | 266 | private: |
aoqi@0 | 267 | CompressedReadStream* _stream; |
aoqi@0 | 268 | int _mask; |
aoqi@0 | 269 | int _size; |
aoqi@0 | 270 | int _position; |
aoqi@0 | 271 | bool _valid_omv; |
aoqi@0 | 272 | OopMapValue _omv; |
aoqi@0 | 273 | void find_next(); |
aoqi@0 | 274 | |
aoqi@0 | 275 | public: |
aoqi@0 | 276 | OopMapStream(OopMap* oop_map); |
aoqi@0 | 277 | OopMapStream(OopMap* oop_map, int oop_types_mask); |
aoqi@0 | 278 | bool is_done() { if(!_valid_omv) { find_next(); } return !_valid_omv; } |
aoqi@0 | 279 | void next() { find_next(); } |
aoqi@0 | 280 | OopMapValue current() { return _omv; } |
aoqi@0 | 281 | }; |
aoqi@0 | 282 | |
aoqi@0 | 283 | |
aoqi@0 | 284 | // Derived pointer support. This table keeps track of all derived points on a |
aoqi@0 | 285 | // stack. It is cleared before each scavenge/GC. During the traversal of all |
aoqi@0 | 286 | // oops, it is filled in with references to all locations that contains a |
aoqi@0 | 287 | // derived oop (assumed to be very few). When the GC is complete, the derived |
aoqi@0 | 288 | // pointers are updated based on their base pointers new value and an offset. |
aoqi@0 | 289 | #ifdef COMPILER2 |
aoqi@0 | 290 | class DerivedPointerTable : public AllStatic { |
aoqi@0 | 291 | friend class VMStructs; |
aoqi@0 | 292 | private: |
aoqi@0 | 293 | static GrowableArray<DerivedPointerEntry*>* _list; |
aoqi@0 | 294 | static bool _active; // do not record pointers for verify pass etc. |
aoqi@0 | 295 | public: |
aoqi@0 | 296 | static void clear(); // Called before scavenge/GC |
aoqi@0 | 297 | static void add(oop *derived, oop *base); // Called during scavenge/GC |
aoqi@0 | 298 | static void update_pointers(); // Called after scavenge/GC |
aoqi@0 | 299 | static bool is_empty() { return _list == NULL || _list->is_empty(); } |
aoqi@0 | 300 | static bool is_active() { return _active; } |
aoqi@0 | 301 | static void set_active(bool value) { _active = value; } |
aoqi@0 | 302 | }; |
aoqi@0 | 303 | |
aoqi@0 | 304 | // A utility class to temporarily "deactivate" the DerivedPointerTable. |
aoqi@0 | 305 | // (Note: clients are responsible for any MT-safety issues) |
aoqi@0 | 306 | class DerivedPointerTableDeactivate: public StackObj { |
aoqi@0 | 307 | private: |
aoqi@0 | 308 | bool _active; |
aoqi@0 | 309 | public: |
aoqi@0 | 310 | DerivedPointerTableDeactivate() { |
aoqi@0 | 311 | _active = DerivedPointerTable::is_active(); |
aoqi@0 | 312 | if (_active) { |
aoqi@0 | 313 | DerivedPointerTable::set_active(false); |
aoqi@0 | 314 | } |
aoqi@0 | 315 | } |
aoqi@0 | 316 | |
aoqi@0 | 317 | ~DerivedPointerTableDeactivate() { |
aoqi@0 | 318 | assert(!DerivedPointerTable::is_active(), |
aoqi@0 | 319 | "Inconsistency: not MT-safe"); |
aoqi@0 | 320 | if (_active) { |
aoqi@0 | 321 | DerivedPointerTable::set_active(true); |
aoqi@0 | 322 | } |
aoqi@0 | 323 | } |
aoqi@0 | 324 | }; |
aoqi@0 | 325 | #endif // COMPILER2 |
aoqi@0 | 326 | |
aoqi@0 | 327 | #endif // SHARE_VM_COMPILER_OOPMAP_HPP |