204 * to the constructor, and the rest are created from those. Used e.g. by Nasgen classes
205 *
206 * @param key the property key
207 * @param flags the property flags
208 * @param slot the property field number or spill slot
209 * @param getter the property getter
210 * @param setter the property setter or null if non writable, non configurable
211 */
212 private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
213 super(key, flags | IS_BUILTIN | DUAL_FIELDS | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
214 assert !isSpill();
215
216 // we don't need to prep the setters these will never be invalidated as this is a nasgen
217 // or known type getter/setter. No invalidations will take place
218
219 final Class<?> getterType = getter.type().returnType();
220 final Class<?> setterType = setter == null ? null : setter.type().parameterType(1);
221
222 assert setterType == null || setterType == getterType;
223
224 if (getterType == int.class || getterType == long.class) {
225 primitiveGetter = MH.asType(getter, Lookup.GET_PRIMITIVE_TYPE);
226 primitiveSetter = setter == null ? null : MH.asType(setter, Lookup.SET_PRIMITIVE_TYPE);
227 } else if (getterType == double.class) {
228 primitiveGetter = MH.asType(MH.filterReturnValue(getter, ObjectClassGenerator.PACK_DOUBLE), Lookup.GET_PRIMITIVE_TYPE);
229 primitiveSetter = setter == null ? null : MH.asType(MH.filterArguments(setter, 1, ObjectClassGenerator.UNPACK_DOUBLE), Lookup.SET_PRIMITIVE_TYPE);
230 } else {
231 primitiveGetter = primitiveSetter = null;
232 }
233
234 assert primitiveGetter == null || primitiveGetter.type() == Lookup.GET_PRIMITIVE_TYPE : primitiveGetter + "!=" + Lookup.GET_PRIMITIVE_TYPE;
235 assert primitiveSetter == null || primitiveSetter.type() == Lookup.SET_PRIMITIVE_TYPE : primitiveSetter;
236
237 objectGetter = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter;
238 objectSetter = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter;
239
240 setType(getterType);
241 }
242
243 /**
244 * Normal ACCESS PROPERTY constructor given a structure class.
384 return new AccessorProperty(this);
385 }
386
387 @Override
388 public Property copy(final Class<?> newType) {
389 return new AccessorProperty(this, newType);
390 }
391
392 @Override
393 public int getIntValue(final ScriptObject self, final ScriptObject owner) {
394 try {
395 return (int)getGetter(int.class).invokeExact((Object)self);
396 } catch (final Error | RuntimeException e) {
397 throw e;
398 } catch (final Throwable e) {
399 throw new RuntimeException(e);
400 }
401 }
402
403 @Override
404 public long getLongValue(final ScriptObject self, final ScriptObject owner) {
405 try {
406 return (long)getGetter(long.class).invokeExact((Object)self);
407 } catch (final Error | RuntimeException e) {
408 throw e;
409 } catch (final Throwable e) {
410 throw new RuntimeException(e);
411 }
412 }
413
414 @Override
415 public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
416 try {
417 return (double)getGetter(double.class).invokeExact((Object)self);
418 } catch (final Error | RuntimeException e) {
419 throw e;
420 } catch (final Throwable e) {
421 throw new RuntimeException(e);
422 }
423 }
424
425 @Override
426 public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
427 try {
428 return getGetter(Object.class).invokeExact((Object)self);
429 } catch (final Error | RuntimeException e) {
430 throw e;
431 } catch (final Throwable e) {
432 throw new RuntimeException(e);
433 }
434 }
436 /**
437 * Invoke setter for this property with a value
438 * @param self owner
439 * @param value value
440 */
441 protected final void invokeSetter(final ScriptObject self, final int value) {
442 try {
443 getSetter(int.class, self.getMap()).invokeExact((Object)self, value);
444 } catch (final Error | RuntimeException e) {
445 throw e;
446 } catch (final Throwable e) {
447 throw new RuntimeException(e);
448 }
449 }
450
451 /**
452 * Invoke setter for this property with a value
453 * @param self owner
454 * @param value value
455 */
456 protected final void invokeSetter(final ScriptObject self, final long value) {
457 try {
458 getSetter(long.class, self.getMap()).invokeExact((Object)self, value);
459 } catch (final Error | RuntimeException e) {
460 throw e;
461 } catch (final Throwable e) {
462 throw new RuntimeException(e);
463 }
464 }
465
466 /**
467 * Invoke setter for this property with a value
468 * @param self owner
469 * @param value value
470 */
471 protected final void invokeSetter(final ScriptObject self, final double value) {
472 try {
473 getSetter(double.class, self.getMap()).invokeExact((Object)self, value);
474 } catch (final Error | RuntimeException e) {
475 throw e;
476 } catch (final Throwable e) {
477 throw new RuntimeException(e);
478 }
479 }
480
481 /**
482 * Invoke setter for this property with a value
483 * @param self owner
484 * @param value value
485 */
486 protected final void invokeSetter(final ScriptObject self, final Object value) {
487 try {
488 getSetter(Object.class, self.getMap()).invokeExact((Object)self, value);
489 } catch (final Error | RuntimeException e) {
490 throw e;
491 } catch (final Throwable e) {
492 throw new RuntimeException(e);
493 }
494 }
495
496 @Override
497 public void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict) {
498 assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
499 invokeSetter(self, value);
500 }
501
502 @Override
503 public void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict) {
504 assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
505 invokeSetter(self, value);
506 }
507
508 @Override
509 public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
510 assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
511 invokeSetter(self, value);
512 }
513
514 @Override
515 public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
516 //this is sometimes used for bootstrapping, hence no assert. ugly.
517 invokeSetter(self, value);
518 }
519
520 @Override
521 void initMethodHandles(final Class<?> structure) {
522 // sanity check for structure class
523 if (!ScriptObject.class.isAssignableFrom(structure) || !StructureLoader.isStructureClass(structure.getName())) {
524 throw new IllegalArgumentException();
525 }
526 // this method is overridden in SpillProperty
527 assert !isSpill();
528 initGetterSetter(structure);
529 }
530
531 @Override
532 public MethodHandle getGetter(final Class<?> type) {
533 final int i = getAccessorTypeIndex(type);
534
535 assert type == int.class ||
536 type == long.class ||
537 type == double.class ||
538 type == Object.class :
539 "invalid getter type " + type + " for " + getKey();
540
541 checkUndeclared();
542
543 //all this does is add a return value filter for object fields only
544 final MethodHandle[] getterCache = GETTER_CACHE;
545 final MethodHandle cachedGetter = getterCache[i];
546 final MethodHandle getter;
547 if (cachedGetter != null) {
548 getter = cachedGetter;
549 } else {
550 getter = debug(
551 createGetter(
552 getLocalType(),
553 type,
554 primitiveGetter,
555 objectGetter,
556 INVALID_PROGRAM_POINT),
|
204 * to the constructor, and the rest are created from those. Used e.g. by Nasgen classes
205 *
206 * @param key the property key
207 * @param flags the property flags
208 * @param slot the property field number or spill slot
209 * @param getter the property getter
210 * @param setter the property setter or null if non writable, non configurable
211 */
212 private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
213 super(key, flags | IS_BUILTIN | DUAL_FIELDS | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
214 assert !isSpill();
215
216 // we don't need to prep the setters these will never be invalidated as this is a nasgen
217 // or known type getter/setter. No invalidations will take place
218
219 final Class<?> getterType = getter.type().returnType();
220 final Class<?> setterType = setter == null ? null : setter.type().parameterType(1);
221
222 assert setterType == null || setterType == getterType;
223
224 if (getterType == int.class) {
225 primitiveGetter = MH.asType(getter, Lookup.GET_PRIMITIVE_TYPE);
226 primitiveSetter = setter == null ? null : MH.asType(setter, Lookup.SET_PRIMITIVE_TYPE);
227 } else if (getterType == double.class) {
228 primitiveGetter = MH.asType(MH.filterReturnValue(getter, ObjectClassGenerator.PACK_DOUBLE), Lookup.GET_PRIMITIVE_TYPE);
229 primitiveSetter = setter == null ? null : MH.asType(MH.filterArguments(setter, 1, ObjectClassGenerator.UNPACK_DOUBLE), Lookup.SET_PRIMITIVE_TYPE);
230 } else {
231 primitiveGetter = primitiveSetter = null;
232 }
233
234 assert primitiveGetter == null || primitiveGetter.type() == Lookup.GET_PRIMITIVE_TYPE : primitiveGetter + "!=" + Lookup.GET_PRIMITIVE_TYPE;
235 assert primitiveSetter == null || primitiveSetter.type() == Lookup.SET_PRIMITIVE_TYPE : primitiveSetter;
236
237 objectGetter = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter;
238 objectSetter = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter;
239
240 setType(getterType);
241 }
242
243 /**
244 * Normal ACCESS PROPERTY constructor given a structure class.
384 return new AccessorProperty(this);
385 }
386
387 @Override
388 public Property copy(final Class<?> newType) {
389 return new AccessorProperty(this, newType);
390 }
391
392 @Override
393 public int getIntValue(final ScriptObject self, final ScriptObject owner) {
394 try {
395 return (int)getGetter(int.class).invokeExact((Object)self);
396 } catch (final Error | RuntimeException e) {
397 throw e;
398 } catch (final Throwable e) {
399 throw new RuntimeException(e);
400 }
401 }
402
403 @Override
404 public double getDoubleValue(final ScriptObject self, final ScriptObject owner) {
405 try {
406 return (double)getGetter(double.class).invokeExact((Object)self);
407 } catch (final Error | RuntimeException e) {
408 throw e;
409 } catch (final Throwable e) {
410 throw new RuntimeException(e);
411 }
412 }
413
414 @Override
415 public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
416 try {
417 return getGetter(Object.class).invokeExact((Object)self);
418 } catch (final Error | RuntimeException e) {
419 throw e;
420 } catch (final Throwable e) {
421 throw new RuntimeException(e);
422 }
423 }
425 /**
426 * Invoke setter for this property with a value
427 * @param self owner
428 * @param value value
429 */
430 protected final void invokeSetter(final ScriptObject self, final int value) {
431 try {
432 getSetter(int.class, self.getMap()).invokeExact((Object)self, value);
433 } catch (final Error | RuntimeException e) {
434 throw e;
435 } catch (final Throwable e) {
436 throw new RuntimeException(e);
437 }
438 }
439
440 /**
441 * Invoke setter for this property with a value
442 * @param self owner
443 * @param value value
444 */
445 protected final void invokeSetter(final ScriptObject self, final double value) {
446 try {
447 getSetter(double.class, self.getMap()).invokeExact((Object)self, value);
448 } catch (final Error | RuntimeException e) {
449 throw e;
450 } catch (final Throwable e) {
451 throw new RuntimeException(e);
452 }
453 }
454
455 /**
456 * Invoke setter for this property with a value
457 * @param self owner
458 * @param value value
459 */
460 protected final void invokeSetter(final ScriptObject self, final Object value) {
461 try {
462 getSetter(Object.class, self.getMap()).invokeExact((Object)self, value);
463 } catch (final Error | RuntimeException e) {
464 throw e;
465 } catch (final Throwable e) {
466 throw new RuntimeException(e);
467 }
468 }
469
470 @Override
471 public void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict) {
472 assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
473 invokeSetter(self, value);
474 }
475
476 @Override
477 public void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict) {
478 assert isConfigurable() || isWritable() : getKey() + " is not writable or configurable";
479 invokeSetter(self, value);
480 }
481
482 @Override
483 public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
484 //this is sometimes used for bootstrapping, hence no assert. ugly.
485 invokeSetter(self, value);
486 }
487
488 @Override
489 void initMethodHandles(final Class<?> structure) {
490 // sanity check for structure class
491 if (!ScriptObject.class.isAssignableFrom(structure) || !StructureLoader.isStructureClass(structure.getName())) {
492 throw new IllegalArgumentException();
493 }
494 // this method is overridden in SpillProperty
495 assert !isSpill();
496 initGetterSetter(structure);
497 }
498
499 @Override
500 public MethodHandle getGetter(final Class<?> type) {
501 final int i = getAccessorTypeIndex(type);
502
503 assert type == int.class ||
504 type == double.class ||
505 type == Object.class :
506 "invalid getter type " + type + " for " + getKey();
507
508 checkUndeclared();
509
510 //all this does is add a return value filter for object fields only
511 final MethodHandle[] getterCache = GETTER_CACHE;
512 final MethodHandle cachedGetter = getterCache[i];
513 final MethodHandle getter;
514 if (cachedGetter != null) {
515 getter = cachedGetter;
516 } else {
517 getter = debug(
518 createGetter(
519 getLocalType(),
520 type,
521 primitiveGetter,
522 objectGetter,
523 INVALID_PROGRAM_POINT),
|