Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-aarch32-jdk8u
Path: blob/jdk8u272-b10-aarch32-20201026/nashorn/src/jdk/internal/dynalink/beans/BeanLinker.java
48797 views
1
/*
2
* Copyright (c) 2010, 2013, 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
Licensed under both the Apache License, Version 2.0 (the "Apache License")
37
and the BSD License (the "BSD License"), with licensee being free to
38
choose either of the two at their discretion.
39
40
You may not use this file except in compliance with either the Apache
41
License or the BSD License.
42
43
If you choose to use this file in compliance with the Apache License, the
44
following notice applies to you:
45
46
You may obtain a copy of the Apache License at
47
48
http://www.apache.org/licenses/LICENSE-2.0
49
50
Unless required by applicable law or agreed to in writing, software
51
distributed under the License is distributed on an "AS IS" BASIS,
52
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
53
implied. See the License for the specific language governing
54
permissions and limitations under the License.
55
56
If you choose to use this file in compliance with the BSD License, the
57
following notice applies to you:
58
59
Redistribution and use in source and binary forms, with or without
60
modification, are permitted provided that the following conditions are
61
met:
62
* Redistributions of source code must retain the above copyright
63
notice, this list of conditions and the following disclaimer.
64
* Redistributions in binary form must reproduce the above copyright
65
notice, this list of conditions and the following disclaimer in the
66
documentation and/or other materials provided with the distribution.
67
* Neither the name of the copyright holder nor the names of
68
contributors may be used to endorse or promote products derived from
69
this software without specific prior written permission.
70
71
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
72
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
74
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
75
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
78
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
80
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
81
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82
*/
83
84
package jdk.internal.dynalink.beans;
85
86
import java.lang.invoke.MethodHandle;
87
import java.lang.invoke.MethodHandles;
88
import java.lang.invoke.MethodType;
89
import java.lang.reflect.Array;
90
import java.util.Collection;
91
import java.util.List;
92
import java.util.Map;
93
import jdk.internal.dynalink.CallSiteDescriptor;
94
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
95
import jdk.internal.dynalink.linker.GuardedInvocation;
96
import jdk.internal.dynalink.linker.LinkerServices;
97
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
98
import jdk.internal.dynalink.support.Guards;
99
import jdk.internal.dynalink.support.Lookup;
100
import jdk.internal.dynalink.support.TypeUtilities;
101
102
/**
103
* A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
104
* {@link BeansLinker}.
105
*
106
* @author Attila Szegedi
107
*/
108
class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicLinker {
109
BeanLinker(final Class<?> clazz) {
110
super(clazz, Guards.getClassGuard(clazz), Guards.getInstanceOfGuard(clazz));
111
if(clazz.isArray()) {
112
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
113
// explicit property is beneficial for them.
114
// REVISIT: is it maybe a code smell that "dyn:getLength" is not needed?
115
setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY);
116
} else if(List.class.isAssignableFrom(clazz)) {
117
setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
118
}
119
}
120
121
@Override
122
public boolean canLinkType(final Class<?> type) {
123
return type == clazz;
124
}
125
126
@Override
127
FacetIntrospector createFacetIntrospector() {
128
return new BeanIntrospector(clazz);
129
}
130
131
@Override
132
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
133
final LinkerServices linkerServices, final List<String> operations) throws Exception {
134
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor,
135
linkerServices, operations);
136
if(superGic != null) {
137
return superGic;
138
}
139
if(operations.isEmpty()) {
140
return null;
141
}
142
final String op = operations.get(0);
143
// dyn:getElem(this, id)
144
// id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide
145
// conversion from call site argument type though.
146
if("getElem".equals(op)) {
147
return getElementGetter(callSiteDescriptor, linkerServices, pop(operations));
148
}
149
if("setElem".equals(op)) {
150
return getElementSetter(callSiteDescriptor, linkerServices, pop(operations));
151
}
152
// dyn:getLength(this) (works on Java arrays, collections, and maps)
153
if("getLength".equals(op)) {
154
return getLengthGetter(callSiteDescriptor);
155
}
156
return null;
157
}
158
159
private static MethodHandle GET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "get",
160
MethodType.methodType(Object.class, int.class));
161
162
private static MethodHandle GET_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "get",
163
MethodType.methodType(Object.class, Object.class));
164
165
private static MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class);
166
private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class);
167
168
private enum CollectionType {
169
ARRAY, LIST, MAP
170
};
171
172
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
173
final LinkerServices linkerServices, final List<String> operations) throws Exception {
174
final MethodType callSiteType = callSiteDescriptor.getMethodType();
175
final Class<?> declaredType = callSiteType.parameterType(0);
176
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
177
linkerServices, operations);
178
179
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
180
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
181
// dealing with an array, or a list or map, but hey...
182
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
183
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
184
final GuardedInvocationComponent gic;
185
final CollectionType collectionType;
186
if(declaredType.isArray()) {
187
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType), linkerServices);
188
collectionType = CollectionType.ARRAY;
189
} else if(List.class.isAssignableFrom(declaredType)) {
190
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, linkerServices);
191
collectionType = CollectionType.LIST;
192
} else if(Map.class.isAssignableFrom(declaredType)) {
193
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, linkerServices);
194
collectionType = CollectionType.MAP;
195
} else if(clazz.isArray()) {
196
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(MethodHandles.arrayElementGetter(clazz)), callSiteType);
197
collectionType = CollectionType.ARRAY;
198
} else if(List.class.isAssignableFrom(clazz)) {
199
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
200
linkerServices);
201
collectionType = CollectionType.LIST;
202
} else if(Map.class.isAssignableFrom(clazz)) {
203
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, ValidationType.INSTANCE_OF,
204
linkerServices);
205
collectionType = CollectionType.MAP;
206
} else {
207
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
208
return nextComponent;
209
}
210
211
// We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo"
212
final String fixedKey = getFixedKey(callSiteDescriptor);
213
// Convert the key to a number if we're working with a list or array
214
final Object typedFixedKey;
215
if(collectionType != CollectionType.MAP && fixedKey != null) {
216
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
217
if(typedFixedKey == null) {
218
// key is not numeric, it can never succeed
219
return nextComponent;
220
}
221
} else {
222
typedFixedKey = fixedKey;
223
}
224
225
final GuardedInvocation gi = gic.getGuardedInvocation();
226
final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
227
final MethodHandle invocation = gi.getInvocation();
228
229
if(nextComponent == null) {
230
return gic.replaceInvocation(binder.bind(invocation));
231
}
232
233
final MethodHandle checkGuard;
234
switch(collectionType) {
235
case LIST:
236
checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
237
break;
238
case MAP:
239
// TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it
240
// into a GWT that tests if it returned null, and if it did, do another GWT with containsKey()
241
// that returns constant null (on true), or falls back to next component (on false)
242
checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP);
243
break;
244
case ARRAY:
245
checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
246
break;
247
default:
248
throw new AssertionError();
249
}
250
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
251
nextComponent.getGuardedInvocation().getInvocation());
252
return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
253
gic.getValidatorClass(), gic.getValidationType());
254
}
255
256
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
257
final MethodHandle invocation, final LinkerServices linkerServices) {
258
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation));
259
}
260
261
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
262
final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass,
263
final ValidationType validationType, final LinkerServices linkerServices) {
264
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation), guard,
265
validatorClass, validationType);
266
}
267
268
private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) {
269
return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken(
270
CallSiteDescriptor.NAME_OPERAND);
271
}
272
273
private static Object convertKeyToInteger(final String fixedKey, final LinkerServices linkerServices) throws Exception {
274
try {
275
if(linkerServices.canConvert(String.class, Number.class)) {
276
try {
277
final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey);
278
if(!(val instanceof Number)) {
279
return null; // not a number
280
}
281
final Number n = (Number)val;
282
if(n instanceof Integer) {
283
return n;
284
}
285
final int intIndex = n.intValue();
286
final double doubleValue = n.doubleValue();
287
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
288
return null; // not an exact integer
289
}
290
return Integer.valueOf(intIndex);
291
} catch(Exception|Error e) {
292
throw e;
293
} catch(final Throwable t) {
294
throw new RuntimeException(t);
295
}
296
}
297
return Integer.valueOf(fixedKey);
298
} catch(final NumberFormatException e) {
299
// key is not a number
300
return null;
301
}
302
}
303
304
private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) {
305
final Class<?> sourceType = desc.getMethodType().parameterType(1);
306
if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) {
307
return mh;
308
} else if(ls.canConvert(sourceType, Number.class)) {
309
final MethodHandle converter = ls.getTypeConverter(sourceType, Number.class);
310
return MethodHandles.filterArguments(mh, 1, converter.asType(converter.type().changeReturnType(
311
mh.type().parameterType(1))));
312
}
313
return mh;
314
}
315
316
/**
317
* Contains methods to adapt an item getter/setter method handle to the requested type, optionally binding it to a
318
* fixed key first.
319
* @author Attila Szegedi
320
* @version $Id: $
321
*/
322
private static class Binder {
323
private final LinkerServices linkerServices;
324
private final MethodType methodType;
325
private final Object fixedKey;
326
327
Binder(final LinkerServices linkerServices, final MethodType methodType, final Object fixedKey) {
328
this.linkerServices = linkerServices;
329
this.methodType = fixedKey == null ? methodType : methodType.insertParameterTypes(1, fixedKey.getClass());
330
this.fixedKey = fixedKey;
331
}
332
333
/*private*/ MethodHandle bind(final MethodHandle handle) {
334
return bindToFixedKey(linkerServices.asTypeLosslessReturn(handle, methodType));
335
}
336
337
/*private*/ MethodHandle bindTest(final MethodHandle handle) {
338
return bindToFixedKey(Guards.asType(handle, methodType));
339
}
340
341
private MethodHandle bindToFixedKey(final MethodHandle handle) {
342
return fixedKey == null ? handle : MethodHandles.insertArguments(handle, 1, fixedKey);
343
}
344
}
345
346
private static MethodHandle RANGE_CHECK_ARRAY = findRangeCheck(Object.class);
347
private static MethodHandle RANGE_CHECK_LIST = findRangeCheck(List.class);
348
private static MethodHandle CONTAINS_MAP = Lookup.PUBLIC.findVirtual(Map.class, "containsKey",
349
MethodType.methodType(boolean.class, Object.class));
350
351
private static MethodHandle findRangeCheck(final Class<?> collectionType) {
352
return Lookup.findOwnStatic(MethodHandles.lookup(), "rangeCheck", boolean.class, collectionType, Object.class);
353
}
354
355
@SuppressWarnings("unused")
356
private static final boolean rangeCheck(final Object array, final Object index) {
357
if(!(index instanceof Number)) {
358
return false;
359
}
360
final Number n = (Number)index;
361
final int intIndex = n.intValue();
362
final double doubleValue = n.doubleValue();
363
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE
364
return false;
365
}
366
if(0 <= intIndex && intIndex < Array.getLength(array)) {
367
return true;
368
}
369
throw new ArrayIndexOutOfBoundsException("Array index out of range: " + n);
370
}
371
372
@SuppressWarnings("unused")
373
private static final boolean rangeCheck(final List<?> list, final Object index) {
374
if(!(index instanceof Number)) {
375
return false;
376
}
377
final Number n = (Number)index;
378
final int intIndex = n.intValue();
379
final double doubleValue = n.doubleValue();
380
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE
381
return false;
382
}
383
if(0 <= intIndex && intIndex < list.size()) {
384
return true;
385
}
386
throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + list.size());
387
}
388
389
private static MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
390
MethodType.methodType(Object.class, int.class, Object.class));
391
392
private static MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
393
MethodType.methodType(Object.class, Object.class, Object.class));
394
395
private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor,
396
final LinkerServices linkerServices, final List<String> operations) throws Exception {
397
final MethodType callSiteType = callSiteDescriptor.getMethodType();
398
final Class<?> declaredType = callSiteType.parameterType(0);
399
400
final GuardedInvocationComponent gic;
401
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
402
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
403
// dealing with an array, or a list or map, but hey...
404
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
405
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
406
final CollectionType collectionType;
407
if(declaredType.isArray()) {
408
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType), linkerServices);
409
collectionType = CollectionType.ARRAY;
410
} else if(List.class.isAssignableFrom(declaredType)) {
411
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, linkerServices);
412
collectionType = CollectionType.LIST;
413
} else if(Map.class.isAssignableFrom(declaredType)) {
414
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, linkerServices);
415
collectionType = CollectionType.MAP;
416
} else if(clazz.isArray()) {
417
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(
418
MethodHandles.arrayElementSetter(clazz)), callSiteType);
419
collectionType = CollectionType.ARRAY;
420
} else if(List.class.isAssignableFrom(clazz)) {
421
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
422
linkerServices);
423
collectionType = CollectionType.LIST;
424
} else if(Map.class.isAssignableFrom(clazz)) {
425
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType),
426
Map.class, ValidationType.INSTANCE_OF, linkerServices);
427
collectionType = CollectionType.MAP;
428
} else {
429
// Can't set elements for objects that are neither arrays, nor list, nor maps.
430
gic = null;
431
collectionType = null;
432
}
433
434
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
435
// as maps will always succeed in setting the element and will never need to fall back to the next component
436
// operation.
437
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
438
callSiteDescriptor, linkerServices, operations);
439
if(gic == null) {
440
return nextComponent;
441
}
442
443
// We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo"
444
final String fixedKey = getFixedKey(callSiteDescriptor);
445
// Convert the key to a number if we're working with a list or array
446
final Object typedFixedKey;
447
if(collectionType != CollectionType.MAP && fixedKey != null) {
448
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
449
if(typedFixedKey == null) {
450
// key is not numeric, it can never succeed
451
return nextComponent;
452
}
453
} else {
454
typedFixedKey = fixedKey;
455
}
456
457
final GuardedInvocation gi = gic.getGuardedInvocation();
458
final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
459
final MethodHandle invocation = gi.getInvocation();
460
461
if(nextComponent == null) {
462
return gic.replaceInvocation(binder.bind(invocation));
463
}
464
465
assert collectionType == CollectionType.LIST || collectionType == CollectionType.ARRAY;
466
final MethodHandle checkGuard = convertArgToInt(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST :
467
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
468
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
469
nextComponent.getGuardedInvocation().getInvocation());
470
return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
471
gic.getValidatorClass(), gic.getValidationType());
472
}
473
474
private static MethodHandle GET_ARRAY_LENGTH = Lookup.PUBLIC.findStatic(Array.class, "getLength",
475
MethodType.methodType(int.class, Object.class));
476
477
private static MethodHandle GET_COLLECTION_LENGTH = Lookup.PUBLIC.findVirtual(Collection.class, "size",
478
MethodType.methodType(int.class));
479
480
private static MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size",
481
MethodType.methodType(int.class));
482
483
private static MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class);
484
485
private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) {
486
assertParameterCount(callSiteDescriptor, 1);
487
final MethodType callSiteType = callSiteDescriptor.getMethodType();
488
final Class<?> declaredType = callSiteType.parameterType(0);
489
// If declared type of receiver at the call site is already an array, collection, or map, bind without guard.
490
// Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance
491
// they're dealing with an array, collection, or map, but hey...
492
if(declaredType.isArray()) {
493
return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType));
494
} else if(Collection.class.isAssignableFrom(declaredType)) {
495
return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType));
496
} else if(Map.class.isAssignableFrom(declaredType)) {
497
return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType));
498
}
499
500
// Otherwise, create a binding based on the actual type of the argument with an appropriate guard.
501
if(clazz.isArray()) {
502
return new GuardedInvocationComponent(GET_ARRAY_LENGTH.asType(callSiteType), Guards.isArray(0,
503
callSiteType), ValidationType.IS_ARRAY);
504
} if(Collection.class.isAssignableFrom(clazz)) {
505
return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType(
506
COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF);
507
} if(Map.class.isAssignableFrom(clazz)) {
508
return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD,
509
callSiteType), Map.class, ValidationType.INSTANCE_OF);
510
}
511
// Can't retrieve length for objects that are neither arrays, nor collections, nor maps.
512
return null;
513
}
514
515
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
516
if(descriptor.getMethodType().parameterCount() != paramCount) {
517
throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
518
}
519
}
520
}
521
522