1/*
2 * Copyright (c) 2019, 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 "jvm.h"
27#include "classfile/javaClasses.inline.hpp"
28#include "classfile/resolutionErrors.hpp"
29#include "interpreter/bootstrapInfo.hpp"
30#include "interpreter/linkResolver.hpp"
31#include "logging/log.hpp"
32#include "logging/logStream.hpp"
33#include "memory/oopFactory.hpp"
34#include "oops/cpCache.inline.hpp"
35#include "oops/objArrayOop.inline.hpp"
36#include "oops/typeArrayOop.inline.hpp"
37#include "runtime/handles.inline.hpp"
38#include "runtime/thread.inline.hpp"
39#include "runtime/vmThread.hpp"
40
41//------------------------------------------------------------------------------------------------------------------------
42// Implementation of BootstrapInfo
43
44BootstrapInfo::BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index)
45 : _pool(pool),
46 _bss_index(bss_index),
47 _indy_index(indy_index),
48 // derived and eagerly cached:
49 _argc( pool->bootstrap_argument_count_at(bss_index) ),
50 _name( pool->uncached_name_ref_at(bss_index) ),
51 _signature( pool->uncached_signature_ref_at(bss_index) )
52{
53 _is_resolved = false;
54 assert(pool->tag_at(bss_index).has_bootstrap(), "");
55 assert(indy_index == -1 || pool->invokedynamic_bootstrap_ref_index_at(indy_index) == bss_index, "invalid bootstrap specifier index");
56}
57
58// If there is evidence this call site was already linked, set the
59// existing linkage data into result, or throw previous exception.
60// Return true if either action is taken, else false.
61bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS) {
62 assert(_indy_index != -1, "");
63 ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
64 if (!cpce->is_f1_null()) {
65 methodHandle method( THREAD, cpce->f1_as_method());
66 Handle appendix( THREAD, cpce->appendix_if_resolved(_pool));
67 result.set_handle(method, appendix, THREAD);
68 Exceptions::wrap_dynamic_exception(CHECK_false);
69 return true;
70 } else if (cpce->indy_resolution_failed()) {
71 int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
72 ConstantPool::throw_resolution_error(_pool, encoded_index, CHECK_false);
73 return true;
74 } else {
75 return false;
76 }
77}
78
79// Resolve the bootstrap specifier in 3 steps:
80// - unpack the BSM by resolving the MH constant
81// - obtain the NameAndType description for the condy/indy
82// - prepare the BSM's static arguments
83Handle BootstrapInfo::resolve_bsm(TRAPS) {
84 if (_bsm.not_null()) return _bsm;
85 // The tag at the bootstrap method index must be a valid method handle or a method handle in error.
86 // If it is a MethodHandleInError, a resolution error will be thrown which will be wrapped if necessary
87 // with a BootstrapMethodError.
88 assert(_pool->tag_at(bsm_index()).is_method_handle() ||
89 _pool->tag_at(bsm_index()).is_method_handle_in_error(), "MH not present, classfile structural constraint");
90 oop bsm_oop = _pool->resolve_possibly_cached_constant_at(bsm_index(), THREAD);
91 Exceptions::wrap_dynamic_exception(CHECK_NH);
92 guarantee(java_lang_invoke_MethodHandle::is_instance(bsm_oop), "classfile must supply a valid BSM");
93 _bsm = Handle(THREAD, bsm_oop);
94
95 // Obtain NameAndType information
96 resolve_bss_name_and_type(THREAD);
97 Exceptions::wrap_dynamic_exception(CHECK_NH);
98
99 // Prepare static arguments
100 resolve_args(THREAD);
101 Exceptions::wrap_dynamic_exception(CHECK_NH);
102
103 return _bsm;
104}
105
106// Resolve metadata from the JVM_Dynamic_info or JVM_InvokeDynamic_info's name and type information.
107void BootstrapInfo::resolve_bss_name_and_type(TRAPS) {
108 assert(_bsm.not_null(), "resolve_bsm first");
109 Symbol* name = this->name();
110 Symbol* type = this->signature();
111 _name_arg = java_lang_String::create_from_symbol(name, CHECK);
112 if (type->char_at(0) == '(') {
113 _type_arg = SystemDictionary::find_method_handle_type(type, caller(), CHECK);
114 } else {
115 _type_arg = SystemDictionary::find_java_mirror_for_type(type, caller(), SignatureStream::NCDFError, CHECK);
116 }
117}
118
119// Resolve the bootstrap method's static arguments and store the result in _arg_values.
120void BootstrapInfo::resolve_args(TRAPS) {
121 assert(_bsm.not_null(), "resolve_bsm first");
122
123 // if there are no static arguments, return leaving _arg_values as null
124 if (_argc == 0 && UseBootstrapCallInfo < 2) return;
125
126 bool use_BSCI;
127 switch (UseBootstrapCallInfo) {
128 default: use_BSCI = true; break; // stress mode
129 case 0: use_BSCI = false; break; // stress mode
130 case 1: // normal mode
131 // If we were to support an alternative mode of BSM invocation,
132 // we'd convert to pull mode here if the BSM could be a candidate
133 // for that alternative mode. We can't easily test for things
134 // like varargs here, but we can get away with approximate testing,
135 // since the JDK runtime will make up the difference either way.
136 // For now, exercise the pull-mode path if the BSM is of arity 2,
137 // or if there is a potential condy loop (see below).
138 oop mt_oop = java_lang_invoke_MethodHandle::type(_bsm());
139 use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
140 break;
141 }
142
143 // Here's a reason to use BSCI even if it wasn't requested:
144 // If a condy uses a condy argument, we want to avoid infinite
145 // recursion (condy loops) in the C code. It's OK in Java,
146 // because Java has stack overflow checking, so we punt
147 // potentially cyclic cases from C to Java.
148 if (!use_BSCI && _pool->tag_at(_bss_index).is_dynamic_constant()) {
149 bool found_unresolved_condy = false;
150 for (int i = 0; i < _argc; i++) {
151 int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
152 if (_pool->tag_at(arg_index).is_dynamic_constant()) {
153 // potential recursion point condy -> condy
154 bool found_it = false;
155 _pool->find_cached_constant_at(arg_index, found_it, CHECK);
156 if (!found_it) { found_unresolved_condy = true; break; }
157 }
158 }
159 if (found_unresolved_condy)
160 use_BSCI = true;
161 }
162
163 const int SMALL_ARITY = 5;
164 if (use_BSCI && _argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
165 // If there are only a few arguments, and none of them need linking,
166 // push them, instead of asking the JDK runtime to turn around and
167 // pull them, saving a JVM/JDK transition in some simple cases.
168 bool all_resolved = true;
169 for (int i = 0; i < _argc; i++) {
170 bool found_it = false;
171 int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
172 _pool->find_cached_constant_at(arg_index, found_it, CHECK);
173 if (!found_it) { all_resolved = false; break; }
174 }
175 if (all_resolved)
176 use_BSCI = false;
177 }
178
179 if (!use_BSCI) {
180 // return {arg...}; resolution of arguments is done immediately, before JDK code is called
181 objArrayOop args_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), _argc, CHECK);
182 objArrayHandle args(THREAD, args_oop);
183 _pool->copy_bootstrap_arguments_at(_bss_index, 0, _argc, args, 0, true, Handle(), CHECK);
184 oop arg_oop = ((_argc == 1) ? args->obj_at(0) : (oop)NULL);
185 // try to discard the singleton array
186 if (arg_oop != NULL && !arg_oop->is_array()) {
187 // JVM treats arrays and nulls specially in this position,
188 // but other things are just single arguments
189 _arg_values = Handle(THREAD, arg_oop);
190 } else {
191 _arg_values = args;
192 }
193 } else {
194 // return {arg_count, pool_index}; JDK code must pull the arguments as needed
195 typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK);
196 ints_oop->int_at_put(0, _argc);
197 ints_oop->int_at_put(1, _bss_index);
198 _arg_values = Handle(THREAD, ints_oop);
199 }
200}
201
202// there must be a LinkageError pending; try to save it and then throw
203bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) {
204 assert(HAS_PENDING_EXCEPTION, "");
205 assert(_indy_index != -1, "");
206 ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
207 int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
208 bool recorded_res_status = cpce->save_and_throw_indy_exc(_pool, _bss_index,
209 encoded_index,
210 pool()->tag_at(_bss_index),
211 CHECK_false);
212 return recorded_res_status;
213}
214
215void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) {
216 assert(is_resolved(), "");
217 result.set_handle(resolved_method(), resolved_appendix(), CHECK);
218}
219
220void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
221 ResourceMark rm;
222 char what[20];
223 st = st ? st : tty;
224
225 if (_indy_index != -1)
226 sprintf(what, "indy#%d", decode_indy_index());
227 else
228 sprintf(what, "condy");
229 bool have_msg = (msg != NULL && strlen(msg) > 0);
230 st->print_cr("%s%sBootstrap in %s %s@CP[%d] %s:%s%s BSMS[%d] BSM@CP[%d]%s argc=%d%s",
231 (have_msg ? msg : ""), (have_msg ? " " : ""),
232 caller()->name()->as_C_string(),
233 what, // "indy#42" or "condy"
234 _bss_index,
235 _name->as_C_string(),
236 _signature->as_C_string(),
237 (_type_arg.is_null() ? "" : "(resolved)"),
238 bsms_attr_index(),
239 bsm_index(), (_bsm.is_null() ? "" : "(resolved)"),
240 _argc, (_arg_values.is_null() ? "" : "(resolved)"));
241 if (_argc > 0) {
242 char argbuf[80];
243 argbuf[0] = 0;
244 for (int i = 0; i < _argc; i++) {
245 int pos = (int) strlen(argbuf);
246 if (pos + 20 > (int)sizeof(argbuf)) {
247 sprintf(argbuf + pos, "...");
248 break;
249 }
250 if (i > 0) argbuf[pos++] = ',';
251 sprintf(argbuf+pos, "%d", arg_index(i));
252 }
253 st->print_cr(" argument indexes: {%s}", argbuf);
254 }
255 if (_bsm.not_null()) {
256 st->print(" resolved BSM: "); _bsm->print();
257 }
258
259 // How the array of resolved arguments is printed depends highly
260 // on how BootstrapInfo::resolve_args structures the array based on
261 // the use_BSCI setting.
262 if (_arg_values.not_null()) {
263 // Find the static arguments within the first element of _arg_values.
264 objArrayOop static_args = (objArrayOop)_arg_values();
265 if (!static_args->is_array()) {
266 assert(_argc == 1, "Invalid BSM _arg_values for non-array");
267 st->print(" resolved arg[0]: "); static_args->print();
268 } else if (static_args->is_objArray()) {
269 int lines = 0;
270 for (int i = 0; i < _argc; i++) {
271 oop x = static_args->obj_at(i);
272 if (x != NULL) {
273 if (++lines > 6) {
274 st->print_cr(" resolved arg[%d]: ...", i);
275 break;
276 }
277 st->print(" resolved arg[%d]: ", i); x->print();
278 }
279 }
280 } else if (static_args->is_typeArray()) {
281 typeArrayOop tmp_array = (typeArrayOop) static_args;
282 assert(tmp_array->length() == 2, "Invalid BSM _arg_values type array");
283 st->print_cr(" resolved arg[0]: %d", tmp_array->int_at(0));
284 st->print_cr(" resolved arg[1]: %d", tmp_array->int_at(1));
285 }
286 }
287}
288