< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java

Print this page




  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 


< prev index next >