24 */
25
26 package jdk.nashorn.internal.codegen;
27
28 import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS;
31 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_MAP;
32 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
33 import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS;
34 import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_DUAL_FIELD_PREFIX;
35 import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_SINGLE_FIELD_PREFIX;
36 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
37 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
38 import static jdk.nashorn.internal.lookup.Lookup.MH;
39 import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT;
40 import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC;
41 import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED;
42 import static jdk.nashorn.internal.runtime.JSType.TYPE_DOUBLE_INDEX;
43 import static jdk.nashorn.internal.runtime.JSType.TYPE_INT_INDEX;
44 import static jdk.nashorn.internal.runtime.JSType.TYPE_LONG_INDEX;
45 import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX;
46 import static jdk.nashorn.internal.runtime.JSType.TYPE_UNDEFINED_INDEX;
47 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
48 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
49
50 import java.lang.invoke.MethodHandle;
51 import java.lang.invoke.MethodHandles;
52 import java.lang.invoke.MethodType;
53 import java.util.EnumSet;
54 import java.util.Iterator;
55 import java.util.LinkedList;
56 import java.util.List;
57 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
58 import jdk.nashorn.internal.codegen.types.Type;
59 import jdk.nashorn.internal.runtime.AccessorProperty;
60 import jdk.nashorn.internal.runtime.AllocationStrategy;
61 import jdk.nashorn.internal.runtime.Context;
62 import jdk.nashorn.internal.runtime.FunctionScope;
63 import jdk.nashorn.internal.runtime.JSType;
64 import jdk.nashorn.internal.runtime.PropertyMap;
518 final MethodHandle mh = MH.asType(sameTypeGetter, sameTypeGetter.type().changeReturnType(Object.class));
519 try {
520 final Object value = mh.invokeExact(receiver);
521 throw new UnwarrantedOptimismException(value, programPoint);
522 } catch (final Error | RuntimeException e) {
523 throw e;
524 } catch (final Throwable e) {
525 throw new RuntimeException(e);
526 }
527 }
528
529 @SuppressWarnings("unused")
530 private static Object getDifferentUndefined(final int programPoint) {
531 throw new UnwarrantedOptimismException(Undefined.getUndefined(), programPoint);
532 }
533
534 private static MethodHandle getterForType(final Class<?> forType, final MethodHandle primitiveGetter, final MethodHandle objectGetter) {
535 switch (getAccessorTypeIndex(forType)) {
536 case TYPE_INT_INDEX:
537 return MH.explicitCastArguments(primitiveGetter, primitiveGetter.type().changeReturnType(int.class));
538 case TYPE_LONG_INDEX:
539 return primitiveGetter;
540 case TYPE_DOUBLE_INDEX:
541 return MH.filterReturnValue(primitiveGetter, UNPACK_DOUBLE);
542 case TYPE_OBJECT_INDEX:
543 return objectGetter;
544 default:
545 throw new AssertionError(forType);
546 }
547 }
548
549 //no optimism here. we do unconditional conversion to types
550 private static MethodHandle createGetterInner(final Class<?> forType, final Class<?> type, final MethodHandle primitiveGetter, final MethodHandle objectGetter, final List<MethodHandle> converters, final int programPoint) {
551 final int fti = forType == null ? TYPE_UNDEFINED_INDEX : getAccessorTypeIndex(forType);
552 final int ti = getAccessorTypeIndex(type);
553 //this means fail if forType != type
554 final boolean isOptimistic = converters == CONVERT_OBJECT_OPTIMISTIC;
555 final boolean isPrimitiveStorage = forType != null && forType.isPrimitive();
556
557 //which is the primordial getter
558 final MethodHandle getter = primitiveGetter == null ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
559
606 }
607
608 //asking for narrower primitive than we have stored, that is an
609 //UnwarrantedOptimismException
610 return MH.asType(
611 MH.filterArguments(
612 objectGetter,
613 0,
614 MH.insertArguments(
615 GET_DIFFERENT,
616 1,
617 forType,
618 primitiveGetter,
619 objectGetter,
620 programPoint)),
621 objectGetter.type().changeReturnType(type));
622 }
623 }
624
625 assert !isOptimistic;
626 //freely coerce the result to whatever you asked for, this is e.g. Object->int for a & b
627 final MethodHandle tgetter = getterForType(forType, primitiveGetter, objectGetter);
628 if (fti == TYPE_OBJECT_INDEX) {
629 if (fti != ti) {
630 return MH.filterReturnValue(tgetter, CONVERT_OBJECT.get(ti));
631 }
632 return tgetter;
633 }
634
635 assert primitiveGetter != null;
636 final MethodType tgetterType = tgetter.type();
637 switch (fti) {
638 case TYPE_INT_INDEX: {
639 return MH.asType(tgetter, tgetterType.changeReturnType(type));
640 }
641 case TYPE_LONG_INDEX:
642 switch (ti) {
643 case TYPE_INT_INDEX:
644 //get int while an int, truncating cast of long value
645 return MH.filterReturnValue(tgetter, JSType.TO_INT32_L.methodHandle);
646 case TYPE_LONG_INDEX:
647 return primitiveGetter;
648 default:
649 return MH.asType(tgetter, tgetterType.changeReturnType(type));
650 }
651 case TYPE_DOUBLE_INDEX:
652 switch (ti) {
653 case TYPE_INT_INDEX:
654 return MH.filterReturnValue(tgetter, JSType.TO_INT32_D.methodHandle);
655 case TYPE_LONG_INDEX:
656 return MH.explicitCastArguments(tgetter, tgetterType.changeReturnType(type));
657 case TYPE_DOUBLE_INDEX:
658 assert tgetterType.returnType() == double.class;
659 return tgetter;
660 default:
661 return MH.asType(tgetter, tgetterType.changeReturnType(Object.class));
662 }
663 default:
664 throw new UnsupportedOperationException(forType + "=>" + type);
665 }
666 }
667
668 /**
669 * Given a primitiveGetter (optional for non dual fields) and an objectSetter that retrieve
670 * the primitive and object version of a field respectively, return one with the correct
671 * method type and the correct filters. For example, if the value is stored as a double
672 * and we want an Object getter, in the dual fields world we'd pick the primitiveGetter,
673 * which reads a long, use longBitsToDouble on the result to unpack it, and then change the
674 * return type to Object, boxing it. In the objects only world there are only object fields,
675 * primitives are boxed when asked for them and we don't need to bother with primitive encoding
676 * (or even undefined, which if forType==null) representation, so we just return whatever is
717 * @return the setter for the given representation that takes a {@code type}
718 */
719 public static MethodHandle createSetter(final Class<?> forType, final Class<?> type, final MethodHandle primitiveSetter, final MethodHandle objectSetter) {
720 assert forType != null;
721
722 final int fti = getAccessorTypeIndex(forType);
723 final int ti = getAccessorTypeIndex(type);
724
725 if (fti == TYPE_OBJECT_INDEX || primitiveSetter == null) {
726 if (ti == TYPE_OBJECT_INDEX) {
727 return objectSetter;
728 }
729
730 return MH.asType(objectSetter, objectSetter.type().changeParameterType(1, type));
731 }
732
733 final MethodType pmt = primitiveSetter.type();
734
735 switch (fti) {
736 case TYPE_INT_INDEX:
737 case TYPE_LONG_INDEX:
738 switch (ti) {
739 case TYPE_INT_INDEX:
740 return MH.asType(primitiveSetter, pmt.changeParameterType(1, int.class));
741 case TYPE_LONG_INDEX:
742 return primitiveSetter;
743 case TYPE_DOUBLE_INDEX:
744 return MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE);
745 default:
746 return objectSetter;
747 }
748 case TYPE_DOUBLE_INDEX:
749 if (ti == TYPE_OBJECT_INDEX) {
750 return objectSetter;
751 }
752 return MH.asType(MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE), pmt.changeParameterType(1, type));
753 default:
754 throw new UnsupportedOperationException(forType + "=>" + type);
755 }
756 }
757
758 @SuppressWarnings("unused")
759 private static boolean isType(final Class<?> boxedForType, final Object x) {
760 return x != null && x.getClass() == boxedForType;
761 }
762
|
24 */
25
26 package jdk.nashorn.internal.codegen;
27
28 import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
30 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS;
31 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_MAP;
32 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
33 import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS;
34 import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_DUAL_FIELD_PREFIX;
35 import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_SINGLE_FIELD_PREFIX;
36 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
37 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
38 import static jdk.nashorn.internal.lookup.Lookup.MH;
39 import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT;
40 import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC;
41 import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED;
42 import static jdk.nashorn.internal.runtime.JSType.TYPE_DOUBLE_INDEX;
43 import static jdk.nashorn.internal.runtime.JSType.TYPE_INT_INDEX;
44 import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX;
45 import static jdk.nashorn.internal.runtime.JSType.TYPE_UNDEFINED_INDEX;
46 import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
47 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
48
49 import java.lang.invoke.MethodHandle;
50 import java.lang.invoke.MethodHandles;
51 import java.lang.invoke.MethodType;
52 import java.util.EnumSet;
53 import java.util.Iterator;
54 import java.util.LinkedList;
55 import java.util.List;
56 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
57 import jdk.nashorn.internal.codegen.types.Type;
58 import jdk.nashorn.internal.runtime.AccessorProperty;
59 import jdk.nashorn.internal.runtime.AllocationStrategy;
60 import jdk.nashorn.internal.runtime.Context;
61 import jdk.nashorn.internal.runtime.FunctionScope;
62 import jdk.nashorn.internal.runtime.JSType;
63 import jdk.nashorn.internal.runtime.PropertyMap;
517 final MethodHandle mh = MH.asType(sameTypeGetter, sameTypeGetter.type().changeReturnType(Object.class));
518 try {
519 final Object value = mh.invokeExact(receiver);
520 throw new UnwarrantedOptimismException(value, programPoint);
521 } catch (final Error | RuntimeException e) {
522 throw e;
523 } catch (final Throwable e) {
524 throw new RuntimeException(e);
525 }
526 }
527
528 @SuppressWarnings("unused")
529 private static Object getDifferentUndefined(final int programPoint) {
530 throw new UnwarrantedOptimismException(Undefined.getUndefined(), programPoint);
531 }
532
533 private static MethodHandle getterForType(final Class<?> forType, final MethodHandle primitiveGetter, final MethodHandle objectGetter) {
534 switch (getAccessorTypeIndex(forType)) {
535 case TYPE_INT_INDEX:
536 return MH.explicitCastArguments(primitiveGetter, primitiveGetter.type().changeReturnType(int.class));
537 case TYPE_DOUBLE_INDEX:
538 return MH.filterReturnValue(primitiveGetter, UNPACK_DOUBLE);
539 case TYPE_OBJECT_INDEX:
540 return objectGetter;
541 default:
542 throw new AssertionError(forType);
543 }
544 }
545
546 //no optimism here. we do unconditional conversion to types
547 private static MethodHandle createGetterInner(final Class<?> forType, final Class<?> type, final MethodHandle primitiveGetter, final MethodHandle objectGetter, final List<MethodHandle> converters, final int programPoint) {
548 final int fti = forType == null ? TYPE_UNDEFINED_INDEX : getAccessorTypeIndex(forType);
549 final int ti = getAccessorTypeIndex(type);
550 //this means fail if forType != type
551 final boolean isOptimistic = converters == CONVERT_OBJECT_OPTIMISTIC;
552 final boolean isPrimitiveStorage = forType != null && forType.isPrimitive();
553
554 //which is the primordial getter
555 final MethodHandle getter = primitiveGetter == null ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
556
603 }
604
605 //asking for narrower primitive than we have stored, that is an
606 //UnwarrantedOptimismException
607 return MH.asType(
608 MH.filterArguments(
609 objectGetter,
610 0,
611 MH.insertArguments(
612 GET_DIFFERENT,
613 1,
614 forType,
615 primitiveGetter,
616 objectGetter,
617 programPoint)),
618 objectGetter.type().changeReturnType(type));
619 }
620 }
621
622 assert !isOptimistic;
623 // freely coerce the result to whatever you asked for, this is e.g. Object->int for a & b
624 final MethodHandle tgetter = getterForType(forType, primitiveGetter, objectGetter);
625 if (fti == TYPE_OBJECT_INDEX) {
626 if (fti != ti) {
627 return MH.filterReturnValue(tgetter, CONVERT_OBJECT.get(ti));
628 }
629 return tgetter;
630 }
631
632 assert primitiveGetter != null;
633 final MethodType tgetterType = tgetter.type();
634 switch (fti) {
635 case TYPE_INT_INDEX: {
636 return MH.asType(tgetter, tgetterType.changeReturnType(type));
637 }
638 case TYPE_DOUBLE_INDEX:
639 switch (ti) {
640 case TYPE_INT_INDEX:
641 return MH.filterReturnValue(tgetter, JSType.TO_INT32_D.methodHandle);
642 case TYPE_DOUBLE_INDEX:
643 assert tgetterType.returnType() == double.class;
644 return tgetter;
645 default:
646 return MH.asType(tgetter, tgetterType.changeReturnType(Object.class));
647 }
648 default:
649 throw new UnsupportedOperationException(forType + "=>" + type);
650 }
651 }
652
653 /**
654 * Given a primitiveGetter (optional for non dual fields) and an objectSetter that retrieve
655 * the primitive and object version of a field respectively, return one with the correct
656 * method type and the correct filters. For example, if the value is stored as a double
657 * and we want an Object getter, in the dual fields world we'd pick the primitiveGetter,
658 * which reads a long, use longBitsToDouble on the result to unpack it, and then change the
659 * return type to Object, boxing it. In the objects only world there are only object fields,
660 * primitives are boxed when asked for them and we don't need to bother with primitive encoding
661 * (or even undefined, which if forType==null) representation, so we just return whatever is
702 * @return the setter for the given representation that takes a {@code type}
703 */
704 public static MethodHandle createSetter(final Class<?> forType, final Class<?> type, final MethodHandle primitiveSetter, final MethodHandle objectSetter) {
705 assert forType != null;
706
707 final int fti = getAccessorTypeIndex(forType);
708 final int ti = getAccessorTypeIndex(type);
709
710 if (fti == TYPE_OBJECT_INDEX || primitiveSetter == null) {
711 if (ti == TYPE_OBJECT_INDEX) {
712 return objectSetter;
713 }
714
715 return MH.asType(objectSetter, objectSetter.type().changeParameterType(1, type));
716 }
717
718 final MethodType pmt = primitiveSetter.type();
719
720 switch (fti) {
721 case TYPE_INT_INDEX:
722 switch (ti) {
723 case TYPE_INT_INDEX:
724 return MH.asType(primitiveSetter, pmt.changeParameterType(1, int.class));
725 case TYPE_DOUBLE_INDEX:
726 return MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE);
727 default:
728 return objectSetter;
729 }
730 case TYPE_DOUBLE_INDEX:
731 if (ti == TYPE_OBJECT_INDEX) {
732 return objectSetter;
733 }
734 return MH.asType(MH.filterArguments(primitiveSetter, 1, PACK_DOUBLE), pmt.changeParameterType(1, type));
735 default:
736 throw new UnsupportedOperationException(forType + "=>" + type);
737 }
738 }
739
740 @SuppressWarnings("unused")
741 private static boolean isType(final Class<?> boxedForType, final Object x) {
742 return x != null && x.getClass() == boxedForType;
743 }
744
|