1 /*
  2  * Copyright (c) 2023, 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 "cds/archiveBuilder.hpp"
 27 #include "cds/cdsAccess.hpp"
 28 #include "cds/cdsConfig.hpp"
 29 #include "cds/filemap.hpp"
 30 #include "cds/heapShared.hpp"
 31 #include "cds/metaspaceShared.hpp"
 32 #include "classfile/stringTable.hpp"
 33 #include "logging/log.hpp"
 34 #include "logging/logStream.hpp"
 35 #include "memory/resourceArea.hpp"
 36 #include "memory/universe.hpp"
 37 #include "memory/virtualspace.hpp"
 38 #include "oops/instanceKlass.hpp"
 39 
 40 size_t _cached_code_size = 0;
 41 
 42 bool CDSAccess::can_generate_cached_code(address addr) {
 43   if (CDSConfig::is_dumping_final_static_archive()) {
 44     return ArchiveBuilder::is_active() && ArchiveBuilder::current()->has_been_archived(addr);
 45   } else {
 46     // Old CDS+AOT workflow.
 47     return MetaspaceShared::is_in_shared_metaspace(addr);
 48   }
 49 }
 50 
 51 bool CDSAccess::can_generate_cached_code(InstanceKlass* ik) {
 52   if (CDSConfig::is_dumping_final_static_archive()) {
 53     if (!ArchiveBuilder::is_active()) {
 54       return false;
 55     }
 56     ArchiveBuilder* builder = ArchiveBuilder::current();
 57     if (!builder->has_been_archived((address)ik)) {
 58       return false;
 59     }
 60     InstanceKlass* buffered_ik = builder->get_buffered_addr(ik);
 61     if (ik->is_shared_unregistered_class()) {
 62       return false;
 63     }
 64     return true;
 65   } else {
 66     // Old CDS+AOT workflow.
 67     return ik->is_shared() && !ik->is_shared_unregistered_class();
 68   }
 69 }
 70 
 71 uint CDSAccess::delta_from_shared_address_base(address addr) {
 72   if (CDSConfig::is_dumping_final_static_archive()) {
 73     assert(ArchiveBuilder::is_active(), "must be");
 74     ArchiveBuilder* builder = ArchiveBuilder::current();
 75     address requested_addr = builder->to_requested(builder->get_buffered_addr(addr));
 76     return (uint)pointer_delta(requested_addr, (address)SharedBaseAddress, 1);
 77   } else {
 78     // Old CDS+AOT workflow.
 79     return (uint)pointer_delta(addr, (address)SharedBaseAddress, 1);
 80   }
 81 }
 82 
 83 Method* CDSAccess::method_in_cached_code(Method* m) {
 84   if (CDSConfig::is_dumping_final_static_archive()) {
 85     assert(ArchiveBuilder::is_active(), "must be");
 86     ArchiveBuilder* builder = ArchiveBuilder::current();
 87     return builder->to_requested(builder->get_buffered_addr(m));
 88   } else {
 89     // Old CDS+AOT workflow.
 90     return m;
 91   }
 92 }
 93 
 94 #if INCLUDE_CDS_JAVA_HEAP
 95 int CDSAccess::get_archived_object_permanent_index(oop obj) {
 96   return HeapShared::get_archived_object_permanent_index(obj);
 97 }
 98 
 99 oop CDSAccess::get_archived_object(int permanent_index) {
100   return HeapShared::get_archived_object(permanent_index);
101 }
102 
103 static void test_cds_heap_access_api_for_object(oop obj) {
104   LogStreamHandle(Info, cds, jit) log;
105 
106   obj->print_on(&log);
107   log.cr();
108 
109   int n = CDSAccess::get_archived_object_permanent_index(obj); // call this when -XX:+StoreCachedCode
110   if (n < 0) {
111     log.print_cr("*** This object is not in CDS archive");
112   } else {
113     log.print_cr("CDSAccess::get_archived_object_permanent_index(s) = %d", n);
114     oop archived_obj = CDSAccess::get_archived_object(n); // call this when -XX:+LoadCachedCode
115     if (archived_obj == obj || archived_obj == HeapShared::orig_to_scratch_object(obj)) {
116       log.print_cr("CDSAccess::get_archived_object(%d) returns the same object, as expected", n);
117     } else {
118       log.print_cr("Error!!! CDSAccess::get_archived_object(%d) returns an unexpected object", n);
119       if (archived_obj == nullptr) {
120         log.print_cr("--> null");
121       } else {
122         archived_obj->print_on(&log);
123         log.cr();
124       }
125     }
126   }
127 }
128 
129 // TEMP: examples for using the CDSAccess::get_archived_object_permanent_index() and CDSAccess::get_archived_object()
130 // APIs for the AOT compiler.
131 
132 void CDSAccess::test_heap_access_api() {
133   ResourceMark rm;
134   const char* tests[] = {
135     "",
136     "null",
137     "NARROW",
138     "not in cds",
139     nullptr,
140   };
141 
142   LogStreamHandle(Info, cds, jit) log;
143 
144   int i;
145   for (i = 0; tests[i] != nullptr; i++) {
146     EXCEPTION_MARK;
147     log.print_cr("Test %d ======================================== \"%s\"", i, tests[i]);
148     oop s = StringTable::intern(tests[i], CHECK);
149     test_cds_heap_access_api_for_object(s);
150   }
151 
152   log.print_cr("Test %d ======================================== Universe::null_ptr_exception_instance()", i);
153   test_cds_heap_access_api_for_object(Universe::null_ptr_exception_instance());
154 }
155 
156 // new workflow only
157 void* CDSAccess::allocate_from_code_cache(size_t size) {
158   assert(CDSConfig::is_dumping_final_static_archive(), "must be");
159   return (void*)ArchiveBuilder::cc_region_alloc(size);
160 }
161 
162 size_t CDSAccess::get_cached_code_size() {
163   return _cached_code_size;
164 }
165 
166 void CDSAccess::set_cached_code_size(size_t sz) {
167   _cached_code_size = sz;
168 }
169 
170 void CDSAccess::set_pointer(address* ptr, address value) {
171   ArchiveBuilder* builder = ArchiveBuilder::current();
172   if (value != nullptr && !builder->is_in_buffer_space(value)) {
173     value = builder->get_buffered_addr(value);
174   }
175   *ptr = value;
176   ArchivePtrMarker::mark_pointer(ptr);
177 }
178 
179 bool CDSAccess::map_cached_code(ReservedSpace rs) {
180   FileMapInfo* static_mapinfo = FileMapInfo::current_info();
181   assert(UseSharedSpaces && static_mapinfo != nullptr, "must be");
182   return static_mapinfo->map_cached_code_region(rs);
183 }
184 
185 #endif // INCLUDE_CDS_JAVA_HEAP