23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package jdk.nashorn.internal.ir; |
26 package jdk.nashorn.internal.ir; |
27 |
27 |
28 import java.io.Serializable; |
|
29 import java.util.Arrays; |
28 import java.util.Arrays; |
30 import java.util.Collections; |
29 import java.util.Collections; |
31 import java.util.List; |
30 import java.util.List; |
32 import jdk.nashorn.internal.codegen.CompileUnit; |
|
33 import jdk.nashorn.internal.codegen.types.ArrayType; |
31 import jdk.nashorn.internal.codegen.types.ArrayType; |
34 import jdk.nashorn.internal.codegen.types.Type; |
32 import jdk.nashorn.internal.codegen.types.Type; |
35 import jdk.nashorn.internal.ir.annotations.Immutable; |
33 import jdk.nashorn.internal.ir.annotations.Immutable; |
36 import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
34 import jdk.nashorn.internal.ir.visitor.NodeVisitor; |
37 import jdk.nashorn.internal.objects.NativeArray; |
35 import jdk.nashorn.internal.objects.NativeArray; |
581 } |
579 } |
582 |
580 |
583 return POSTSET_MARKER; |
581 return POSTSET_MARKER; |
584 } |
582 } |
585 |
583 |
|
584 /** |
|
585 * Test whether {@code object} represents a constant value. |
|
586 * @param object a node or value object |
|
587 * @return true if object is a constant value |
|
588 */ |
|
589 public static boolean isConstant(final Object object) { |
|
590 return objectAsConstant(object) != POSTSET_MARKER; |
|
591 } |
|
592 |
586 private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> { |
593 private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> { |
587 private static final long serialVersionUID = 1L; |
594 private static final long serialVersionUID = 1L; |
588 |
595 |
589 private NullLiteralNode(final long token, final int finish) { |
596 private NullLiteralNode(final long token, final int finish) { |
590 super(Token.recast(token, TokenType.OBJECT), finish, null); |
597 super(Token.recast(token, TokenType.OBJECT), finish, null); |
624 private final Object presets; |
631 private final Object presets; |
625 |
632 |
626 /** Indices of array elements requiring computed post sets. */ |
633 /** Indices of array elements requiring computed post sets. */ |
627 private final int[] postsets; |
634 private final int[] postsets; |
628 |
635 |
629 /** Sub units with indexes ranges, in which to split up code generation, for large literals */ |
636 /** Ranges for splitting up large literals in code generation */ |
630 private final List<ArrayUnit> units; |
637 private final List<Splittable.SplitRange> splitRanges; |
631 |
638 |
632 @Override |
639 @Override |
633 public boolean isArray() { |
640 public boolean isArray() { |
634 return true; |
641 return true; |
635 } |
642 } |
636 |
643 |
637 |
|
638 /** |
|
639 * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can |
|
640 * be split if they are too large, for bytecode generation reasons |
|
641 */ |
|
642 public static final class ArrayUnit implements CompileUnitHolder, Serializable { |
|
643 private static final long serialVersionUID = 1L; |
|
644 |
|
645 /** Compile unit associated with the postsets range. */ |
|
646 private final CompileUnit compileUnit; |
|
647 |
|
648 /** postsets range associated with the unit (hi not inclusive). */ |
|
649 private final int lo, hi; |
|
650 |
|
651 /** |
|
652 * Constructor |
|
653 * @param compileUnit compile unit |
|
654 * @param lo lowest array index in unit |
|
655 * @param hi highest array index in unit + 1 |
|
656 */ |
|
657 public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) { |
|
658 this.compileUnit = compileUnit; |
|
659 this.lo = lo; |
|
660 this.hi = hi; |
|
661 } |
|
662 |
|
663 /** |
|
664 * Get the high index position of the ArrayUnit (non inclusive) |
|
665 * @return high index position |
|
666 */ |
|
667 public int getHi() { |
|
668 return hi; |
|
669 } |
|
670 |
|
671 /** |
|
672 * Get the low index position of the ArrayUnit (inclusive) |
|
673 * @return low index position |
|
674 */ |
|
675 public int getLo() { |
|
676 return lo; |
|
677 } |
|
678 |
|
679 /** |
|
680 * The array compile unit |
|
681 * @return array compile unit |
|
682 */ |
|
683 @Override |
|
684 public CompileUnit getCompileUnit() { |
|
685 return compileUnit; |
|
686 } |
|
687 } |
|
688 |
644 |
689 private static final class ArrayLiteralInitializer { |
645 private static final class ArrayLiteralInitializer { |
690 |
646 |
691 static ArrayLiteralNode initialize(final ArrayLiteralNode node) { |
647 static ArrayLiteralNode initialize(final ArrayLiteralNode node) { |
692 final Type elementType = computeElementType(node.value); |
648 final Type elementType = computeElementType(node.value); |
693 final int[] postsets = computePostsets(node.value); |
649 final int[] postsets = computePostsets(node.value); |
694 final Object presets = computePresets(node.value, elementType, postsets); |
650 final Object presets = computePresets(node.value, elementType, postsets); |
695 return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units); |
651 return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.splitRanges); |
696 } |
652 } |
697 |
653 |
698 private static Type computeElementType(final Expression[] value) { |
654 private static Type computeElementType(final Expression[] value) { |
699 Type widestElementType = Type.INT; |
655 Type widestElementType = Type.INT; |
700 |
656 |
723 final int[] computed = new int[value.length]; |
679 final int[] computed = new int[value.length]; |
724 int nComputed = 0; |
680 int nComputed = 0; |
725 |
681 |
726 for (int i = 0; i < value.length; i++) { |
682 for (int i = 0; i < value.length; i++) { |
727 final Expression element = value[i]; |
683 final Expression element = value[i]; |
728 if (element == null || objectAsConstant(element) == POSTSET_MARKER) { |
684 if (element == null || !isConstant(element)) { |
729 computed[nComputed++] = i; |
685 computed[nComputed++] = i; |
730 } |
686 } |
731 } |
687 } |
732 return Arrays.copyOf(computed, nComputed); |
688 return Arrays.copyOf(computed, nComputed); |
733 } |
689 } |
840 protected ArrayLiteralNode(final long token, final int finish, final Expression[] value) { |
796 protected ArrayLiteralNode(final long token, final int finish, final Expression[] value) { |
841 super(Token.recast(token, TokenType.ARRAY), finish, value); |
797 super(Token.recast(token, TokenType.ARRAY), finish, value); |
842 this.elementType = Type.UNKNOWN; |
798 this.elementType = Type.UNKNOWN; |
843 this.presets = null; |
799 this.presets = null; |
844 this.postsets = null; |
800 this.postsets = null; |
845 this.units = null; |
801 this.splitRanges = null; |
846 } |
802 } |
847 |
803 |
848 /** |
804 /** |
849 * Copy constructor |
805 * Copy constructor |
850 * @param node source array literal node |
806 * @param node source array literal node |
851 */ |
807 */ |
852 private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<ArrayUnit> units) { |
808 private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<Splittable.SplitRange> splitRanges) { |
853 super(node, value); |
809 super(node, value); |
854 this.elementType = elementType; |
810 this.elementType = elementType; |
855 this.postsets = postsets; |
811 this.postsets = postsets; |
856 this.presets = presets; |
812 this.presets = presets; |
857 this.units = units; |
813 this.splitRanges = splitRanges; |
858 } |
814 } |
859 |
815 |
860 /** |
816 /** |
861 * Returns a list of array element expressions. Note that empty array elements manifest themselves as |
817 * Returns a list of array element expressions. Note that empty array elements manifest themselves as |
862 * null. |
818 * null. |
944 assert presets != null && presetsMatchElementType() : this + " doesn't have presets, or invalid preset type: " + presets; |
900 assert presets != null && presetsMatchElementType() : this + " doesn't have presets, or invalid preset type: " + presets; |
945 return presets; |
901 return presets; |
946 } |
902 } |
947 |
903 |
948 /** |
904 /** |
949 * Get the array units that make up this ArrayLiteral |
905 * Get the split ranges for this ArrayLiteral, or null if this array does not have to be split. |
950 * @see ArrayUnit |
906 * @see Splittable.SplitRange |
951 * @return list of array units |
907 * @return list of split ranges |
952 */ |
908 */ |
953 public List<ArrayUnit> getUnits() { |
909 @Override |
954 return units == null ? null : Collections.unmodifiableList(units); |
910 public List<Splittable.SplitRange> getSplitRanges() { |
|
911 return splitRanges == null ? null : Collections.unmodifiableList(splitRanges); |
955 } |
912 } |
956 |
913 |
957 /** |
914 /** |
958 * Set the ArrayUnits that make up this ArrayLiteral |
915 * Set the SplitRanges that make up this ArrayLiteral |
959 * @param lc lexical context |
916 * @param lc lexical context |
960 * @see ArrayUnit |
917 * @see Splittable.SplitRange |
961 * @param units list of array units |
918 * @param splitRanges list of split ranges |
962 * @return new or changed arrayliteralnode |
919 * @return new or changed node |
963 */ |
920 */ |
964 public ArrayLiteralNode setUnits(final LexicalContext lc, final List<ArrayUnit> units) { |
921 public ArrayLiteralNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) { |
965 if (this.units == units) { |
922 if (this.splitRanges == splitRanges) { |
966 return this; |
923 return this; |
967 } |
924 } |
968 return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units)); |
925 return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges)); |
969 } |
926 } |
970 |
927 |
971 @Override |
928 @Override |
972 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { |
929 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { |
973 return Acceptor.accept(this, visitor); |
930 return Acceptor.accept(this, visitor); |
985 |
942 |
986 private ArrayLiteralNode setValue(final LexicalContext lc, final Expression[] value) { |
943 private ArrayLiteralNode setValue(final LexicalContext lc, final Expression[] value) { |
987 if (this.value == value) { |
944 if (this.value == value) { |
988 return this; |
945 return this; |
989 } |
946 } |
990 return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units)); |
947 return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges)); |
991 } |
948 } |
992 |
949 |
993 private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) { |
950 private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) { |
994 return setValue(lc, value.toArray(new Expression[value.size()])); |
951 return setValue(lc, value.toArray(new Expression[value.size()])); |
995 } |
952 } |