1 /*
  2  * Copyright (c) 1997, 2024, 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 "runtime/interfaceSupport.inline.hpp"
 27 #include "runtime/methodDetails.hpp"
 28 #include "runtime/runtimeUpcalls.hpp"
 29 
 30 GrowableArray<RuntimeUpcallInfo*>* RuntimeUpcalls::_upcalls[RuntimeUpcallType::numTypes];
 31 RuntimeUpcalls::State RuntimeUpcalls::_state = RuntimeUpcalls::Uninitialized;
 32 
 33 bool runtimeUpcalls_open_registration() {
 34   return RuntimeUpcalls::open_upcall_registration();
 35 }
 36 
 37 bool RuntimeUpcalls::open_upcall_registration() {
 38   assert(_state == Uninitialized, "upcalls are already open");
 39   for (int i = 0; i < RuntimeUpcallType::numTypes; i++) {
 40     RuntimeUpcalls::_upcalls[i] = nullptr;
 41   }
 42   _state = Open;
 43   return true;
 44 }
 45 
 46 void runtimeUpcalls_close_registration() {
 47   RuntimeUpcalls::close_upcall_registration();
 48 }
 49 
 50 void RuntimeUpcalls::close_upcall_registration() {
 51   assert(_state == Open, "upcalls are not open");
 52   _state = Closed;
 53 }
 54 
 55 void RuntimeUpcalls::mark_for_upcalls(RuntimeUpcallType upcall_type, const methodHandle& method) {
 56   if (_upcalls[upcall_type] != nullptr) {
 57     MethodDetails method_details(method);
 58     for(RuntimeUpcallInfo* info : *(_upcalls[upcall_type])) {
 59       if(info->includes(method_details)) {
 60         switch(upcall_type) {
 61           case onMethodEntry: method->set_has_upcall_on_method_entry(true); break;
 62           case onMethodExit:  method->set_has_upcall_on_method_exit(true);  break;
 63           default:            ShouldNotReachHere();
 64         }
 65         break;
 66       }
 67     }
 68   }
 69 }
 70 
 71 bool RuntimeUpcalls::register_upcall(RuntimeUpcallType upcall_type, RuntimeUpcallInfo* info) {
 72   assert(upcall_type != onMethodExit, "Upcalls on method exit are not supported yet");
 73   assert(info != nullptr, "upcall info is null");
 74   if (_upcalls[upcall_type] == nullptr) {
 75     _upcalls[upcall_type] = new (mtServiceability) GrowableArray<RuntimeUpcallInfo*>(1, mtServiceability);
 76   }
 77   info->set_index(_upcalls[upcall_type]->length());
 78   _upcalls[upcall_type]->append(info);
 79   return true;
 80 }
 81 
 82 int RuntimeUpcalls::get_num_upcalls(RuntimeUpcallType upcall_type) {
 83   return (_upcalls[upcall_type] == nullptr) ? 0 : _upcalls[upcall_type]->length();
 84 }
 85 
 86 void RuntimeUpcalls::upcall_redirect(RuntimeUpcallType upcall_type, JavaThread* current, Method* method) {
 87   MethodDetails method_details(method);
 88 
 89   // This redirection occurs when there are more than one upcalls setup.  Currently each method is marked
 90   // to indicate either none, entry and/or exit upcalls (two bits total); then we have to iterate over
 91   // all upcalls and test the method details to determine which upcalls to call.  This is not optimal.
 92   // One possible optimization is to use more bits to support more upcalls.  The method flags currently use 18
 93   // out of 32 bits, so there are still 14 bits available for use.  We could set a limit of say 4-8 entry/exit
 94   // upcalls combined, leaving 10-6 bits for other uses.  This still requires a redirect here to determine
 95   // which upcalls to call, but it would be more efficient than the current implementation as we'd avoid the
 96   // method matching and simply map bits to indexes.
 97 
 98   RuntimeUpcallInfo* upcall = get_first_upcall(upcall_type, method_details);
 99   while (upcall != nullptr) {
100     upcall->upcall()(current);
101     upcall = get_next_upcall(upcall_type, method_details, upcall);
102   }
103 }
104 
105 JRT_BLOCK_ENTRY(void, RuntimeUpcalls::on_method_entry_upcall_redirect(JavaThread* current, Method* method)) {
106     RuntimeUpcalls::upcall_redirect(onMethodEntry, current, method);
107 }
108 JRT_END
109 
110 JRT_BLOCK_ENTRY(void, RuntimeUpcalls::on_method_exit_upcall_redirect(JavaThread* current, Method* method)) {
111     RuntimeUpcalls::upcall_redirect(onMethodExit, current, method);
112 }
113 JRT_END
114 
115 //-------------------------------RuntimeUpcalls---------------------------------------
116 
117 void RuntimeUpcalls::install_upcalls(const methodHandle& method) {
118   for (int i = 0; i < RuntimeUpcallType::numTypes; i++) {
119       mark_for_upcalls(static_cast<RuntimeUpcallType>(i), method);
120   }
121 }
122 
123 bool RuntimeUpcalls::register_upcall(RuntimeUpcallType upcall_type, const char* upcall_name, RuntimeUpcall upcall, RuntimeUpcallMethodFilterCallback method_filter_callback)
124 {
125   assert(upcall_type < numTypes, "invalid upcall type");
126   assert(_state == Open, "upcalls are not open for registration");
127   if (_state != Open) return false;
128   return register_upcall(upcall_type, RuntimeUpcallInfo::create(upcall_name, upcall, method_filter_callback));
129 }
130 
131 RuntimeUpcallInfo* RuntimeUpcalls::get_next_upcall(RuntimeUpcallType upcall_type, MethodDetails& method_details, RuntimeUpcallInfo* prev_upcall_info) {
132   assert(upcall_type < numTypes, "invalid upcall type");
133   if (_upcalls[upcall_type] != nullptr) {
134     // simple case where there's only one upcall
135     if (_upcalls[upcall_type]->length() == 1) {
136       if (prev_upcall_info != nullptr) {
137         return nullptr;
138       }
139       RuntimeUpcallInfo* upcall = _upcalls[upcall_type]->at(0);
140       return upcall->includes(method_details) ? upcall : nullptr;
141     }
142 
143     // Resume from where we left off, unless we are the last entry.
144     assert(prev_upcall_info == nullptr || (prev_upcall_info->get_index() >= 0 && prev_upcall_info->get_index() < _upcalls[upcall_type]->length()), "invalid upcall index");
145     int index = (prev_upcall_info != nullptr) ? prev_upcall_info->get_index() + 1 : 0;
146     for (int i = index; i < _upcalls[upcall_type]->length(); i++) {
147       RuntimeUpcallInfo* upcall = _upcalls[upcall_type]->at(i);
148       if (upcall->includes(method_details)) {
149         return upcall;
150       }
151     }
152   }
153 
154   return nullptr;
155 }
156 
157 RuntimeUpcallInfo* RuntimeUpcalls::get_first_upcall(RuntimeUpcallType upcall_type, MethodDetails& method_details) {
158   return get_next_upcall(upcall_type, method_details, nullptr);
159 }
160 
161 bool RuntimeUpcalls::does_upcall_need_method_parameter(address upcall_address)
162 {
163   // Redirect needs the method parameter for filtering.
164   if((upcall_address == CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_entry_upcall_redirect)) ||
165      (upcall_address == CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_exit_upcall_redirect))) {
166     return true;
167   }
168 
169   return false;
170 }
171 
172 address RuntimeUpcalls::on_method_entry_upcall_address()
173 {
174   // Optimized case when there's only one upcall (no need to redirect).
175   if(_upcalls[onMethodEntry] != nullptr && _upcalls[onMethodEntry]->length() == 1) {
176     return _upcalls[onMethodEntry]->at(0)->upcall_address();
177   }
178 
179   return CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_entry_upcall_redirect);
180 }
181 
182 address RuntimeUpcalls::on_method_exit_upcall_address()
183 {
184   // Optimized case when there's only one upcall (no need to redirect).
185   if(_upcalls[onMethodExit] != nullptr && _upcalls[onMethodExit]->length() == 1) {
186     return _upcalls[onMethodExit]->at(0)->upcall_address();
187   }
188 
189   return CAST_FROM_FN_PTR(address, RuntimeUpcalls::on_method_exit_upcall_redirect);
190 }
191 
192 const char* RuntimeUpcalls::get_name_for_upcall_address(address upcall_address)
193 {
194   for(int i = 0; i < RuntimeUpcallType::numTypes; i++) {
195     if (_upcalls[i] != nullptr) {
196       for (int j = 0; j < _upcalls[i]->length(); j++) {
197         RuntimeUpcallInfo* upcall = _upcalls[i]->at(j);
198         if (upcall->upcall_address() == upcall_address) {
199           return upcall->upcall_name();
200         }
201       }
202     }
203   }
204   return nullptr;
205 }