< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java

Print this page




  53 
  54     private final Expression rhs;
  55 
  56     private final int programPoint;
  57 
  58     private final Type type;
  59     private transient Type cachedType;
  60 
  61     @Ignore
  62     private static final Set<TokenType> CAN_OVERFLOW =
  63         Collections.unmodifiableSet(new HashSet<>(Arrays.asList(new TokenType[] {
  64                 TokenType.ADD,
  65                 TokenType.DIV,
  66                 TokenType.MOD,
  67                 TokenType.MUL,
  68                 TokenType.SUB,
  69                 TokenType.ASSIGN_ADD,
  70                 TokenType.ASSIGN_DIV,
  71                 TokenType.ASSIGN_MOD,
  72                 TokenType.ASSIGN_MUL,
  73                 TokenType.ASSIGN_SUB


  74             })));
  75 
  76     /**
  77      * Constructor
  78      *
  79      * @param token  token
  80      * @param lhs    left hand side
  81      * @param rhs    right hand side
  82      */
  83     public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
  84         super(token, lhs.getStart(), rhs.getFinish());
  85         assert !(isTokenType(TokenType.AND) || isTokenType(TokenType.OR)) || lhs instanceof JoinPredecessorExpression;
  86         this.lhs   = lhs;
  87         this.rhs   = rhs;
  88         this.programPoint = INVALID_PROGRAM_POINT;
  89         this.type = null;
  90     }
  91 
  92     private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs, final Type type, final int programPoint) {
  93         super(binaryNode);


 179     @Override
 180     public Type getWidestOperationType() {
 181         switch (tokenType()) {
 182         case ADD:
 183         case ASSIGN_ADD: {
 184             // Compare this logic to decideType(Type, Type); it's similar, but it handles the optimistic type
 185             // calculation case while this handles the conservative case.
 186             final Type lhsType = lhs.getType();
 187             final Type rhsType = rhs.getType();
 188             if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
 189                 // Will always fit in an int, as the value range is [0, 1, 2]. If we didn't treat them specially here,
 190                 // they'd end up being treated as generic INT operands and their sum would be conservatively considered
 191                 // to be a LONG in the generic case below; we can do better here.
 192                 return Type.INT;
 193             } else if(isString(lhsType) || isString(rhsType)) {
 194                 // We can statically figure out that this is a string if either operand is a string. In this case, use
 195                 // CHARSEQUENCE to prevent it from being proactively flattened.
 196                 return Type.CHARSEQUENCE;
 197             }
 198             final Type widestOperandType = Type.widest(undefinedToNumber(booleanToInt(lhsType)), undefinedToNumber(booleanToInt(rhsType)));
 199             if(widestOperandType == Type.INT) {
 200                 return Type.LONG;
 201             } else if (widestOperandType.isNumeric()) {
 202                 return Type.NUMBER;
 203             }
 204             // We pretty much can't know what it will be statically. Must presume OBJECT conservatively, as we can end
 205             // up getting either a string or an object when adding something + object, e.g.:
 206             // 1 + {} == "1[object Object]", but
 207             // 1 + {valueOf: function() { return 2 }} == 3. Also:
 208             // 1 + {valueOf: function() { return "2" }} == "12".
 209             return Type.OBJECT;
 210         }
 211         case SHR:
 212         case ASSIGN_SHR:
 213             return Type.LONG;
 214         case ASSIGN_SAR:
 215         case ASSIGN_SHL:
 216         case BIT_AND:
 217         case BIT_OR:
 218         case BIT_XOR:
 219         case ASSIGN_BIT_AND:
 220         case ASSIGN_BIT_OR:
 221         case ASSIGN_BIT_XOR:
 222         case SAR:
 223         case SHL:
 224             return Type.INT;
 225         case DIV:
 226         case MOD:
 227         case ASSIGN_DIV:
 228         case ASSIGN_MOD: {
 229             // Naively, one might think MOD has the same type as the widest of its operands, this is unfortunately not
 230             // true when denominator is zero, so even type(int % int) == double.
 231             return Type.NUMBER;
 232         }
 233         case MUL:
 234         case SUB:
 235         case ASSIGN_MUL:
 236         case ASSIGN_SUB: {
 237             final Type lhsType = lhs.getType();
 238             final Type rhsType = rhs.getType();
 239             if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
 240                 return Type.INT;
 241             }
 242             final Type widestOperandType = Type.widest(booleanToInt(lhsType), booleanToInt(rhsType));
 243             if(widestOperandType == Type.INT) {
 244                 return Type.LONG;
 245             }
 246             return Type.NUMBER;
 247         }
 248         case VOID: {
 249             return Type.UNDEFINED;
 250         }
 251         case ASSIGN: {
 252             return rhs.getType();
 253         }
 254         case INSTANCEOF: {
 255             return Type.BOOLEAN;
 256         }
 257         case COMMALEFT: {
 258             return lhs.getType();
 259         }
 260         case COMMARIGHT: {
 261             return rhs.getType();
 262         }
 263         case AND:
 264         case OR:{
 265             return Type.widestReturnType(lhs.getType(), rhs.getType());


 547      */
 548     public boolean isOptimisticUndecidedType() {
 549         return type == OPTIMISTIC_UNDECIDED_TYPE;
 550     }
 551 
 552     @Override
 553     public Type getType() {
 554         if (cachedType == null) {
 555             cachedType = getTypeUncached();
 556         }
 557         return cachedType;
 558     }
 559 
 560     private Type getTypeUncached() {
 561         if(type == OPTIMISTIC_UNDECIDED_TYPE) {
 562             return decideType(lhs.getType(), rhs.getType());
 563         }
 564         final Type widest = getWidestOperationType();
 565         if(type == null) {
 566             return widest;



 567         }
 568         return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
 569     }
 570 
 571     private static Type decideType(final Type lhsType, final Type rhsType) {
 572         // Compare this to getWidestOperationType() for ADD and ASSIGN_ADD cases. There's some similar logic, but these
 573         // are optimistic decisions, meaning that we don't have to treat boolean addition separately (as it'll become
 574         // int addition in the general case anyway), and that we also don't conservatively widen sums of ints to
 575         // longs, or sums of longs to doubles.
 576         if(isString(lhsType) || isString(rhsType)) {
 577             return Type.CHARSEQUENCE;
 578         }
 579         // NOTE: We don't have optimistic object-to-(int, long) conversions. Therefore, if any operand is an Object, we
 580         // bail out of optimism here and presume a conservative Object return value, as the object's ToPrimitive() can
 581         // end up returning either a number or a string, and their common supertype is Object, for better or worse.
 582         final Type widest = Type.widest(undefinedToNumber(booleanToInt(lhsType)), undefinedToNumber(booleanToInt(rhsType)));
 583         return widest.isObject() ? Type.OBJECT : widest;
 584     }
 585 
 586     /**


  53 
  54     private final Expression rhs;
  55 
  56     private final int programPoint;
  57 
  58     private final Type type;
  59     private transient Type cachedType;
  60 
  61     @Ignore
  62     private static final Set<TokenType> CAN_OVERFLOW =
  63         Collections.unmodifiableSet(new HashSet<>(Arrays.asList(new TokenType[] {
  64                 TokenType.ADD,
  65                 TokenType.DIV,
  66                 TokenType.MOD,
  67                 TokenType.MUL,
  68                 TokenType.SUB,
  69                 TokenType.ASSIGN_ADD,
  70                 TokenType.ASSIGN_DIV,
  71                 TokenType.ASSIGN_MOD,
  72                 TokenType.ASSIGN_MUL,
  73                 TokenType.ASSIGN_SUB,
  74                 TokenType.SHR,
  75                 TokenType.ASSIGN_SHR
  76             })));
  77 
  78     /**
  79      * Constructor
  80      *
  81      * @param token  token
  82      * @param lhs    left hand side
  83      * @param rhs    right hand side
  84      */
  85     public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
  86         super(token, lhs.getStart(), rhs.getFinish());
  87         assert !(isTokenType(TokenType.AND) || isTokenType(TokenType.OR)) || lhs instanceof JoinPredecessorExpression;
  88         this.lhs   = lhs;
  89         this.rhs   = rhs;
  90         this.programPoint = INVALID_PROGRAM_POINT;
  91         this.type = null;
  92     }
  93 
  94     private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs, final Type type, final int programPoint) {
  95         super(binaryNode);


 181     @Override
 182     public Type getWidestOperationType() {
 183         switch (tokenType()) {
 184         case ADD:
 185         case ASSIGN_ADD: {
 186             // Compare this logic to decideType(Type, Type); it's similar, but it handles the optimistic type
 187             // calculation case while this handles the conservative case.
 188             final Type lhsType = lhs.getType();
 189             final Type rhsType = rhs.getType();
 190             if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
 191                 // Will always fit in an int, as the value range is [0, 1, 2]. If we didn't treat them specially here,
 192                 // they'd end up being treated as generic INT operands and their sum would be conservatively considered
 193                 // to be a LONG in the generic case below; we can do better here.
 194                 return Type.INT;
 195             } else if(isString(lhsType) || isString(rhsType)) {
 196                 // We can statically figure out that this is a string if either operand is a string. In this case, use
 197                 // CHARSEQUENCE to prevent it from being proactively flattened.
 198                 return Type.CHARSEQUENCE;
 199             }
 200             final Type widestOperandType = Type.widest(undefinedToNumber(booleanToInt(lhsType)), undefinedToNumber(booleanToInt(rhsType)));
 201             if (widestOperandType.isNumeric()) {


 202                 return Type.NUMBER;
 203             }
 204             // We pretty much can't know what it will be statically. Must presume OBJECT conservatively, as we can end
 205             // up getting either a string or an object when adding something + object, e.g.:
 206             // 1 + {} == "1[object Object]", but
 207             // 1 + {valueOf: function() { return 2 }} == 3. Also:
 208             // 1 + {valueOf: function() { return "2" }} == "12".
 209             return Type.OBJECT;
 210         }
 211         case SHR:
 212         case ASSIGN_SHR:
 213             return Type.NUMBER;
 214         case ASSIGN_SAR:
 215         case ASSIGN_SHL:
 216         case BIT_AND:
 217         case BIT_OR:
 218         case BIT_XOR:
 219         case ASSIGN_BIT_AND:
 220         case ASSIGN_BIT_OR:
 221         case ASSIGN_BIT_XOR:
 222         case SAR:
 223         case SHL:
 224             return Type.INT;
 225         case DIV:
 226         case MOD:
 227         case ASSIGN_DIV:
 228         case ASSIGN_MOD: {
 229             // Naively, one might think MOD has the same type as the widest of its operands, this is unfortunately not
 230             // true when denominator is zero, so even type(int % int) == double.
 231             return Type.NUMBER;
 232         }
 233         case MUL:
 234         case SUB:
 235         case ASSIGN_MUL:
 236         case ASSIGN_SUB: {
 237             final Type lhsType = lhs.getType();
 238             final Type rhsType = rhs.getType();
 239             if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
 240                 return Type.INT;
 241             }




 242             return Type.NUMBER;
 243         }
 244         case VOID: {
 245             return Type.UNDEFINED;
 246         }
 247         case ASSIGN: {
 248             return rhs.getType();
 249         }
 250         case INSTANCEOF: {
 251             return Type.BOOLEAN;
 252         }
 253         case COMMALEFT: {
 254             return lhs.getType();
 255         }
 256         case COMMARIGHT: {
 257             return rhs.getType();
 258         }
 259         case AND:
 260         case OR:{
 261             return Type.widestReturnType(lhs.getType(), rhs.getType());


 543      */
 544     public boolean isOptimisticUndecidedType() {
 545         return type == OPTIMISTIC_UNDECIDED_TYPE;
 546     }
 547 
 548     @Override
 549     public Type getType() {
 550         if (cachedType == null) {
 551             cachedType = getTypeUncached();
 552         }
 553         return cachedType;
 554     }
 555 
 556     private Type getTypeUncached() {
 557         if(type == OPTIMISTIC_UNDECIDED_TYPE) {
 558             return decideType(lhs.getType(), rhs.getType());
 559         }
 560         final Type widest = getWidestOperationType();
 561         if(type == null) {
 562             return widest;
 563         }
 564         if (tokenType() == TokenType.ASSIGN_SHR || tokenType() == TokenType.SHR) {
 565             return type;
 566         }
 567         return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
 568     }
 569 
 570     private static Type decideType(final Type lhsType, final Type rhsType) {
 571         // Compare this to getWidestOperationType() for ADD and ASSIGN_ADD cases. There's some similar logic, but these
 572         // are optimistic decisions, meaning that we don't have to treat boolean addition separately (as it'll become
 573         // int addition in the general case anyway), and that we also don't conservatively widen sums of ints to
 574         // longs, or sums of longs to doubles.
 575         if(isString(lhsType) || isString(rhsType)) {
 576             return Type.CHARSEQUENCE;
 577         }
 578         // NOTE: We don't have optimistic object-to-(int, long) conversions. Therefore, if any operand is an Object, we
 579         // bail out of optimism here and presume a conservative Object return value, as the object's ToPrimitive() can
 580         // end up returning either a number or a string, and their common supertype is Object, for better or worse.
 581         final Type widest = Type.widest(undefinedToNumber(booleanToInt(lhsType)), undefinedToNumber(booleanToInt(rhsType)));
 582         return widest.isObject() ? Type.OBJECT : widest;
 583     }
 584 
 585     /**
< prev index next >