| File: | jdk/src/hotspot/share/oops/constMethod.hpp |
| Warning: | line 449, column 7 Null pointer passed to 2nd parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | ||||||||||
| 2 | * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. | ||||||||||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||||||||||
| 4 | * | ||||||||||
| 5 | * This code is free software; you can redistribute it and/or modify it | ||||||||||
| 6 | * under the terms of the GNU General Public License version 2 only, as | ||||||||||
| 7 | * published by the Free Software Foundation. | ||||||||||
| 8 | * | ||||||||||
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | ||||||||||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||||||||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||||||||||
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | ||||||||||
| 13 | * accompanied this code). | ||||||||||
| 14 | * | ||||||||||
| 15 | * You should have received a copy of the GNU General Public License version | ||||||||||
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | ||||||||||
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||||||||||
| 18 | * | ||||||||||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||||||||||
| 20 | * or visit www.oracle.com if you need additional information or have any | ||||||||||
| 21 | * questions. | ||||||||||
| 22 | * | ||||||||||
| 23 | */ | ||||||||||
| 24 | |||||||||||
| 25 | #include "precompiled.hpp" | ||||||||||
| 26 | #include "classfile/bytecodeAssembler.hpp" | ||||||||||
| 27 | #include "classfile/defaultMethods.hpp" | ||||||||||
| 28 | #include "classfile/symbolTable.hpp" | ||||||||||
| 29 | #include "classfile/systemDictionary.hpp" | ||||||||||
| 30 | #include "classfile/vmClasses.hpp" | ||||||||||
| 31 | #include "classfile/vmSymbols.hpp" | ||||||||||
| 32 | #include "logging/log.hpp" | ||||||||||
| 33 | #include "logging/logStream.hpp" | ||||||||||
| 34 | #include "memory/allocation.hpp" | ||||||||||
| 35 | #include "memory/metadataFactory.hpp" | ||||||||||
| 36 | #include "memory/resourceArea.hpp" | ||||||||||
| 37 | #include "memory/universe.hpp" | ||||||||||
| 38 | #include "prims/jvmtiExport.hpp" | ||||||||||
| 39 | #include "runtime/arguments.hpp" | ||||||||||
| 40 | #include "runtime/handles.inline.hpp" | ||||||||||
| 41 | #include "runtime/signature.hpp" | ||||||||||
| 42 | #include "runtime/thread.hpp" | ||||||||||
| 43 | #include "oops/instanceKlass.hpp" | ||||||||||
| 44 | #include "oops/klass.hpp" | ||||||||||
| 45 | #include "oops/method.hpp" | ||||||||||
| 46 | #include "utilities/accessFlags.hpp" | ||||||||||
| 47 | #include "utilities/exceptions.hpp" | ||||||||||
| 48 | #include "utilities/ostream.hpp" | ||||||||||
| 49 | #include "utilities/pair.hpp" | ||||||||||
| 50 | #include "utilities/resourceHash.hpp" | ||||||||||
| 51 | |||||||||||
| 52 | typedef enum { QUALIFIED, DISQUALIFIED } QualifiedState; | ||||||||||
| 53 | |||||||||||
| 54 | static void print_slot(outputStream* str, Symbol* name, Symbol* signature) { | ||||||||||
| 55 | str->print("%s%s", name->as_C_string(), signature->as_C_string()); | ||||||||||
| 56 | } | ||||||||||
| 57 | |||||||||||
| 58 | static void print_method(outputStream* str, Method* mo, bool with_class=true) { | ||||||||||
| 59 | if (with_class) { | ||||||||||
| 60 | str->print("%s.", mo->klass_name()->as_C_string()); | ||||||||||
| 61 | } | ||||||||||
| 62 | print_slot(str, mo->name(), mo->signature()); | ||||||||||
| 63 | } | ||||||||||
| 64 | |||||||||||
| 65 | /** | ||||||||||
| 66 | * Perform a depth-first iteration over the class hierarchy, applying | ||||||||||
| 67 | * algorithmic logic as it goes. | ||||||||||
| 68 | * | ||||||||||
| 69 | * This class is one half of the inheritance hierarchy analysis mechanism. | ||||||||||
| 70 | * It is meant to be used in conjunction with another class, the algorithm, | ||||||||||
| 71 | * which is indicated by the ALGO template parameter. This class can be | ||||||||||
| 72 | * paired with any algorithm class that provides the required methods. | ||||||||||
| 73 | * | ||||||||||
| 74 | * This class contains all the mechanics for iterating over the class hierarchy | ||||||||||
| 75 | * starting at a particular root, without recursing (thus limiting stack growth | ||||||||||
| 76 | * from this point). It visits each superclass (if present) and superinterface | ||||||||||
| 77 | * in a depth-first manner, with callbacks to the ALGO class as each class is | ||||||||||
| 78 | * encountered (visit()), The algorithm can cut-off further exploration of a | ||||||||||
| 79 | * particular branch by returning 'false' from a visit() call. | ||||||||||
| 80 | * | ||||||||||
| 81 | * The ALGO class, must provide a visit() method, which each of which will be | ||||||||||
| 82 | * called once for each node in the inheritance tree during the iteration. In | ||||||||||
| 83 | * addition, it can provide a memory block via new_node_data(), which it can | ||||||||||
| 84 | * use for node-specific storage (and access via the current_data() and | ||||||||||
| 85 | * data_at_depth(int) methods). | ||||||||||
| 86 | * | ||||||||||
| 87 | * Bare minimum needed to be an ALGO class: | ||||||||||
| 88 | * class Algo : public HierarchyVisitor<Algo> { | ||||||||||
| 89 | * void* new_node_data() { return NULL; } | ||||||||||
| 90 | * void free_node_data(void* data) { return; } | ||||||||||
| 91 | * bool visit() { return true; } | ||||||||||
| 92 | * }; | ||||||||||
| 93 | */ | ||||||||||
| 94 | template <class ALGO> | ||||||||||
| 95 | class HierarchyVisitor : StackObj { | ||||||||||
| 96 | private: | ||||||||||
| 97 | |||||||||||
| 98 | class Node : public ResourceObj { | ||||||||||
| 99 | public: | ||||||||||
| 100 | InstanceKlass* _class; | ||||||||||
| 101 | bool _super_was_visited; | ||||||||||
| 102 | int _interface_index; | ||||||||||
| 103 | void* _algorithm_data; | ||||||||||
| 104 | |||||||||||
| 105 | Node(InstanceKlass* cls, void* data, bool visit_super) | ||||||||||
| 106 | : _class(cls), _super_was_visited(!visit_super), | ||||||||||
| 107 | _interface_index(0), _algorithm_data(data) {} | ||||||||||
| 108 | |||||||||||
| 109 | void update(InstanceKlass* cls, void* data, bool visit_super) { | ||||||||||
| 110 | _class = cls; | ||||||||||
| 111 | _super_was_visited = !visit_super; | ||||||||||
| 112 | _interface_index = 0; | ||||||||||
| 113 | _algorithm_data = data; | ||||||||||
| 114 | } | ||||||||||
| 115 | int number_of_interfaces() { return _class->local_interfaces()->length(); } | ||||||||||
| 116 | int interface_index() { return _interface_index; } | ||||||||||
| 117 | void set_super_visited() { _super_was_visited = true; } | ||||||||||
| 118 | void increment_visited_interface() { ++_interface_index; } | ||||||||||
| 119 | void set_all_interfaces_visited() { | ||||||||||
| 120 | _interface_index = number_of_interfaces(); | ||||||||||
| 121 | } | ||||||||||
| 122 | bool has_visited_super() { return _super_was_visited; } | ||||||||||
| 123 | bool has_visited_all_interfaces() { | ||||||||||
| 124 | return interface_index() >= number_of_interfaces(); | ||||||||||
| 125 | } | ||||||||||
| 126 | InstanceKlass* interface_at(int index) { | ||||||||||
| 127 | return _class->local_interfaces()->at(index); | ||||||||||
| 128 | } | ||||||||||
| 129 | InstanceKlass* next_super() { return _class->java_super(); } | ||||||||||
| 130 | InstanceKlass* next_interface() { | ||||||||||
| 131 | return interface_at(interface_index()); | ||||||||||
| 132 | } | ||||||||||
| 133 | }; | ||||||||||
| 134 | |||||||||||
| 135 | bool _visited_Object; | ||||||||||
| 136 | |||||||||||
| 137 | GrowableArray<Node*> _path; | ||||||||||
| 138 | GrowableArray<Node*> _free_nodes; | ||||||||||
| 139 | |||||||||||
| 140 | Node* current_top() const { return _path.top(); } | ||||||||||
| 141 | bool has_more_nodes() const { return _path.length() > 0; } | ||||||||||
| 142 | void push(InstanceKlass* cls, ALGO* algo) { | ||||||||||
| 143 | assert(cls != NULL, "Requires a valid instance class")do { if (!(cls != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 143, "assert(" "cls != __null" ") failed", "Requires a valid instance class" ); ::breakpoint(); } } while (0); | ||||||||||
| 144 | if (cls == vmClasses::Object_klass()) { | ||||||||||
| 145 | _visited_Object = true; | ||||||||||
| 146 | } | ||||||||||
| 147 | void* data = algo->new_node_data(); | ||||||||||
| 148 | Node* node; | ||||||||||
| 149 | if (_free_nodes.is_empty()) { // Add a new node | ||||||||||
| 150 | node = new Node(cls, data, has_super(cls)); | ||||||||||
| 151 | } else { // Reuse existing node and data | ||||||||||
| 152 | node = _free_nodes.pop(); | ||||||||||
| 153 | node->update(cls, data, has_super(cls)); | ||||||||||
| 154 | } | ||||||||||
| 155 | _path.push(node); | ||||||||||
| 156 | } | ||||||||||
| 157 | void pop() { | ||||||||||
| 158 | Node* node = _path.pop(); | ||||||||||
| 159 | // Make the node available for reuse | ||||||||||
| 160 | _free_nodes.push(node); | ||||||||||
| 161 | } | ||||||||||
| 162 | |||||||||||
| 163 | // Since the starting point can be an interface, we must ensure we catch | ||||||||||
| 164 | // j.l.Object as the super once in those cases. The _visited_Object flag | ||||||||||
| 165 | // only ensures we don't then repeatedly enqueue Object for each interface | ||||||||||
| 166 | // in the class hierarchy. | ||||||||||
| 167 | bool has_super(InstanceKlass* cls) { | ||||||||||
| 168 | return cls->super() != NULL__null && (!_visited_Object || !cls->is_interface()); | ||||||||||
| 169 | } | ||||||||||
| 170 | |||||||||||
| 171 | Node* node_at_depth(int i) const { | ||||||||||
| 172 | return (i >= _path.length()) ? NULL__null : _path.at(_path.length() - i - 1); | ||||||||||
| 173 | } | ||||||||||
| 174 | |||||||||||
| 175 | protected: | ||||||||||
| 176 | |||||||||||
| 177 | // Resets the visitor | ||||||||||
| 178 | void reset() { | ||||||||||
| 179 | _visited_Object = false; | ||||||||||
| 180 | } | ||||||||||
| 181 | |||||||||||
| 182 | // Accessors available to the algorithm | ||||||||||
| 183 | int current_depth() const { return _path.length() - 1; } | ||||||||||
| 184 | |||||||||||
| 185 | InstanceKlass* class_at_depth(int i) { | ||||||||||
| 186 | Node* n = node_at_depth(i); | ||||||||||
| 187 | return n == NULL__null ? NULL__null : n->_class; | ||||||||||
| 188 | } | ||||||||||
| 189 | InstanceKlass* current_class() { return class_at_depth(0); } | ||||||||||
| 190 | |||||||||||
| 191 | void* data_at_depth(int i) { | ||||||||||
| 192 | Node* n = node_at_depth(i); | ||||||||||
| 193 | return n == NULL__null ? NULL__null : n->_algorithm_data; | ||||||||||
| 194 | } | ||||||||||
| 195 | void* current_data() { return data_at_depth(0); } | ||||||||||
| 196 | |||||||||||
| 197 | public: | ||||||||||
| 198 | HierarchyVisitor() : _visited_Object(false), _path() {} | ||||||||||
| 199 | |||||||||||
| 200 | void run(InstanceKlass* root) { | ||||||||||
| 201 | ALGO* algo = static_cast<ALGO*>(this); | ||||||||||
| 202 | |||||||||||
| 203 | push(root, algo); | ||||||||||
| 204 | bool top_needs_visit = true; | ||||||||||
| 205 | do { | ||||||||||
| 206 | Node* top = current_top(); | ||||||||||
| 207 | if (top_needs_visit) { | ||||||||||
| 208 | if (algo->visit() == false) { | ||||||||||
| 209 | // algorithm does not want to continue along this path. Arrange | ||||||||||
| 210 | // it so that this state is immediately popped off the stack | ||||||||||
| 211 | top->set_super_visited(); | ||||||||||
| 212 | top->set_all_interfaces_visited(); | ||||||||||
| 213 | } | ||||||||||
| 214 | top_needs_visit = false; | ||||||||||
| 215 | } | ||||||||||
| 216 | |||||||||||
| 217 | if (top->has_visited_super() && top->has_visited_all_interfaces()) { | ||||||||||
| 218 | algo->free_node_data(top->_algorithm_data); | ||||||||||
| 219 | pop(); | ||||||||||
| 220 | } else { | ||||||||||
| 221 | InstanceKlass* next = NULL__null; | ||||||||||
| 222 | if (top->has_visited_super() == false) { | ||||||||||
| 223 | next = top->next_super(); | ||||||||||
| 224 | top->set_super_visited(); | ||||||||||
| 225 | } else { | ||||||||||
| 226 | next = top->next_interface(); | ||||||||||
| 227 | top->increment_visited_interface(); | ||||||||||
| 228 | } | ||||||||||
| 229 | assert(next != NULL, "Otherwise we shouldn't be here")do { if (!(next != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 229, "assert(" "next != __null" ") failed", "Otherwise we shouldn't be here" ); ::breakpoint(); } } while (0); | ||||||||||
| 230 | push(next, algo); | ||||||||||
| 231 | top_needs_visit = true; | ||||||||||
| 232 | } | ||||||||||
| 233 | } while (has_more_nodes()); | ||||||||||
| 234 | } | ||||||||||
| 235 | }; | ||||||||||
| 236 | |||||||||||
| 237 | class PrintHierarchy : public HierarchyVisitor<PrintHierarchy> { | ||||||||||
| 238 | private: | ||||||||||
| 239 | outputStream* _st; | ||||||||||
| 240 | public: | ||||||||||
| 241 | bool visit() { | ||||||||||
| 242 | InstanceKlass* cls = current_class(); | ||||||||||
| 243 | streamIndentor si(_st, current_depth() * 2); | ||||||||||
| 244 | _st->indent().print_cr("%s", cls->name()->as_C_string()); | ||||||||||
| 245 | return true; | ||||||||||
| 246 | } | ||||||||||
| 247 | |||||||||||
| 248 | void* new_node_data() { return NULL__null; } | ||||||||||
| 249 | void free_node_data(void* data) { return; } | ||||||||||
| 250 | |||||||||||
| 251 | PrintHierarchy(outputStream* st = tty) : _st(st) {} | ||||||||||
| 252 | }; | ||||||||||
| 253 | |||||||||||
| 254 | // Used to register InstanceKlass objects and all related metadata structures | ||||||||||
| 255 | // (Methods, ConstantPools) as "in-use" by the current thread so that they can't | ||||||||||
| 256 | // be deallocated by class redefinition while we're using them. The classes are | ||||||||||
| 257 | // de-registered when this goes out of scope. | ||||||||||
| 258 | // | ||||||||||
| 259 | // Once a class is registered, we need not bother with methodHandles or | ||||||||||
| 260 | // constantPoolHandles for it's associated metadata. | ||||||||||
| 261 | class KeepAliveRegistrar : public StackObj { | ||||||||||
| 262 | private: | ||||||||||
| 263 | Thread* _thread; | ||||||||||
| 264 | GrowableArray<ConstantPool*> _keep_alive; | ||||||||||
| 265 | |||||||||||
| 266 | public: | ||||||||||
| 267 | KeepAliveRegistrar(Thread* thread) : _thread(thread), _keep_alive(6) { | ||||||||||
| 268 | assert(thread == Thread::current(), "Must be current thread")do { if (!(thread == Thread::current())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 268, "assert(" "thread == Thread::current()" ") failed", "Must be current thread" ); ::breakpoint(); } } while (0); | ||||||||||
| 269 | } | ||||||||||
| 270 | |||||||||||
| 271 | ~KeepAliveRegistrar() { | ||||||||||
| 272 | for (int i = _keep_alive.length() - 1; i >= 0; --i) { | ||||||||||
| 273 | ConstantPool* cp = _keep_alive.at(i); | ||||||||||
| 274 | int idx = _thread->metadata_handles()->find_from_end(cp); | ||||||||||
| 275 | assert(idx > 0, "Must be in the list")do { if (!(idx > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 275, "assert(" "idx > 0" ") failed", "Must be in the list" ); ::breakpoint(); } } while (0); | ||||||||||
| 276 | _thread->metadata_handles()->remove_at(idx); | ||||||||||
| 277 | } | ||||||||||
| 278 | } | ||||||||||
| 279 | |||||||||||
| 280 | // Register a class as 'in-use' by the thread. It's fine to register a class | ||||||||||
| 281 | // multiple times (though perhaps inefficient) | ||||||||||
| 282 | void register_class(InstanceKlass* ik) { | ||||||||||
| 283 | ConstantPool* cp = ik->constants(); | ||||||||||
| 284 | _keep_alive.push(cp); | ||||||||||
| 285 | _thread->metadata_handles()->push(cp); | ||||||||||
| 286 | } | ||||||||||
| 287 | }; | ||||||||||
| 288 | |||||||||||
| 289 | class KeepAliveVisitor : public HierarchyVisitor<KeepAliveVisitor> { | ||||||||||
| 290 | private: | ||||||||||
| 291 | KeepAliveRegistrar* _registrar; | ||||||||||
| 292 | |||||||||||
| 293 | public: | ||||||||||
| 294 | KeepAliveVisitor(KeepAliveRegistrar* registrar) : _registrar(registrar) {} | ||||||||||
| 295 | |||||||||||
| 296 | void* new_node_data() { return NULL__null; } | ||||||||||
| 297 | void free_node_data(void* data) { return; } | ||||||||||
| 298 | |||||||||||
| 299 | bool visit() { | ||||||||||
| 300 | _registrar->register_class(current_class()); | ||||||||||
| 301 | return true; | ||||||||||
| 302 | } | ||||||||||
| 303 | }; | ||||||||||
| 304 | |||||||||||
| 305 | |||||||||||
| 306 | // A method family contains a set of all methods that implement a single | ||||||||||
| 307 | // erased method. As members of the set are collected while walking over the | ||||||||||
| 308 | // hierarchy, they are tagged with a qualification state. The qualification | ||||||||||
| 309 | // state for an erased method is set to disqualified if there exists a path | ||||||||||
| 310 | // from the root of hierarchy to the method that contains an interleaving | ||||||||||
| 311 | // erased method defined in an interface. | ||||||||||
| 312 | |||||||||||
| 313 | class MethodState { | ||||||||||
| 314 | public: | ||||||||||
| 315 | Method* _method; | ||||||||||
| 316 | QualifiedState _state; | ||||||||||
| 317 | |||||||||||
| 318 | MethodState() : _method(NULL__null), _state(DISQUALIFIED) {} | ||||||||||
| 319 | MethodState(Method* method, QualifiedState state) : _method(method), _state(state) {} | ||||||||||
| 320 | }; | ||||||||||
| 321 | |||||||||||
| 322 | class MethodFamily : public ResourceObj { | ||||||||||
| 323 | private: | ||||||||||
| 324 | |||||||||||
| 325 | GrowableArray<MethodState> _members; | ||||||||||
| 326 | |||||||||||
| 327 | Method* _selected_target; // Filled in later, if a unique target exists | ||||||||||
| 328 | Symbol* _exception_message; // If no unique target is found | ||||||||||
| 329 | Symbol* _exception_name; // If no unique target is found | ||||||||||
| 330 | |||||||||||
| 331 | MethodState* find_method(Method* method) { | ||||||||||
| 332 | for (int i = 0; i < _members.length(); i++) { | ||||||||||
| 333 | if (_members.at(i)._method == method) { | ||||||||||
| 334 | return &_members.at(i); | ||||||||||
| 335 | } | ||||||||||
| 336 | } | ||||||||||
| 337 | return NULL__null; | ||||||||||
| 338 | } | ||||||||||
| 339 | |||||||||||
| 340 | void add_method(Method* method, QualifiedState state) { | ||||||||||
| 341 | MethodState method_state(method, state); | ||||||||||
| 342 | _members.append(method_state); | ||||||||||
| 343 | } | ||||||||||
| 344 | |||||||||||
| 345 | Symbol* generate_no_defaults_message() const; | ||||||||||
| 346 | Symbol* generate_method_message(Symbol *klass_name, Method* method) const; | ||||||||||
| 347 | Symbol* generate_conflicts_message(GrowableArray<MethodState>* methods) const; | ||||||||||
| 348 | |||||||||||
| 349 | public: | ||||||||||
| 350 | |||||||||||
| 351 | MethodFamily() | ||||||||||
| 352 | : _selected_target(NULL__null), _exception_message(NULL__null), _exception_name(NULL__null) {} | ||||||||||
| 353 | |||||||||||
| 354 | void set_target_if_empty(Method* m) { | ||||||||||
| 355 | if (_selected_target == NULL__null && !m->is_overpass()) { | ||||||||||
| 356 | _selected_target = m; | ||||||||||
| 357 | } | ||||||||||
| 358 | } | ||||||||||
| 359 | |||||||||||
| 360 | void record_method(Method* m, QualifiedState state) { | ||||||||||
| 361 | // If not in the set, add it. If it's already in the set, then leave it | ||||||||||
| 362 | // as is if state is qualified, or set it to disqualified if state is | ||||||||||
| 363 | // disqualified. | ||||||||||
| 364 | MethodState* method_state = find_method(m); | ||||||||||
| 365 | if (method_state == NULL__null) { | ||||||||||
| 366 | add_method(m, state); | ||||||||||
| 367 | } else if (state == DISQUALIFIED) { | ||||||||||
| 368 | method_state->_state = DISQUALIFIED; | ||||||||||
| 369 | } | ||||||||||
| 370 | } | ||||||||||
| 371 | |||||||||||
| 372 | bool has_target() const { return _selected_target != NULL__null; } | ||||||||||
| 373 | bool throws_exception() { return _exception_message != NULL__null; } | ||||||||||
| 374 | |||||||||||
| 375 | Method* get_selected_target() { return _selected_target; } | ||||||||||
| 376 | Symbol* get_exception_message() { return _exception_message; } | ||||||||||
| 377 | Symbol* get_exception_name() { return _exception_name; } | ||||||||||
| 378 | |||||||||||
| 379 | // Either sets the target or the exception error message | ||||||||||
| 380 | void determine_target_or_set_exception_message(InstanceKlass* root) { | ||||||||||
| 381 | if (has_target() || throws_exception()) { | ||||||||||
| 382 | return; | ||||||||||
| 383 | } | ||||||||||
| 384 | |||||||||||
| 385 | // Qualified methods are maximally-specific methods | ||||||||||
| 386 | // These include public, instance concrete (=default) and abstract methods | ||||||||||
| 387 | int num_defaults = 0; | ||||||||||
| 388 | int default_index = -1; | ||||||||||
| 389 | for (int i = 0; i < _members.length(); i++) { | ||||||||||
| 390 | MethodState &member = _members.at(i); | ||||||||||
| 391 | if (member._state == QUALIFIED) { | ||||||||||
| 392 | if (member._method->is_default_method()) { | ||||||||||
| 393 | num_defaults++; | ||||||||||
| 394 | default_index = i; | ||||||||||
| 395 | } | ||||||||||
| 396 | } | ||||||||||
| 397 | } | ||||||||||
| 398 | |||||||||||
| 399 | if (num_defaults == 1) { | ||||||||||
| 400 | assert(_members.at(default_index)._state == QUALIFIED, "")do { if (!(_members.at(default_index)._state == QUALIFIED)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 400, "assert(" "_members.at(default_index)._state == QUALIFIED" ") failed", ""); ::breakpoint(); } } while (0); | ||||||||||
| 401 | _selected_target = _members.at(default_index)._method; | ||||||||||
| 402 | } else { | ||||||||||
| 403 | generate_and_set_exception_message(root, num_defaults, default_index); | ||||||||||
| 404 | } | ||||||||||
| 405 | } | ||||||||||
| 406 | |||||||||||
| 407 | void generate_and_set_exception_message(InstanceKlass* root, int num_defaults, int default_index) { | ||||||||||
| 408 | assert(num_defaults != 1, "invariant - should've been handled calling method")do { if (!(num_defaults != 1)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 408, "assert(" "num_defaults != 1" ") failed", "invariant - should've been handled calling method" ); ::breakpoint(); } } while (0); | ||||||||||
| 409 | |||||||||||
| 410 | GrowableArray<Method*> qualified_methods; | ||||||||||
| 411 | for (int i = 0; i < _members.length(); i++) { | ||||||||||
| 412 | MethodState& member = _members.at(i); | ||||||||||
| 413 | if (member._state == QUALIFIED) { | ||||||||||
| 414 | qualified_methods.push(member._method); | ||||||||||
| 415 | } | ||||||||||
| 416 | } | ||||||||||
| 417 | if (num_defaults == 0) { | ||||||||||
| 418 | // If the root klass has a static method with matching name and signature | ||||||||||
| 419 | // then do not generate an overpass method because it will hide the | ||||||||||
| 420 | // static method during resolution. | ||||||||||
| 421 | if (qualified_methods.length() == 0) { | ||||||||||
| 422 | _exception_message = generate_no_defaults_message(); | ||||||||||
| 423 | } else { | ||||||||||
| 424 | assert(root != NULL, "Null root class")do { if (!(root != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 424, "assert(" "root != __null" ") failed", "Null root class" ); ::breakpoint(); } } while (0); | ||||||||||
| 425 | _exception_message = generate_method_message(root->name(), qualified_methods.at(0)); | ||||||||||
| 426 | } | ||||||||||
| 427 | _exception_name = vmSymbols::java_lang_AbstractMethodError(); | ||||||||||
| 428 | } else { | ||||||||||
| 429 | _exception_message = generate_conflicts_message(&_members); | ||||||||||
| 430 | _exception_name = vmSymbols::java_lang_IncompatibleClassChangeError(); | ||||||||||
| 431 | LogTarget(Debug, defaultmethods)LogTargetImpl<LogLevel::Debug, (LogTag::_defaultmethods), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||||||||
| 432 | if (lt.is_enabled()) { | ||||||||||
| 433 | LogStream ls(lt); | ||||||||||
| 434 | _exception_message->print_value_on(&ls); | ||||||||||
| 435 | ls.cr(); | ||||||||||
| 436 | } | ||||||||||
| 437 | } | ||||||||||
| 438 | } | ||||||||||
| 439 | |||||||||||
| 440 | void print_selected(outputStream* str, int indent) const { | ||||||||||
| 441 | assert(has_target(), "Should be called otherwise")do { if (!(has_target())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 441, "assert(" "has_target()" ") failed", "Should be called otherwise" ); ::breakpoint(); } } while (0); | ||||||||||
| 442 | streamIndentor si(str, indent * 2); | ||||||||||
| 443 | str->indent().print("Selected method: "); | ||||||||||
| 444 | print_method(str, _selected_target); | ||||||||||
| 445 | Klass* method_holder = _selected_target->method_holder(); | ||||||||||
| 446 | if (!method_holder->is_interface()) { | ||||||||||
| 447 | str->print(" : in superclass"); | ||||||||||
| 448 | } | ||||||||||
| 449 | str->cr(); | ||||||||||
| 450 | } | ||||||||||
| 451 | |||||||||||
| 452 | void print_exception(outputStream* str, int indent) { | ||||||||||
| 453 | assert(throws_exception(), "Should be called otherwise")do { if (!(throws_exception())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 453, "assert(" "throws_exception()" ") failed", "Should be called otherwise" ); ::breakpoint(); } } while (0); | ||||||||||
| 454 | assert(_exception_name != NULL, "exception_name should be set")do { if (!(_exception_name != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 454, "assert(" "_exception_name != __null" ") failed", "exception_name should be set" ); ::breakpoint(); } } while (0); | ||||||||||
| 455 | streamIndentor si(str, indent * 2); | ||||||||||
| 456 | str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string()); | ||||||||||
| 457 | } | ||||||||||
| 458 | }; | ||||||||||
| 459 | |||||||||||
| 460 | Symbol* MethodFamily::generate_no_defaults_message() const { | ||||||||||
| 461 | return SymbolTable::new_symbol("No qualifying defaults found"); | ||||||||||
| 462 | } | ||||||||||
| 463 | |||||||||||
| 464 | Symbol* MethodFamily::generate_method_message(Symbol *klass_name, Method* method) const { | ||||||||||
| 465 | stringStream ss; | ||||||||||
| 466 | ss.print("Method "); | ||||||||||
| 467 | Symbol* name = method->name(); | ||||||||||
| 468 | Symbol* signature = method->signature(); | ||||||||||
| 469 | ss.write((const char*)klass_name->bytes(), klass_name->utf8_length()); | ||||||||||
| 470 | ss.print("."); | ||||||||||
| 471 | ss.write((const char*)name->bytes(), name->utf8_length()); | ||||||||||
| 472 | ss.write((const char*)signature->bytes(), signature->utf8_length()); | ||||||||||
| 473 | ss.print(" is abstract"); | ||||||||||
| 474 | return SymbolTable::new_symbol(ss.base(), (int)ss.size()); | ||||||||||
| 475 | } | ||||||||||
| 476 | |||||||||||
| 477 | Symbol* MethodFamily::generate_conflicts_message(GrowableArray<MethodState>* methods) const { | ||||||||||
| 478 | stringStream ss; | ||||||||||
| 479 | ss.print("Conflicting default methods:"); | ||||||||||
| 480 | for (int i = 0; i < methods->length(); ++i) { | ||||||||||
| 481 | Method *method = methods->at(i)._method; | ||||||||||
| 482 | Symbol *klass = method->klass_name(); | ||||||||||
| 483 | Symbol *name = method->name(); | ||||||||||
| 484 | ss.print(" "); | ||||||||||
| 485 | ss.write((const char*) klass->bytes(), klass->utf8_length()); | ||||||||||
| 486 | ss.print("."); | ||||||||||
| 487 | ss.write((const char*) name->bytes(), name->utf8_length()); | ||||||||||
| 488 | } | ||||||||||
| 489 | return SymbolTable::new_symbol(ss.base(), (int)ss.size()); | ||||||||||
| 490 | } | ||||||||||
| 491 | |||||||||||
| 492 | |||||||||||
| 493 | class StateRestorerScope; | ||||||||||
| 494 | |||||||||||
| 495 | // StatefulMethodFamily is a wrapper around a MethodFamily that maintains the | ||||||||||
| 496 | // qualification state during hierarchy visitation, and applies that state | ||||||||||
| 497 | // when adding members to the MethodFamily | ||||||||||
| 498 | class StatefulMethodFamily : public ResourceObj { | ||||||||||
| 499 | friend class StateRestorer; | ||||||||||
| 500 | private: | ||||||||||
| 501 | QualifiedState _qualification_state; | ||||||||||
| 502 | |||||||||||
| 503 | void set_qualification_state(QualifiedState state) { | ||||||||||
| 504 | _qualification_state = state; | ||||||||||
| 505 | } | ||||||||||
| 506 | |||||||||||
| 507 | protected: | ||||||||||
| 508 | MethodFamily _method_family; | ||||||||||
| 509 | |||||||||||
| 510 | public: | ||||||||||
| 511 | StatefulMethodFamily() { | ||||||||||
| 512 | _qualification_state = QUALIFIED; | ||||||||||
| 513 | } | ||||||||||
| 514 | |||||||||||
| 515 | void set_target_if_empty(Method* m) { _method_family.set_target_if_empty(m); } | ||||||||||
| 516 | |||||||||||
| 517 | MethodFamily* get_method_family() { return &_method_family; } | ||||||||||
| 518 | |||||||||||
| 519 | void record_method_and_dq_further(StateRestorerScope* scope, Method* mo); | ||||||||||
| 520 | }; | ||||||||||
| 521 | |||||||||||
| 522 | // Because we use an iterative algorithm when iterating over the type | ||||||||||
| 523 | // hierarchy, we can't use traditional scoped objects which automatically do | ||||||||||
| 524 | // cleanup in the destructor when the scope is exited. StateRestorerScope (and | ||||||||||
| 525 | // StateRestorer) provides a similar functionality, but for when you want a | ||||||||||
| 526 | // scoped object in non-stack memory (such as in resource memory, as we do | ||||||||||
| 527 | // here). You've just got to remember to call 'restore_state()' on the scope when | ||||||||||
| 528 | // leaving it (and marks have to be explicitly added). The scope is reusable after | ||||||||||
| 529 | // 'restore_state()' has been called. | ||||||||||
| 530 | class StateRestorer : public ResourceObj { | ||||||||||
| 531 | public: | ||||||||||
| 532 | StatefulMethodFamily* _method; | ||||||||||
| 533 | QualifiedState _state_to_restore; | ||||||||||
| 534 | |||||||||||
| 535 | StateRestorer() : _method(NULL__null), _state_to_restore(DISQUALIFIED) {} | ||||||||||
| 536 | |||||||||||
| 537 | void restore_state() { _method->set_qualification_state(_state_to_restore); } | ||||||||||
| 538 | }; | ||||||||||
| 539 | |||||||||||
| 540 | class StateRestorerScope : public ResourceObj { | ||||||||||
| 541 | private: | ||||||||||
| 542 | GrowableArray<StateRestorer*> _marks; | ||||||||||
| 543 | GrowableArray<StateRestorer*>* _free_list; // Shared between scopes | ||||||||||
| 544 | public: | ||||||||||
| 545 | StateRestorerScope(GrowableArray<StateRestorer*>* free_list) : _marks(), _free_list(free_list) {} | ||||||||||
| 546 | |||||||||||
| 547 | static StateRestorerScope* cast(void* data) { | ||||||||||
| 548 | return static_cast<StateRestorerScope*>(data); | ||||||||||
| 549 | } | ||||||||||
| 550 | |||||||||||
| 551 | void mark(StatefulMethodFamily* family, QualifiedState qualification_state) { | ||||||||||
| 552 | StateRestorer* restorer; | ||||||||||
| 553 | if (!_free_list->is_empty()) { | ||||||||||
| 554 | restorer = _free_list->pop(); | ||||||||||
| 555 | } else { | ||||||||||
| 556 | restorer = new StateRestorer(); | ||||||||||
| 557 | } | ||||||||||
| 558 | restorer->_method = family; | ||||||||||
| 559 | restorer->_state_to_restore = qualification_state; | ||||||||||
| 560 | _marks.append(restorer); | ||||||||||
| 561 | } | ||||||||||
| 562 | |||||||||||
| 563 | #ifdef ASSERT1 | ||||||||||
| 564 | bool is_empty() { | ||||||||||
| 565 | return _marks.is_empty(); | ||||||||||
| 566 | } | ||||||||||
| 567 | #endif | ||||||||||
| 568 | |||||||||||
| 569 | void restore_state() { | ||||||||||
| 570 | while(!_marks.is_empty()) { | ||||||||||
| 571 | StateRestorer* restorer = _marks.pop(); | ||||||||||
| 572 | restorer->restore_state(); | ||||||||||
| 573 | _free_list->push(restorer); | ||||||||||
| 574 | } | ||||||||||
| 575 | } | ||||||||||
| 576 | }; | ||||||||||
| 577 | |||||||||||
| 578 | void StatefulMethodFamily::record_method_and_dq_further(StateRestorerScope* scope, Method* mo) { | ||||||||||
| 579 | scope->mark(this, _qualification_state); | ||||||||||
| 580 | _method_family.record_method(mo, _qualification_state); | ||||||||||
| 581 | |||||||||||
| 582 | // Everything found "above"??? this method in the hierarchy walk is set to | ||||||||||
| 583 | // disqualified | ||||||||||
| 584 | set_qualification_state(DISQUALIFIED); | ||||||||||
| 585 | } | ||||||||||
| 586 | |||||||||||
| 587 | // Represents a location corresponding to a vtable slot for methods that | ||||||||||
| 588 | // neither the class nor any of it's ancestors provide an implementaion. | ||||||||||
| 589 | // Default methods may be present to fill this slot. | ||||||||||
| 590 | class EmptyVtableSlot : public ResourceObj { | ||||||||||
| 591 | private: | ||||||||||
| 592 | Symbol* _name; | ||||||||||
| 593 | Symbol* _signature; | ||||||||||
| 594 | int _size_of_parameters; | ||||||||||
| 595 | MethodFamily* _binding; | ||||||||||
| 596 | |||||||||||
| 597 | public: | ||||||||||
| 598 | EmptyVtableSlot(Method* method) | ||||||||||
| 599 | : _name(method->name()), _signature(method->signature()), | ||||||||||
| 600 | _size_of_parameters(method->size_of_parameters()), _binding(NULL__null) {} | ||||||||||
| 601 | |||||||||||
| 602 | Symbol* name() const { return _name; } | ||||||||||
| 603 | Symbol* signature() const { return _signature; } | ||||||||||
| 604 | int size_of_parameters() const { return _size_of_parameters; } | ||||||||||
| 605 | |||||||||||
| 606 | void bind_family(MethodFamily* lm) { _binding = lm; } | ||||||||||
| 607 | bool is_bound() { return _binding != NULL__null; } | ||||||||||
| 608 | MethodFamily* get_binding() { return _binding; } | ||||||||||
| 609 | |||||||||||
| 610 | void print_on(outputStream* str) const { | ||||||||||
| 611 | print_slot(str, name(), signature()); | ||||||||||
| 612 | } | ||||||||||
| 613 | }; | ||||||||||
| 614 | |||||||||||
| 615 | static bool already_in_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, Method* m) { | ||||||||||
| 616 | bool found = false; | ||||||||||
| 617 | for (int j = 0; j < slots->length(); ++j) { | ||||||||||
| 618 | if (slots->at(j)->name() == m->name() && | ||||||||||
| 619 | slots->at(j)->signature() == m->signature() ) { | ||||||||||
| 620 | found = true; | ||||||||||
| 621 | break; | ||||||||||
| 622 | } | ||||||||||
| 623 | } | ||||||||||
| 624 | return found; | ||||||||||
| 625 | } | ||||||||||
| 626 | |||||||||||
| 627 | static void find_empty_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, | ||||||||||
| 628 | InstanceKlass* klass, const GrowableArray<Method*>* mirandas) { | ||||||||||
| 629 | |||||||||||
| 630 | assert(klass != NULL, "Must be valid class")do { if (!(klass != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 630, "assert(" "klass != __null" ") failed", "Must be valid class" ); ::breakpoint(); } } while (0); | ||||||||||
| 631 | |||||||||||
| 632 | // All miranda methods are obvious candidates | ||||||||||
| 633 | for (int i = 0; i < mirandas->length(); ++i) { | ||||||||||
| 634 | Method* m = mirandas->at(i); | ||||||||||
| 635 | if (!already_in_vtable_slots(slots, m)) { | ||||||||||
| 636 | slots->append(new EmptyVtableSlot(m)); | ||||||||||
| 637 | } | ||||||||||
| 638 | } | ||||||||||
| 639 | |||||||||||
| 640 | // Also any overpasses in our superclasses, that we haven't implemented. | ||||||||||
| 641 | // (can't use the vtable because it is not guaranteed to be initialized yet) | ||||||||||
| 642 | InstanceKlass* super = klass->java_super(); | ||||||||||
| 643 | while (super != NULL__null) { | ||||||||||
| 644 | for (int i = 0; i < super->methods()->length(); ++i) { | ||||||||||
| 645 | Method* m = super->methods()->at(i); | ||||||||||
| 646 | if (m->is_overpass() || m->is_static()) { | ||||||||||
| 647 | // m is a method that would have been a miranda if not for the | ||||||||||
| 648 | // default method processing that occurred on behalf of our superclass, | ||||||||||
| 649 | // so it's a method we want to re-examine in this new context. That is, | ||||||||||
| 650 | // unless we have a real implementation of it in the current class. | ||||||||||
| 651 | if (!already_in_vtable_slots(slots, m)) { | ||||||||||
| 652 | Method *impl = klass->lookup_method(m->name(), m->signature()); | ||||||||||
| 653 | if (impl == NULL__null || impl->is_overpass() || impl->is_static()) { | ||||||||||
| 654 | slots->append(new EmptyVtableSlot(m)); | ||||||||||
| 655 | } | ||||||||||
| 656 | } | ||||||||||
| 657 | } | ||||||||||
| 658 | } | ||||||||||
| 659 | |||||||||||
| 660 | // also any default methods in our superclasses | ||||||||||
| 661 | if (super->default_methods() != NULL__null) { | ||||||||||
| 662 | for (int i = 0; i < super->default_methods()->length(); ++i) { | ||||||||||
| 663 | Method* m = super->default_methods()->at(i); | ||||||||||
| 664 | // m is a method that would have been a miranda if not for the | ||||||||||
| 665 | // default method processing that occurred on behalf of our superclass, | ||||||||||
| 666 | // so it's a method we want to re-examine in this new context. That is, | ||||||||||
| 667 | // unless we have a real implementation of it in the current class. | ||||||||||
| 668 | if (!already_in_vtable_slots(slots, m)) { | ||||||||||
| 669 | Method* impl = klass->lookup_method(m->name(), m->signature()); | ||||||||||
| 670 | if (impl == NULL__null || impl->is_overpass() || impl->is_static()) { | ||||||||||
| 671 | slots->append(new EmptyVtableSlot(m)); | ||||||||||
| 672 | } | ||||||||||
| 673 | } | ||||||||||
| 674 | } | ||||||||||
| 675 | } | ||||||||||
| 676 | super = super->java_super(); | ||||||||||
| 677 | } | ||||||||||
| 678 | |||||||||||
| 679 | LogTarget(Debug, defaultmethods)LogTargetImpl<LogLevel::Debug, (LogTag::_defaultmethods), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||||||||
| 680 | if (lt.is_enabled()) { | ||||||||||
| 681 | lt.print("Slots that need filling:"); | ||||||||||
| 682 | ResourceMark rm; | ||||||||||
| 683 | LogStream ls(lt); | ||||||||||
| 684 | streamIndentor si(&ls); | ||||||||||
| 685 | for (int i = 0; i < slots->length(); ++i) { | ||||||||||
| 686 | ls.indent(); | ||||||||||
| 687 | slots->at(i)->print_on(&ls); | ||||||||||
| 688 | ls.cr(); | ||||||||||
| 689 | } | ||||||||||
| 690 | } | ||||||||||
| 691 | } | ||||||||||
| 692 | |||||||||||
| 693 | // Iterates over the superinterface type hierarchy looking for all methods | ||||||||||
| 694 | // with a specific erased signature. | ||||||||||
| 695 | class FindMethodsByErasedSig : public HierarchyVisitor<FindMethodsByErasedSig> { | ||||||||||
| 696 | private: | ||||||||||
| 697 | // Context data | ||||||||||
| 698 | Symbol* _method_name; | ||||||||||
| 699 | Symbol* _method_signature; | ||||||||||
| 700 | StatefulMethodFamily* _family; | ||||||||||
| 701 | bool _cur_class_is_interface; | ||||||||||
| 702 | // Free lists, used as an optimization | ||||||||||
| 703 | GrowableArray<StateRestorerScope*> _free_scopes; | ||||||||||
| 704 | GrowableArray<StateRestorer*> _free_restorers; | ||||||||||
| 705 | public: | ||||||||||
| 706 | FindMethodsByErasedSig() : _free_scopes(6), _free_restorers(6) {}; | ||||||||||
| 707 | |||||||||||
| 708 | void prepare(Symbol* name, Symbol* signature, bool is_interf) { | ||||||||||
| 709 | reset(); | ||||||||||
| 710 | _method_name = name; | ||||||||||
| 711 | _method_signature = signature; | ||||||||||
| 712 | _family = NULL__null; | ||||||||||
| 713 | _cur_class_is_interface = is_interf; | ||||||||||
| 714 | } | ||||||||||
| 715 | |||||||||||
| 716 | void get_discovered_family(MethodFamily** family) { | ||||||||||
| 717 | if (_family != NULL__null) { | ||||||||||
| 718 | *family = _family->get_method_family(); | ||||||||||
| 719 | } else { | ||||||||||
| 720 | *family = NULL__null; | ||||||||||
| 721 | } | ||||||||||
| 722 | } | ||||||||||
| 723 | |||||||||||
| 724 | void* new_node_data() { | ||||||||||
| 725 | if (!_free_scopes.is_empty()) { | ||||||||||
| 726 | StateRestorerScope* free_scope = _free_scopes.pop(); | ||||||||||
| 727 | assert(free_scope->is_empty(), "StateRestorerScope::_marks array not empty")do { if (!(free_scope->is_empty())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 727, "assert(" "free_scope->is_empty()" ") failed", "StateRestorerScope::_marks array not empty" ); ::breakpoint(); } } while (0); | ||||||||||
| 728 | return free_scope; | ||||||||||
| 729 | } | ||||||||||
| 730 | return new StateRestorerScope(&_free_restorers); | ||||||||||
| 731 | } | ||||||||||
| 732 | void free_node_data(void* node_data) { | ||||||||||
| 733 | StateRestorerScope* scope = StateRestorerScope::cast(node_data); | ||||||||||
| 734 | scope->restore_state(); | ||||||||||
| 735 | // Reuse scopes | ||||||||||
| 736 | _free_scopes.push(scope); | ||||||||||
| 737 | } | ||||||||||
| 738 | |||||||||||
| 739 | // Find all methods on this hierarchy that match this | ||||||||||
| 740 | // method's erased (name, signature) | ||||||||||
| 741 | bool visit() { | ||||||||||
| 742 | StateRestorerScope* scope = StateRestorerScope::cast(current_data()); | ||||||||||
| 743 | InstanceKlass* iklass = current_class(); | ||||||||||
| 744 | |||||||||||
| 745 | Method* m = iklass->find_method(_method_name, _method_signature); | ||||||||||
| 746 | // Private interface methods are not candidates for default methods. | ||||||||||
| 747 | // invokespecial to private interface methods doesn't use default method logic. | ||||||||||
| 748 | // Private class methods are not candidates for default methods. | ||||||||||
| 749 | // Private methods do not override default methods, so need to perform | ||||||||||
| 750 | // default method inheritance without including private methods. | ||||||||||
| 751 | // The overpasses are your supertypes' errors, we do not include them. | ||||||||||
| 752 | // Non-public methods in java.lang.Object are not candidates for default | ||||||||||
| 753 | // methods. | ||||||||||
| 754 | // Future: take access controls into account for superclass methods | ||||||||||
| 755 | if (m != NULL__null && !m->is_static() && !m->is_overpass() && !m->is_private() && | ||||||||||
| 756 | (!_cur_class_is_interface || !SystemDictionary::is_nonpublic_Object_method(m))) { | ||||||||||
| 757 | if (_family == NULL__null) { | ||||||||||
| 758 | _family = new StatefulMethodFamily(); | ||||||||||
| 759 | } | ||||||||||
| 760 | |||||||||||
| 761 | if (iklass->is_interface()) { | ||||||||||
| 762 | _family->record_method_and_dq_further(scope, m); | ||||||||||
| 763 | } else { | ||||||||||
| 764 | // This is the rule that methods in classes "win" (bad word) over | ||||||||||
| 765 | // methods in interfaces. This works because of single inheritance. | ||||||||||
| 766 | // Private methods in classes do not "win", they will be found | ||||||||||
| 767 | // first on searching, but overriding for invokevirtual needs | ||||||||||
| 768 | // to find default method candidates for the same signature | ||||||||||
| 769 | _family->set_target_if_empty(m); | ||||||||||
| 770 | } | ||||||||||
| 771 | } | ||||||||||
| 772 | return true; | ||||||||||
| 773 | } | ||||||||||
| 774 | |||||||||||
| 775 | }; | ||||||||||
| 776 | |||||||||||
| 777 | |||||||||||
| 778 | |||||||||||
| 779 | static void create_defaults_and_exceptions( | ||||||||||
| 780 | GrowableArray<EmptyVtableSlot*>* slots, InstanceKlass* klass, TRAPSJavaThread* __the_thread__); | ||||||||||
| 781 | |||||||||||
| 782 | static void generate_erased_defaults( | ||||||||||
| 783 | FindMethodsByErasedSig* visitor, | ||||||||||
| 784 | InstanceKlass* klass, EmptyVtableSlot* slot, bool is_intf) { | ||||||||||
| 785 | |||||||||||
| 786 | // the visitor needs to be initialized or re-initialized before use | ||||||||||
| 787 | // - this facilitates reusing the same visitor instance on multiple | ||||||||||
| 788 | // generation passes as an optimization | ||||||||||
| 789 | visitor->prepare(slot->name(), slot->signature(), is_intf); | ||||||||||
| 790 | // sets up a set of methods with the same exact erased signature | ||||||||||
| 791 | visitor->run(klass); | ||||||||||
| 792 | |||||||||||
| 793 | MethodFamily* family; | ||||||||||
| 794 | visitor->get_discovered_family(&family); | ||||||||||
| 795 | if (family != NULL__null) { | ||||||||||
| 796 | family->determine_target_or_set_exception_message(klass); | ||||||||||
| 797 | slot->bind_family(family); | ||||||||||
| 798 | } | ||||||||||
| 799 | } | ||||||||||
| 800 | |||||||||||
| 801 | static void merge_in_new_methods(InstanceKlass* klass, | ||||||||||
| 802 | GrowableArray<Method*>* new_methods, TRAPSJavaThread* __the_thread__); | ||||||||||
| 803 | static void create_default_methods( InstanceKlass* klass, | ||||||||||
| 804 | GrowableArray<Method*>* new_methods, TRAPSJavaThread* __the_thread__); | ||||||||||
| 805 | |||||||||||
| 806 | // This is the guts of the default methods implementation. This is called just | ||||||||||
| 807 | // after the classfile has been parsed if some ancestor has default methods. | ||||||||||
| 808 | // | ||||||||||
| 809 | // First it finds any name/signature slots that need any implementation (either | ||||||||||
| 810 | // because they are miranda or a superclass's implementation is an overpass | ||||||||||
| 811 | // itself). For each slot, iterate over the hierarchy, to see if they contain a | ||||||||||
| 812 | // signature that matches the slot we are looking at. | ||||||||||
| 813 | // | ||||||||||
| 814 | // For each slot filled, we either record the default method candidate in the | ||||||||||
| 815 | // klass default_methods list or, only to handle exception cases, we create an | ||||||||||
| 816 | // overpass method that throws an exception and add it to the klass methods list. | ||||||||||
| 817 | // The JVM does not create bridges nor handle generic signatures here. | ||||||||||
| 818 | void DefaultMethods::generate_default_methods( | ||||||||||
| 819 | InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 820 | assert(klass != NULL, "invariant")do { if (!(klass != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 820, "assert(" "klass != __null" ") failed", "invariant"); :: breakpoint(); } } while (0); | ||||||||||
| |||||||||||
| 821 | assert(klass != vmClasses::Object_klass(), "Shouldn't be called for Object")do { if (!(klass != vmClasses::Object_klass())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 821, "assert(" "klass != vmClasses::Object_klass()" ") failed" , "Shouldn't be called for Object"); ::breakpoint(); } } while (0); | ||||||||||
| 822 | |||||||||||
| 823 | // This resource mark is the bound for all memory allocation that takes | ||||||||||
| 824 | // place during default method processing. After this goes out of scope, | ||||||||||
| 825 | // all (Resource) objects' memory will be reclaimed. Be careful if adding an | ||||||||||
| 826 | // embedded resource mark under here as that memory can't be used outside | ||||||||||
| 827 | // whatever scope it's in. | ||||||||||
| 828 | ResourceMark rm(THREAD__the_thread__); | ||||||||||
| 829 | |||||||||||
| 830 | // Keep entire hierarchy alive for the duration of the computation | ||||||||||
| 831 | constantPoolHandle cp(THREAD__the_thread__, klass->constants()); | ||||||||||
| 832 | KeepAliveRegistrar keepAlive(THREAD__the_thread__); | ||||||||||
| 833 | KeepAliveVisitor loadKeepAlive(&keepAlive); | ||||||||||
| 834 | loadKeepAlive.run(klass); | ||||||||||
| 835 | |||||||||||
| 836 | LogTarget(Debug, defaultmethods)LogTargetImpl<LogLevel::Debug, (LogTag::_defaultmethods), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||||||||
| 837 | if (lt.is_enabled()) { | ||||||||||
| 838 | ResourceMark rm(THREAD__the_thread__); | ||||||||||
| 839 | lt.print("%s %s requires default method processing", | ||||||||||
| 840 | klass->is_interface() ? "Interface" : "Class", | ||||||||||
| 841 | klass->name()->as_klass_external_name()); | ||||||||||
| 842 | LogStream ls(lt); | ||||||||||
| 843 | PrintHierarchy printer(&ls); | ||||||||||
| 844 | printer.run(klass); | ||||||||||
| 845 | } | ||||||||||
| 846 | |||||||||||
| 847 | GrowableArray<EmptyVtableSlot*> empty_slots; | ||||||||||
| 848 | find_empty_vtable_slots(&empty_slots, klass, mirandas); | ||||||||||
| 849 | |||||||||||
| 850 | if (empty_slots.length() > 0) { | ||||||||||
| 851 | FindMethodsByErasedSig findMethodsByErasedSig; | ||||||||||
| 852 | for (int i = 0; i < empty_slots.length(); ++i) { | ||||||||||
| 853 | EmptyVtableSlot* slot = empty_slots.at(i); | ||||||||||
| 854 | LogTarget(Debug, defaultmethods)LogTargetImpl<LogLevel::Debug, (LogTag::_defaultmethods), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||||||||
| 855 | if (lt.is_enabled()) { | ||||||||||
| 856 | LogStream ls(lt); | ||||||||||
| 857 | streamIndentor si(&ls, 2); | ||||||||||
| 858 | ls.indent().print("Looking for default methods for slot "); | ||||||||||
| 859 | slot->print_on(&ls); | ||||||||||
| 860 | ls.cr(); | ||||||||||
| 861 | } | ||||||||||
| 862 | generate_erased_defaults(&findMethodsByErasedSig, klass, slot, klass->is_interface()); | ||||||||||
| 863 | } | ||||||||||
| 864 | log_debug(defaultmethods)(!(LogImpl<(LogTag::_defaultmethods), (LogTag::__NO_TAG), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_defaultmethods), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("Creating defaults and overpasses..."); | ||||||||||
| 865 | create_defaults_and_exceptions(&empty_slots, klass, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 866 | } | ||||||||||
| 867 | log_debug(defaultmethods)(!(LogImpl<(LogTag::_defaultmethods), (LogTag::__NO_TAG), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_defaultmethods), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("Default method processing complete"); | ||||||||||
| 868 | } | ||||||||||
| 869 | |||||||||||
| 870 | static int assemble_method_error( | ||||||||||
| 871 | BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* errorName, Symbol* message) { | ||||||||||
| 872 | |||||||||||
| 873 | Symbol* init = vmSymbols::object_initializer_name(); | ||||||||||
| 874 | Symbol* sig = vmSymbols::string_void_signature(); | ||||||||||
| 875 | |||||||||||
| 876 | BytecodeAssembler assem(buffer, cp); | ||||||||||
| 877 | |||||||||||
| 878 | assem._new(errorName); | ||||||||||
| 879 | assem.dup(); | ||||||||||
| 880 | assem.load_string(message); | ||||||||||
| 881 | assem.invokespecial(errorName, init, sig); | ||||||||||
| 882 | assem.athrow(); | ||||||||||
| 883 | |||||||||||
| 884 | return 3; // max stack size: [ exception, exception, string ] | ||||||||||
| 885 | } | ||||||||||
| 886 | |||||||||||
| 887 | static Method* new_method( | ||||||||||
| 888 | BytecodeConstantPool* cp, BytecodeBuffer* bytecodes, Symbol* name, | ||||||||||
| 889 | Symbol* sig, AccessFlags flags, int max_stack, int params, | ||||||||||
| 890 | ConstMethod::MethodType mt, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 891 | |||||||||||
| 892 | address code_start = 0; | ||||||||||
| 893 | int code_length = 0; | ||||||||||
| 894 | InlineTableSizes sizes; | ||||||||||
| 895 | |||||||||||
| 896 | if (bytecodes != NULL__null && bytecodes->length() > 0) { | ||||||||||
| 897 | code_start = static_cast<address>(bytecodes->adr_at(0)); | ||||||||||
| 898 | code_length = bytecodes->length(); | ||||||||||
| 899 | } | ||||||||||
| 900 | |||||||||||
| 901 | Method* m = Method::allocate(cp->pool_holder()->class_loader_data(), | ||||||||||
| 902 | code_length, flags, &sizes, | ||||||||||
| 903 | mt, CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); | ||||||||||
| 904 | |||||||||||
| 905 | m->set_constants(NULL__null); // This will get filled in later | ||||||||||
| 906 | m->set_name_index(cp->utf8(name)); | ||||||||||
| 907 | m->set_signature_index(cp->utf8(sig)); | ||||||||||
| 908 | m->compute_from_signature(sig); | ||||||||||
| 909 | m->set_size_of_parameters(params); | ||||||||||
| 910 | m->set_max_stack(max_stack); | ||||||||||
| 911 | m->set_max_locals(params); | ||||||||||
| 912 | m->constMethod()->set_stackmap_data(NULL__null); | ||||||||||
| 913 | m->set_code(code_start); | ||||||||||
| 914 | |||||||||||
| 915 | return m; | ||||||||||
| 916 | } | ||||||||||
| 917 | |||||||||||
| 918 | static void switchover_constant_pool(BytecodeConstantPool* bpool, | ||||||||||
| 919 | InstanceKlass* klass, GrowableArray<Method*>* new_methods, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 920 | |||||||||||
| 921 | if (new_methods->length() > 0) { | ||||||||||
| 922 | ConstantPool* cp = bpool->create_constant_pool(CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 923 | if (cp != klass->constants()) { | ||||||||||
| 924 | // Copy resolved hidden class into new constant pool. | ||||||||||
| 925 | if (klass->is_hidden()) { | ||||||||||
| 926 | cp->klass_at_put(klass->this_class_index(), klass); | ||||||||||
| 927 | } | ||||||||||
| 928 | klass->class_loader_data()->add_to_deallocate_list(klass->constants()); | ||||||||||
| 929 | klass->set_constants(cp); | ||||||||||
| 930 | cp->set_pool_holder(klass); | ||||||||||
| 931 | |||||||||||
| 932 | for (int i = 0; i < new_methods->length(); ++i) { | ||||||||||
| 933 | new_methods->at(i)->set_constants(cp); | ||||||||||
| 934 | } | ||||||||||
| 935 | for (int i = 0; i < klass->methods()->length(); ++i) { | ||||||||||
| 936 | Method* mo = klass->methods()->at(i); | ||||||||||
| 937 | mo->set_constants(cp); | ||||||||||
| 938 | } | ||||||||||
| 939 | } | ||||||||||
| 940 | } | ||||||||||
| 941 | } | ||||||||||
| 942 | |||||||||||
| 943 | // Create default_methods list for the current class. | ||||||||||
| 944 | // With the VM only processing erased signatures, the VM only | ||||||||||
| 945 | // creates an overpass in a conflict case or a case with no candidates. | ||||||||||
| 946 | // This allows virtual methods to override the overpass, but ensures | ||||||||||
| 947 | // that a local method search will find the exception rather than an abstract | ||||||||||
| 948 | // or default method that is not a valid candidate. | ||||||||||
| 949 | // | ||||||||||
| 950 | // Note that if overpass method are ever created that are not exception | ||||||||||
| 951 | // throwing methods then the loader constraint checking logic for vtable and | ||||||||||
| 952 | // itable creation needs to be changed to check loader constraints for the | ||||||||||
| 953 | // overpass methods that do not throw exceptions. | ||||||||||
| 954 | static void create_defaults_and_exceptions(GrowableArray<EmptyVtableSlot*>* slots, | ||||||||||
| 955 | InstanceKlass* klass, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 956 | |||||||||||
| 957 | GrowableArray<Method*> overpasses; | ||||||||||
| 958 | GrowableArray<Method*> defaults; | ||||||||||
| 959 | BytecodeConstantPool bpool(klass->constants()); | ||||||||||
| 960 | |||||||||||
| 961 | BytecodeBuffer* buffer = NULL__null; // Lazily create a reusable buffer | ||||||||||
| 962 | for (int i = 0; i < slots->length(); ++i) { | ||||||||||
| 963 | EmptyVtableSlot* slot = slots->at(i); | ||||||||||
| 964 | |||||||||||
| 965 | if (slot->is_bound()) { | ||||||||||
| 966 | MethodFamily* method = slot->get_binding(); | ||||||||||
| 967 | |||||||||||
| 968 | LogTarget(Debug, defaultmethods)LogTargetImpl<LogLevel::Debug, (LogTag::_defaultmethods), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG), (LogTag::__NO_TAG)> lt; | ||||||||||
| 969 | if (lt.is_enabled()) { | ||||||||||
| 970 | ResourceMark rm(THREAD__the_thread__); | ||||||||||
| 971 | LogStream ls(lt); | ||||||||||
| 972 | ls.print("for slot: "); | ||||||||||
| 973 | slot->print_on(&ls); | ||||||||||
| 974 | ls.cr(); | ||||||||||
| 975 | if (method->has_target()) { | ||||||||||
| 976 | method->print_selected(&ls, 1); | ||||||||||
| 977 | } else if (method->throws_exception()) { | ||||||||||
| 978 | method->print_exception(&ls, 1); | ||||||||||
| 979 | } | ||||||||||
| 980 | } | ||||||||||
| 981 | |||||||||||
| 982 | if (method->has_target()) { | ||||||||||
| 983 | Method* selected = method->get_selected_target(); | ||||||||||
| 984 | if (selected->method_holder()->is_interface()) { | ||||||||||
| 985 | assert(!selected->is_private(), "pushing private interface method as default")do { if (!(!selected->is_private())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 985, "assert(" "!selected->is_private()" ") failed", "pushing private interface method as default" ); ::breakpoint(); } } while (0); | ||||||||||
| 986 | defaults.push(selected); | ||||||||||
| 987 | } | ||||||||||
| 988 | } else if (method->throws_exception()) { | ||||||||||
| 989 | if (buffer
| ||||||||||
| 990 | buffer = new BytecodeBuffer(); | ||||||||||
| 991 | } else { | ||||||||||
| 992 | buffer->clear(); | ||||||||||
| 993 | } | ||||||||||
| 994 | int max_stack = assemble_method_error(&bpool, buffer, | ||||||||||
| 995 | method->get_exception_name(), method->get_exception_message()); | ||||||||||
| 996 | AccessFlags flags = accessFlags_from( | ||||||||||
| 997 | JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE); | ||||||||||
| 998 | Method* m = new_method(&bpool, buffer, slot->name(), slot->signature(), | ||||||||||
| 999 | flags, max_stack, slot->size_of_parameters(), | ||||||||||
| 1000 | ConstMethod::OVERPASS, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1001 | // We push to the methods list: | ||||||||||
| 1002 | // overpass methods which are exception throwing methods | ||||||||||
| 1003 | if (m != NULL__null) { | ||||||||||
| 1004 | overpasses.push(m); | ||||||||||
| 1005 | } | ||||||||||
| 1006 | } | ||||||||||
| 1007 | } | ||||||||||
| 1008 | } | ||||||||||
| 1009 | |||||||||||
| 1010 | |||||||||||
| 1011 | log_debug(defaultmethods)(!(LogImpl<(LogTag::_defaultmethods), (LogTag::__NO_TAG), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_defaultmethods), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("Created %d overpass methods", overpasses.length()); | ||||||||||
| 1012 | log_debug(defaultmethods)(!(LogImpl<(LogTag::_defaultmethods), (LogTag::__NO_TAG), ( LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag ::__NO_TAG)>::is_level(LogLevel::Debug))) ? (void)0 : LogImpl <(LogTag::_defaultmethods), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::write<LogLevel::Debug>("Created %d default methods", defaults.length()); | ||||||||||
| 1013 | |||||||||||
| 1014 | if (overpasses.length() > 0) { | ||||||||||
| 1015 | switchover_constant_pool(&bpool, klass, &overpasses, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1016 | merge_in_new_methods(klass, &overpasses, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1017 | } | ||||||||||
| 1018 | if (defaults.length() > 0) { | ||||||||||
| 1019 | create_default_methods(klass, &defaults, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1020 | } | ||||||||||
| 1021 | } | ||||||||||
| 1022 | |||||||||||
| 1023 | static void create_default_methods(InstanceKlass* klass, | ||||||||||
| 1024 | GrowableArray<Method*>* new_methods, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 1025 | |||||||||||
| 1026 | int new_size = new_methods->length(); | ||||||||||
| 1027 | Array<Method*>* total_default_methods = MetadataFactory::new_array<Method*>( | ||||||||||
| 1028 | klass->class_loader_data(), new_size, NULL__null, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1029 | for (int index = 0; index < new_size; index++ ) { | ||||||||||
| 1030 | total_default_methods->at_put(index, new_methods->at(index)); | ||||||||||
| 1031 | } | ||||||||||
| 1032 | Method::sort_methods(total_default_methods, /*set_idnums=*/false); | ||||||||||
| 1033 | |||||||||||
| 1034 | klass->set_default_methods(total_default_methods); | ||||||||||
| 1035 | // Create an array for mapping default methods to their vtable indices in | ||||||||||
| 1036 | // this class, since default methods vtable indices are the indices for | ||||||||||
| 1037 | // the defining class. | ||||||||||
| 1038 | klass->create_new_default_vtable_indices(new_size, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1039 | } | ||||||||||
| 1040 | |||||||||||
| 1041 | static void sort_methods(GrowableArray<Method*>* methods) { | ||||||||||
| 1042 | // Note that this must sort using the same key as is used for sorting | ||||||||||
| 1043 | // methods in InstanceKlass. | ||||||||||
| 1044 | bool sorted = true; | ||||||||||
| 1045 | for (int i = methods->length() - 1; i > 0; --i) { | ||||||||||
| 1046 | for (int j = 0; j < i; ++j) { | ||||||||||
| 1047 | Method* m1 = methods->at(j); | ||||||||||
| 1048 | Method* m2 = methods->at(j + 1); | ||||||||||
| 1049 | if ((uintptr_t)m1->name() > (uintptr_t)m2->name()) { | ||||||||||
| 1050 | methods->at_put(j, m2); | ||||||||||
| 1051 | methods->at_put(j + 1, m1); | ||||||||||
| 1052 | sorted = false; | ||||||||||
| 1053 | } | ||||||||||
| 1054 | } | ||||||||||
| 1055 | if (sorted) break; | ||||||||||
| 1056 | sorted = true; | ||||||||||
| 1057 | } | ||||||||||
| 1058 | #ifdef ASSERT1 | ||||||||||
| 1059 | uintptr_t prev = 0; | ||||||||||
| 1060 | for (int i = 0; i < methods->length(); ++i) { | ||||||||||
| 1061 | Method* mh = methods->at(i); | ||||||||||
| 1062 | uintptr_t nv = (uintptr_t)mh->name(); | ||||||||||
| 1063 | assert(nv >= prev, "Incorrect overpass method ordering")do { if (!(nv >= prev)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 1063, "assert(" "nv >= prev" ") failed", "Incorrect overpass method ordering" ); ::breakpoint(); } } while (0); | ||||||||||
| 1064 | prev = nv; | ||||||||||
| 1065 | } | ||||||||||
| 1066 | #endif | ||||||||||
| 1067 | } | ||||||||||
| 1068 | |||||||||||
| 1069 | static void merge_in_new_methods(InstanceKlass* klass, | ||||||||||
| 1070 | GrowableArray<Method*>* new_methods, TRAPSJavaThread* __the_thread__) { | ||||||||||
| 1071 | |||||||||||
| 1072 | enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS }; | ||||||||||
| 1073 | |||||||||||
| 1074 | Array<Method*>* original_methods = klass->methods(); | ||||||||||
| 1075 | Array<int>* original_ordering = klass->method_ordering(); | ||||||||||
| 1076 | Array<int>* merged_ordering = Universe::the_empty_int_array(); | ||||||||||
| 1077 | |||||||||||
| 1078 | int new_size = klass->methods()->length() + new_methods->length(); | ||||||||||
| 1079 | |||||||||||
| 1080 | Array<Method*>* merged_methods = MetadataFactory::new_array<Method*>( | ||||||||||
| 1081 | klass->class_loader_data(), new_size, NULL__null, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1082 | |||||||||||
| 1083 | // original_ordering might be empty if this class has no methods of its own | ||||||||||
| 1084 | if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) { | ||||||||||
| 1085 | merged_ordering = MetadataFactory::new_array<int>( | ||||||||||
| 1086 | klass->class_loader_data(), new_size, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | ||||||||||
| 1087 | } | ||||||||||
| 1088 | int method_order_index = klass->methods()->length(); | ||||||||||
| 1089 | |||||||||||
| 1090 | sort_methods(new_methods); | ||||||||||
| 1091 | |||||||||||
| 1092 | // Perform grand merge of existing methods and new methods | ||||||||||
| 1093 | int orig_idx = 0; | ||||||||||
| 1094 | int new_idx = 0; | ||||||||||
| 1095 | |||||||||||
| 1096 | for (int i = 0; i < new_size; ++i) { | ||||||||||
| 1097 | Method* orig_method = NULL__null; | ||||||||||
| 1098 | Method* new_method = NULL__null; | ||||||||||
| 1099 | if (orig_idx < original_methods->length()) { | ||||||||||
| 1100 | orig_method = original_methods->at(orig_idx); | ||||||||||
| 1101 | } | ||||||||||
| 1102 | if (new_idx < new_methods->length()) { | ||||||||||
| 1103 | new_method = new_methods->at(new_idx); | ||||||||||
| 1104 | } | ||||||||||
| 1105 | |||||||||||
| 1106 | if (orig_method != NULL__null && | ||||||||||
| 1107 | (new_method == NULL__null || orig_method->name() < new_method->name())) { | ||||||||||
| 1108 | merged_methods->at_put(i, orig_method); | ||||||||||
| 1109 | original_methods->at_put(orig_idx, NULL__null); | ||||||||||
| 1110 | if (merged_ordering->length() > 0) { | ||||||||||
| 1111 | assert(original_ordering != NULL && original_ordering->length() > 0,do { if (!(original_ordering != __null && original_ordering ->length() > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 1112, "assert(" "original_ordering != __null && original_ordering->length() > 0" ") failed", "should have original order information for this method" ); ::breakpoint(); } } while (0) | ||||||||||
| 1112 | "should have original order information for this method")do { if (!(original_ordering != __null && original_ordering ->length() > 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 1112, "assert(" "original_ordering != __null && original_ordering->length() > 0" ") failed", "should have original order information for this method" ); ::breakpoint(); } } while (0); | ||||||||||
| 1113 | merged_ordering->at_put(i, original_ordering->at(orig_idx)); | ||||||||||
| 1114 | } | ||||||||||
| 1115 | ++orig_idx; | ||||||||||
| 1116 | } else { | ||||||||||
| 1117 | merged_methods->at_put(i, new_method); | ||||||||||
| 1118 | if (merged_ordering->length() > 0) { | ||||||||||
| 1119 | merged_ordering->at_put(i, method_order_index++); | ||||||||||
| 1120 | } | ||||||||||
| 1121 | ++new_idx; | ||||||||||
| 1122 | } | ||||||||||
| 1123 | // update idnum for new location | ||||||||||
| 1124 | merged_methods->at(i)->set_method_idnum(i); | ||||||||||
| 1125 | merged_methods->at(i)->set_orig_method_idnum(i); | ||||||||||
| 1126 | } | ||||||||||
| 1127 | |||||||||||
| 1128 | // Verify correct order | ||||||||||
| 1129 | #ifdef ASSERT1 | ||||||||||
| 1130 | uintptr_t prev = 0; | ||||||||||
| 1131 | for (int i = 0; i < merged_methods->length(); ++i) { | ||||||||||
| 1132 | Method* mo = merged_methods->at(i); | ||||||||||
| 1133 | uintptr_t nv = (uintptr_t)mo->name(); | ||||||||||
| 1134 | assert(nv >= prev, "Incorrect method ordering")do { if (!(nv >= prev)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/classfile/defaultMethods.cpp" , 1134, "assert(" "nv >= prev" ") failed", "Incorrect method ordering" ); ::breakpoint(); } } while (0); | ||||||||||
| 1135 | prev = nv; | ||||||||||
| 1136 | } | ||||||||||
| 1137 | #endif | ||||||||||
| 1138 | |||||||||||
| 1139 | // Replace klass methods with new merged lists | ||||||||||
| 1140 | klass->set_methods(merged_methods); | ||||||||||
| 1141 | klass->set_initial_method_idnum(new_size); | ||||||||||
| 1142 | klass->set_method_ordering(merged_ordering); | ||||||||||
| 1143 | |||||||||||
| 1144 | // Free metadata | ||||||||||
| 1145 | ClassLoaderData* cld = klass->class_loader_data(); | ||||||||||
| 1146 | if (original_methods->length() > 0) { | ||||||||||
| 1147 | MetadataFactory::free_array(cld, original_methods); | ||||||||||
| 1148 | } | ||||||||||
| 1149 | if (original_ordering != NULL__null && original_ordering->length() > 0) { | ||||||||||
| 1150 | MetadataFactory::free_array(cld, original_ordering); | ||||||||||
| 1151 | } | ||||||||||
| 1152 | } |
| 1 | /* |
| 2 | * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_UTILITIES_EXCEPTIONS_HPP |
| 26 | #define SHARE_UTILITIES_EXCEPTIONS_HPP |
| 27 | |
| 28 | #include "memory/allocation.hpp" |
| 29 | #include "oops/oopsHierarchy.hpp" |
| 30 | #include "utilities/ostream.hpp" |
| 31 | #include "utilities/sizes.hpp" |
| 32 | |
| 33 | // This file provides the basic support for exception handling in the VM. |
| 34 | // Note: We do not use C++ exceptions to avoid compiler dependencies and |
| 35 | // unpredictable performance. |
| 36 | // |
| 37 | // Scheme: Exceptions are stored with the thread. There is never more |
| 38 | // than one pending exception per thread. All functions that can throw |
| 39 | // an exception carry a THREAD argument (usually the last argument and |
| 40 | // declared with the TRAPS macro). Throwing an exception means setting |
| 41 | // a pending exception in the thread. Upon return from a function that |
| 42 | // can throw an exception, we must check if an exception is pending. |
| 43 | // The CHECK macros do this in a convenient way. Carrying around the |
| 44 | // thread provides also convenient access to it (e.g. for Handle |
| 45 | // creation, w/o the need for recomputation). |
| 46 | |
| 47 | |
| 48 | |
| 49 | // Forward declarations to be independent of the include structure. |
| 50 | |
| 51 | class JavaThread; |
| 52 | class Handle; |
| 53 | class Symbol; |
| 54 | class JavaCallArguments; |
| 55 | class methodHandle; |
| 56 | |
| 57 | // The ThreadShadow class is a helper class to access the _pending_exception |
| 58 | // field of the Thread class w/o having access to the Thread's interface (for |
| 59 | // include hierachy reasons). |
| 60 | |
| 61 | class ThreadShadow: public CHeapObj<mtThread> { |
| 62 | friend class VMStructs; |
| 63 | friend class JVMCIVMStructs; |
| 64 | |
| 65 | protected: |
| 66 | oop _pending_exception; // Thread has gc actions. |
| 67 | const char* _exception_file; // file information for exception (debugging only) |
| 68 | int _exception_line; // line information for exception (debugging only) |
| 69 | friend void check_ThreadShadow(); // checks _pending_exception offset |
| 70 | |
| 71 | // The following virtual exists only to force creation of a vtable. |
| 72 | // We need ThreadShadow to have a vtable, even in product builds, |
| 73 | // so that its layout will start at an offset of zero relative to Thread. |
| 74 | // Some C++ compilers are so "clever" that they put the ThreadShadow |
| 75 | // base class at offset 4 in Thread (after Thread's vtable), if they |
| 76 | // notice that Thread has a vtable but ThreadShadow does not. |
| 77 | virtual void unused_initial_virtual() { } |
| 78 | |
| 79 | public: |
| 80 | oop pending_exception() const { return _pending_exception; } |
| 81 | bool has_pending_exception() const { return _pending_exception != NULL__null; } |
| 82 | const char* exception_file() const { return _exception_file; } |
| 83 | int exception_line() const { return _exception_line; } |
| 84 | |
| 85 | // Code generation support |
| 86 | static ByteSize pending_exception_offset() { return byte_offset_of(ThreadShadow, _pending_exception)in_ByteSize((int)(size_t)((intx)&(((ThreadShadow*)16)-> _pending_exception) - 16)); } |
| 87 | |
| 88 | // use THROW whenever possible! |
| 89 | void set_pending_exception(oop exception, const char* file, int line); |
| 90 | |
| 91 | // use CLEAR_PENDING_EXCEPTION whenever possible! |
| 92 | void clear_pending_exception(); |
| 93 | |
| 94 | // use CLEAR_PENDING_NONASYNC_EXCEPTION to clear probable nonasync exception. |
| 95 | void clear_pending_nonasync_exception(); |
| 96 | |
| 97 | ThreadShadow() : _pending_exception(NULL__null), |
| 98 | _exception_file(NULL__null), _exception_line(0) {} |
| 99 | }; |
| 100 | |
| 101 | |
| 102 | // Exceptions is a helper class that encapsulates all operations |
| 103 | // that require access to the thread interface and which are |
| 104 | // relatively rare. The Exceptions operations should only be |
| 105 | // used directly if the macros below are insufficient. |
| 106 | |
| 107 | class Exceptions { |
| 108 | static bool special_exception(JavaThread* thread, const char* file, int line, Handle exception); |
| 109 | static bool special_exception(JavaThread* thread, const char* file, int line, Symbol* name, const char* message); |
| 110 | |
| 111 | // Count out of memory errors that are interesting in error diagnosis |
| 112 | static volatile int _out_of_memory_error_java_heap_errors; |
| 113 | static volatile int _out_of_memory_error_metaspace_errors; |
| 114 | static volatile int _out_of_memory_error_class_metaspace_errors; |
| 115 | |
| 116 | // Count linkage errors |
| 117 | static volatile int _linkage_errors; |
| 118 | public: |
| 119 | // this enum is defined to indicate whether it is safe to |
| 120 | // ignore the encoding scheme of the original message string. |
| 121 | typedef enum { |
| 122 | safe_to_utf8 = 0, |
| 123 | unsafe_to_utf8 = 1 |
| 124 | } ExceptionMsgToUtf8Mode; |
| 125 | // Throw exceptions: w/o message, w/ message & with formatted message. |
| 126 | static void _throw_oop(JavaThread* thread, const char* file, int line, oop exception); |
| 127 | static void _throw(JavaThread* thread, const char* file, int line, Handle exception, const char* msg = NULL__null); |
| 128 | |
| 129 | static void _throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message); |
| 130 | static void _throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, |
| 131 | Handle loader, Handle protection_domain); |
| 132 | |
| 133 | static void _throw_msg_cause(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause); |
| 134 | static void _throw_msg_cause(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause, |
| 135 | Handle h_loader, Handle h_protection_domain); |
| 136 | |
| 137 | static void _throw_cause(JavaThread* thread, const char* file, int line, Symbol* name, Handle h_cause); |
| 138 | static void _throw_cause(JavaThread* thread, const char* file, int line, Symbol* name, Handle h_cause, |
| 139 | Handle h_loader, Handle h_protection_domain); |
| 140 | |
| 141 | static void _throw_args(JavaThread* thread, const char* file, int line, |
| 142 | Symbol* name, Symbol* signature, |
| 143 | JavaCallArguments* args); |
| 144 | |
| 145 | // There is no THROW... macro for this method. Caller should remember |
| 146 | // to do a return after calling it. |
| 147 | static void fthrow(JavaThread* thread, const char* file, int line, Symbol* name, |
| 148 | const char* format, ...) ATTRIBUTE_PRINTF(5, 6)__attribute__((format(printf, 5, 6))); |
| 149 | |
| 150 | // Create and initialize a new exception |
| 151 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 152 | Symbol* signature, JavaCallArguments* args, |
| 153 | Handle loader, Handle protection_domain); |
| 154 | |
| 155 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 156 | Symbol* signature, JavaCallArguments* args, |
| 157 | Handle cause, |
| 158 | Handle loader, Handle protection_domain); |
| 159 | |
| 160 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 161 | Handle cause, |
| 162 | Handle loader, Handle protection_domain, |
| 163 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 164 | |
| 165 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 166 | const char* message, Handle cause, |
| 167 | Handle loader, Handle protection_domain, |
| 168 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 169 | |
| 170 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 171 | const char* message, |
| 172 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 173 | |
| 174 | static void throw_stack_overflow_exception(JavaThread* thread, const char* file, int line, const methodHandle& method); |
| 175 | |
| 176 | static void throw_unsafe_access_internal_error(JavaThread* thread, const char* file, int line, const char* message); |
| 177 | |
| 178 | static void wrap_dynamic_exception(bool is_indy, JavaThread* thread); |
| 179 | |
| 180 | // Exception counting for error files of interesting exceptions that may have |
| 181 | // caused a problem for the jvm |
| 182 | static volatile int _stack_overflow_errors; |
| 183 | |
| 184 | static bool has_exception_counts(); |
| 185 | static void count_out_of_memory_exceptions(Handle exception); |
| 186 | static void print_exception_counts_on_error(outputStream* st); |
| 187 | |
| 188 | // for AbortVMOnException flag |
| 189 | static void debug_check_abort(Handle exception, const char* message = NULL__null); |
| 190 | static void debug_check_abort_helper(Handle exception, const char* message = NULL__null); |
| 191 | static void debug_check_abort(const char *value_string, const char* message = NULL__null); |
| 192 | |
| 193 | // for logging exceptions |
| 194 | static void log_exception(Handle exception, const char* message); |
| 195 | }; |
| 196 | |
| 197 | |
| 198 | // The THREAD & TRAPS macros facilitate the declaration of functions that throw exceptions. |
| 199 | // Convention: Use the TRAPS macro as the last argument of such a function; e.g.: |
| 200 | // |
| 201 | // int this_function_may_trap(int x, float y, TRAPS) |
| 202 | |
| 203 | #define THREAD__the_thread__ __the_thread__ |
| 204 | #define TRAPSJavaThread* __the_thread__ JavaThread* THREAD__the_thread__ |
| 205 | |
| 206 | |
| 207 | // The CHECK... macros should be used to pass along a THREAD reference and to check for pending |
| 208 | // exceptions. In special situations it is necessary to handle pending exceptions explicitly, |
| 209 | // in these cases the PENDING_EXCEPTION helper macros should be used. |
| 210 | // |
| 211 | // Macro naming conventions: Macros that end with _ require a result value to be returned. They |
| 212 | // are for functions with non-void result type. The result value is usually ignored because of |
| 213 | // the exception and is only needed for syntactic correctness. The _0 ending is a shortcut for |
| 214 | // _(0) since this is a frequent case. Example: |
| 215 | // |
| 216 | // int result = this_function_may_trap(x_arg, y_arg, CHECK_0); |
| 217 | // |
| 218 | // CAUTION: make sure that the function call using a CHECK macro is not the only statement of a |
| 219 | // conditional branch w/o enclosing {} braces, since the CHECK macros expand into several state- |
| 220 | // ments! Also make sure it is not used on a function call that is part of a return statement! |
| 221 | |
| 222 | #define PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception()) (((ThreadShadow*)THREAD__the_thread__)->pending_exception()) |
| 223 | #define HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception()) (((ThreadShadow*)THREAD__the_thread__)->has_pending_exception()) |
| 224 | #define CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )) (((ThreadShadow*)THREAD__the_thread__)->clear_pending_exception()) |
| 225 | |
| 226 | #define CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) return ; (void)(0 |
| 227 | #define CHECK_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return result; (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) return result; (void)(0 |
| 228 | #define CHECK_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0 CHECK_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0 |
| 229 | #define CHECK_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return Handle(); (void)(0 CHECK_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return Handle(); (void)(0 |
| 230 | #define CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0 CHECK_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0 |
| 231 | #define CHECK_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return false; (void)(0 CHECK_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return false; (void)(0 |
| 232 | #define CHECK_JNI_ERR__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return (-1); (void)(0 CHECK_(JNI_ERR)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return (-1); (void)(0 |
| 233 | |
| 234 | // CAUTION: These macros clears all exceptions including async exceptions, use it with caution. |
| 235 | #define CHECK_AND_CLEAR__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); return; } (void)(0 |
| 236 | #define CHECK_AND_CLEAR_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return result; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); return result; } (void)(0 |
| 237 | #define CHECK_AND_CLEAR_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return 0; } (void)(0 CHECK_AND_CLEAR_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return 0; } (void)(0 |
| 238 | #define CHECK_AND_CLEAR_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return Handle(); } (void)(0 CHECK_AND_CLEAR_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return Handle(); } (void)(0 |
| 239 | #define CHECK_AND_CLEAR_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return __null; } (void)(0 CHECK_AND_CLEAR_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return __null; } (void)(0 |
| 240 | #define CHECK_AND_CLEAR_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return false; } (void)(0 CHECK_AND_CLEAR_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return false; } (void)(0 |
| 241 | |
| 242 | // CAUTION: These macros clears all exceptions except probable async exceptions j.l.InternalError and j.l.ThreadDeath. |
| 243 | // So use it with caution. |
| 244 | #define CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()) (((ThreadShadow*)THREAD__the_thread__)->clear_pending_nonasync_exception()) |
| 245 | #define CHECK_AND_CLEAR_NONASYNC__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return; } (void)(0 |
| 246 | #define CHECK_AND_CLEAR_NONASYNC_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return result; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return result; } (void)(0 |
| 247 | #define CHECK_AND_CLEAR_NONASYNC_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return 0; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return 0; } (void)(0 |
| 248 | #define CHECK_AND_CLEAR_NONASYNC_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return Handle(); } (void)(0 CHECK_AND_CLEAR_NONASYNC_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return Handle(); } (void)(0 |
| 249 | #define CHECK_AND_CLEAR_NONASYNC_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return __null; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return __null; } (void)(0 |
| 250 | #define CHECK_AND_CLEAR_NONASYNC_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return false; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return false; } (void)(0 |
| 251 | |
| 252 | // The THROW... macros should be used to throw an exception. They require a THREAD variable to be |
| 253 | // visible within the scope containing the THROW. Usually this is achieved by declaring the function |
| 254 | // with a TRAPS argument. |
| 255 | |
| 256 | #define THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 256 THREAD__the_thread__, __FILE__"/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp", __LINE__256 |
| 257 | |
| 258 | #define THROW_OOP(e){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 258, e); return; } \ |
| 259 | { Exceptions::_throw_oop(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 259, e); return; } |
| 260 | |
| 261 | #define THROW_HANDLE(e){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 261, e); return; } \ |
| 262 | { Exceptions::_throw(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 262, e); return; } |
| 263 | |
| 264 | #define THROW(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 264, name, __null); return; } \ |
| 265 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 265, name, NULL__null); return; } |
| 266 | |
| 267 | #define THROW_MSG(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 267, name, message); return; } \ |
| 268 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 268, name, message); return; } |
| 269 | |
| 270 | #define THROW_CAUSE(name, cause){ Exceptions::_throw_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 270, name, cause); return; } \ |
| 271 | { Exceptions::_throw_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 271, name, cause); return; } |
| 272 | |
| 273 | #define THROW_MSG_LOADER(name, message, loader, protection_domain){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 273, name, message, loader, protection_domain); return; } \ |
| 274 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 274, name, message, loader, protection_domain); return; } |
| 275 | |
| 276 | #define THROW_ARG(name, signature, args){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 276, name, signature, args); return; } \ |
| 277 | { Exceptions::_throw_args(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 277, name, signature, args); return; } |
| 278 | |
| 279 | #define THROW_OOP_(e, result){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 279, e); return result; } \ |
| 280 | { Exceptions::_throw_oop(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 280, e); return result; } |
| 281 | |
| 282 | #define THROW_HANDLE_(e, result){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 282, e); return result; } \ |
| 283 | { Exceptions::_throw(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 283, e); return result; } |
| 284 | |
| 285 | #define THROW_(name, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 285, name, __null); return result; } \ |
| 286 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 286, name, NULL__null); return result; } |
| 287 | |
| 288 | #define THROW_MSG_(name, message, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 288, name, message); return result; } \ |
| 289 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 289, name, message); return result; } |
| 290 | |
| 291 | #define THROW_MSG_LOADER_(name, message, loader, protection_domain, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 291, name, message, loader, protection_domain); return result ; } \ |
| 292 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 292, name, message, loader, protection_domain); return result; } |
| 293 | |
| 294 | #define THROW_ARG_(name, signature, args, result){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 294, name, signature, args); return result; } \ |
| 295 | { Exceptions::_throw_args(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 295, name, signature, args); return result; } |
| 296 | |
| 297 | #define THROW_MSG_CAUSE(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 297, name, message, cause); return; } \ |
| 298 | { Exceptions::_throw_msg_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 298, name, message, cause); return; } |
| 299 | |
| 300 | #define THROW_MSG_CAUSE_(name, message, cause, result){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 300, name, message, cause); return result; } \ |
| 301 | { Exceptions::_throw_msg_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 301, name, message, cause); return result; } |
| 302 | |
| 303 | |
| 304 | #define THROW_OOP_0(e){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 304, e); return 0; } THROW_OOP_(e, 0){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 304, e); return 0; } |
| 305 | #define THROW_HANDLE_0(e){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 305, e); return 0; } THROW_HANDLE_(e, 0){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 305, e); return 0; } |
| 306 | #define THROW_0(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 306, name, __null); return 0; } THROW_(name, 0){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 306, name, __null); return 0; } |
| 307 | #define THROW_MSG_0(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 307, name, message); return 0; } THROW_MSG_(name, message, 0){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 307, name, message); return 0; } |
| 308 | #define THROW_WRAPPED_0(name, oop_to_wrap)THROW_WRAPPED_(name, oop_to_wrap, 0) THROW_WRAPPED_(name, oop_to_wrap, 0) |
| 309 | #define THROW_ARG_0(name, signature, arg){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 309, name, signature, arg); return 0; } THROW_ARG_(name, signature, arg, 0){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 309, name, signature, arg); return 0; } |
| 310 | #define THROW_MSG_CAUSE_0(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 310, name, message, cause); return 0; } THROW_MSG_CAUSE_(name, message, cause, 0){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 310, name, message, cause); return 0; } |
| 311 | #define THROW_MSG_CAUSE_NULL(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 311, name, message, cause); return __null; } THROW_MSG_CAUSE_(name, message, cause, NULL){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 311, name, message, cause); return __null; } |
| 312 | |
| 313 | #define THROW_NULL(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 313, name, __null); return __null; } THROW_(name, NULL){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 313, name, __null); return __null; } |
| 314 | #define THROW_MSG_NULL(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 314, name, message); return __null; } THROW_MSG_(name, message, NULL){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 314, name, message); return __null; } |
| 315 | |
| 316 | // The CATCH macro checks that no exception has been thrown by a function; it is used at |
| 317 | // call sites about which is statically known that the callee cannot throw an exception |
| 318 | // even though it is declared with TRAPS. |
| 319 | |
| 320 | #define CATCH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { oop ex = (((ThreadShadow*)__the_thread__)->pending_exception ()); (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); ex->print(); do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 320, "assert(" "false" ") failed", "CATCH"); ::breakpoint() ; } } while (0); } (void)(0 \ |
| 321 | THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { \ |
| 322 | oop ex = PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception()); \ |
| 323 | CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); \ |
| 324 | DEBUG_ONLY(ex->print();)ex->print(); \ |
| 325 | assert(false, "CATCH")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 325, "assert(" "false" ") failed", "CATCH"); ::breakpoint() ; } } while (0); \ |
| 326 | } (void)(0 |
| 327 | |
| 328 | // ExceptionMark is a stack-allocated helper class for local exception handling. |
| 329 | // It is used with the EXCEPTION_MARK macro. |
| 330 | |
| 331 | class ExceptionMark { |
| 332 | private: |
| 333 | JavaThread* _thread; |
| 334 | inline void check_no_pending_exception(); |
| 335 | |
| 336 | public: |
| 337 | ExceptionMark(); |
| 338 | ExceptionMark(JavaThread* thread); |
| 339 | ~ExceptionMark(); |
| 340 | |
| 341 | JavaThread* thread() { |
| 342 | return _thread; |
| 343 | } |
| 344 | }; |
| 345 | |
| 346 | // Use an EXCEPTION_MARK for 'local' exceptions. EXCEPTION_MARK makes sure that no |
| 347 | // pending exception exists upon entering its scope and tests that no pending exception |
| 348 | // exists when leaving the scope. |
| 349 | |
| 350 | // See also preserveException.hpp for PreserveExceptionMark |
| 351 | // which preserves pre-existing exceptions and does not allow new |
| 352 | // exceptions. |
| 353 | |
| 354 | #define EXCEPTION_MARKExceptionMark __em; JavaThread* __the_thread__ = __em.thread( ); ExceptionMark __em; JavaThread* THREAD__the_thread__ = __em.thread(); |
| 355 | |
| 356 | #endif // SHARE_UTILITIES_EXCEPTIONS_HPP |
| 1 | /* |
| 2 | * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_OOPS_OOPSHIERARCHY_HPP |
| 26 | #define SHARE_OOPS_OOPSHIERARCHY_HPP |
| 27 | |
| 28 | #include "metaprogramming/integralConstant.hpp" |
| 29 | #include "metaprogramming/primitiveConversions.hpp" |
| 30 | #include "utilities/globalDefinitions.hpp" |
| 31 | |
| 32 | // OBJECT hierarchy |
| 33 | // This hierarchy is a representation hierarchy, i.e. if A is a superclass |
| 34 | // of B, A's representation is a prefix of B's representation. |
| 35 | |
| 36 | // Global offset instead of address for an oop within a java object. |
| 37 | enum class narrowOop : uint32_t { null = 0 }; |
| 38 | |
| 39 | // If compressed klass pointers then use narrowKlass. |
| 40 | typedef juint narrowKlass; |
| 41 | |
| 42 | typedef void* OopOrNarrowOopStar; |
| 43 | |
| 44 | #ifndef CHECK_UNHANDLED_OOPS1 |
| 45 | |
| 46 | typedef class oopDesc* oop; |
| 47 | typedef class instanceOopDesc* instanceOop; |
| 48 | typedef class arrayOopDesc* arrayOop; |
| 49 | typedef class objArrayOopDesc* objArrayOop; |
| 50 | typedef class typeArrayOopDesc* typeArrayOop; |
| 51 | |
| 52 | #else |
| 53 | |
| 54 | // When CHECK_UNHANDLED_OOPS is defined, an "oop" is a class with a |
| 55 | // carefully chosen set of constructors and conversion operators to go |
| 56 | // to and from the underlying oopDesc pointer type. |
| 57 | // |
| 58 | // Because oop and its subclasses <type>Oop are class types, arbitrary |
| 59 | // conversions are not accepted by the compiler. Applying a cast to |
| 60 | // an oop will cause the best matched conversion operator to be |
| 61 | // invoked returning the underlying oopDesc* type if appropriate. |
| 62 | // No copy constructors, explicit user conversions or operators of |
| 63 | // numerical type should be defined within the oop class. Most C++ |
| 64 | // compilers will issue a compile time error concerning the overloading |
| 65 | // ambiguity between operators of numerical and pointer types. If |
| 66 | // a conversion to or from an oop to a numerical type is needed, |
| 67 | // use the inline template methods, cast_*_oop, defined below. |
| 68 | // |
| 69 | // Converting NULL to oop to Handle implicit is no longer accepted by the |
| 70 | // compiler because there are too many steps in the conversion. Use Handle() |
| 71 | // instead, which generates less code anyway. |
| 72 | |
| 73 | class Thread; |
| 74 | class oopDesc; |
| 75 | |
| 76 | extern "C" bool CheckUnhandledOops; |
| 77 | |
| 78 | class oop { |
| 79 | oopDesc* _o; |
| 80 | |
| 81 | void register_oop(); |
| 82 | void unregister_oop(); |
| 83 | |
| 84 | void register_if_checking() { |
| 85 | if (CheckUnhandledOops) register_oop(); |
| 86 | } |
| 87 | |
| 88 | public: |
| 89 | oop() : _o(nullptr) { register_if_checking(); } |
| 90 | oop(const oop& o) : _o(o._o) { register_if_checking(); } |
| 91 | oop(oopDesc* o) : _o(o) { register_if_checking(); } |
| 92 | ~oop() { |
| 93 | if (CheckUnhandledOops) unregister_oop(); |
| 94 | } |
| 95 | |
| 96 | oopDesc* obj() const { return _o; } |
| 97 | oopDesc* operator->() const { return _o; } |
| 98 | operator oopDesc* () const { return _o; } |
| 99 | |
| 100 | bool operator==(const oop& o) const { return _o == o._o; } |
| 101 | bool operator!=(const oop& o) const { return _o != o._o; } |
| 102 | |
| 103 | bool operator==(std::nullptr_t) const { return _o == nullptr; } |
| 104 | bool operator!=(std::nullptr_t) const { return _o != nullptr; } |
| 105 | |
| 106 | oop& operator=(const oop& o) { _o = o._o; return *this; } |
| 107 | }; |
| 108 | |
| 109 | template<> |
| 110 | struct PrimitiveConversions::Translate<oop> : public TrueType { |
| 111 | typedef oop Value; |
| 112 | typedef oopDesc* Decayed; |
| 113 | |
| 114 | static Decayed decay(Value x) { return x.obj(); } |
| 115 | static Value recover(Decayed x) { return oop(x); } |
| 116 | }; |
| 117 | |
| 118 | #define DEF_OOP(type)class typeOopDesc; class typeOop : public oop { public: typeOop () : oop() {} typeOop(const typeOop& o) : oop(o) {} typeOop (const oop& o) : oop(o) {} typeOop(typeOopDesc* o) : oop( (oopDesc*)o) {} operator typeOopDesc* () const { return (typeOopDesc *)obj(); } typeOopDesc* operator->() const { return (typeOopDesc *)obj(); } typeOop& operator=(const typeOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeOop> : public TrueType { typedef typeOop Value; typedef typeOopDesc* Decayed; static Decayed decay(Value x) { return (typeOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeOop(x); } }; \ |
| 119 | class type##OopDesc; \ |
| 120 | class type##Oop : public oop { \ |
| 121 | public: \ |
| 122 | type##Oop() : oop() {} \ |
| 123 | type##Oop(const type##Oop& o) : oop(o) {} \ |
| 124 | type##Oop(const oop& o) : oop(o) {} \ |
| 125 | type##Oop(type##OopDesc* o) : oop((oopDesc*)o) {} \ |
| 126 | operator type##OopDesc* () const { return (type##OopDesc*)obj(); } \ |
| 127 | type##OopDesc* operator->() const { \ |
| 128 | return (type##OopDesc*)obj(); \ |
| 129 | } \ |
| 130 | type##Oop& operator=(const type##Oop& o) { \ |
| 131 | oop::operator=(o); \ |
| 132 | return *this; \ |
| 133 | } \ |
| 134 | }; \ |
| 135 | \ |
| 136 | template<> \ |
| 137 | struct PrimitiveConversions::Translate<type##Oop> : public TrueType { \ |
| 138 | typedef type##Oop Value; \ |
| 139 | typedef type##OopDesc* Decayed; \ |
| 140 | \ |
| 141 | static Decayed decay(Value x) { return (type##OopDesc*)x.obj(); } \ |
| 142 | static Value recover(Decayed x) { return type##Oop(x); } \ |
| 143 | }; |
| 144 | |
| 145 | DEF_OOP(instance)class instanceOopDesc; class instanceOop : public oop { public : instanceOop() : oop() {} instanceOop(const instanceOop& o) : oop(o) {} instanceOop(const oop& o) : oop(o) {} instanceOop (instanceOopDesc* o) : oop((oopDesc*)o) {} operator instanceOopDesc * () const { return (instanceOopDesc*)obj(); } instanceOopDesc * operator->() const { return (instanceOopDesc*)obj(); } instanceOop & operator=(const instanceOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<instanceOop> : public TrueType { typedef instanceOop Value; typedef instanceOopDesc* Decayed; static Decayed decay (Value x) { return (instanceOopDesc*)x.obj(); } static Value recover (Decayed x) { return instanceOop(x); } };; |
| 146 | DEF_OOP(array)class arrayOopDesc; class arrayOop : public oop { public: arrayOop () : oop() {} arrayOop(const arrayOop& o) : oop(o) {} arrayOop (const oop& o) : oop(o) {} arrayOop(arrayOopDesc* o) : oop ((oopDesc*)o) {} operator arrayOopDesc* () const { return (arrayOopDesc *)obj(); } arrayOopDesc* operator->() const { return (arrayOopDesc *)obj(); } arrayOop& operator=(const arrayOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<arrayOop> : public TrueType { typedef arrayOop Value; typedef arrayOopDesc* Decayed; static Decayed decay(Value x) { return (arrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return arrayOop(x); } };; |
| 147 | DEF_OOP(objArray)class objArrayOopDesc; class objArrayOop : public oop { public : objArrayOop() : oop() {} objArrayOop(const objArrayOop& o) : oop(o) {} objArrayOop(const oop& o) : oop(o) {} objArrayOop (objArrayOopDesc* o) : oop((oopDesc*)o) {} operator objArrayOopDesc * () const { return (objArrayOopDesc*)obj(); } objArrayOopDesc * operator->() const { return (objArrayOopDesc*)obj(); } objArrayOop & operator=(const objArrayOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<objArrayOop> : public TrueType { typedef objArrayOop Value; typedef objArrayOopDesc* Decayed; static Decayed decay (Value x) { return (objArrayOopDesc*)x.obj(); } static Value recover (Decayed x) { return objArrayOop(x); } };; |
| 148 | DEF_OOP(typeArray)class typeArrayOopDesc; class typeArrayOop : public oop { public : typeArrayOop() : oop() {} typeArrayOop(const typeArrayOop& o) : oop(o) {} typeArrayOop(const oop& o) : oop(o) {} typeArrayOop (typeArrayOopDesc* o) : oop((oopDesc*)o) {} operator typeArrayOopDesc * () const { return (typeArrayOopDesc*)obj(); } typeArrayOopDesc * operator->() const { return (typeArrayOopDesc*)obj(); } typeArrayOop & operator=(const typeArrayOop& o) { oop::operator=(o ); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeArrayOop> : public TrueType { typedef typeArrayOop Value; typedef typeArrayOopDesc* Decayed; static Decayed decay (Value x) { return (typeArrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeArrayOop(x); } };; |
| 149 | |
| 150 | #endif // CHECK_UNHANDLED_OOPS |
| 151 | |
| 152 | // Cast functions to convert to and from oops. |
| 153 | template <typename T> inline oop cast_to_oop(T value) { |
| 154 | return (oopDesc*)value; |
| 155 | } |
| 156 | template <typename T> inline T cast_from_oop(oop o) { |
| 157 | return (T)(CHECK_UNHANDLED_OOPS_ONLY((oopDesc*))(oopDesc*)o); |
| 158 | } |
| 159 | |
| 160 | // The metadata hierarchy is separate from the oop hierarchy |
| 161 | |
| 162 | // class MetaspaceObj |
| 163 | class ConstMethod; |
| 164 | class ConstantPoolCache; |
| 165 | class MethodData; |
| 166 | // class Metadata |
| 167 | class Method; |
| 168 | class ConstantPool; |
| 169 | // class CHeapObj |
| 170 | class CompiledICHolder; |
| 171 | |
| 172 | |
| 173 | // The klass hierarchy is separate from the oop hierarchy. |
| 174 | |
| 175 | class Klass; |
| 176 | class InstanceKlass; |
| 177 | class InstanceMirrorKlass; |
| 178 | class InstanceClassLoaderKlass; |
| 179 | class InstanceRefKlass; |
| 180 | class ArrayKlass; |
| 181 | class ObjArrayKlass; |
| 182 | class TypeArrayKlass; |
| 183 | |
| 184 | #endif // SHARE_OOPS_OOPSHIERARCHY_HPP |
| 1 | /* |
| 2 | * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_OOPS_METHOD_HPP |
| 26 | #define SHARE_OOPS_METHOD_HPP |
| 27 | |
| 28 | #include "code/compressedStream.hpp" |
| 29 | #include "compiler/compilerDefinitions.hpp" |
| 30 | #include "interpreter/invocationCounter.hpp" |
| 31 | #include "oops/annotations.hpp" |
| 32 | #include "oops/constantPool.hpp" |
| 33 | #include "oops/methodCounters.hpp" |
| 34 | #include "oops/instanceKlass.hpp" |
| 35 | #include "oops/oop.hpp" |
| 36 | #include "oops/typeArrayOop.hpp" |
| 37 | #include "utilities/accessFlags.hpp" |
| 38 | #include "utilities/align.hpp" |
| 39 | #include "utilities/growableArray.hpp" |
| 40 | #include "utilities/macros.hpp" |
| 41 | #include "utilities/vmEnums.hpp" |
| 42 | #if INCLUDE_JFR1 |
| 43 | #include "jfr/support/jfrTraceIdExtension.hpp" |
| 44 | #endif |
| 45 | |
| 46 | |
| 47 | // A Method represents a Java method. |
| 48 | // |
| 49 | // Note that most applications load thousands of methods, so keeping the size of this |
| 50 | // class small has a big impact on footprint. |
| 51 | // |
| 52 | // Note that native_function and signature_handler have to be at fixed offsets |
| 53 | // (required by the interpreter) |
| 54 | // |
| 55 | // Method embedded field layout (after declared fields): |
| 56 | // [EMBEDDED native_function (present only if native) ] |
| 57 | // [EMBEDDED signature_handler (present only if native) ] |
| 58 | |
| 59 | class CheckedExceptionElement; |
| 60 | class LocalVariableTableElement; |
| 61 | class AdapterHandlerEntry; |
| 62 | class MethodData; |
| 63 | class MethodCounters; |
| 64 | class ConstMethod; |
| 65 | class InlineTableSizes; |
| 66 | class CompiledMethod; |
| 67 | class InterpreterOopMap; |
| 68 | |
| 69 | class Method : public Metadata { |
| 70 | friend class VMStructs; |
| 71 | friend class JVMCIVMStructs; |
| 72 | private: |
| 73 | // If you add a new field that points to any metaspace object, you |
| 74 | // must add this field to Method::metaspace_pointers_do(). |
| 75 | ConstMethod* _constMethod; // Method read-only data. |
| 76 | MethodData* _method_data; |
| 77 | MethodCounters* _method_counters; |
| 78 | AdapterHandlerEntry* _adapter; |
| 79 | AccessFlags _access_flags; // Access flags |
| 80 | int _vtable_index; // vtable index of this method (see VtableIndexFlag) |
| 81 | // note: can have vtables with >2**16 elements (because of inheritance) |
| 82 | u2 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none) |
| 83 | |
| 84 | // Flags |
| 85 | enum Flags { |
| 86 | _caller_sensitive = 1 << 0, |
| 87 | _force_inline = 1 << 1, |
| 88 | _dont_inline = 1 << 2, |
| 89 | _hidden = 1 << 3, |
| 90 | _has_injected_profile = 1 << 4, |
| 91 | _intrinsic_candidate = 1 << 5, |
| 92 | _reserved_stack_access = 1 << 6, |
| 93 | _scoped = 1 << 7 |
| 94 | }; |
| 95 | mutable u2 _flags; |
| 96 | |
| 97 | JFR_ONLY(DEFINE_TRACE_FLAG;)mutable JfrTraceFlag _trace_flags; |
| 98 | |
| 99 | #ifndef PRODUCT |
| 100 | int64_t _compiled_invocation_count; |
| 101 | #endif |
| 102 | // Entry point for calling both from and to the interpreter. |
| 103 | address _i2i_entry; // All-args-on-stack calling convention |
| 104 | // Entry point for calling from compiled code, to compiled code if it exists |
| 105 | // or else the interpreter. |
| 106 | volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() |
| 107 | // The entry point for calling both from and to compiled code is |
| 108 | // "_code->entry_point()". Because of tiered compilation and de-opt, this |
| 109 | // field can come and go. It can transition from NULL to not-null at any |
| 110 | // time (whenever a compile completes). It can transition from not-null to |
| 111 | // NULL only at safepoints (because of a de-opt). |
| 112 | CompiledMethod* volatile _code; // Points to the corresponding piece of native code |
| 113 | volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry |
| 114 | |
| 115 | // Constructor |
| 116 | Method(ConstMethod* xconst, AccessFlags access_flags); |
| 117 | public: |
| 118 | |
| 119 | static Method* allocate(ClassLoaderData* loader_data, |
| 120 | int byte_code_size, |
| 121 | AccessFlags access_flags, |
| 122 | InlineTableSizes* sizes, |
| 123 | ConstMethod::MethodType method_type, |
| 124 | TRAPSJavaThread* __the_thread__); |
| 125 | |
| 126 | // CDS and vtbl checking can create an empty Method to get vtbl pointer. |
| 127 | Method(){} |
| 128 | |
| 129 | virtual bool is_method() const { return true; } |
| 130 | |
| 131 | void restore_unshareable_info(TRAPSJavaThread* __the_thread__); |
| 132 | |
| 133 | // accessors for instance variables |
| 134 | |
| 135 | ConstMethod* constMethod() const { return _constMethod; } |
| 136 | void set_constMethod(ConstMethod* xconst) { _constMethod = xconst; } |
| 137 | |
| 138 | |
| 139 | static address make_adapters(const methodHandle& mh, TRAPSJavaThread* __the_thread__); |
| 140 | address from_compiled_entry() const; |
| 141 | address from_compiled_entry_no_trampoline() const; |
| 142 | address from_interpreted_entry() const; |
| 143 | |
| 144 | // access flag |
| 145 | AccessFlags access_flags() const { return _access_flags; } |
| 146 | void set_access_flags(AccessFlags flags) { _access_flags = flags; } |
| 147 | |
| 148 | // name |
| 149 | Symbol* name() const { return constants()->symbol_at(name_index()); } |
| 150 | int name_index() const { return constMethod()->name_index(); } |
| 151 | void set_name_index(int index) { constMethod()->set_name_index(index); } |
| 152 | |
| 153 | // signature |
| 154 | Symbol* signature() const { return constants()->symbol_at(signature_index()); } |
| 155 | int signature_index() const { return constMethod()->signature_index(); } |
| 156 | void set_signature_index(int index) { constMethod()->set_signature_index(index); } |
| 157 | |
| 158 | // generics support |
| 159 | Symbol* generic_signature() const { int idx = generic_signature_index(); return ((idx != 0) ? constants()->symbol_at(idx) : (Symbol*)NULL__null); } |
| 160 | int generic_signature_index() const { return constMethod()->generic_signature_index(); } |
| 161 | void set_generic_signature_index(int index) { constMethod()->set_generic_signature_index(index); } |
| 162 | |
| 163 | // annotations support |
| 164 | AnnotationArray* annotations() const { |
| 165 | return constMethod()->method_annotations(); |
| 166 | } |
| 167 | AnnotationArray* parameter_annotations() const { |
| 168 | return constMethod()->parameter_annotations(); |
| 169 | } |
| 170 | AnnotationArray* annotation_default() const { |
| 171 | return constMethod()->default_annotations(); |
| 172 | } |
| 173 | AnnotationArray* type_annotations() const { |
| 174 | return constMethod()->type_annotations(); |
| 175 | } |
| 176 | |
| 177 | // Helper routine: get klass name + "." + method name + signature as |
| 178 | // C string, for the purpose of providing more useful |
| 179 | // fatal error handling. The string is allocated in resource |
| 180 | // area if a buffer is not provided by the caller. |
| 181 | char* name_and_sig_as_C_string() const; |
| 182 | char* name_and_sig_as_C_string(char* buf, int size) const; |
| 183 | |
| 184 | // Static routine in the situations we don't have a Method* |
| 185 | static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature); |
| 186 | static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, char* buf, int size); |
| 187 | |
| 188 | // Get return type + klass name + "." + method name + ( parameters types ) |
| 189 | // as a C string or print it to an outputStream. |
| 190 | // This is to be used to assemble strings passed to Java, so that |
| 191 | // the text more resembles Java code. Used in exception messages. |
| 192 | // Memory is allocated in the resource area; the caller needs |
| 193 | // a ResourceMark. |
| 194 | const char* external_name() const; |
| 195 | void print_external_name(outputStream *os) const; |
| 196 | |
| 197 | static const char* external_name( Klass* klass, Symbol* method_name, Symbol* signature); |
| 198 | static void print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature); |
| 199 | |
| 200 | Bytecodes::Code java_code_at(int bci) const { |
| 201 | return Bytecodes::java_code_at(this, bcp_from(bci)); |
| 202 | } |
| 203 | Bytecodes::Code code_at(int bci) const { |
| 204 | return Bytecodes::code_at(this, bcp_from(bci)); |
| 205 | } |
| 206 | |
| 207 | // JVMTI breakpoints |
| 208 | #if !INCLUDE_JVMTI1 |
| 209 | Bytecodes::Code orig_bytecode_at(int bci) const { |
| 210 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 210); ::breakpoint(); } while (0); |
| 211 | return Bytecodes::_shouldnotreachhere; |
| 212 | } |
| 213 | void set_orig_bytecode_at(int bci, Bytecodes::Code code) { |
| 214 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 214); ::breakpoint(); } while (0); |
| 215 | }; |
| 216 | u2 number_of_breakpoints() const {return 0;} |
| 217 | #else // !INCLUDE_JVMTI |
| 218 | Bytecodes::Code orig_bytecode_at(int bci) const; |
| 219 | void set_orig_bytecode_at(int bci, Bytecodes::Code code); |
| 220 | void set_breakpoint(int bci); |
| 221 | void clear_breakpoint(int bci); |
| 222 | void clear_all_breakpoints(); |
| 223 | // Tracking number of breakpoints, for fullspeed debugging. |
| 224 | // Only mutated by VM thread. |
| 225 | u2 number_of_breakpoints() const { |
| 226 | MethodCounters* mcs = method_counters(); |
| 227 | if (mcs == NULL__null) { |
| 228 | return 0; |
| 229 | } else { |
| 230 | return mcs->number_of_breakpoints(); |
| 231 | } |
| 232 | } |
| 233 | void incr_number_of_breakpoints(Thread* current) { |
| 234 | MethodCounters* mcs = get_method_counters(current); |
| 235 | if (mcs != NULL__null) { |
| 236 | mcs->incr_number_of_breakpoints(); |
| 237 | } |
| 238 | } |
| 239 | void decr_number_of_breakpoints(Thread* current) { |
| 240 | MethodCounters* mcs = get_method_counters(current); |
| 241 | if (mcs != NULL__null) { |
| 242 | mcs->decr_number_of_breakpoints(); |
| 243 | } |
| 244 | } |
| 245 | // Initialization only |
| 246 | void clear_number_of_breakpoints() { |
| 247 | MethodCounters* mcs = method_counters(); |
| 248 | if (mcs != NULL__null) { |
| 249 | mcs->clear_number_of_breakpoints(); |
| 250 | } |
| 251 | } |
| 252 | #endif // !INCLUDE_JVMTI |
| 253 | |
| 254 | // index into InstanceKlass methods() array |
| 255 | // note: also used by jfr |
| 256 | u2 method_idnum() const { return constMethod()->method_idnum(); } |
| 257 | void set_method_idnum(u2 idnum) { constMethod()->set_method_idnum(idnum); } |
| 258 | |
| 259 | u2 orig_method_idnum() const { return constMethod()->orig_method_idnum(); } |
| 260 | void set_orig_method_idnum(u2 idnum) { constMethod()->set_orig_method_idnum(idnum); } |
| 261 | |
| 262 | // code size |
| 263 | int code_size() const { return constMethod()->code_size(); } |
| 264 | |
| 265 | // method size in words |
| 266 | int method_size() const { return sizeof(Method)/wordSize + ( is_native() ? 2 : 0 ); } |
| 267 | |
| 268 | // constant pool for Klass* holding this method |
| 269 | ConstantPool* constants() const { return constMethod()->constants(); } |
| 270 | void set_constants(ConstantPool* c) { constMethod()->set_constants(c); } |
| 271 | |
| 272 | // max stack |
| 273 | // return original max stack size for method verification |
| 274 | int verifier_max_stack() const { return constMethod()->max_stack(); } |
| 275 | int max_stack() const { return constMethod()->max_stack() + extra_stack_entries(); } |
| 276 | void set_max_stack(int size) { constMethod()->set_max_stack(size); } |
| 277 | |
| 278 | // max locals |
| 279 | int max_locals() const { return constMethod()->max_locals(); } |
| 280 | void set_max_locals(int size) { constMethod()->set_max_locals(size); } |
| 281 | |
| 282 | int highest_comp_level() const; |
| 283 | void set_highest_comp_level(int level); |
| 284 | int highest_osr_comp_level() const; |
| 285 | void set_highest_osr_comp_level(int level); |
| 286 | |
| 287 | #if COMPILER2_OR_JVMCI1 |
| 288 | // Count of times method was exited via exception while interpreting |
| 289 | void interpreter_throwout_increment(Thread* current) { |
| 290 | MethodCounters* mcs = get_method_counters(current); |
| 291 | if (mcs != NULL__null) { |
| 292 | mcs->interpreter_throwout_increment(); |
| 293 | } |
| 294 | } |
| 295 | #endif |
| 296 | |
| 297 | int interpreter_throwout_count() const { |
| 298 | MethodCounters* mcs = method_counters(); |
| 299 | if (mcs == NULL__null) { |
| 300 | return 0; |
| 301 | } else { |
| 302 | return mcs->interpreter_throwout_count(); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | // Derive stuff from the signature at load time. |
| 307 | void compute_from_signature(Symbol* sig); |
| 308 | |
| 309 | // size of parameters (receiver if any + arguments) |
| 310 | int size_of_parameters() const { return constMethod()->size_of_parameters(); } |
| 311 | void set_size_of_parameters(int size) { constMethod()->set_size_of_parameters(size); } |
| 312 | |
| 313 | bool has_stackmap_table() const { |
| 314 | return constMethod()->has_stackmap_table(); |
| 315 | } |
| 316 | |
| 317 | Array<u1>* stackmap_data() const { |
| 318 | return constMethod()->stackmap_data(); |
| 319 | } |
| 320 | |
| 321 | void set_stackmap_data(Array<u1>* sd) { |
| 322 | constMethod()->set_stackmap_data(sd); |
| 323 | } |
| 324 | |
| 325 | // exception handler table |
| 326 | bool has_exception_handler() const |
| 327 | { return constMethod()->has_exception_handler(); } |
| 328 | int exception_table_length() const |
| 329 | { return constMethod()->exception_table_length(); } |
| 330 | ExceptionTableElement* exception_table_start() const |
| 331 | { return constMethod()->exception_table_start(); } |
| 332 | |
| 333 | // Finds the first entry point bci of an exception handler for an |
| 334 | // exception of klass ex_klass thrown at throw_bci. A value of NULL |
| 335 | // for ex_klass indicates that the exception klass is not known; in |
| 336 | // this case it matches any constraint class. Returns -1 if the |
| 337 | // exception cannot be handled in this method. The handler |
| 338 | // constraint classes are loaded if necessary. Note that this may |
| 339 | // throw an exception if loading of the constraint classes causes |
| 340 | // an IllegalAccessError (bugid 4307310) or an OutOfMemoryError. |
| 341 | // If an exception is thrown, returns the bci of the |
| 342 | // exception handler which caused the exception to be thrown, which |
| 343 | // is needed for proper retries. See, for example, |
| 344 | // InterpreterRuntime::exception_handler_for_exception. |
| 345 | static int fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_klass, int throw_bci, TRAPSJavaThread* __the_thread__); |
| 346 | |
| 347 | static bool register_native(Klass* k, |
| 348 | Symbol* name, |
| 349 | Symbol* signature, |
| 350 | address entry, |
| 351 | TRAPSJavaThread* __the_thread__); |
| 352 | |
| 353 | // method data access |
| 354 | MethodData* method_data() const { |
| 355 | return _method_data; |
| 356 | } |
| 357 | |
| 358 | void set_method_data(MethodData* data); |
| 359 | |
| 360 | MethodCounters* method_counters() const { |
| 361 | return _method_counters; |
| 362 | } |
| 363 | |
| 364 | void clear_method_counters() { |
| 365 | _method_counters = NULL__null; |
| 366 | } |
| 367 | |
| 368 | bool init_method_counters(MethodCounters* counters); |
| 369 | |
| 370 | int prev_event_count() const { |
| 371 | MethodCounters* mcs = method_counters(); |
| 372 | return mcs == NULL__null ? 0 : mcs->prev_event_count(); |
| 373 | } |
| 374 | void set_prev_event_count(int count) { |
| 375 | MethodCounters* mcs = method_counters(); |
| 376 | if (mcs != NULL__null) { |
| 377 | mcs->set_prev_event_count(count); |
| 378 | } |
| 379 | } |
| 380 | jlong prev_time() const { |
| 381 | MethodCounters* mcs = method_counters(); |
| 382 | return mcs == NULL__null ? 0 : mcs->prev_time(); |
| 383 | } |
| 384 | void set_prev_time(jlong time) { |
| 385 | MethodCounters* mcs = method_counters(); |
| 386 | if (mcs != NULL__null) { |
| 387 | mcs->set_prev_time(time); |
| 388 | } |
| 389 | } |
| 390 | float rate() const { |
| 391 | MethodCounters* mcs = method_counters(); |
| 392 | return mcs == NULL__null ? 0 : mcs->rate(); |
| 393 | } |
| 394 | void set_rate(float rate) { |
| 395 | MethodCounters* mcs = method_counters(); |
| 396 | if (mcs != NULL__null) { |
| 397 | mcs->set_rate(rate); |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | int nmethod_age() const { |
| 402 | if (method_counters() == NULL__null) { |
| 403 | return INT_MAX2147483647; |
| 404 | } else { |
| 405 | return method_counters()->nmethod_age(); |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | int invocation_count() const; |
| 410 | int backedge_count() const; |
| 411 | |
| 412 | bool was_executed_more_than(int n); |
| 413 | bool was_never_executed() { return !was_executed_more_than(0); } |
| 414 | |
| 415 | static void build_interpreter_method_data(const methodHandle& method, TRAPSJavaThread* __the_thread__); |
| 416 | |
| 417 | static MethodCounters* build_method_counters(Thread* current, Method* m); |
| 418 | |
| 419 | int interpreter_invocation_count() { return invocation_count(); } |
| 420 | |
| 421 | #ifndef PRODUCT |
| 422 | int64_t compiled_invocation_count() const { return _compiled_invocation_count;} |
| 423 | void set_compiled_invocation_count(int count) { _compiled_invocation_count = (int64_t)count; } |
| 424 | #else |
| 425 | // for PrintMethodData in a product build |
| 426 | int64_t compiled_invocation_count() const { return 0; } |
| 427 | #endif // not PRODUCT |
| 428 | |
| 429 | // Clear (non-shared space) pointers which could not be relevant |
| 430 | // if this (shared) method were mapped into another JVM. |
| 431 | void remove_unshareable_info(); |
| 432 | |
| 433 | // nmethod/verified compiler entry |
| 434 | address verified_code_entry(); |
| 435 | bool check_code() const; // Not inline to avoid circular ref |
| 436 | CompiledMethod* volatile code() const; |
| 437 | |
| 438 | // Locks CompiledMethod_lock if not held. |
| 439 | void unlink_code(CompiledMethod *compare); |
| 440 | // Locks CompiledMethod_lock if not held. |
| 441 | void unlink_code(); |
| 442 | |
| 443 | private: |
| 444 | // Either called with CompiledMethod_lock held or from constructor. |
| 445 | void clear_code(); |
| 446 | |
| 447 | public: |
| 448 | static void set_code(const methodHandle& mh, CompiledMethod* code); |
| 449 | void set_adapter_entry(AdapterHandlerEntry* adapter) { |
| 450 | _adapter = adapter; |
| 451 | } |
| 452 | void set_from_compiled_entry(address entry) { |
| 453 | _from_compiled_entry = entry; |
| 454 | } |
| 455 | |
| 456 | address get_i2c_entry(); |
| 457 | address get_c2i_entry(); |
| 458 | address get_c2i_unverified_entry(); |
| 459 | address get_c2i_no_clinit_check_entry(); |
| 460 | AdapterHandlerEntry* adapter() const { |
| 461 | return _adapter; |
| 462 | } |
| 463 | // setup entry points |
| 464 | void link_method(const methodHandle& method, TRAPSJavaThread* __the_thread__); |
| 465 | // clear entry points. Used by sharing code during dump time |
| 466 | void unlink_method() NOT_CDS_RETURN; |
| 467 | |
| 468 | virtual void metaspace_pointers_do(MetaspaceClosure* iter); |
| 469 | virtual MetaspaceObj::Type type() const { return MethodType; } |
| 470 | |
| 471 | // vtable index |
| 472 | enum VtableIndexFlag { |
| 473 | // Valid vtable indexes are non-negative (>= 0). |
| 474 | // These few negative values are used as sentinels. |
| 475 | itable_index_max = -10, // first itable index, growing downward |
| 476 | pending_itable_index = -9, // itable index will be assigned |
| 477 | invalid_vtable_index = -4, // distinct from any valid vtable index |
| 478 | garbage_vtable_index = -3, // not yet linked; no vtable layout yet |
| 479 | nonvirtual_vtable_index = -2 // there is no need for vtable dispatch |
| 480 | // 6330203 Note: Do not use -1, which was overloaded with many meanings. |
| 481 | }; |
| 482 | DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; })bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index ; } |
| 483 | bool has_vtable_index() const { return _vtable_index >= 0; } |
| 484 | int vtable_index() const { return _vtable_index; } |
| 485 | void set_vtable_index(int index); |
| 486 | DEBUG_ONLY(bool valid_itable_index() const { return _vtable_index <= pending_itable_index; })bool valid_itable_index() const { return _vtable_index <= pending_itable_index ; } |
| 487 | bool has_itable_index() const { return _vtable_index <= itable_index_max; } |
| 488 | int itable_index() const { assert(valid_itable_index(), "")do { if (!(valid_itable_index())) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 488, "assert(" "valid_itable_index()" ") failed", ""); ::breakpoint (); } } while (0); |
| 489 | return itable_index_max - _vtable_index; } |
| 490 | void set_itable_index(int index); |
| 491 | |
| 492 | // interpreter entry |
| 493 | address interpreter_entry() const { return _i2i_entry; } |
| 494 | // Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry |
| 495 | void set_interpreter_entry(address entry) { |
| 496 | if (_i2i_entry != entry) { |
| 497 | _i2i_entry = entry; |
| 498 | } |
| 499 | if (_from_interpreted_entry != entry) { |
| 500 | _from_interpreted_entry = entry; |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | // native function (used for native methods only) |
| 505 | enum { |
| 506 | native_bind_event_is_interesting = true |
| 507 | }; |
| 508 | address native_function() const { return *(native_function_addr()); } |
| 509 | |
| 510 | // Must specify a real function (not NULL). |
| 511 | // Use clear_native_function() to unregister. |
| 512 | void set_native_function(address function, bool post_event_flag); |
| 513 | bool has_native_function() const; |
| 514 | void clear_native_function(); |
| 515 | |
| 516 | // signature handler (used for native methods only) |
| 517 | address signature_handler() const { return *(signature_handler_addr()); } |
| 518 | void set_signature_handler(address handler); |
| 519 | |
| 520 | // Interpreter oopmap support |
| 521 | void mask_for(int bci, InterpreterOopMap* mask); |
| 522 | |
| 523 | // operations on invocation counter |
| 524 | void print_invocation_count(); |
| 525 | |
| 526 | // byte codes |
| 527 | void set_code(address code) { return constMethod()->set_code(code); } |
| 528 | address code_base() const { return constMethod()->code_base(); } |
| 529 | bool contains(address bcp) const { return constMethod()->contains(bcp); } |
| 530 | |
| 531 | // prints byte codes |
| 532 | void print_codes() const { print_codes_on(tty); } |
| 533 | void print_codes_on(outputStream* st) const; |
| 534 | void print_codes_on(int from, int to, outputStream* st) const; |
| 535 | |
| 536 | // method parameters |
| 537 | bool has_method_parameters() const |
| 538 | { return constMethod()->has_method_parameters(); } |
| 539 | int method_parameters_length() const |
| 540 | { return constMethod()->method_parameters_length(); } |
| 541 | MethodParametersElement* method_parameters_start() const |
| 542 | { return constMethod()->method_parameters_start(); } |
| 543 | |
| 544 | // checked exceptions |
| 545 | int checked_exceptions_length() const |
| 546 | { return constMethod()->checked_exceptions_length(); } |
| 547 | CheckedExceptionElement* checked_exceptions_start() const |
| 548 | { return constMethod()->checked_exceptions_start(); } |
| 549 | |
| 550 | // localvariable table |
| 551 | bool has_localvariable_table() const |
| 552 | { return constMethod()->has_localvariable_table(); } |
| 553 | int localvariable_table_length() const |
| 554 | { return constMethod()->localvariable_table_length(); } |
| 555 | LocalVariableTableElement* localvariable_table_start() const |
| 556 | { return constMethod()->localvariable_table_start(); } |
| 557 | |
| 558 | bool has_linenumber_table() const |
| 559 | { return constMethod()->has_linenumber_table(); } |
| 560 | u_char* compressed_linenumber_table() const |
| 561 | { return constMethod()->compressed_linenumber_table(); } |
| 562 | |
| 563 | // method holder (the Klass* holding this method) |
| 564 | InstanceKlass* method_holder() const { return constants()->pool_holder(); } |
| 565 | |
| 566 | Symbol* klass_name() const; // returns the name of the method holder |
| 567 | BasicType result_type() const { return constMethod()->result_type(); } |
| 568 | bool is_returning_oop() const { BasicType r = result_type(); return is_reference_type(r); } |
| 569 | bool is_returning_fp() const { BasicType r = result_type(); return (r == T_FLOAT || r == T_DOUBLE); } |
| 570 | |
| 571 | // Checked exceptions thrown by this method (resolved to mirrors) |
| 572 | objArrayHandle resolved_checked_exceptions(TRAPSJavaThread* __the_thread__) { return resolved_checked_exceptions_impl(this, THREAD__the_thread__); } |
| 573 | |
| 574 | // Access flags |
| 575 | bool is_public() const { return access_flags().is_public(); } |
| 576 | bool is_private() const { return access_flags().is_private(); } |
| 577 | bool is_protected() const { return access_flags().is_protected(); } |
| 578 | bool is_package_private() const { return !is_public() && !is_private() && !is_protected(); } |
| 579 | bool is_static() const { return access_flags().is_static(); } |
| 580 | bool is_final() const { return access_flags().is_final(); } |
| 581 | bool is_synchronized() const { return access_flags().is_synchronized();} |
| 582 | bool is_native() const { return access_flags().is_native(); } |
| 583 | bool is_abstract() const { return access_flags().is_abstract(); } |
| 584 | bool is_synthetic() const { return access_flags().is_synthetic(); } |
| 585 | |
| 586 | // returns true if contains only return operation |
| 587 | bool is_empty_method() const; |
| 588 | |
| 589 | // returns true if this is a vanilla constructor |
| 590 | bool is_vanilla_constructor() const; |
| 591 | |
| 592 | // checks method and its method holder |
| 593 | bool is_final_method() const; |
| 594 | bool is_final_method(AccessFlags class_access_flags) const; |
| 595 | // interface method declared with 'default' - excludes private interface methods |
| 596 | bool is_default_method() const; |
| 597 | |
| 598 | // true if method needs no dynamic dispatch (final and/or no vtable entry) |
| 599 | bool can_be_statically_bound() const; |
| 600 | bool can_be_statically_bound(InstanceKlass* context) const; |
| 601 | bool can_be_statically_bound(AccessFlags class_access_flags) const; |
| 602 | |
| 603 | // true if method can omit stack trace in throw in compiled code. |
| 604 | bool can_omit_stack_trace(); |
| 605 | |
| 606 | // returns true if the method has any backward branches. |
| 607 | bool has_loops() { |
| 608 | return access_flags().loops_flag_init() ? access_flags().has_loops() : compute_has_loops_flag(); |
| 609 | }; |
| 610 | |
| 611 | bool compute_has_loops_flag(); |
| 612 | |
| 613 | bool has_jsrs() { |
| 614 | return access_flags().has_jsrs(); |
| 615 | }; |
| 616 | void set_has_jsrs() { |
| 617 | _access_flags.set_has_jsrs(); |
| 618 | } |
| 619 | |
| 620 | // returns true if the method has any monitors. |
| 621 | bool has_monitors() const { return is_synchronized() || access_flags().has_monitor_bytecodes(); } |
| 622 | bool has_monitor_bytecodes() const { return access_flags().has_monitor_bytecodes(); } |
| 623 | |
| 624 | void set_has_monitor_bytecodes() { _access_flags.set_has_monitor_bytecodes(); } |
| 625 | |
| 626 | // monitor matching. This returns a conservative estimate of whether the monitorenter/monitorexit bytecodes |
| 627 | // propererly nest in the method. It might return false, even though they actually nest properly, since the info. |
| 628 | // has not been computed yet. |
| 629 | bool guaranteed_monitor_matching() const { return access_flags().is_monitor_matching(); } |
| 630 | void set_guaranteed_monitor_matching() { _access_flags.set_monitor_matching(); } |
| 631 | |
| 632 | // returns true if the method is an accessor function (setter/getter). |
| 633 | bool is_accessor() const; |
| 634 | |
| 635 | // returns true if the method is a getter |
| 636 | bool is_getter() const; |
| 637 | |
| 638 | // returns true if the method is a setter |
| 639 | bool is_setter() const; |
| 640 | |
| 641 | // returns true if the method does nothing but return a constant of primitive type |
| 642 | bool is_constant_getter() const; |
| 643 | |
| 644 | // returns true if the method is an initializer (<init> or <clinit>). |
| 645 | bool is_initializer() const; |
| 646 | |
| 647 | // returns true if the method is static OR if the classfile version < 51 |
| 648 | bool has_valid_initializer_flags() const; |
| 649 | |
| 650 | // returns true if the method name is <clinit> and the method has |
| 651 | // valid static initializer flags. |
| 652 | bool is_static_initializer() const; |
| 653 | |
| 654 | // returns true if the method name is <init> |
| 655 | bool is_object_initializer() const; |
| 656 | |
| 657 | // compiled code support |
| 658 | // NOTE: code() is inherently racy as deopt can be clearing code |
| 659 | // simultaneously. Use with caution. |
| 660 | bool has_compiled_code() const; |
| 661 | |
| 662 | bool needs_clinit_barrier() const; |
| 663 | |
| 664 | // sizing |
| 665 | static int header_size() { |
| 666 | return align_up((int)sizeof(Method), wordSize) / wordSize; |
| 667 | } |
| 668 | static int size(bool is_native); |
| 669 | int size() const { return method_size(); } |
| 670 | void log_touched(Thread* current); |
| 671 | static void print_touched_methods(outputStream* out); |
| 672 | |
| 673 | // interpreter support |
| 674 | static ByteSize const_offset() { return byte_offset_of(Method, _constMethod )in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_constMethod ) - 16)); } |
| 675 | static ByteSize access_flags_offset() { return byte_offset_of(Method, _access_flags )in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_access_flags ) - 16)); } |
| 676 | static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry)in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_from_compiled_entry ) - 16)); } |
| 677 | static ByteSize code_offset() { return byte_offset_of(Method, _code)in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_code ) - 16)); } |
| 678 | static ByteSize method_data_offset() { |
| 679 | return byte_offset_of(Method, _method_data)in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_method_data ) - 16)); |
| 680 | } |
| 681 | static ByteSize method_counters_offset() { |
| 682 | return byte_offset_of(Method, _method_counters)in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_method_counters ) - 16)); |
| 683 | } |
| 684 | #ifndef PRODUCT |
| 685 | static ByteSize compiled_invocation_counter_offset() { return byte_offset_of(Method, _compiled_invocation_count)in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_compiled_invocation_count ) - 16)); } |
| 686 | #endif // not PRODUCT |
| 687 | static ByteSize native_function_offset() { return in_ByteSize(sizeof(Method)); } |
| 688 | static ByteSize from_interpreted_offset() { return byte_offset_of(Method, _from_interpreted_entry )in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_from_interpreted_entry ) - 16)); } |
| 689 | static ByteSize interpreter_entry_offset() { return byte_offset_of(Method, _i2i_entry )in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_i2i_entry ) - 16)); } |
| 690 | static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } |
| 691 | static ByteSize itable_index_offset() { return byte_offset_of(Method, _vtable_index )in_ByteSize((int)(size_t)((intx)&(((Method*)16)->_vtable_index ) - 16)); } |
| 692 | |
| 693 | // for code generation |
| 694 | static int method_data_offset_in_bytes() { return offset_of(Method, _method_data)(size_t)((intx)&(((Method*)16)->_method_data) - 16); } |
| 695 | static int intrinsic_id_offset_in_bytes() { return offset_of(Method, _intrinsic_id)(size_t)((intx)&(((Method*)16)->_intrinsic_id) - 16); } |
| 696 | static int intrinsic_id_size_in_bytes() { return sizeof(u2); } |
| 697 | |
| 698 | // Static methods that are used to implement member methods where an exposed this pointer |
| 699 | // is needed due to possible GCs |
| 700 | static objArrayHandle resolved_checked_exceptions_impl(Method* method, TRAPSJavaThread* __the_thread__); |
| 701 | |
| 702 | // Returns the byte code index from the byte code pointer |
| 703 | int bci_from(address bcp) const; |
| 704 | address bcp_from(int bci) const; |
| 705 | address bcp_from(address bcp) const; |
| 706 | int validate_bci_from_bcp(address bcp) const; |
| 707 | int validate_bci(int bci) const; |
| 708 | |
| 709 | // Returns the line number for a bci if debugging information for the method is prowided, |
| 710 | // -1 is returned otherwise. |
| 711 | int line_number_from_bci(int bci) const; |
| 712 | |
| 713 | // Reflection support |
| 714 | bool is_overridden_in(Klass* k) const; |
| 715 | |
| 716 | // Stack walking support |
| 717 | bool is_ignored_by_security_stack_walk() const; |
| 718 | |
| 719 | // JSR 292 support |
| 720 | bool is_method_handle_intrinsic() const; // MethodHandles::is_signature_polymorphic_intrinsic(intrinsic_id) |
| 721 | bool is_compiled_lambda_form() const; // intrinsic_id() == vmIntrinsics::_compiledLambdaForm |
| 722 | bool has_member_arg() const; // intrinsic_id() == vmIntrinsics::_linkToSpecial, etc. |
| 723 | static methodHandle make_method_handle_intrinsic(vmIntrinsicID iid, // _invokeBasic, _linkToVirtual |
| 724 | Symbol* signature, //anything at all |
| 725 | TRAPSJavaThread* __the_thread__); |
| 726 | static Klass* check_non_bcp_klass(Klass* klass); |
| 727 | |
| 728 | enum { |
| 729 | // How many extra stack entries for invokedynamic |
| 730 | extra_stack_entries_for_jsr292 = 1 |
| 731 | }; |
| 732 | |
| 733 | // this operates only on invoke methods: |
| 734 | // presize interpreter frames for extra interpreter stack entries, if needed |
| 735 | // Account for the extra appendix argument for invokehandle/invokedynamic |
| 736 | static int extra_stack_entries() { return extra_stack_entries_for_jsr292; } |
| 737 | static int extra_stack_words(); // = extra_stack_entries() * Interpreter::stackElementSize |
| 738 | |
| 739 | // RedefineClasses() support: |
| 740 | bool is_old() const { return access_flags().is_old(); } |
| 741 | void set_is_old() { _access_flags.set_is_old(); } |
| 742 | bool is_obsolete() const { return access_flags().is_obsolete(); } |
| 743 | void set_is_obsolete() { _access_flags.set_is_obsolete(); } |
| 744 | bool is_deleted() const { return access_flags().is_deleted(); } |
| 745 | void set_is_deleted() { _access_flags.set_is_deleted(); } |
| 746 | |
| 747 | bool on_stack() const { return access_flags().on_stack(); } |
| 748 | void set_on_stack(const bool value); |
| 749 | |
| 750 | // see the definition in Method*.cpp for the gory details |
| 751 | bool should_not_be_cached() const; |
| 752 | |
| 753 | // JVMTI Native method prefixing support: |
| 754 | bool is_prefixed_native() const { return access_flags().is_prefixed_native(); } |
| 755 | void set_is_prefixed_native() { _access_flags.set_is_prefixed_native(); } |
| 756 | |
| 757 | // Rewriting support |
| 758 | static methodHandle clone_with_new_data(const methodHandle& m, u_char* new_code, int new_code_length, |
| 759 | u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPSJavaThread* __the_thread__); |
| 760 | |
| 761 | // jmethodID handling |
| 762 | // Because the useful life-span of a jmethodID cannot be determined, |
| 763 | // once created they are never reclaimed. The methods to which they refer, |
| 764 | // however, can be GC'ed away if the class is unloaded or if the method is |
| 765 | // made obsolete or deleted -- in these cases, the jmethodID |
| 766 | // refers to NULL (as is the case for any weak reference). |
| 767 | static jmethodID make_jmethod_id(ClassLoaderData* loader_data, Method* mh); |
| 768 | static void destroy_jmethod_id(ClassLoaderData* loader_data, jmethodID mid); |
| 769 | |
| 770 | // Ensure there is enough capacity in the internal tracking data |
| 771 | // structures to hold the number of jmethodIDs you plan to generate. |
| 772 | // This saves substantial time doing allocations. |
| 773 | static void ensure_jmethod_ids(ClassLoaderData* loader_data, int capacity); |
| 774 | |
| 775 | // Use resolve_jmethod_id() in situations where the caller is expected |
| 776 | // to provide a valid jmethodID; the only sanity checks are in asserts; |
| 777 | // result guaranteed not to be NULL. |
| 778 | inline static Method* resolve_jmethod_id(jmethodID mid) { |
| 779 | assert(mid != NULL, "JNI method id should not be null")do { if (!(mid != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 779, "assert(" "mid != __null" ") failed", "JNI method id should not be null" ); ::breakpoint(); } } while (0); |
| 780 | return *((Method**)mid); |
| 781 | } |
| 782 | |
| 783 | // Use checked_resolve_jmethod_id() in situations where the caller |
| 784 | // should provide a valid jmethodID, but might not. NULL is returned |
| 785 | // when the jmethodID does not refer to a valid method. |
| 786 | static Method* checked_resolve_jmethod_id(jmethodID mid); |
| 787 | |
| 788 | static void change_method_associated_with_jmethod_id(jmethodID old_jmid_ptr, Method* new_method); |
| 789 | static bool is_method_id(jmethodID mid); |
| 790 | |
| 791 | // Clear methods |
| 792 | static void clear_jmethod_ids(ClassLoaderData* loader_data); |
| 793 | static void print_jmethod_ids_count(const ClassLoaderData* loader_data, outputStream* out) PRODUCT_RETURN; |
| 794 | |
| 795 | // Get this method's jmethodID -- allocate if it doesn't exist |
| 796 | jmethodID jmethod_id(); |
| 797 | |
| 798 | // Lookup the jmethodID for this method. Return NULL if not found. |
| 799 | // NOTE that this function can be called from a signal handler |
| 800 | // (see AsyncGetCallTrace support for Forte Analyzer) and this |
| 801 | // needs to be async-safe. No allocation should be done and |
| 802 | // so handles are not used to avoid deadlock. |
| 803 | jmethodID find_jmethod_id_or_null() { return method_holder()->jmethod_id_or_null(this); } |
| 804 | |
| 805 | // Support for inlining of intrinsic methods |
| 806 | vmIntrinsicID intrinsic_id() const { return (vmIntrinsicID) _intrinsic_id; } |
| 807 | void set_intrinsic_id(vmIntrinsicID id) { _intrinsic_id = (u2) id; } |
| 808 | |
| 809 | // Helper routines for intrinsic_id() and vmIntrinsics::method(). |
| 810 | void init_intrinsic_id(vmSymbolID klass_id); // updates from _none if a match |
| 811 | static vmSymbolID klass_id_for_intrinsics(const Klass* holder); |
| 812 | |
| 813 | bool caller_sensitive() { |
| 814 | return (_flags & _caller_sensitive) != 0; |
| 815 | } |
| 816 | void set_caller_sensitive(bool x) { |
| 817 | _flags = x ? (_flags | _caller_sensitive) : (_flags & ~_caller_sensitive); |
| 818 | } |
| 819 | |
| 820 | bool force_inline() { |
| 821 | return (_flags & _force_inline) != 0; |
| 822 | } |
| 823 | void set_force_inline(bool x) { |
| 824 | _flags = x ? (_flags | _force_inline) : (_flags & ~_force_inline); |
| 825 | } |
| 826 | |
| 827 | bool dont_inline() { |
| 828 | return (_flags & _dont_inline) != 0; |
| 829 | } |
| 830 | void set_dont_inline(bool x) { |
| 831 | _flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline); |
| 832 | } |
| 833 | |
| 834 | bool is_hidden() const { |
| 835 | return (_flags & _hidden) != 0; |
| 836 | } |
| 837 | |
| 838 | void set_hidden(bool x) { |
| 839 | _flags = x ? (_flags | _hidden) : (_flags & ~_hidden); |
| 840 | } |
| 841 | |
| 842 | bool is_scoped() const { |
| 843 | return (_flags & _scoped) != 0; |
| 844 | } |
| 845 | |
| 846 | void set_scoped(bool x) { |
| 847 | _flags = x ? (_flags | _scoped) : (_flags & ~_scoped); |
| 848 | } |
| 849 | |
| 850 | bool intrinsic_candidate() { |
| 851 | return (_flags & _intrinsic_candidate) != 0; |
| 852 | } |
| 853 | void set_intrinsic_candidate(bool x) { |
| 854 | _flags = x ? (_flags | _intrinsic_candidate) : (_flags & ~_intrinsic_candidate); |
| 855 | } |
| 856 | |
| 857 | bool has_injected_profile() { |
| 858 | return (_flags & _has_injected_profile) != 0; |
| 859 | } |
| 860 | void set_has_injected_profile(bool x) { |
| 861 | _flags = x ? (_flags | _has_injected_profile) : (_flags & ~_has_injected_profile); |
| 862 | } |
| 863 | |
| 864 | bool has_reserved_stack_access() { |
| 865 | return (_flags & _reserved_stack_access) != 0; |
| 866 | } |
| 867 | |
| 868 | void set_has_reserved_stack_access(bool x) { |
| 869 | _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access); |
| 870 | } |
| 871 | |
| 872 | JFR_ONLY(DEFINE_TRACE_FLAG_ACCESSOR;)bool is_trace_flag_set(jshort flag) const { return _trace_flags .is_set(flag); } jshort trace_flags() const { return _trace_flags .flags(); } void set_trace_flags(jshort flags) const { _trace_flags .set_flags(flags); } jbyte* trace_flags_addr() const { return _trace_flags.flags_addr(); } jbyte* trace_meta_addr() const { return _trace_flags.meta_addr(); }; |
| 873 | |
| 874 | ConstMethod::MethodType method_type() const { |
| 875 | return _constMethod->method_type(); |
| 876 | } |
| 877 | bool is_overpass() const { return method_type() == ConstMethod::OVERPASS; } |
| 878 | |
| 879 | // On-stack replacement support |
| 880 | bool has_osr_nmethod(int level, bool match_level) { |
| 881 | return method_holder()->lookup_osr_nmethod(this, InvocationEntryBci, level, match_level) != NULL__null; |
| 882 | } |
| 883 | |
| 884 | int mark_osr_nmethods() { |
| 885 | return method_holder()->mark_osr_nmethods(this); |
| 886 | } |
| 887 | |
| 888 | nmethod* lookup_osr_nmethod_for(int bci, int level, bool match_level) { |
| 889 | return method_holder()->lookup_osr_nmethod(this, bci, level, match_level); |
| 890 | } |
| 891 | |
| 892 | // Find if klass for method is loaded |
| 893 | bool is_klass_loaded_by_klass_index(int klass_index) const; |
| 894 | bool is_klass_loaded(int refinfo_index, bool must_be_resolved = false) const; |
| 895 | |
| 896 | // Indicates whether compilation failed earlier for this method, or |
| 897 | // whether it is not compilable for another reason like having a |
| 898 | // breakpoint set in it. |
| 899 | bool is_not_compilable(int comp_level = CompLevel_any) const; |
| 900 | void set_not_compilable(const char* reason, int comp_level = CompLevel_all, bool report = true); |
| 901 | void set_not_compilable_quietly(const char* reason, int comp_level = CompLevel_all) { |
| 902 | set_not_compilable(reason, comp_level, false); |
| 903 | } |
| 904 | bool is_not_osr_compilable(int comp_level = CompLevel_any) const; |
| 905 | void set_not_osr_compilable(const char* reason, int comp_level = CompLevel_all, bool report = true); |
| 906 | void set_not_osr_compilable_quietly(const char* reason, int comp_level = CompLevel_all) { |
| 907 | set_not_osr_compilable(reason, comp_level, false); |
| 908 | } |
| 909 | bool is_always_compilable() const; |
| 910 | |
| 911 | private: |
| 912 | void print_made_not_compilable(int comp_level, bool is_osr, bool report, const char* reason); |
| 913 | |
| 914 | public: |
| 915 | MethodCounters* get_method_counters(Thread* current) { |
| 916 | if (_method_counters == NULL__null) { |
| 917 | build_method_counters(current, this); |
| 918 | } |
| 919 | return _method_counters; |
| 920 | } |
| 921 | |
| 922 | bool is_not_c1_compilable() const { return access_flags().is_not_c1_compilable(); } |
| 923 | void set_not_c1_compilable() { _access_flags.set_not_c1_compilable(); } |
| 924 | void clear_not_c1_compilable() { _access_flags.clear_not_c1_compilable(); } |
| 925 | bool is_not_c2_compilable() const { return access_flags().is_not_c2_compilable(); } |
| 926 | void set_not_c2_compilable() { _access_flags.set_not_c2_compilable(); } |
| 927 | void clear_not_c2_compilable() { _access_flags.clear_not_c2_compilable(); } |
| 928 | |
| 929 | bool is_not_c1_osr_compilable() const { return is_not_c1_compilable(); } // don't waste an accessFlags bit |
| 930 | void set_not_c1_osr_compilable() { set_not_c1_compilable(); } // don't waste an accessFlags bit |
| 931 | void clear_not_c1_osr_compilable() { clear_not_c1_compilable(); } // don't waste an accessFlags bit |
| 932 | bool is_not_c2_osr_compilable() const { return access_flags().is_not_c2_osr_compilable(); } |
| 933 | void set_not_c2_osr_compilable() { _access_flags.set_not_c2_osr_compilable(); } |
| 934 | void clear_not_c2_osr_compilable() { _access_flags.clear_not_c2_osr_compilable(); } |
| 935 | |
| 936 | // Background compilation support |
| 937 | bool queued_for_compilation() const { return access_flags().queued_for_compilation(); } |
| 938 | void set_queued_for_compilation() { _access_flags.set_queued_for_compilation(); } |
| 939 | void clear_queued_for_compilation() { _access_flags.clear_queued_for_compilation(); } |
| 940 | |
| 941 | // Resolve all classes in signature, return 'true' if successful |
| 942 | static bool load_signature_classes(const methodHandle& m, TRAPSJavaThread* __the_thread__); |
| 943 | |
| 944 | // Return if true if not all classes references in signature, including return type, has been loaded |
| 945 | static bool has_unloaded_classes_in_signature(const methodHandle& m, TRAPSJavaThread* __the_thread__); |
| 946 | |
| 947 | // Printing |
| 948 | void print_short_name(outputStream* st = tty); // prints as klassname::methodname; Exposed so field engineers can debug VM |
| 949 | #if INCLUDE_JVMTI1 |
| 950 | void print_name(outputStream* st = tty); // prints as "virtual void foo(int)"; exposed for -Xlog:redefine+class |
| 951 | #else |
| 952 | void print_name(outputStream* st = tty) PRODUCT_RETURN; // prints as "virtual void foo(int)" |
| 953 | #endif |
| 954 | |
| 955 | typedef int (*method_comparator_func)(Method* a, Method* b); |
| 956 | |
| 957 | // Helper routine used for method sorting |
| 958 | static void sort_methods(Array<Method*>* methods, bool set_idnums = true, method_comparator_func func = NULL__null); |
| 959 | |
| 960 | // Deallocation function for redefine classes or if an error occurs |
| 961 | void deallocate_contents(ClassLoaderData* loader_data); |
| 962 | |
| 963 | void release_C_heap_structures(); |
| 964 | |
| 965 | Method* get_new_method() const { |
| 966 | InstanceKlass* holder = method_holder(); |
| 967 | Method* new_method = holder->method_with_idnum(orig_method_idnum()); |
| 968 | |
| 969 | assert(new_method != NULL, "method_with_idnum() should not be NULL")do { if (!(new_method != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 969, "assert(" "new_method != __null" ") failed", "method_with_idnum() should not be NULL" ); ::breakpoint(); } } while (0); |
| 970 | assert(this != new_method, "sanity check")do { if (!(this != new_method)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 970, "assert(" "this != new_method" ") failed", "sanity check" ); ::breakpoint(); } } while (0); |
| 971 | return new_method; |
| 972 | } |
| 973 | |
| 974 | // Printing |
| 975 | #ifndef PRODUCT |
| 976 | void print_on(outputStream* st) const; |
| 977 | #endif |
| 978 | void print_value_on(outputStream* st) const; |
| 979 | void print_linkage_flags(outputStream* st) PRODUCT_RETURN; |
| 980 | |
| 981 | const char* internal_name() const { return "{method}"; } |
| 982 | |
| 983 | // Check for valid method pointer |
| 984 | static bool has_method_vptr(const void* ptr); |
| 985 | static bool is_valid_method(const Method* m); |
| 986 | |
| 987 | // Verify |
| 988 | void verify() { verify_on(tty); } |
| 989 | void verify_on(outputStream* st); |
| 990 | |
| 991 | private: |
| 992 | |
| 993 | // Inlined elements |
| 994 | address* native_function_addr() const { assert(is_native(), "must be native")do { if (!(is_native())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 994, "assert(" "is_native()" ") failed", "must be native"); ::breakpoint(); } } while (0); return (address*) (this+1); } |
| 995 | address* signature_handler_addr() const { return native_function_addr() + 1; } |
| 996 | }; |
| 997 | |
| 998 | |
| 999 | // Utility class for compressing line number tables |
| 1000 | |
| 1001 | class CompressedLineNumberWriteStream: public CompressedWriteStream { |
| 1002 | private: |
| 1003 | int _bci; |
| 1004 | int _line; |
| 1005 | public: |
| 1006 | // Constructor |
| 1007 | CompressedLineNumberWriteStream(int initial_size) : CompressedWriteStream(initial_size), _bci(0), _line(0) {} |
| 1008 | CompressedLineNumberWriteStream(u_char* buffer, int initial_size) : CompressedWriteStream(buffer, initial_size), _bci(0), _line(0) {} |
| 1009 | |
| 1010 | // Write (bci, line number) pair to stream |
| 1011 | void write_pair_regular(int bci_delta, int line_delta); |
| 1012 | |
| 1013 | // If (bci delta, line delta) fits in (5-bit unsigned, 3-bit unsigned) |
| 1014 | // we save it as one byte, otherwise we write a 0xFF escape character |
| 1015 | // and use regular compression. 0x0 is used as end-of-stream terminator. |
| 1016 | void write_pair_inline(int bci, int line); |
| 1017 | |
| 1018 | void write_pair(int bci, int line); |
| 1019 | |
| 1020 | // Write end-of-stream marker |
| 1021 | void write_terminator() { write_byte(0); } |
| 1022 | }; |
| 1023 | |
| 1024 | |
| 1025 | // Utility class for decompressing line number tables |
| 1026 | |
| 1027 | class CompressedLineNumberReadStream: public CompressedReadStream { |
| 1028 | private: |
| 1029 | int _bci; |
| 1030 | int _line; |
| 1031 | public: |
| 1032 | // Constructor |
| 1033 | CompressedLineNumberReadStream(u_char* buffer); |
| 1034 | // Read (bci, line number) pair from stream. Returns false at end-of-stream. |
| 1035 | bool read_pair(); |
| 1036 | // Accessing bci and line number (after calling read_pair) |
| 1037 | int bci() const { return _bci; } |
| 1038 | int line() const { return _line; } |
| 1039 | }; |
| 1040 | |
| 1041 | |
| 1042 | #if INCLUDE_JVMTI1 |
| 1043 | |
| 1044 | /// Fast Breakpoints. |
| 1045 | |
| 1046 | // If this structure gets more complicated (because bpts get numerous), |
| 1047 | // move it into its own header. |
| 1048 | |
| 1049 | // There is presently no provision for concurrent access |
| 1050 | // to breakpoint lists, which is only OK for JVMTI because |
| 1051 | // breakpoints are written only at safepoints, and are read |
| 1052 | // concurrently only outside of safepoints. |
| 1053 | |
| 1054 | class BreakpointInfo : public CHeapObj<mtClass> { |
| 1055 | friend class VMStructs; |
| 1056 | private: |
| 1057 | Bytecodes::Code _orig_bytecode; |
| 1058 | int _bci; |
| 1059 | u2 _name_index; // of method |
| 1060 | u2 _signature_index; // of method |
| 1061 | BreakpointInfo* _next; // simple storage allocation |
| 1062 | |
| 1063 | public: |
| 1064 | BreakpointInfo(Method* m, int bci); |
| 1065 | |
| 1066 | // accessors |
| 1067 | Bytecodes::Code orig_bytecode() { return _orig_bytecode; } |
| 1068 | void set_orig_bytecode(Bytecodes::Code code) { _orig_bytecode = code; } |
| 1069 | int bci() { return _bci; } |
| 1070 | |
| 1071 | BreakpointInfo* next() const { return _next; } |
| 1072 | void set_next(BreakpointInfo* n) { _next = n; } |
| 1073 | |
| 1074 | // helps for searchers |
| 1075 | bool match(const Method* m, int bci) { |
| 1076 | return bci == _bci && match(m); |
| 1077 | } |
| 1078 | |
| 1079 | bool match(const Method* m) { |
| 1080 | return _name_index == m->name_index() && |
| 1081 | _signature_index == m->signature_index(); |
| 1082 | } |
| 1083 | |
| 1084 | void set(Method* method); |
| 1085 | void clear(Method* method); |
| 1086 | }; |
| 1087 | |
| 1088 | #endif // INCLUDE_JVMTI |
| 1089 | |
| 1090 | // Utility class for access exception handlers |
| 1091 | class ExceptionTable : public StackObj { |
| 1092 | private: |
| 1093 | ExceptionTableElement* _table; |
| 1094 | u2 _length; |
| 1095 | |
| 1096 | public: |
| 1097 | ExceptionTable(const Method* m) { |
| 1098 | if (m->has_exception_handler()) { |
| 1099 | _table = m->exception_table_start(); |
| 1100 | _length = m->exception_table_length(); |
| 1101 | } else { |
| 1102 | _table = NULL__null; |
| 1103 | _length = 0; |
| 1104 | } |
| 1105 | } |
| 1106 | |
| 1107 | int length() const { |
| 1108 | return _length; |
| 1109 | } |
| 1110 | |
| 1111 | u2 start_pc(int idx) const { |
| 1112 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1112, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1113 | return _table[idx].start_pc; |
| 1114 | } |
| 1115 | |
| 1116 | void set_start_pc(int idx, u2 value) { |
| 1117 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1117, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1118 | _table[idx].start_pc = value; |
| 1119 | } |
| 1120 | |
| 1121 | u2 end_pc(int idx) const { |
| 1122 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1122, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1123 | return _table[idx].end_pc; |
| 1124 | } |
| 1125 | |
| 1126 | void set_end_pc(int idx, u2 value) { |
| 1127 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1127, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1128 | _table[idx].end_pc = value; |
| 1129 | } |
| 1130 | |
| 1131 | u2 handler_pc(int idx) const { |
| 1132 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1132, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1133 | return _table[idx].handler_pc; |
| 1134 | } |
| 1135 | |
| 1136 | void set_handler_pc(int idx, u2 value) { |
| 1137 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1137, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1138 | _table[idx].handler_pc = value; |
| 1139 | } |
| 1140 | |
| 1141 | u2 catch_type_index(int idx) const { |
| 1142 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1142, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1143 | return _table[idx].catch_type_index; |
| 1144 | } |
| 1145 | |
| 1146 | void set_catch_type_index(int idx, u2 value) { |
| 1147 | assert(idx < _length, "out of bounds")do { if (!(idx < _length)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/method.hpp" , 1147, "assert(" "idx < _length" ") failed", "out of bounds" ); ::breakpoint(); } } while (0); |
| 1148 | _table[idx].catch_type_index = value; |
| 1149 | } |
| 1150 | }; |
| 1151 | |
| 1152 | #endif // SHARE_OOPS_METHOD_HPP |
| 1 | /* | |||
| 2 | * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. | |||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
| 4 | * | |||
| 5 | * This code is free software; you can redistribute it and/or modify it | |||
| 6 | * under the terms of the GNU General Public License version 2 only, as | |||
| 7 | * published by the Free Software Foundation. | |||
| 8 | * | |||
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | |||
| 13 | * accompanied this code). | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License version | |||
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| 18 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #ifndef SHARE_OOPS_CONSTMETHOD_HPP | |||
| 26 | #define SHARE_OOPS_CONSTMETHOD_HPP | |||
| 27 | ||||
| 28 | #include "oops/oop.hpp" | |||
| 29 | #include "utilities/align.hpp" | |||
| 30 | ||||
| 31 | // An ConstMethod represents portions of a Java method which are not written to after | |||
| 32 | // the classfile is parsed(*see below). This part of the method can be shared across | |||
| 33 | // processes in a read-only section with Class Data Sharing (CDS). It's important | |||
| 34 | // that this class doesn't have virtual functions because the vptr cannot be shared | |||
| 35 | // with CDS. | |||
| 36 | // | |||
| 37 | // Note that most applications load thousands of methods, so keeping the size of this | |||
| 38 | // structure small has a big impact on footprint. | |||
| 39 | ||||
| 40 | // The actual bytecodes are inlined after the end of the ConstMethod struct. | |||
| 41 | // | |||
| 42 | // The line number table is compressed and inlined following the byte codes. It is | |||
| 43 | // found as the first byte following the byte codes. Note that accessing the line | |||
| 44 | // number and local variable tables is not performance critical at all. | |||
| 45 | // | |||
| 46 | // The checked exceptions table and the local variable table are inlined after the | |||
| 47 | // line number table, and indexed from the end of the method. We do not compress the | |||
| 48 | // checked exceptions table since the average length is less than 2, and it is used | |||
| 49 | // by reflection so access should be fast. We do not bother to compress the local | |||
| 50 | // variable table either since it is mostly absent. | |||
| 51 | // | |||
| 52 | // | |||
| 53 | // ConstMethod embedded field layout (after declared fields): | |||
| 54 | // [EMBEDDED byte codes] | |||
| 55 | // [EMBEDDED compressed linenumber table] | |||
| 56 | // (see class CompressedLineNumberReadStream) | |||
| 57 | // (note that length is unknown until decompressed) | |||
| 58 | // (access flags bit tells whether table is present) | |||
| 59 | // (indexed from start of ConstMethod) | |||
| 60 | // (elements not necessarily sorted!) | |||
| 61 | // [EMBEDDED localvariable table elements + length (length last)] | |||
| 62 | // (length is u2, elements are 6-tuples of u2) | |||
| 63 | // (see class LocalVariableTableElement) | |||
| 64 | // (access flags bit tells whether table is present) | |||
| 65 | // (indexed from end of ConstMethod*) | |||
| 66 | // [EMBEDDED exception table + length (length last)] | |||
| 67 | // (length is u2, elements are 4-tuples of u2) | |||
| 68 | // (see class ExceptionTableElement) | |||
| 69 | // (access flags bit tells whether table is present) | |||
| 70 | // (indexed from end of ConstMethod*) | |||
| 71 | // [EMBEDDED checked exceptions elements + length (length last)] | |||
| 72 | // (length is u2, elements are u2) | |||
| 73 | // (see class CheckedExceptionElement) | |||
| 74 | // (access flags bit tells whether table is present) | |||
| 75 | // (indexed from end of ConstMethod*) | |||
| 76 | // [EMBEDDED method parameters elements + length (length last)] | |||
| 77 | // (length is u2, elements are u2, u4 structures) | |||
| 78 | // (see class MethodParametersElement) | |||
| 79 | // (access flags bit tells whether table is present) | |||
| 80 | // (indexed from end of ConstMethod*) | |||
| 81 | // [EMBEDDED generic signature index (u2)] | |||
| 82 | // (indexed from end of constMethodOop) | |||
| 83 | // [EMBEDDED annotations arrays - method, parameter, type, default] | |||
| 84 | // pointer to Array<u1> if annotation is present | |||
| 85 | // | |||
| 86 | // IMPORTANT: If anything gets added here, there need to be changes to | |||
| 87 | // ensure that ServicabilityAgent doesn't get broken as a result! | |||
| 88 | ||||
| 89 | ||||
| 90 | // Utility class describing elements in checked exceptions table inlined in Method*. | |||
| 91 | class CheckedExceptionElement { | |||
| 92 | public: | |||
| 93 | u2 class_cp_index; | |||
| 94 | }; | |||
| 95 | ||||
| 96 | ||||
| 97 | // Utility class describing elements in local variable table inlined in Method*. | |||
| 98 | class LocalVariableTableElement { | |||
| 99 | public: | |||
| 100 | u2 start_bci; | |||
| 101 | u2 length; | |||
| 102 | u2 name_cp_index; | |||
| 103 | u2 descriptor_cp_index; | |||
| 104 | u2 signature_cp_index; | |||
| 105 | u2 slot; | |||
| 106 | }; | |||
| 107 | ||||
| 108 | // Utility class describing elements in exception table | |||
| 109 | class ExceptionTableElement { | |||
| 110 | public: | |||
| 111 | u2 start_pc; | |||
| 112 | u2 end_pc; | |||
| 113 | u2 handler_pc; | |||
| 114 | u2 catch_type_index; | |||
| 115 | }; | |||
| 116 | ||||
| 117 | // Utility class describing elements in method parameters | |||
| 118 | class MethodParametersElement { | |||
| 119 | public: | |||
| 120 | u2 name_cp_index; | |||
| 121 | u2 flags; | |||
| 122 | }; | |||
| 123 | ||||
| 124 | // Class to collect the sizes of ConstMethod inline tables | |||
| 125 | #define INLINE_TABLES_DO(do_element)do_element(localvariable_table_length) do_element(compressed_linenumber_size ) do_element(exception_table_length) do_element(checked_exceptions_length ) do_element(method_parameters_length) do_element(generic_signature_index ) do_element(method_annotations_length) do_element(parameter_annotations_length ) do_element(type_annotations_length) do_element(default_annotations_length ) \ | |||
| 126 | do_element(localvariable_table_length) \ | |||
| 127 | do_element(compressed_linenumber_size) \ | |||
| 128 | do_element(exception_table_length) \ | |||
| 129 | do_element(checked_exceptions_length) \ | |||
| 130 | do_element(method_parameters_length) \ | |||
| 131 | do_element(generic_signature_index) \ | |||
| 132 | do_element(method_annotations_length) \ | |||
| 133 | do_element(parameter_annotations_length) \ | |||
| 134 | do_element(type_annotations_length) \ | |||
| 135 | do_element(default_annotations_length) | |||
| 136 | ||||
| 137 | #define INLINE_TABLE_DECLARE(sym) int _##sym; | |||
| 138 | #define INLINE_TABLE_PARAM(sym) int sym, | |||
| 139 | #define INLINE_TABLE_INIT(sym) _##sym(sym), | |||
| 140 | #define INLINE_TABLE_NULL(sym) _##sym(0), | |||
| 141 | #define INLINE_TABLE_ACCESSOR(sym) int sym() const { return _##sym; } | |||
| 142 | ||||
| 143 | class InlineTableSizes : StackObj { | |||
| 144 | // declarations | |||
| 145 | INLINE_TABLES_DO(INLINE_TABLE_DECLARE)INLINE_TABLE_DECLARE(localvariable_table_length) INLINE_TABLE_DECLARE (compressed_linenumber_size) INLINE_TABLE_DECLARE(exception_table_length ) INLINE_TABLE_DECLARE(checked_exceptions_length) INLINE_TABLE_DECLARE (method_parameters_length) INLINE_TABLE_DECLARE(generic_signature_index ) INLINE_TABLE_DECLARE(method_annotations_length) INLINE_TABLE_DECLARE (parameter_annotations_length) INLINE_TABLE_DECLARE(type_annotations_length ) INLINE_TABLE_DECLARE(default_annotations_length) | |||
| 146 | int _end; | |||
| 147 | public: | |||
| 148 | InlineTableSizes( | |||
| 149 | INLINE_TABLES_DO(INLINE_TABLE_PARAM)INLINE_TABLE_PARAM(localvariable_table_length) INLINE_TABLE_PARAM (compressed_linenumber_size) INLINE_TABLE_PARAM(exception_table_length ) INLINE_TABLE_PARAM(checked_exceptions_length) INLINE_TABLE_PARAM (method_parameters_length) INLINE_TABLE_PARAM(generic_signature_index ) INLINE_TABLE_PARAM(method_annotations_length) INLINE_TABLE_PARAM (parameter_annotations_length) INLINE_TABLE_PARAM(type_annotations_length ) INLINE_TABLE_PARAM(default_annotations_length) | |||
| 150 | int end) : | |||
| 151 | INLINE_TABLES_DO(INLINE_TABLE_INIT)INLINE_TABLE_INIT(localvariable_table_length) INLINE_TABLE_INIT (compressed_linenumber_size) INLINE_TABLE_INIT(exception_table_length ) INLINE_TABLE_INIT(checked_exceptions_length) INLINE_TABLE_INIT (method_parameters_length) INLINE_TABLE_INIT(generic_signature_index ) INLINE_TABLE_INIT(method_annotations_length) INLINE_TABLE_INIT (parameter_annotations_length) INLINE_TABLE_INIT(type_annotations_length ) INLINE_TABLE_INIT(default_annotations_length) | |||
| 152 | _end(end) {} | |||
| 153 | ||||
| 154 | // Default constructor for no inlined tables | |||
| 155 | InlineTableSizes() : | |||
| 156 | INLINE_TABLES_DO(INLINE_TABLE_NULL)INLINE_TABLE_NULL(localvariable_table_length) INLINE_TABLE_NULL (compressed_linenumber_size) INLINE_TABLE_NULL(exception_table_length ) INLINE_TABLE_NULL(checked_exceptions_length) INLINE_TABLE_NULL (method_parameters_length) INLINE_TABLE_NULL(generic_signature_index ) INLINE_TABLE_NULL(method_annotations_length) INLINE_TABLE_NULL (parameter_annotations_length) INLINE_TABLE_NULL(type_annotations_length ) INLINE_TABLE_NULL(default_annotations_length) | |||
| 157 | _end(0) {} | |||
| 158 | ||||
| 159 | // Accessors | |||
| 160 | INLINE_TABLES_DO(INLINE_TABLE_ACCESSOR)INLINE_TABLE_ACCESSOR(localvariable_table_length) INLINE_TABLE_ACCESSOR (compressed_linenumber_size) INLINE_TABLE_ACCESSOR(exception_table_length ) INLINE_TABLE_ACCESSOR(checked_exceptions_length) INLINE_TABLE_ACCESSOR (method_parameters_length) INLINE_TABLE_ACCESSOR(generic_signature_index ) INLINE_TABLE_ACCESSOR(method_annotations_length) INLINE_TABLE_ACCESSOR (parameter_annotations_length) INLINE_TABLE_ACCESSOR(type_annotations_length ) INLINE_TABLE_ACCESSOR(default_annotations_length) | |||
| 161 | }; | |||
| 162 | #undef INLINE_TABLE_ACCESSOR | |||
| 163 | #undef INLINE_TABLE_NULL | |||
| 164 | #undef INLINE_TABLE_INIT | |||
| 165 | #undef INLINE_TABLE_PARAM | |||
| 166 | #undef INLINE_TABLE_DECLARE | |||
| 167 | ||||
| 168 | class ConstMethod : public MetaspaceObj { | |||
| 169 | friend class VMStructs; | |||
| 170 | friend class JVMCIVMStructs; | |||
| 171 | ||||
| 172 | public: | |||
| 173 | typedef enum { NORMAL, OVERPASS } MethodType; | |||
| 174 | ||||
| 175 | private: | |||
| 176 | enum { | |||
| 177 | _has_linenumber_table = 0x0001, | |||
| 178 | _has_checked_exceptions = 0x0002, | |||
| 179 | _has_localvariable_table = 0x0004, | |||
| 180 | _has_exception_table = 0x0008, | |||
| 181 | _has_generic_signature = 0x0010, | |||
| 182 | _has_method_parameters = 0x0020, | |||
| 183 | _is_overpass = 0x0040, | |||
| 184 | _has_method_annotations = 0x0080, | |||
| 185 | _has_parameter_annotations = 0x0100, | |||
| 186 | _has_type_annotations = 0x0200, | |||
| 187 | _has_default_annotations = 0x0400 | |||
| 188 | }; | |||
| 189 | ||||
| 190 | // Bit vector of signature | |||
| 191 | // Callers interpret 0=not initialized yet and | |||
| 192 | // -1=too many args to fix, must parse the slow way. | |||
| 193 | // The real initial value is special to account for nonatomicity of 64 bit | |||
| 194 | // loads and stores. This value may updated and read without a lock by | |||
| 195 | // multiple threads, so is volatile. | |||
| 196 | volatile uint64_t _fingerprint; | |||
| 197 | ||||
| 198 | // If you add a new field that points to any metaspace object, you | |||
| 199 | // must add this field to ConstMethod::metaspace_pointers_do(). | |||
| 200 | ||||
| 201 | ConstantPool* _constants; // Constant pool | |||
| 202 | ||||
| 203 | // Raw stackmap data for the method | |||
| 204 | Array<u1>* _stackmap_data; | |||
| 205 | ||||
| 206 | int _constMethod_size; | |||
| 207 | u2 _flags; | |||
| 208 | u1 _result_type; // BasicType of result | |||
| 209 | ||||
| 210 | // Size of Java bytecodes allocated immediately after Method*. | |||
| 211 | u2 _code_size; | |||
| 212 | u2 _name_index; // Method name (index in constant pool) | |||
| 213 | u2 _signature_index; // Method signature (index in constant pool) | |||
| 214 | u2 _method_idnum; // unique identification number for the method within the class | |||
| 215 | // initially corresponds to the index into the methods array. | |||
| 216 | // but this may change with redefinition | |||
| 217 | u2 _max_stack; // Maximum number of entries on the expression stack | |||
| 218 | u2 _max_locals; // Number of local variables used by this method | |||
| 219 | u2 _size_of_parameters; // size of the parameter block (receiver + arguments) in words | |||
| 220 | u2 _orig_method_idnum; // Original unique identification number for the method | |||
| 221 | ||||
| 222 | // Constructor | |||
| 223 | ConstMethod(int byte_code_size, | |||
| 224 | InlineTableSizes* sizes, | |||
| 225 | MethodType is_overpass, | |||
| 226 | int size); | |||
| 227 | public: | |||
| 228 | ||||
| 229 | static ConstMethod* allocate(ClassLoaderData* loader_data, | |||
| 230 | int byte_code_size, | |||
| 231 | InlineTableSizes* sizes, | |||
| 232 | MethodType mt, | |||
| 233 | TRAPSJavaThread* __the_thread__); | |||
| 234 | ||||
| 235 | // Inlined tables | |||
| 236 | void set_inlined_tables_length(InlineTableSizes* sizes); | |||
| 237 | ||||
| 238 | bool has_generic_signature() const | |||
| 239 | { return (_flags & _has_generic_signature) != 0; } | |||
| 240 | ||||
| 241 | bool has_linenumber_table() const | |||
| 242 | { return (_flags & _has_linenumber_table) != 0; } | |||
| 243 | ||||
| 244 | bool has_checked_exceptions() const | |||
| 245 | { return (_flags & _has_checked_exceptions) != 0; } | |||
| 246 | ||||
| 247 | bool has_localvariable_table() const | |||
| 248 | { return (_flags & _has_localvariable_table) != 0; } | |||
| 249 | ||||
| 250 | bool has_exception_handler() const | |||
| 251 | { return (_flags & _has_exception_table) != 0; } | |||
| 252 | ||||
| 253 | bool has_method_parameters() const | |||
| 254 | { return (_flags & _has_method_parameters) != 0; } | |||
| 255 | ||||
| 256 | MethodType method_type() const { | |||
| 257 | return ((_flags & _is_overpass) == 0) ? NORMAL : OVERPASS; | |||
| 258 | } | |||
| 259 | ||||
| 260 | void set_method_type(MethodType mt) { | |||
| 261 | if (mt == NORMAL) { | |||
| 262 | _flags &= ~(_is_overpass); | |||
| 263 | } else { | |||
| 264 | _flags |= _is_overpass; | |||
| 265 | } | |||
| 266 | } | |||
| 267 | ||||
| 268 | // constant pool | |||
| 269 | ConstantPool* constants() const { return _constants; } | |||
| 270 | void set_constants(ConstantPool* c) { _constants = c; } | |||
| 271 | ||||
| 272 | Method* method() const; | |||
| 273 | ||||
| 274 | // stackmap table data | |||
| 275 | Array<u1>* stackmap_data() const { return _stackmap_data; } | |||
| 276 | void set_stackmap_data(Array<u1>* sd) { _stackmap_data = sd; } | |||
| 277 | void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPSJavaThread* __the_thread__); | |||
| 278 | bool has_stackmap_table() const { return _stackmap_data != NULL__null; } | |||
| 279 | ||||
| 280 | void init_fingerprint() { | |||
| 281 | const uint64_t initval = UCONST64(0x8000000000000000)(0x8000000000000000ULL); | |||
| 282 | _fingerprint = initval; | |||
| 283 | } | |||
| 284 | ||||
| 285 | uint64_t fingerprint() const { | |||
| 286 | // Since reads aren't atomic for 64 bits, if any of the high or low order | |||
| 287 | // word is the initial value, return 0. See init_fingerprint for initval. | |||
| 288 | uint high_fp = (uint)(_fingerprint >> 32); | |||
| 289 | if ((int) _fingerprint == 0 || high_fp == 0x80000000) { | |||
| 290 | return 0L; | |||
| 291 | } else { | |||
| 292 | return _fingerprint; | |||
| 293 | } | |||
| 294 | } | |||
| 295 | ||||
| 296 | uint64_t set_fingerprint(uint64_t new_fingerprint) { | |||
| 297 | #ifdef ASSERT1 | |||
| 298 | // Assert only valid if complete/valid 64 bit _fingerprint value is read. | |||
| 299 | uint64_t oldfp = fingerprint(); | |||
| 300 | #endif // ASSERT | |||
| 301 | _fingerprint = new_fingerprint; | |||
| 302 | assert(oldfp == 0L || new_fingerprint == oldfp,do { if (!(oldfp == 0L || new_fingerprint == oldfp)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 303, "assert(" "oldfp == 0L || new_fingerprint == oldfp" ") failed" , "fingerprint cannot change"); ::breakpoint(); } } while (0) | |||
| 303 | "fingerprint cannot change")do { if (!(oldfp == 0L || new_fingerprint == oldfp)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 303, "assert(" "oldfp == 0L || new_fingerprint == oldfp" ") failed" , "fingerprint cannot change"); ::breakpoint(); } } while (0); | |||
| 304 | assert(((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0,do { if (!(((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 305, "assert(" "((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0" ") failed", "fingerprint should call init to set initial value" ); ::breakpoint(); } } while (0) | |||
| 305 | "fingerprint should call init to set initial value")do { if (!(((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 305, "assert(" "((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0" ") failed", "fingerprint should call init to set initial value" ); ::breakpoint(); } } while (0); | |||
| 306 | return new_fingerprint; | |||
| 307 | } | |||
| 308 | ||||
| 309 | // name | |||
| 310 | int name_index() const { return _name_index; } | |||
| 311 | void set_name_index(int index) { _name_index = index; } | |||
| 312 | ||||
| 313 | // signature | |||
| 314 | int signature_index() const { return _signature_index; } | |||
| 315 | void set_signature_index(int index) { _signature_index = index; } | |||
| 316 | ||||
| 317 | // generics support | |||
| 318 | int generic_signature_index() const { | |||
| 319 | if (has_generic_signature()) { | |||
| 320 | return *generic_signature_index_addr(); | |||
| 321 | } else { | |||
| 322 | return 0; | |||
| 323 | } | |||
| 324 | } | |||
| 325 | void set_generic_signature_index(u2 index) { | |||
| 326 | assert(has_generic_signature(), "")do { if (!(has_generic_signature())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 326, "assert(" "has_generic_signature()" ") failed", ""); :: breakpoint(); } } while (0); | |||
| 327 | u2* addr = generic_signature_index_addr(); | |||
| 328 | *addr = index; | |||
| 329 | } | |||
| 330 | ||||
| 331 | // Sizing | |||
| 332 | static int header_size() { | |||
| 333 | return align_up((int)sizeof(ConstMethod), wordSize) / wordSize; | |||
| 334 | } | |||
| 335 | ||||
| 336 | // Size needed | |||
| 337 | static int size(int code_size, InlineTableSizes* sizes); | |||
| 338 | ||||
| 339 | int size() const { return _constMethod_size;} | |||
| 340 | void set_constMethod_size(int size) { _constMethod_size = size; } | |||
| 341 | ||||
| 342 | // ConstMethods should be stored in the read-only region of CDS archive. | |||
| 343 | static bool is_read_only_by_default() { return true; } | |||
| 344 | ||||
| 345 | // code size | |||
| 346 | int code_size() const { return _code_size; } | |||
| 347 | void set_code_size(int size) { | |||
| 348 | assert(max_method_code_size < (1 << 16),do { if (!(max_method_code_size < (1 << 16))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 349, "assert(" "max_method_code_size < (1 << 16)" ") failed" , "u2 is too small to hold method code size in general"); ::breakpoint (); } } while (0) | |||
| 349 | "u2 is too small to hold method code size in general")do { if (!(max_method_code_size < (1 << 16))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 349, "assert(" "max_method_code_size < (1 << 16)" ") failed" , "u2 is too small to hold method code size in general"); ::breakpoint (); } } while (0); | |||
| 350 | assert(0 <= size && size <= max_method_code_size, "invalid code size")do { if (!(0 <= size && size <= max_method_code_size )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 350, "assert(" "0 <= size && size <= max_method_code_size" ") failed", "invalid code size"); ::breakpoint(); } } while ( 0); | |||
| 351 | _code_size = size; | |||
| 352 | } | |||
| 353 | ||||
| 354 | // linenumber table - note that length is unknown until decompression, | |||
| 355 | // see class CompressedLineNumberReadStream. | |||
| 356 | u_char* compressed_linenumber_table() const; // not preserved by gc | |||
| 357 | u2* generic_signature_index_addr() const; | |||
| 358 | u2* checked_exceptions_length_addr() const; | |||
| 359 | u2* localvariable_table_length_addr() const; | |||
| 360 | u2* exception_table_length_addr() const; | |||
| 361 | u2* method_parameters_length_addr() const; | |||
| 362 | ||||
| 363 | // checked exceptions | |||
| 364 | int checked_exceptions_length() const; | |||
| 365 | CheckedExceptionElement* checked_exceptions_start() const; | |||
| 366 | ||||
| 367 | // localvariable table | |||
| 368 | int localvariable_table_length() const; | |||
| 369 | LocalVariableTableElement* localvariable_table_start() const; | |||
| 370 | ||||
| 371 | // exception table | |||
| 372 | int exception_table_length() const; | |||
| 373 | ExceptionTableElement* exception_table_start() const; | |||
| 374 | ||||
| 375 | // method parameters table | |||
| 376 | ||||
| 377 | // This returns -1 if no parameters are present, a non-negative | |||
| 378 | // value otherwise. Note: sometimes, there are 0-length parameters | |||
| 379 | // attributes that must be reported up to the reflection API all the | |||
| 380 | // same. | |||
| 381 | int method_parameters_length() const; | |||
| 382 | MethodParametersElement* method_parameters_start() const; | |||
| 383 | ||||
| 384 | // method annotations | |||
| 385 | bool has_method_annotations() const | |||
| 386 | { return (_flags & _has_method_annotations) != 0; } | |||
| 387 | ||||
| 388 | bool has_parameter_annotations() const | |||
| 389 | { return (_flags & _has_parameter_annotations) != 0; } | |||
| 390 | ||||
| 391 | bool has_type_annotations() const | |||
| 392 | { return (_flags & _has_type_annotations) != 0; } | |||
| 393 | ||||
| 394 | bool has_default_annotations() const | |||
| 395 | { return (_flags & _has_default_annotations) != 0; } | |||
| 396 | ||||
| 397 | ||||
| 398 | AnnotationArray** method_annotations_addr() const; | |||
| 399 | AnnotationArray* method_annotations() const { | |||
| 400 | return has_method_annotations() ? *(method_annotations_addr()) : NULL__null; | |||
| 401 | } | |||
| 402 | void set_method_annotations(AnnotationArray* anno) { | |||
| 403 | *(method_annotations_addr()) = anno; | |||
| 404 | } | |||
| 405 | ||||
| 406 | AnnotationArray** parameter_annotations_addr() const; | |||
| 407 | AnnotationArray* parameter_annotations() const { | |||
| 408 | return has_parameter_annotations() ? *(parameter_annotations_addr()) : NULL__null; | |||
| 409 | } | |||
| 410 | void set_parameter_annotations(AnnotationArray* anno) { | |||
| 411 | *(parameter_annotations_addr()) = anno; | |||
| 412 | } | |||
| 413 | ||||
| 414 | AnnotationArray** type_annotations_addr() const; | |||
| 415 | AnnotationArray* type_annotations() const { | |||
| 416 | return has_type_annotations() ? *(type_annotations_addr()) : NULL__null; | |||
| 417 | } | |||
| 418 | void set_type_annotations(AnnotationArray* anno) { | |||
| 419 | *(type_annotations_addr()) = anno; | |||
| 420 | } | |||
| 421 | ||||
| 422 | AnnotationArray** default_annotations_addr() const; | |||
| 423 | AnnotationArray* default_annotations() const { | |||
| 424 | return has_default_annotations() ? *(default_annotations_addr()) : NULL__null; | |||
| 425 | } | |||
| 426 | void set_default_annotations(AnnotationArray* anno) { | |||
| 427 | *(default_annotations_addr()) = anno; | |||
| 428 | } | |||
| 429 | ||||
| 430 | int method_annotations_length() const { | |||
| 431 | return has_method_annotations() ? method_annotations()->length() : 0; | |||
| 432 | } | |||
| 433 | int parameter_annotations_length() const { | |||
| 434 | return has_parameter_annotations() ? parameter_annotations()->length() : 0; | |||
| 435 | } | |||
| 436 | int type_annotations_length() const { | |||
| 437 | return has_type_annotations() ? type_annotations()->length() : 0; | |||
| 438 | } | |||
| 439 | int default_annotations_length() const { | |||
| 440 | return has_default_annotations() ? default_annotations()->length() : 0; | |||
| 441 | } | |||
| 442 | ||||
| 443 | // Copy annotations from other ConstMethod | |||
| 444 | void copy_annotations_from(ClassLoaderData* loader_data, ConstMethod* cm, TRAPSJavaThread* __the_thread__); | |||
| 445 | ||||
| 446 | // byte codes | |||
| 447 | void set_code(address code) { | |||
| 448 | if (code_size() > 0) { | |||
| 449 | memcpy(code_base(), code, code_size()); | |||
| ||||
| 450 | } | |||
| 451 | } | |||
| 452 | address code_base() const { return (address) (this+1); } | |||
| 453 | address code_end() const { return code_base() + code_size(); } | |||
| 454 | bool contains(address bcp) const { return code_base() <= bcp | |||
| 455 | && bcp < code_end(); } | |||
| 456 | // Offset to bytecodes | |||
| 457 | static ByteSize codes_offset() | |||
| 458 | { return in_ByteSize(sizeof(ConstMethod)); } | |||
| 459 | ||||
| 460 | static ByteSize constants_offset() | |||
| 461 | { return byte_offset_of(ConstMethod, _constants)in_ByteSize((int)(size_t)((intx)&(((ConstMethod*)16)-> _constants) - 16)); } | |||
| 462 | ||||
| 463 | static ByteSize max_stack_offset() | |||
| 464 | { return byte_offset_of(ConstMethod, _max_stack)in_ByteSize((int)(size_t)((intx)&(((ConstMethod*)16)-> _max_stack) - 16)); } | |||
| 465 | static ByteSize size_of_locals_offset() | |||
| 466 | { return byte_offset_of(ConstMethod, _max_locals)in_ByteSize((int)(size_t)((intx)&(((ConstMethod*)16)-> _max_locals) - 16)); } | |||
| 467 | static ByteSize size_of_parameters_offset() | |||
| 468 | { return byte_offset_of(ConstMethod, _size_of_parameters)in_ByteSize((int)(size_t)((intx)&(((ConstMethod*)16)-> _size_of_parameters) - 16)); } | |||
| 469 | ||||
| 470 | static ByteSize result_type_offset() | |||
| 471 | { return byte_offset_of(ConstMethod, _result_type)in_ByteSize((int)(size_t)((intx)&(((ConstMethod*)16)-> _result_type) - 16)); } | |||
| 472 | ||||
| 473 | // Unique id for the method | |||
| 474 | static const u2 MAX_IDNUM; | |||
| 475 | static const u2 UNSET_IDNUM; | |||
| 476 | u2 method_idnum() const { return _method_idnum; } | |||
| 477 | void set_method_idnum(u2 idnum) { _method_idnum = idnum; } | |||
| 478 | ||||
| 479 | u2 orig_method_idnum() const { return _orig_method_idnum; } | |||
| 480 | void set_orig_method_idnum(u2 idnum) { _orig_method_idnum = idnum; } | |||
| 481 | ||||
| 482 | // max stack | |||
| 483 | int max_stack() const { return _max_stack; } | |||
| 484 | void set_max_stack(int size) { _max_stack = size; } | |||
| 485 | ||||
| 486 | // max locals | |||
| 487 | int max_locals() const { return _max_locals; } | |||
| 488 | void set_max_locals(int size) { _max_locals = size; } | |||
| 489 | ||||
| 490 | // size of parameters | |||
| 491 | int size_of_parameters() const { return _size_of_parameters; } | |||
| 492 | void set_size_of_parameters(int size) { _size_of_parameters = size; } | |||
| 493 | ||||
| 494 | // result type (basic type of return value) | |||
| 495 | BasicType result_type() const { assert(_result_type >= T_BOOLEAN, "Must be set")do { if (!(_result_type >= T_BOOLEAN)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 495, "assert(" "_result_type >= T_BOOLEAN" ") failed", "Must be set" ); ::breakpoint(); } } while (0); | |||
| 496 | return (BasicType)_result_type; } | |||
| 497 | ||||
| 498 | void set_result_type(BasicType rt) { assert(rt < 16, "result type too large")do { if (!(rt < 16)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/oops/constMethod.hpp" , 498, "assert(" "rt < 16" ") failed", "result type too large" ); ::breakpoint(); } } while (0); | |||
| 499 | _result_type = (u1)rt; } | |||
| 500 | // Deallocation for RedefineClasses | |||
| 501 | void deallocate_contents(ClassLoaderData* loader_data); | |||
| 502 | bool is_klass() const { return false; } | |||
| 503 | DEBUG_ONLY(bool on_stack() { return false; })bool on_stack() { return false; } | |||
| 504 | ||||
| 505 | void metaspace_pointers_do(MetaspaceClosure* it); | |||
| 506 | MetaspaceObj::Type type() const { return ConstMethodType; } | |||
| 507 | private: | |||
| 508 | // Since the size of the compressed line number table is unknown, the | |||
| 509 | // offsets of the other variable sized sections are computed backwards | |||
| 510 | // from the end of the ConstMethod*. | |||
| 511 | ||||
| 512 | // First byte after ConstMethod* | |||
| 513 | address constMethod_end() const | |||
| 514 | { return (address)((intptr_t*)this + _constMethod_size); } | |||
| 515 | ||||
| 516 | // Last short in ConstMethod* | |||
| 517 | u2* last_u2_element() const; | |||
| 518 | ||||
| 519 | public: | |||
| 520 | // Printing | |||
| 521 | void print_on (outputStream* st) const; | |||
| 522 | void print_value_on(outputStream* st) const; | |||
| 523 | ||||
| 524 | const char* internal_name() const { return "{constMethod}"; } | |||
| 525 | ||||
| 526 | // Verify | |||
| 527 | void verify_on(outputStream* st); | |||
| 528 | }; | |||
| 529 | ||||
| 530 | #endif // SHARE_OOPS_CONSTMETHOD_HPP |