1 /*
2 * Copyright (c) 2023, 2025, 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 "cds/archiveBuilder.hpp"
26 #include "cppstdlib/type_traits.hpp"
27 #include "oops/method.hpp"
28 #include "oops/resolvedMethodEntry.hpp"
29
30 static_assert(std::is_trivially_copyable_v<ResolvedMethodEntry>);
31
32 // Detect inadvertently introduced trailing padding.
33 class ResolvedMethodEntryWithExtra : public ResolvedMethodEntry {
34 u1 _extra_field;
35 };
36 static_assert(sizeof(ResolvedMethodEntryWithExtra) > sizeof(ResolvedMethodEntry));
37
38 bool ResolvedMethodEntry::check_no_old_or_obsolete_entry() {
39 // return false if m refers to a non-deleted old or obsolete method
40 if (_method != nullptr) {
41 assert(_method->is_valid() && _method->is_method(), "m is a valid method");
42 return !_method->is_old() && !_method->is_obsolete(); // old is always set for old and obsolete
43 } else {
44 return true;
45 }
46 }
47
48 void ResolvedMethodEntry::reset_entry() {
49 if (has_resolved_references_index()) {
50 u2 saved_resolved_references_index = _entry_specific._resolved_references_index;
51 *this = ResolvedMethodEntry(_cpool_index);
52 set_resolved_references_index(saved_resolved_references_index);
53 } else {
54 *this = ResolvedMethodEntry(_cpool_index);
55 }
56 }
57
58 #if INCLUDE_CDS
59 void ResolvedMethodEntry::remove_unshareable_info() {
60 reset_entry();
61 }
62
63 void ResolvedMethodEntry::mark_and_relocate(ConstantPool* src_cp) {
64 if (_method == nullptr) {
65 assert(bytecode2() == Bytecodes::_invokevirtual, "");
66 } else {
67 ArchiveBuilder::current()->mark_and_relocate_to_buffered_addr(&_method);
68 }
69 if (bytecode1() == Bytecodes::_invokeinterface) {
70 ArchiveBuilder::current()->mark_and_relocate_to_buffered_addr(&_entry_specific._interface_klass);
71 }
72 #if 0 73 // OLD CODE ... some of it may need to be salvaged. 74 Bytecodes::Code invoke_code = bytecode_1(); 75 if (invoke_code != (Bytecodes::Code)0) { 76 Metadata* f1 = f1_ord(); 77 if (f1 != nullptr) { 78 ArchiveBuilder::current()->mark_and_relocate_to_buffered_addr(&_f1); 79 switch (invoke_code) { 80 case Bytecodes::_invokeinterface: 81 assert(0, "not implemented"); 82 //assert(f1->is_klass(), ""); 83 //ArchiveBuilder::current()->mark_and_relocate_to_buffered_addr(&_f2); // f2 is interface method 84 return false; 85 case Bytecodes::_invokestatic: 86 // For safety, we support invokestatic only for invoking methods in MethodHandle. 87 // FIXME -- further restrict it to linkToStatic(), etc? 88 assert(bytecode_2() == (Bytecodes::Code)0, "must be"); 89 assert(f1->is_method(), ""); 90 assert(f1_as_method()->method_holder()->name()->equals("java/lang/invoke/MethodHandle") || 91 f1_as_method()->method_holder()->name()->equals("java/lang/invoke/MethodHandleNatives"), "sanity"); 92 return true; 93 case Bytecodes::_invokespecial: 94 assert(f1->is_method(), "must be"); 95 // Also need to work on bytecode_2() below. 96 break; 97 case Bytecodes::_invokehandle: 98 assert(bytecode_2() == (Bytecodes::Code)0, "must be"); 99 assert(f1->is_method(), "");100 return true;101 default:102 ShouldNotReachHere();103 break;104 }105 }106 }107 108 // TODO test case: can invokespecial and invokevirtual share the same CP?109 invoke_code = bytecode_2();110 if (invoke_code != (Bytecodes::Code)0) {111 assert(invoke_code == Bytecodes::_invokevirtual, "must be");112 if (is_vfinal()) {113 // f2 is vfinal method114 ArchiveBuilder::current()->mark_and_relocate_to_buffered_addr(&_f2); // f2 is final method115 } else {116 // f2 is vtable index, no need to mark117 if (DynamicDumpSharedSpaces) {118 // InstanceKlass::methods() is has been resorted, so we need to119 // update the vtable_index.120 int holder_index = src_cp->uncached_klass_ref_index_at(constant_pool_index());121 Klass* src_klass = src_cp->resolved_klass_at(holder_index);122 Method* src_m = src_klass->method_at_vtable(f2_as_index());123 if (!ArchiveBuilder::current()->is_in_mapped_static_archive(src_m->method_holder()) &&124 !ArchiveBuilder::current()->is_in_mapped_static_archive(src_m)) {125 Klass* buffered_klass = ArchiveBuilder::current()->get_buffered_addr(src_klass);126 Method* buffered_m = ArchiveBuilder::current()->get_buffered_addr(src_m);127 int vtable_index;128 if (src_m->method_holder()->is_interface()) { // default or miranda method129 assert(src_m->vtable_index() < 0, "must be");130 assert(buffered_klass->is_instance_klass(), "must be");131 vtable_index = InstanceKlass::cast(buffered_klass)->vtable_index_of_interface_method(buffered_m);132 assert(vtable_index >= 0, "must be");133 } else {134 vtable_index = buffered_m->vtable_index();135 assert(vtable_index >= 0, "must be");136 }137 if (_f2 != vtable_index) {138 log_trace(cds, resolve)("vtable_index changed %d => %d", (int)_f2, vtable_index);139 _f2 = vtable_index;140 }141 }142 }143 }144 }145 146 #endif
147 }
148 #endif
149
150 void ResolvedMethodEntry::print_on(outputStream* st) const {
151 st->print_cr("Method Entry:");
152
153 if (method() != nullptr) {
154 st->print_cr(" - Method: " INTPTR_FORMAT " %s", p2i(method()), method()->external_name());
155 } else {
156 st->print_cr("- Method: null");
157 }
158 // Some fields are mutually exclusive and are only used by certain invoke codes
159 if (bytecode1() == Bytecodes::_invokeinterface && interface_klass() != nullptr) {
160 st->print_cr(" - Klass: " INTPTR_FORMAT " %s", p2i(interface_klass()), interface_klass()->external_name());
161 } else {
162 st->print_cr("- Klass: null");
163 }
164 if (bytecode1() == Bytecodes::_invokehandle) {
165 st->print_cr(" - Resolved References Index: %d", resolved_references_index());
166 } else {
167 st->print_cr(" - Resolved References Index: none");
168 }
169 if (bytecode2() == Bytecodes::_invokevirtual) {
170 #ifdef ASSERT
171 if (_has_table_index) {
172 st->print_cr(" - Table Index: %d", table_index());
173 }
174 #else
175 st->print_cr(" - Table Index: %d", table_index());
176 #endif
177 } else {
178 st->print_cr(" - Table Index: none");
179 }
180 st->print_cr(" - CP Index: %d", constant_pool_index());
181 st->print_cr(" - TOS: %s", type2name(as_BasicType((TosState)tos_state())));
182 st->print_cr(" - Number of Parameters: %d", number_of_parameters());
183 st->print_cr(" - Is Virtual Final: %d", is_vfinal());
184 st->print_cr(" - Is Final: %d", is_final());
185 st->print_cr(" - Is Forced Virtual: %d", is_forced_virtual());
186 st->print_cr(" - Has Appendix: %d", has_appendix());
187 st->print_cr(" - Has Local Signature: %d", has_local_signature());
188 st->print_cr(" - Bytecode 1: %s", Bytecodes::name((Bytecodes::Code)bytecode1()));
189 st->print_cr(" - Bytecode 2: %s", Bytecodes::name((Bytecodes::Code)bytecode2()));
190 }
--- EOF ---