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 }