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