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 |