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