jdk

Форк
0
/
bootstrapInfo.cpp 
297 строк · 12.4 Кб
1
/*
2
 * Copyright (c) 2019, 2023, 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 "classfile/javaClasses.inline.hpp"
27
#include "classfile/resolutionErrors.hpp"
28
#include "classfile/systemDictionary.hpp"
29
#include "classfile/vmClasses.hpp"
30
#include "interpreter/bootstrapInfo.hpp"
31
#include "interpreter/linkResolver.hpp"
32
#include "jvm.h"
33
#include "logging/log.hpp"
34
#include "logging/logStream.hpp"
35
#include "memory/oopFactory.hpp"
36
#include "memory/resourceArea.hpp"
37
#include "oops/constantPool.inline.hpp"
38
#include "oops/cpCache.inline.hpp"
39
#include "oops/objArrayOop.inline.hpp"
40
#include "oops/resolvedIndyEntry.hpp"
41
#include "oops/typeArrayOop.inline.hpp"
42
#include "runtime/handles.inline.hpp"
43
#include "runtime/javaThread.hpp"
44
#include "runtime/vmThread.hpp"
45

46
//------------------------------------------------------------------------------------------------------------------------
47
// Implementation of BootstrapInfo
48

49
BootstrapInfo::BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index)
50
  : _pool(pool),
51
    _bss_index(bss_index),
52
    _indy_index(indy_index),
53
    // derived and eagerly cached:
54
    _argc(      pool->bootstrap_argument_count_at(bss_index) ),
55
    _name(      pool->uncached_name_ref_at(bss_index) ),
56
    _signature( pool->uncached_signature_ref_at(bss_index) )
57
{
58
  _is_resolved = false;
59
  assert(pool->tag_at(bss_index).has_bootstrap(), "");
60
  assert(indy_index == -1 || pool->resolved_indy_entry_at(indy_index)->constant_pool_index() == bss_index, "invalid bootstrap specifier index");
61
}
62

63
// If there is evidence this call site was already linked, set the
64
// existing linkage data into result, or throw previous exception.
65
// Return true if either action is taken, else false.
66
bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS) {
67
  assert(_indy_index != -1, "");
68
  // Check if method is not null
69
  ResolvedIndyEntry* indy_entry = _pool->resolved_indy_entry_at(_indy_index);
70
  if (indy_entry->method() != nullptr) {
71
    methodHandle method(THREAD, indy_entry->method());
72
    Handle appendix(THREAD, _pool->resolved_reference_from_indy(_indy_index));
73
    result.set_handle(vmClasses::MethodHandle_klass(), method, appendix, THREAD);
74
    Exceptions::wrap_dynamic_exception(/* is_indy */ true, CHECK_false);
75
    return true;
76
  } else if (indy_entry->resolution_failed()) {
77
    int encoded_index = ResolutionErrorTable::encode_indy_index(_indy_index);
78
    ConstantPool::throw_resolution_error(_pool, encoded_index, CHECK_false); // Doesn't necessarily need to be resolved yet
79
    return true;
80
  } else {
81
    return false;
82
  }
83
}
84

85
// Resolve the bootstrap specifier in 3 steps:
86
// - unpack the BSM by resolving the MH constant
87
// - obtain the NameAndType description for the condy/indy
88
// - prepare the BSM's static arguments
89
Handle BootstrapInfo::resolve_bsm(TRAPS) {
90
  if (_bsm.not_null()) {
91
    return _bsm;
92
  }
93

94
  bool is_indy = is_method_call();
95
  // The tag at the bootstrap method index must be a valid method handle or a method handle in error.
96
  // If it is a MethodHandleInError, a resolution error will be thrown which will be wrapped if necessary
97
  // with a BootstrapMethodError.
98
  assert(_pool->tag_at(bsm_index()).is_method_handle() ||
99
         _pool->tag_at(bsm_index()).is_method_handle_in_error(), "MH not present, classfile structural constraint");
100
  oop bsm_oop = _pool->resolve_possibly_cached_constant_at(bsm_index(), THREAD);
101
  Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);
102
  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm_oop), "classfile must supply a valid BSM");
103
  _bsm = Handle(THREAD, bsm_oop);
104

105
  // Obtain NameAndType information
106
  resolve_bss_name_and_type(THREAD);
107
  Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);
108

109
  // Prepare static arguments
110
  resolve_args(THREAD);
111
  Exceptions::wrap_dynamic_exception(is_indy, CHECK_NH);
112

113
  return _bsm;
114
}
115

116
// Resolve metadata from the JVM_Dynamic_info or JVM_InvokeDynamic_info's name and type information.
117
void BootstrapInfo::resolve_bss_name_and_type(TRAPS) {
118
  assert(_bsm.not_null(), "resolve_bsm first");
119
  Symbol* name = this->name();
120
  Symbol* type = this->signature();
121
  _name_arg = java_lang_String::create_from_symbol(name, CHECK);
122
  if (type->char_at(0) == '(') {
123
    _type_arg = SystemDictionary::find_method_handle_type(type, caller(), CHECK);
124
  } else {
125
    _type_arg = SystemDictionary::find_java_mirror_for_type(type, caller(), SignatureStream::NCDFError, CHECK);
126
  }
127
}
128

129
// Resolve the bootstrap method's static arguments and store the result in _arg_values.
130
void BootstrapInfo::resolve_args(TRAPS) {
131
  assert(_bsm.not_null(), "resolve_bsm first");
132

133
  // if there are no static arguments, return leaving _arg_values as null
134
  if (_argc == 0 && UseBootstrapCallInfo < 2) return;
135

136
  bool use_BSCI;
137
  switch (UseBootstrapCallInfo) {
138
  default: use_BSCI = true;  break;  // stress mode
139
  case 0:  use_BSCI = false; break;  // stress mode
140
  case 1:                            // normal mode
141
    // If we were to support an alternative mode of BSM invocation,
142
    // we'd convert to pull mode here if the BSM could be a candidate
143
    // for that alternative mode.  We can't easily test for things
144
    // like varargs here, but we can get away with approximate testing,
145
    // since the JDK runtime will make up the difference either way.
146
    // For now, exercise the pull-mode path if the BSM is of arity 2,
147
    // or if there is a potential condy loop (see below).
148
    oop mt_oop = java_lang_invoke_MethodHandle::type(_bsm());
149
    use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
150
    break;
151
  }
152

153
  // Here's a reason to use BSCI even if it wasn't requested:
154
  // If a condy uses a condy argument, we want to avoid infinite
155
  // recursion (condy loops) in the C code.  It's OK in Java,
156
  // because Java has stack overflow checking, so we punt
157
  // potentially cyclic cases from C to Java.
158
  if (!use_BSCI && _pool->tag_at(_bss_index).is_dynamic_constant()) {
159
    bool found_unresolved_condy = false;
160
    for (int i = 0; i < _argc; i++) {
161
      int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
162
      if (_pool->tag_at(arg_index).is_dynamic_constant()) {
163
        // potential recursion point condy -> condy
164
        bool found_it = false;
165
        _pool->find_cached_constant_at(arg_index, found_it, CHECK);
166
        if (!found_it) { found_unresolved_condy = true; break; }
167
      }
168
    }
169
    if (found_unresolved_condy)
170
      use_BSCI = true;
171
  }
172

173
  const int SMALL_ARITY = 5;
174
  if (use_BSCI && _argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
175
    // If there are only a few arguments, and none of them need linking,
176
    // push them, instead of asking the JDK runtime to turn around and
177
    // pull them, saving a JVM/JDK transition in some simple cases.
178
    bool all_resolved = true;
179
    for (int i = 0; i < _argc; i++) {
180
      bool found_it = false;
181
      int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
182
      _pool->find_cached_constant_at(arg_index, found_it, CHECK);
183
      if (!found_it) { all_resolved = false; break; }
184
    }
185
    if (all_resolved)
186
      use_BSCI = false;
187
  }
188

189
  if (!use_BSCI) {
190
    // return {arg...}; resolution of arguments is done immediately, before JDK code is called
191
    objArrayOop args_oop = oopFactory::new_objArray(vmClasses::Object_klass(), _argc, CHECK);
192
    objArrayHandle args(THREAD, args_oop);
193
    _pool->copy_bootstrap_arguments_at(_bss_index, 0, _argc, args, 0, true, Handle(), CHECK);
194
    oop arg_oop = ((_argc == 1) ? args->obj_at(0) : (oop)nullptr);
195
    // try to discard the singleton array
196
    if (arg_oop != nullptr && !arg_oop->is_array()) {
197
      // JVM treats arrays and nulls specially in this position,
198
      // but other things are just single arguments
199
      _arg_values = Handle(THREAD, arg_oop);
200
    } else {
201
      _arg_values = args;
202
    }
203
  } else {
204
    // return {arg_count, pool_index}; JDK code must pull the arguments as needed
205
    typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK);
206
    ints_oop->int_at_put(0, _argc);
207
    ints_oop->int_at_put(1, _bss_index);
208
    _arg_values = Handle(THREAD, ints_oop);
209
  }
210
}
211

212
// there must be a LinkageError pending; try to save it and then throw
213
bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) {
214
  assert(HAS_PENDING_EXCEPTION, "");
215
  assert(_indy_index != -1, "");
216
  assert(_indy_index >= 0, "Indy index must be decoded by now");
217
  bool recorded_res_status = _pool->cache()->save_and_throw_indy_exc(_pool, _bss_index,
218
                                                                     _indy_index,
219
                                                                     pool()->tag_at(_bss_index),
220
                                                                     CHECK_false);
221
  return recorded_res_status;
222
}
223

224
void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) {
225
  assert(is_resolved(), "");
226
  result.set_handle(vmClasses::MethodHandle_klass(), resolved_method(), resolved_appendix(), CHECK);
227
}
228

229
void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
230
  ResourceMark rm;
231
  char what[20];
232
  st = st ? st : tty;
233

234
  if (_indy_index > -1) {
235
    os::snprintf_checked(what, sizeof(what), "indy#%d", _indy_index);
236
  } else {
237
    os::snprintf_checked(what, sizeof(what), "condy");
238
  }
239
  bool have_msg = (msg != nullptr && strlen(msg) > 0);
240
  st->print_cr("%s%sBootstrap in %s %s@CP[%d] %s:%s%s BSMS[%d] BSM@CP[%d]%s argc=%d%s",
241
                (have_msg ? msg : ""), (have_msg ? " " : ""),
242
                caller()->name()->as_C_string(),
243
                what,  // "indy#42" or "condy"
244
                _bss_index,
245
                _name->as_C_string(),
246
                _signature->as_C_string(),
247
                (_type_arg.is_null() ? "" : "(resolved)"),
248
                bsms_attr_index(),
249
                bsm_index(), (_bsm.is_null() ? "" : "(resolved)"),
250
                _argc, (_arg_values.is_null() ? "" : "(resolved)"));
251
  if (_argc > 0) {
252
    char argbuf[80];
253
    argbuf[0] = 0;
254
    for (int i = 0; i < _argc; i++) {
255
      int pos = (int) strlen(argbuf);
256
      if (pos + 20 > (int)sizeof(argbuf)) {
257
        os::snprintf_checked(argbuf + pos, sizeof(argbuf) - pos, "...");
258
        break;
259
      }
260
      if (i > 0)  argbuf[pos++] = ',';
261
      os::snprintf_checked(argbuf+pos, sizeof(argbuf) - pos, "%d", arg_index(i));
262
    }
263
    st->print_cr("  argument indexes: {%s}", argbuf);
264
  }
265
  if (_bsm.not_null()) {
266
    st->print("  resolved BSM: "); _bsm->print_on(st);
267
  }
268

269
  // How the array of resolved arguments is printed depends highly
270
  // on how BootstrapInfo::resolve_args structures the array based on
271
  // the use_BSCI setting.
272
  if (_arg_values.not_null()) {
273
    // Find the static arguments within the first element of _arg_values.
274
    objArrayOop static_args = (objArrayOop)_arg_values();
275
    if (!static_args->is_array()) {
276
      assert(_argc == 1, "Invalid BSM _arg_values for non-array");
277
      st->print("  resolved arg[0]: "); static_args->print_on(st);
278
    } else if (static_args->is_objArray()) {
279
      int lines = 0;
280
      for (int i = 0; i < _argc; i++) {
281
        oop x = static_args->obj_at(i);
282
        if (x != nullptr) {
283
          if (++lines > 6) {
284
            st->print_cr("  resolved arg[%d]: ...", i);
285
            break;
286
          }
287
          st->print("  resolved arg[%d]: ", i); x->print_on(st);
288
        }
289
      }
290
    } else if (static_args->is_typeArray()) {
291
      typeArrayOop tmp_array = (typeArrayOop) static_args;
292
      assert(tmp_array->length() == 2, "Invalid BSM _arg_values type array");
293
      st->print_cr("  resolved arg[0]: %d", tmp_array->int_at(0));
294
      st->print_cr("  resolved arg[1]: %d", tmp_array->int_at(1));
295
    }
296
  }
297
}
298

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.