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