Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
41161 views
1
/*
2
* Copyright (c) 2010, 2016, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
/*
27
* This file is available under and governed by the GNU General Public
28
* License version 2 only, as published by the Free Software Foundation.
29
* However, the following notice accompanied the original version of this
30
* file, and Oracle licenses the original version of this file under the BSD
31
* license:
32
*/
33
/*
34
Copyright 2009-2013 Attila Szegedi
35
36
Redistribution and use in source and binary forms, with or without
37
modification, are permitted provided that the following conditions are
38
met:
39
* Redistributions of source code must retain the above copyright
40
notice, this list of conditions and the following disclaimer.
41
* Redistributions in binary form must reproduce the above copyright
42
notice, this list of conditions and the following disclaimer in the
43
documentation and/or other materials provided with the distribution.
44
* Neither the name of the copyright holder nor the names of
45
contributors may be used to endorse or promote products derived from
46
this software without specific prior written permission.
47
48
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
49
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
51
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
52
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
55
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
56
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
57
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
58
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59
*/
60
61
package jdk.dynalink.beans;
62
63
import java.lang.invoke.MethodHandle;
64
import java.lang.invoke.MethodHandles;
65
import java.lang.invoke.MethodType;
66
import java.lang.reflect.Array;
67
import java.util.Collection;
68
import java.util.Collections;
69
import java.util.List;
70
import java.util.Map;
71
import java.util.function.Function;
72
import jdk.dynalink.CallSiteDescriptor;
73
import jdk.dynalink.Namespace;
74
import jdk.dynalink.Operation;
75
import jdk.dynalink.StandardNamespace;
76
import jdk.dynalink.StandardOperation;
77
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
78
import jdk.dynalink.linker.GuardedInvocation;
79
import jdk.dynalink.linker.LinkerServices;
80
import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
81
import jdk.dynalink.linker.support.Guards;
82
import jdk.dynalink.linker.support.Lookup;
83
import jdk.dynalink.linker.support.TypeUtilities;
84
85
/**
86
* A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
87
* {@link BeansLinker}. Most of the functionality is provided by the {@link AbstractJavaLinker} superclass; this
88
* class adds length and element operations for arrays and collections.
89
*/
90
class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker {
91
BeanLinker(final Class<?> clazz) {
92
super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz));
93
if(clazz.isArray()) {
94
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
95
// explicit property is beneficial for them.
96
setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY);
97
} else if(Collection.class.isAssignableFrom(clazz)) {
98
setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
99
} else if(Map.class.isAssignableFrom(clazz)) {
100
setPropertyGetter("length", GET_MAP_LENGTH, ValidationType.INSTANCE_OF);
101
}
102
}
103
104
@Override
105
public boolean canLinkType(final Class<?> type) {
106
return type == clazz;
107
}
108
109
@Override
110
FacetIntrospector createFacetIntrospector() {
111
return new BeanIntrospector(clazz);
112
}
113
114
@Override
115
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception {
116
if (req.namespaces.isEmpty()) {
117
return null;
118
}
119
final Namespace ns = req.namespaces.get(0);
120
if (ns == StandardNamespace.ELEMENT) {
121
final Operation op = req.baseOperation;
122
if (op == StandardOperation.GET) {
123
return getElementGetter(req.popNamespace());
124
} else if (op == StandardOperation.SET) {
125
return getElementSetter(req.popNamespace());
126
} else if (op == StandardOperation.REMOVE) {
127
return getElementRemover(req.popNamespace());
128
}
129
}
130
return super.getGuardedInvocationComponent(req);
131
}
132
133
@Override
134
SingleDynamicMethod getConstructorMethod(final String signature) {
135
return null;
136
}
137
138
private static final MethodHandle GET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "get",
139
MethodType.methodType(Object.class, int.class));
140
141
private static final MethodHandle GET_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "get",
142
MethodType.methodType(Object.class, Object.class));
143
144
private static final MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class);
145
private static final MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class);
146
147
private static final MethodHandle NULL_GETTER_1;
148
private static final MethodHandle NULL_GETTER_2;
149
static {
150
final MethodHandle constantNull = MethodHandles.constant(Object.class, null);
151
NULL_GETTER_1 = dropObjectArguments(constantNull, 1);
152
NULL_GETTER_2 = dropObjectArguments(constantNull, 2);
153
}
154
155
private static MethodHandle dropObjectArguments(final MethodHandle m, final int n) {
156
return MethodHandles.dropArguments(m, 0, Collections.nCopies(n, Object.class));
157
}
158
159
private enum CollectionType {
160
ARRAY, LIST, MAP
161
}
162
163
private GuardedInvocationComponent getElementGetter(final ComponentLinkRequest req) throws Exception {
164
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
165
final Object name = req.name;
166
final boolean isFixedKey = name != null;
167
assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
168
final LinkerServices linkerServices = req.linkerServices;
169
final MethodType callSiteType = callSiteDescriptor.getMethodType();
170
final GuardedInvocationComponent nextComponent = getNextComponent(req);
171
172
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
173
callSiteType, linkerServices, MethodHandles::arrayElementGetter, GET_LIST_ELEMENT, GET_MAP_ELEMENT);
174
175
if (gicact == null) {
176
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
177
return nextComponent;
178
}
179
180
final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices);
181
if (typedName == INVALID_NAME) {
182
return nextComponent;
183
}
184
185
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent,
186
new Binder(linkerServices, callSiteType, typedName), isFixedKey ? NULL_GETTER_1 : NULL_GETTER_2);
187
}
188
189
private static class GuardedInvocationComponentAndCollectionType {
190
final GuardedInvocationComponent gic;
191
final CollectionType collectionType;
192
193
GuardedInvocationComponentAndCollectionType(final GuardedInvocationComponent gic, final CollectionType collectionType) {
194
this.gic = gic;
195
this.collectionType = collectionType;
196
}
197
}
198
199
private GuardedInvocationComponentAndCollectionType guardedInvocationComponentAndCollectionType(
200
final MethodType callSiteType, final LinkerServices linkerServices,
201
final Function<Class<?>, MethodHandle> arrayMethod, final MethodHandle listMethod, final MethodHandle mapMethod) {
202
final Class<?> declaredType = callSiteType.parameterType(0);
203
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
204
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
205
// dealing with an array, or a list or map, but hey...
206
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
207
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
208
if(declaredType.isArray() && arrayMethod != null) {
209
return new GuardedInvocationComponentAndCollectionType(
210
createInternalFilteredGuardedInvocationComponent(arrayMethod.apply(declaredType), linkerServices),
211
CollectionType.ARRAY);
212
} else if(List.class.isAssignableFrom(declaredType)) {
213
return new GuardedInvocationComponentAndCollectionType(
214
createInternalFilteredGuardedInvocationComponent(listMethod, linkerServices),
215
CollectionType.LIST);
216
} else if(Map.class.isAssignableFrom(declaredType)) {
217
return new GuardedInvocationComponentAndCollectionType(
218
createInternalFilteredGuardedInvocationComponent(mapMethod, linkerServices),
219
CollectionType.MAP);
220
} else if(clazz.isArray() && arrayMethod != null) {
221
return new GuardedInvocationComponentAndCollectionType(
222
getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(arrayMethod.apply(clazz)), callSiteType),
223
CollectionType.ARRAY);
224
} else if(List.class.isAssignableFrom(clazz)) {
225
return new GuardedInvocationComponentAndCollectionType(
226
createInternalFilteredGuardedInvocationComponent(listMethod, Guards.asType(LIST_GUARD, callSiteType),
227
List.class, ValidationType.INSTANCE_OF, linkerServices),
228
CollectionType.LIST);
229
} else if(Map.class.isAssignableFrom(clazz)) {
230
return new GuardedInvocationComponentAndCollectionType(
231
createInternalFilteredGuardedInvocationComponent(mapMethod, Guards.asType(MAP_GUARD, callSiteType),
232
Map.class, ValidationType.INSTANCE_OF, linkerServices),
233
CollectionType.MAP);
234
}
235
return null;
236
}
237
238
private static final Object INVALID_NAME = new Object();
239
240
private static Object getTypedName(final Object name, final boolean isMap, final LinkerServices linkerServices) throws Exception {
241
// Convert the key to a number if we're working with a list or array
242
if (!isMap && name != null) {
243
final Integer integer = convertKeyToInteger(name, linkerServices);
244
if (integer == null || integer < 0) {
245
// key is not a non-negative integer, it can never address an
246
// array or list element
247
return INVALID_NAME;
248
}
249
return integer;
250
}
251
return name;
252
}
253
254
private static GuardedInvocationComponent guardComponentWithRangeCheck(
255
final GuardedInvocationComponentAndCollectionType gicact, final MethodType callSiteType,
256
final GuardedInvocationComponent nextComponent, final Binder binder, final MethodHandle noOp) {
257
258
final MethodHandle checkGuard;
259
switch(gicact.collectionType) {
260
case LIST:
261
checkGuard = binder.convertArgToNumber(RANGE_CHECK_LIST);
262
break;
263
case MAP:
264
checkGuard = binder.linkerServices.filterInternalObjects(CONTAINS_MAP);
265
break;
266
case ARRAY:
267
checkGuard = binder.convertArgToNumber(RANGE_CHECK_ARRAY);
268
break;
269
default:
270
throw new AssertionError();
271
}
272
273
// If there's no next component, produce a fixed no-op one
274
final GuardedInvocationComponent finalNextComponent;
275
if (nextComponent != null) {
276
finalNextComponent = nextComponent;
277
} else {
278
finalNextComponent = createGuardedInvocationComponentAsType(noOp, callSiteType, binder.linkerServices);
279
}
280
281
final GuardedInvocationComponent gic = gicact.gic;
282
final GuardedInvocation gi = gic.getGuardedInvocation();
283
284
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(gi.getInvocation()),
285
finalNextComponent.getGuardedInvocation().getInvocation());
286
287
return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
288
gic.getValidatorClass(), gic.getValidationType());
289
}
290
291
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
292
final MethodHandle invocation, final LinkerServices linkerServices) {
293
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation));
294
}
295
296
private static GuardedInvocationComponent createGuardedInvocationComponentAsType(
297
final MethodHandle invocation, final MethodType fromType, final LinkerServices linkerServices) {
298
return new GuardedInvocationComponent(linkerServices.asType(invocation, fromType));
299
}
300
301
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
302
final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass,
303
final ValidationType validationType, final LinkerServices linkerServices) {
304
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation), guard,
305
validatorClass, validationType);
306
}
307
308
private static Integer convertKeyToInteger(final Object fixedKey, final LinkerServices linkerServices) throws Exception {
309
if (fixedKey instanceof Integer) {
310
return (Integer)fixedKey;
311
}
312
313
final Number n;
314
if (fixedKey instanceof Number) {
315
n = (Number)fixedKey;
316
} else {
317
final Class<?> keyClass = fixedKey.getClass();
318
if(linkerServices.canConvert(keyClass, Number.class)) {
319
final Object val;
320
try {
321
val = linkerServices.getTypeConverter(keyClass, Number.class).invoke(fixedKey);
322
} catch(Exception|Error e) {
323
throw e;
324
} catch(final Throwable t) {
325
throw new RuntimeException(t);
326
}
327
if(!(val instanceof Number)) {
328
return null; // not a number
329
}
330
n = (Number)val;
331
} else if (fixedKey instanceof String){
332
try {
333
return Integer.valueOf((String)fixedKey);
334
} catch(final NumberFormatException e) {
335
// key is not a number
336
return null;
337
}
338
} else {
339
return null;
340
}
341
}
342
343
if(n instanceof Integer) {
344
return (Integer)n;
345
}
346
final int intIndex = n.intValue();
347
final double doubleValue = n.doubleValue();
348
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
349
return null; // not an exact integer
350
}
351
return intIndex;
352
}
353
354
/**
355
* Contains methods to adapt an item getter/setter method handle to the requested type, optionally binding it to a
356
* fixed key first.
357
*/
358
private static class Binder {
359
private final LinkerServices linkerServices;
360
private final MethodType methodType;
361
private final Object fixedKey;
362
363
Binder(final LinkerServices linkerServices, final MethodType methodType, final Object fixedKey) {
364
this.linkerServices = linkerServices;
365
this.methodType = fixedKey == null ? methodType : methodType.insertParameterTypes(1, fixedKey.getClass());
366
this.fixedKey = fixedKey;
367
}
368
369
/*private*/ MethodHandle bind(final MethodHandle handle) {
370
return bindToFixedKey(linkerServices.asTypeLosslessReturn(handle, methodType));
371
}
372
373
/*private*/ MethodHandle bindTest(final MethodHandle handle) {
374
return bindToFixedKey(Guards.asType(handle, methodType));
375
}
376
377
/*private*/ MethodHandle convertArgToNumber(final MethodHandle mh) {
378
final Class<?> sourceType = methodType.parameterType(1);
379
if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) {
380
return mh;
381
} else if(linkerServices.canConvert(sourceType, Number.class)) {
382
final MethodHandle converter = linkerServices.getTypeConverter(sourceType, Number.class);
383
return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType(
384
mh.type().parameterType(1))));
385
}
386
return mh;
387
}
388
389
private MethodHandle bindToFixedKey(final MethodHandle handle) {
390
return fixedKey == null ? handle : MethodHandles.insertArguments(handle, 1, fixedKey);
391
}
392
}
393
394
private static final MethodHandle RANGE_CHECK_ARRAY = findRangeCheck(Object.class);
395
private static final MethodHandle RANGE_CHECK_LIST = findRangeCheck(List.class);
396
private static final MethodHandle CONTAINS_MAP = Lookup.PUBLIC.findVirtual(Map.class, "containsKey",
397
MethodType.methodType(boolean.class, Object.class));
398
399
private static MethodHandle findRangeCheck(final Class<?> collectionType) {
400
return Lookup.findOwnStatic(MethodHandles.lookup(), "rangeCheck", boolean.class, collectionType, Object.class);
401
}
402
403
@SuppressWarnings("unused")
404
private static boolean rangeCheck(final Object array, final Object index) {
405
if(!(index instanceof Number)) {
406
return false;
407
}
408
final Number n = (Number)index;
409
final int intIndex = n.intValue();
410
if (intIndex != n.doubleValue()) {
411
return false;
412
}
413
return 0 <= intIndex && intIndex < Array.getLength(array);
414
}
415
416
@SuppressWarnings("unused")
417
private static boolean rangeCheck(final List<?> list, final Object index) {
418
if(!(index instanceof Number)) {
419
return false;
420
}
421
final Number n = (Number)index;
422
final int intIndex = n.intValue();
423
if (intIndex != n.doubleValue()) {
424
return false;
425
}
426
return 0 <= intIndex && intIndex < list.size();
427
}
428
429
@SuppressWarnings("unused")
430
private static void noOp() {
431
}
432
433
private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
434
MethodType.methodType(Object.class, int.class, Object.class));
435
436
private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
437
MethodType.methodType(Object.class, Object.class, Object.class));
438
439
private static final MethodHandle NO_OP_1;
440
private static final MethodHandle NO_OP_2;
441
private static final MethodHandle NO_OP_3;
442
static {
443
final MethodHandle noOp = Lookup.findOwnStatic(MethodHandles.lookup(), "noOp", void.class);
444
NO_OP_1 = dropObjectArguments(noOp, 1);
445
NO_OP_2 = dropObjectArguments(noOp, 2);
446
NO_OP_3 = dropObjectArguments(noOp, 3);
447
}
448
449
private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
450
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
451
final Object name = req.name;
452
final boolean isFixedKey = name != null;
453
assertParameterCount(callSiteDescriptor, isFixedKey ? 2 : 3);
454
final LinkerServices linkerServices = req.linkerServices;
455
final MethodType callSiteType = callSiteDescriptor.getMethodType();
456
457
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
458
callSiteType, linkerServices, MethodHandles::arrayElementSetter, SET_LIST_ELEMENT, PUT_MAP_ELEMENT);
459
460
if(gicact == null) {
461
return getNextComponent(req);
462
}
463
464
final boolean isMap = gicact.collectionType == CollectionType.MAP;
465
466
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
467
// as maps will always succeed in setting the element and will never need to fall back to the next component
468
// operation.
469
final GuardedInvocationComponent nextComponent = isMap ? null : getNextComponent(req);
470
471
final Object typedName = getTypedName(name, isMap, linkerServices);
472
if (typedName == INVALID_NAME) {
473
return nextComponent;
474
}
475
476
final GuardedInvocationComponent gic = gicact.gic;
477
final GuardedInvocation gi = gic.getGuardedInvocation();
478
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
479
final MethodHandle invocation = gi.getInvocation();
480
481
if (isMap) {
482
return gic.replaceInvocation(binder.bind(invocation));
483
}
484
485
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent, binder, isFixedKey ? NO_OP_2 : NO_OP_3);
486
}
487
488
private static final MethodHandle REMOVE_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "remove",
489
MethodType.methodType(Object.class, int.class));
490
491
private static final MethodHandle REMOVE_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "remove",
492
MethodType.methodType(Object.class, Object.class));
493
494
private GuardedInvocationComponent getElementRemover(final ComponentLinkRequest req) throws Exception {
495
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
496
final Object name = req.name;
497
final boolean isFixedKey = name != null;
498
assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
499
final LinkerServices linkerServices = req.linkerServices;
500
final MethodType callSiteType = callSiteDescriptor.getMethodType();
501
final GuardedInvocationComponent nextComponent = getNextComponent(req);
502
503
final GuardedInvocationComponentAndCollectionType gicact = guardedInvocationComponentAndCollectionType(
504
callSiteType, linkerServices, null, REMOVE_LIST_ELEMENT, REMOVE_MAP_ELEMENT);
505
506
if (gicact == null) {
507
// Can't remove elements for objects that are neither lists, nor maps.
508
return nextComponent;
509
}
510
511
final Object typedName = getTypedName(name, gicact.collectionType == CollectionType.MAP, linkerServices);
512
if (typedName == INVALID_NAME) {
513
return nextComponent;
514
}
515
516
return guardComponentWithRangeCheck(gicact, callSiteType, nextComponent,
517
new Binder(linkerServices, callSiteType, typedName), isFixedKey ? NO_OP_1: NO_OP_2);
518
}
519
520
private static final MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",
521
MethodType.methodType(int.class));
522
523
private static final MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size",
524
MethodType.methodType(int.class));
525
526
private static final MethodHandle GET_ARRAY_LENGTH = Lookup.PUBLIC.findStatic(Array.class, "getLength",
527
MethodType.methodType(int.class, Object.class));
528
529
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
530
if(descriptor.getMethodType().parameterCount() != paramCount) {
531
throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
532
}
533
}
534
}
535
536