< prev index next >

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

Print this page




 114 
 115         JumpOrigin(final JoinPredecessor node, final Map<Symbol, LvarType> types) {
 116             this.node = node;
 117             this.types = types;
 118         }
 119     }
 120 
 121     private static class JumpTarget {
 122         private final List<JumpOrigin> origins = new LinkedList<>();
 123         private Map<Symbol, LvarType> types = Collections.emptyMap();
 124 
 125         void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
 126             origins.add(new JumpOrigin(originNode, originTypes));
 127             this.types = getUnionTypes(this.types, originTypes);
 128         }
 129     }
 130     private enum LvarType {
 131         UNDEFINED(Type.UNDEFINED),
 132         BOOLEAN(Type.BOOLEAN),
 133         INT(Type.INT),
 134         LONG(Type.LONG),
 135         DOUBLE(Type.NUMBER),
 136         OBJECT(Type.OBJECT);
 137 
 138         private final Type type;
 139         private final TypeHolderExpression typeExpression;
 140 
 141         private LvarType(final Type type) {
 142             this.type = type;
 143             this.typeExpression = new TypeHolderExpression(type);
 144         }
 145     }
 146 
 147     /**
 148      * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
 149      * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
 150      * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
 151      * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
 152      * generation of higher number of temporary short lived nodes, though.
 153      */
 154     private static class TypeHolderExpression extends Expression {


 255             union.putAll(types2);
 256         } else {
 257             union = cloneMap(types2);
 258             union.putAll(types1);
 259         }
 260         for(final Symbol symbol: commonSymbols) {
 261             final LvarType type1 = types1.get(symbol);
 262             final LvarType type2 = types2.get(symbol);
 263             union.put(symbol, widestLvarType(type1,  type2));
 264         }
 265         return union;
 266     }
 267 
 268     private static void symbolIsUsed(final Symbol symbol, final LvarType type) {
 269         if(type != LvarType.UNDEFINED) {
 270             symbol.setHasSlotFor(type.type);
 271         }
 272     }
 273 
 274     private static class SymbolConversions {
 275         private static final byte I2L = 1 << 0;
 276         private static final byte I2D = 1 << 1;
 277         private static final byte I2O = 1 << 2;
 278         private static final byte L2D = 1 << 3;
 279         private static final byte L2O = 1 << 4;
 280         private static final byte D2O = 1 << 5;
 281 
 282         private byte conversions;
 283 
 284         void recordConversion(final LvarType from, final LvarType to) {
 285             switch (from) {
 286             case UNDEFINED:
 287                 return;
 288             case INT:
 289             case BOOLEAN:
 290                 switch (to) {
 291                 case LONG:
 292                     recordConversion(I2L);
 293                     return;
 294                 case DOUBLE:
 295                     recordConversion(I2D);
 296                     return;
 297                 case OBJECT:
 298                     recordConversion(I2O);
 299                     return;
 300                 default:
 301                     illegalConversion(from, to);
 302                     return;
 303                 }
 304             case LONG:
 305                 switch (to) {
 306                 case DOUBLE:
 307                     recordConversion(L2D);
 308                     return;
 309                 case OBJECT:
 310                     recordConversion(L2O);
 311                     return;
 312                 default:
 313                     illegalConversion(from, to);
 314                     return;
 315                 }
 316             case DOUBLE:
 317                 if(to == LvarType.OBJECT) {
 318                     recordConversion(D2O);
 319                 }
 320                 return;
 321             default:
 322                 illegalConversion(from, to);
 323             }
 324         }
 325 
 326         private static void illegalConversion(final LvarType from, final LvarType to) {
 327             throw new AssertionError("Invalid conversion from " + from + " to " + to);
 328         }
 329 
 330         void recordConversion(final byte convFlag) {
 331             conversions = (byte)(conversions | convFlag);
 332         }
 333 
 334         boolean hasConversion(final byte convFlag) {
 335             return (conversions & convFlag) != 0;
 336         }
 337 
 338         void calculateTypeLiveness(final Symbol symbol) {
 339             if(symbol.hasSlotFor(Type.OBJECT)) {
 340                 if(hasConversion(D2O)) {
 341                     symbol.setHasSlotFor(Type.NUMBER);
 342                 }
 343                 if(hasConversion(L2O)) {
 344                     symbol.setHasSlotFor(Type.LONG);
 345                 }
 346                 if(hasConversion(I2O)) {
 347                     symbol.setHasSlotFor(Type.INT);
 348                 }
 349             }
 350             if(symbol.hasSlotFor(Type.NUMBER)) {
 351                 if(hasConversion(L2D)) {
 352                     symbol.setHasSlotFor(Type.LONG);
 353                 }
 354                 if(hasConversion(I2D)) {
 355                     symbol.setHasSlotFor(Type.INT);
 356                 }
 357             }
 358             if(symbol.hasSlotFor(Type.LONG)) {
 359                 if(hasConversion(I2L)) {
 360                     symbol.setHasSlotFor(Type.INT);
 361                 }
 362             }
 363         }
 364     }
 365 
 366     private void symbolIsConverted(final Symbol symbol, final LvarType from, final LvarType to) {
 367         SymbolConversions conversions = symbolConversions.get(symbol);
 368         if(conversions == null) {
 369             conversions = new SymbolConversions();
 370             symbolConversions.put(symbol, conversions);
 371         }
 372         conversions.recordConversion(from, to);
 373     }
 374 
 375     private static LvarType toLvarType(final Type type) {
 376         assert type != null;
 377         final LvarType lvarType = TO_LVAR_TYPE.get(type);
 378         if(lvarType != null) {
 379             return lvarType;
 380         }
 381         assert type.isObject();
 382         return LvarType.OBJECT;
 383     }
 384     private static LvarType widestLvarType(final LvarType t1, final LvarType t2) {
 385         if(t1 == t2) {
 386             return t1;
 387         }
 388         // Undefined or boolean to anything always widens to object.
 389         if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
 390             return LvarType.OBJECT;
 391         }
 392         // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
 393         // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
 394         return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
 395     }
 396     private final Compiler compiler;
 397     private final Map<Label, JumpTarget> jumpTargets = new IdentityHashMap<>();
 398     // Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
 399     // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
 400     // value.
 401     private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();




 114 
 115         JumpOrigin(final JoinPredecessor node, final Map<Symbol, LvarType> types) {
 116             this.node = node;
 117             this.types = types;
 118         }
 119     }
 120 
 121     private static class JumpTarget {
 122         private final List<JumpOrigin> origins = new LinkedList<>();
 123         private Map<Symbol, LvarType> types = Collections.emptyMap();
 124 
 125         void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
 126             origins.add(new JumpOrigin(originNode, originTypes));
 127             this.types = getUnionTypes(this.types, originTypes);
 128         }
 129     }
 130     private enum LvarType {
 131         UNDEFINED(Type.UNDEFINED),
 132         BOOLEAN(Type.BOOLEAN),
 133         INT(Type.INT),

 134         DOUBLE(Type.NUMBER),
 135         OBJECT(Type.OBJECT);
 136 
 137         private final Type type;
 138         private final TypeHolderExpression typeExpression;
 139 
 140         private LvarType(final Type type) {
 141             this.type = type;
 142             this.typeExpression = new TypeHolderExpression(type);
 143         }
 144     }
 145 
 146     /**
 147      * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
 148      * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
 149      * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
 150      * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
 151      * generation of higher number of temporary short lived nodes, though.
 152      */
 153     private static class TypeHolderExpression extends Expression {


 254             union.putAll(types2);
 255         } else {
 256             union = cloneMap(types2);
 257             union.putAll(types1);
 258         }
 259         for(final Symbol symbol: commonSymbols) {
 260             final LvarType type1 = types1.get(symbol);
 261             final LvarType type2 = types2.get(symbol);
 262             union.put(symbol, widestLvarType(type1,  type2));
 263         }
 264         return union;
 265     }
 266 
 267     private static void symbolIsUsed(final Symbol symbol, final LvarType type) {
 268         if(type != LvarType.UNDEFINED) {
 269             symbol.setHasSlotFor(type.type);
 270         }
 271     }
 272 
 273     private static class SymbolConversions {
 274         private static final byte I2D = 1 << 0;
 275         private static final byte I2O = 1 << 1;
 276         private static final byte D2O = 1 << 2;



 277 
 278         private byte conversions;
 279 
 280         void recordConversion(final LvarType from, final LvarType to) {
 281             switch (from) {
 282             case UNDEFINED:
 283                 return;
 284             case INT:
 285             case BOOLEAN:
 286                 switch (to) {



 287                 case DOUBLE:
 288                     recordConversion(I2D);
 289                     return;
 290                 case OBJECT:
 291                     recordConversion(I2O);
 292                     return;
 293                 default:
 294                     illegalConversion(from, to);
 295                     return;
 296                 }












 297             case DOUBLE:
 298                 if(to == LvarType.OBJECT) {
 299                     recordConversion(D2O);
 300                 }
 301                 return;
 302             default:
 303                 illegalConversion(from, to);
 304             }
 305         }
 306 
 307         private static void illegalConversion(final LvarType from, final LvarType to) {
 308             throw new AssertionError("Invalid conversion from " + from + " to " + to);
 309         }
 310 
 311         void recordConversion(final byte convFlag) {
 312             conversions = (byte)(conversions | convFlag);
 313         }
 314 
 315         boolean hasConversion(final byte convFlag) {
 316             return (conversions & convFlag) != 0;
 317         }
 318 
 319         void calculateTypeLiveness(final Symbol symbol) {
 320             if(symbol.hasSlotFor(Type.OBJECT)) {
 321                 if(hasConversion(D2O)) {
 322                     symbol.setHasSlotFor(Type.NUMBER);
 323                 }



 324                 if(hasConversion(I2O)) {
 325                     symbol.setHasSlotFor(Type.INT);
 326                 }
 327             }
 328             if(symbol.hasSlotFor(Type.NUMBER)) {



 329                 if(hasConversion(I2D)) {
 330                     symbol.setHasSlotFor(Type.INT);
 331                 }
 332             }





 333         }
 334     }
 335 
 336     private void symbolIsConverted(final Symbol symbol, final LvarType from, final LvarType to) {
 337         SymbolConversions conversions = symbolConversions.get(symbol);
 338         if(conversions == null) {
 339             conversions = new SymbolConversions();
 340             symbolConversions.put(symbol, conversions);
 341         }
 342         conversions.recordConversion(from, to);
 343     }
 344 
 345     private static LvarType toLvarType(final Type type) {
 346         assert type != null;
 347         final LvarType lvarType = TO_LVAR_TYPE.get(type);
 348         if(lvarType != null) {
 349             return lvarType;
 350         }
 351         assert type.isObject() : "Unsupported primitive type: " + type;
 352         return LvarType.OBJECT;
 353     }
 354     private static LvarType widestLvarType(final LvarType t1, final LvarType t2) {
 355         if(t1 == t2) {
 356             return t1;
 357         }
 358         // Undefined or boolean to anything always widens to object.
 359         if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
 360             return LvarType.OBJECT;
 361         }
 362         // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
 363         // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
 364         return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
 365     }
 366     private final Compiler compiler;
 367     private final Map<Label, JumpTarget> jumpTargets = new IdentityHashMap<>();
 368     // Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
 369     // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
 370     // value.
 371     private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();


< prev index next >