< prev index next >

src/jdk/nashorn/internal/codegen/CodeGenerator.java

Print this page




 171  * </pre>
 172  * This quickly became apparent when the code generator was generalized to work
 173  * with all types, and not just numbers or objects.
 174  * <p>
 175  * The CodeGenerator visits nodes only once and emits bytecode for them.
 176  */
 177 @Logger(name="codegen")
 178 final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> implements Loggable {
 179 
 180     private static final Type SCOPE_TYPE = Type.typeFor(ScriptObject.class);
 181 
 182     private static final String GLOBAL_OBJECT = Type.getInternalName(Global.class);
 183 
 184     private static final Call CREATE_REWRITE_EXCEPTION = CompilerConstants.staticCallNoLookup(RewriteException.class,
 185             "create", RewriteException.class, UnwarrantedOptimismException.class, Object[].class, String[].class);
 186     private static final Call CREATE_REWRITE_EXCEPTION_REST_OF = CompilerConstants.staticCallNoLookup(RewriteException.class,
 187             "create", RewriteException.class, UnwarrantedOptimismException.class, Object[].class, String[].class, int[].class);
 188 
 189     private static final Call ENSURE_INT = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
 190             "ensureInt", int.class, Object.class, int.class);
 191     private static final Call ENSURE_LONG = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
 192             "ensureLong", long.class, Object.class, int.class);
 193     private static final Call ENSURE_NUMBER = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
 194             "ensureNumber", double.class, Object.class, int.class);
 195 
 196     private static final Call CREATE_FUNCTION_OBJECT = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
 197             "create", ScriptFunction.class, Object[].class, int.class, ScriptObject.class);
 198     private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
 199             "create", ScriptFunction.class, Object[].class, int.class);
 200 
 201     private static final Call TO_NUMBER_FOR_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
 202             "toNumberForEq", double.class, Object.class);
 203     private static final Call TO_NUMBER_FOR_STRICT_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
 204             "toNumberForStrictEq", double.class, Object.class);
 205 
 206 
 207     private static final Class<?> ITERATOR_CLASS = Iterator.class;
 208     static {
 209         assert ITERATOR_CLASS == CompilerConstants.ITERATOR_PREFIX.type();
 210     }
 211     private static final Type ITERATOR_TYPE = Type.typeFor(ITERATOR_CLASS);
 212     private static final Type EXCEPTION_TYPE = Type.typeFor(CompilerConstants.EXCEPTION_PREFIX.type());


1703 
1704     @Override
1705     public boolean enterContinueNode(final ContinueNode continueNode) {
1706         return enterJumpStatement(continueNode);
1707     }
1708 
1709     @Override
1710     public boolean enterEmptyNode(final EmptyNode emptyNode) {
1711         // Don't even record the line number, it's irrelevant as there's no code.
1712         return false;
1713     }
1714 
1715     @Override
1716     public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
1717         if(!method.isReachable()) {
1718             return false;
1719         }
1720         enterStatement(expressionStatement);
1721 
1722         loadAndDiscard(expressionStatement.getExpression());
1723         assert method.getStackSize() == 0;
1724 
1725         return false;
1726     }
1727 
1728     @Override
1729     public boolean enterBlockStatement(final BlockStatement blockStatement) {
1730         if(!method.isReachable()) {
1731             return false;
1732         }
1733         enterStatement(blockStatement);
1734 
1735         blockStatement.getBlock().accept(this);
1736 
1737         return false;
1738     }
1739 
1740     @Override
1741     public boolean enterForNode(final ForNode forNode) {
1742         if(!method.isReachable()) {
1743             return false;


2218 
2219     private void lineNumber(final int lineNumber) {
2220         if (lineNumber != lastLineNumber && lineNumber != Node.NO_LINE_NUMBER) {
2221             method.lineNumber(lineNumber);
2222             lastLineNumber = lineNumber;
2223         }
2224     }
2225 
2226     int getLastLineNumber() {
2227         return lastLineNumber;
2228     }
2229 
2230     /**
2231      * Load a list of nodes as an array of a specific type
2232      * The array will contain the visited nodes.
2233      *
2234      * @param arrayLiteralNode the array of contents
2235      * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
2236      */
2237     private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
2238         assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
2239 
2240         final Expression[]     nodes    = arrayLiteralNode.getValue();
2241         final Object           presets  = arrayLiteralNode.getPresets();
2242         final int[]            postsets = arrayLiteralNode.getPostsets();
2243         final List<Splittable.SplitRange> ranges   = arrayLiteralNode.getSplitRanges();
2244 
2245         loadConstant(presets);
2246 
2247         final Type elementType = arrayType.getElementType();
2248 
2249         if (ranges != null) {
2250 
2251             loadSplitLiteral(new SplitLiteralCreator() {
2252                 @Override
2253                 public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
2254                     for (int i = start; i < end; i++) {
2255                         method.load(type, slot);
2256                         storeElement(nodes, elementType, postsets[i]);
2257                     }
2258                     method.load(type, slot);


2366         } else if (value instanceof Undefined) {
2367             method.loadUndefined(resultBounds.within(Type.OBJECT));
2368         } else if (value instanceof String) {
2369             final String string = (String)value;
2370 
2371             if (string.length() > MethodEmitter.LARGE_STRING_THRESHOLD / 3) { // 3 == max bytes per encoded char
2372                 loadConstant(string);
2373             } else {
2374                 method.load(string);
2375             }
2376         } else if (value instanceof RegexToken) {
2377             loadRegex((RegexToken)value);
2378         } else if (value instanceof Boolean) {
2379             method.load((Boolean)value);
2380         } else if (value instanceof Integer) {
2381             if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
2382                 method.load((Integer)value);
2383                 method.convert(Type.OBJECT);
2384             } else if(!resultBounds.canBeNarrowerThan(Type.NUMBER)) {
2385                 method.load(((Integer)value).doubleValue());
2386             } else if(!resultBounds.canBeNarrowerThan(Type.LONG)) {
2387                 method.load(((Integer)value).longValue());
2388             } else {
2389                 method.load((Integer)value);
2390             }
2391         } else if (value instanceof Long) {
2392             if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
2393                 method.load((Long)value);
2394                 method.convert(Type.OBJECT);
2395             } else if(!resultBounds.canBeNarrowerThan(Type.NUMBER)) {
2396                 method.load(((Long)value).doubleValue());
2397             } else {
2398                 method.load((Long)value);
2399             }
2400         } else if (value instanceof Double) {
2401             if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
2402                 method.load((Double)value);
2403                 method.convert(Type.OBJECT);
2404             } else {
2405                 method.load((Double)value);
2406             }
2407         } else if (node instanceof ArrayLiteralNode) {
2408             final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node;
2409             final ArrayType atype = arrayLiteral.getArrayType();
2410             loadArray(arrayLiteral, atype);
2411             globalAllocateArray(atype);
2412         } else {
2413             throw new UnsupportedOperationException("Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value);
2414         }
2415     }
2416 
2417     private MethodEmitter loadRegexToken(final RegexToken value) {
2418         method.load(value.getExpression());
2419         method.load(value.getOptions());


3630             @Override
3631             protected void storeNonDiscard() {
3632                 super.storeNonDiscard();
3633                 if (isPostfix) {
3634                     new OptimisticOperation(unaryNode, typeBounds) {
3635                         @Override
3636                         void loadStack() {
3637                             loadMinusOne();
3638                         }
3639                         @Override
3640                         void consumeStack() {
3641                             doDecInc(getProgramPoint());
3642                         }
3643                     }.emit(1); // 1 for non-incremented result on the top of the stack pushed in evaluate()
3644                 }
3645             }
3646 
3647             private void loadMinusOne() {
3648                 if (type.isInteger()) {
3649                     method.load(isIncrement ? 1 : -1);
3650                 } else if (type.isLong()) {
3651                     method.load(isIncrement ? 1L : -1L);
3652                 } else {
3653                     method.load(isIncrement ? 1.0 : -1.0);
3654                 }
3655             }
3656 
3657             private void doDecInc(final int programPoint) {
3658                 method.add(programPoint);
3659             }
3660         }.store();
3661     }
3662 
3663     private static int getOptimisticIgnoreCountForSelfModifyingExpression(final Expression target) {
3664         return target instanceof AccessNode ? 1 : target instanceof IndexNode ? 2 : 0;
3665     }
3666 
3667     private void loadAndDiscard(final Expression expr) {
3668         // TODO: move checks for discarding to actual expression load code (e.g. as we do with void). That way we might
3669         // be able to eliminate even more checks.
3670         if(expr instanceof PrimitiveLiteralNode | isLocalVariable(expr)) {
3671             assert !lc.isCurrentDiscard(expr);


4013 
4014     private void loadASSIGN_SAR(final BinaryNode binaryNode) {
4015         new BinarySelfAssignment(binaryNode) {
4016             @Override
4017             protected void op() {
4018                 method.sar();
4019             }
4020         }.store();
4021     }
4022 
4023     private void loadASSIGN_SHL(final BinaryNode binaryNode) {
4024         new BinarySelfAssignment(binaryNode) {
4025             @Override
4026             protected void op() {
4027                 method.shl();
4028             }
4029         }.store();
4030     }
4031 
4032     private void loadASSIGN_SHR(final BinaryNode binaryNode) {
4033         new BinarySelfAssignment(binaryNode) {
4034             @Override
4035             protected void op() {
4036                 doSHR();









4037             }
4038 











4039         }.store();
4040     }
4041 
4042     private void doSHR() {
4043         // TODO: make SHR optimistic






4044         method.shr();
4045         toUint();

















4046     }
4047 
4048     private void toUint() {
4049         JSType.TO_UINT32_I.invoke(method);
4050     }
4051 
4052     private void loadASSIGN_SUB(final BinaryNode binaryNode) {
4053         new BinaryOptimisticSelfAssignment(binaryNode) {
4054             @Override
4055             protected void op(final OptimisticOperation oo) {
4056                 method.sub(oo.getProgramPoint());
4057             }
4058         }.store();
4059     }
4060 
4061     /**
4062      * Helper class for binary arithmetic ops
4063      */
4064     private abstract class BinaryArith {
4065         protected abstract void op(int programPoint);
4066 
4067         protected void evaluate(final BinaryNode node, final TypeBounds resultBounds) {
4068             final TypeBounds numericBounds = resultBounds.booleanToInt().objectToNumber();
4069             new OptimisticOperation(node, numericBounds) {
4070                 @Override
4071                 void loadStack() {
4072                     final TypeBounds operandBounds;
4073                     boolean forceConversionSeparation = false;
4074                     if(numericBounds.narrowest == Type.NUMBER) {
4075                         // Result should be double always. Propagate it into the operands so we don't have lots of I2D
4076                         // and L2D after operand evaluation.
4077                         assert numericBounds.widest == Type.NUMBER;
4078                         operandBounds = numericBounds;
4079                     } else {
4080                         final boolean isOptimistic = isValid(getProgramPoint());
4081                         if(isOptimistic || node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
4082                             operandBounds = new TypeBounds(node.getType(), Type.NUMBER);
4083                         } else {
4084                             // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
4085                             operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
4086                                     numericBounds.widest), Type.NUMBER);
4087                             forceConversionSeparation = node.getWidestOperationType().narrowerThan(numericBounds.widest);
4088                         }
4089                     }
4090                     loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false, forceConversionSeparation);
4091                 }
4092 
4093                 @Override
4094                 void consumeStack() {
4095                     op(getProgramPoint());
4096                 }
4097             }.emit();
4098         }
4099     }
4100 
4101     private void loadBIT_AND(final BinaryNode binaryNode) {
4102         loadBinaryOperands(binaryNode);
4103         method.and();
4104     }
4105 
4106     private void loadBIT_OR(final BinaryNode binaryNode) {
4107         // Optimize x|0 to (int)x


4169     private void loadMUL(final BinaryNode binaryNode, final TypeBounds resultBounds) {
4170         new BinaryArith() {
4171             @Override
4172             protected void op(final int programPoint) {
4173                 method.mul(programPoint);
4174             }
4175         }.evaluate(binaryNode, resultBounds);
4176     }
4177 
4178     private void loadSAR(final BinaryNode binaryNode) {
4179         loadBinaryOperands(binaryNode);
4180         method.sar();
4181     }
4182 
4183     private void loadSHL(final BinaryNode binaryNode) {
4184         loadBinaryOperands(binaryNode);
4185         method.shl();
4186     }
4187 
4188     private void loadSHR(final BinaryNode binaryNode) {
4189         // Optimize x >>> 0 to (uint)x
4190         if (isRhsZero(binaryNode)) {
4191             loadExpressionAsType(binaryNode.lhs(), Type.INT);
4192             toUint();
4193         } else {
4194             loadBinaryOperands(binaryNode);
4195             doSHR();
4196         }
4197     }
4198 
4199     private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) {
4200         new BinaryArith() {
4201             @Override
4202             protected void op(final int programPoint) {
4203                 method.sub(programPoint);
4204             }
4205         }.evaluate(binaryNode, resultBounds);
4206     }
4207 
4208     @Override
4209     public boolean enterLabelNode(final LabelNode labelNode) {
4210         labeledBlockBreakLiveLocals.push(lc.getUsedSlotCount());
4211         return true;
4212     }
4213 
4214     @Override
4215     protected boolean enterDefault(final Node node) {
4216         throw new AssertionError("Code generator entered node of type " + node.getClass().getName());


4447              */
4448             target.accept(new SimpleNodeVisitor() {
4449                 @Override
4450                 protected boolean enterDefault(final Node node) {
4451                     throw new AssertionError("Unexpected node " + node + " in store epilogue");
4452                 }
4453 
4454                 @Override
4455                 public boolean enterIdentNode(final IdentNode node) {
4456                     final Symbol symbol = node.getSymbol();
4457                     assert symbol != null;
4458                     if (symbol.isScope()) {
4459                         final int flags = getScopeCallSiteFlags(symbol);
4460                         if (isFastScope(symbol)) {
4461                             storeFastScopeVar(symbol, flags);
4462                         } else {
4463                             method.dynamicSet(node.getName(), flags, false);
4464                         }
4465                     } else {
4466                         final Type storeType = assignNode.getType();

4467                         if (symbol.hasSlotFor(storeType)) {
4468                             // Only emit a convert for a store known to be live; converts for dead stores can
4469                             // give us an unnecessary ClassCastException.
4470                             method.convert(storeType);
4471                         }
4472                         storeIdentWithCatchConversion(node, storeType);
4473                     }
4474                     return false;
4475 
4476                 }
4477 
4478                 @Override
4479                 public boolean enterAccessNode(final AccessNode node) {
4480                     method.dynamicSet(node.getProperty(), getCallSiteFlags(), node.isIndex());
4481                     return false;
4482                 }
4483 
4484                 @Override
4485                 public boolean enterIndexNode(final IndexNode node) {
4486                     method.dynamicSetIndex(getCallSiteFlags());


4831                 return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags), msg);
4832             }
4833             return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags), msg);
4834         }
4835 
4836         int getOptimisticFlags(final int flags) {
4837             return flags | CALLSITE_OPTIMISTIC | (optimistic.getProgramPoint() << CALLSITE_PROGRAM_POINT_SHIFT); //encode program point in high bits
4838         }
4839 
4840         int getProgramPoint() {
4841             return isOptimistic ? optimistic.getProgramPoint() : INVALID_PROGRAM_POINT;
4842         }
4843 
4844         void convertOptimisticReturnValue() {
4845             if (isOptimistic) {
4846                 final Type optimisticType = getOptimisticCoercedType();
4847                 if(!optimisticType.isObject()) {
4848                     method.load(optimistic.getProgramPoint());
4849                     if(optimisticType.isInteger()) {
4850                         method.invoke(ENSURE_INT);
4851                     } else if(optimisticType.isLong()) {
4852                         method.invoke(ENSURE_LONG);
4853                     } else if(optimisticType.isNumber()) {
4854                         method.invoke(ENSURE_NUMBER);
4855                     } else {
4856                         throw new AssertionError(optimisticType);
4857                     }
4858                 }
4859             }
4860         }
4861 
4862         void replaceCompileTimeProperty() {
4863             final IdentNode identNode = (IdentNode)expression;
4864             final String name = identNode.getSymbol().getName();
4865             if (CompilerConstants.__FILE__.name().equals(name)) {
4866                 replaceCompileTimeProperty(getCurrentSource().getName());
4867             } else if (CompilerConstants.__DIR__.name().equals(name)) {
4868                 replaceCompileTimeProperty(getCurrentSource().getBase());
4869             } else if (CompilerConstants.__LINE__.name().equals(name)) {
4870                 replaceCompileTimeProperty(getCurrentSource().getLine(identNode.position()));
4871             }
4872         }




 171  * </pre>
 172  * This quickly became apparent when the code generator was generalized to work
 173  * with all types, and not just numbers or objects.
 174  * <p>
 175  * The CodeGenerator visits nodes only once and emits bytecode for them.
 176  */
 177 @Logger(name="codegen")
 178 final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContext> implements Loggable {
 179 
 180     private static final Type SCOPE_TYPE = Type.typeFor(ScriptObject.class);
 181 
 182     private static final String GLOBAL_OBJECT = Type.getInternalName(Global.class);
 183 
 184     private static final Call CREATE_REWRITE_EXCEPTION = CompilerConstants.staticCallNoLookup(RewriteException.class,
 185             "create", RewriteException.class, UnwarrantedOptimismException.class, Object[].class, String[].class);
 186     private static final Call CREATE_REWRITE_EXCEPTION_REST_OF = CompilerConstants.staticCallNoLookup(RewriteException.class,
 187             "create", RewriteException.class, UnwarrantedOptimismException.class, Object[].class, String[].class, int[].class);
 188 
 189     private static final Call ENSURE_INT = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
 190             "ensureInt", int.class, Object.class, int.class);


 191     private static final Call ENSURE_NUMBER = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
 192             "ensureNumber", double.class, Object.class, int.class);
 193 
 194     private static final Call CREATE_FUNCTION_OBJECT = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
 195             "create", ScriptFunction.class, Object[].class, int.class, ScriptObject.class);
 196     private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
 197             "create", ScriptFunction.class, Object[].class, int.class);
 198 
 199     private static final Call TO_NUMBER_FOR_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
 200             "toNumberForEq", double.class, Object.class);
 201     private static final Call TO_NUMBER_FOR_STRICT_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
 202             "toNumberForStrictEq", double.class, Object.class);
 203 
 204 
 205     private static final Class<?> ITERATOR_CLASS = Iterator.class;
 206     static {
 207         assert ITERATOR_CLASS == CompilerConstants.ITERATOR_PREFIX.type();
 208     }
 209     private static final Type ITERATOR_TYPE = Type.typeFor(ITERATOR_CLASS);
 210     private static final Type EXCEPTION_TYPE = Type.typeFor(CompilerConstants.EXCEPTION_PREFIX.type());


1701 
1702     @Override
1703     public boolean enterContinueNode(final ContinueNode continueNode) {
1704         return enterJumpStatement(continueNode);
1705     }
1706 
1707     @Override
1708     public boolean enterEmptyNode(final EmptyNode emptyNode) {
1709         // Don't even record the line number, it's irrelevant as there's no code.
1710         return false;
1711     }
1712 
1713     @Override
1714     public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
1715         if(!method.isReachable()) {
1716             return false;
1717         }
1718         enterStatement(expressionStatement);
1719 
1720         loadAndDiscard(expressionStatement.getExpression());
1721         assert method.getStackSize() == 0 : "stack not empty in " + expressionStatement;
1722 
1723         return false;
1724     }
1725 
1726     @Override
1727     public boolean enterBlockStatement(final BlockStatement blockStatement) {
1728         if(!method.isReachable()) {
1729             return false;
1730         }
1731         enterStatement(blockStatement);
1732 
1733         blockStatement.getBlock().accept(this);
1734 
1735         return false;
1736     }
1737 
1738     @Override
1739     public boolean enterForNode(final ForNode forNode) {
1740         if(!method.isReachable()) {
1741             return false;


2216 
2217     private void lineNumber(final int lineNumber) {
2218         if (lineNumber != lastLineNumber && lineNumber != Node.NO_LINE_NUMBER) {
2219             method.lineNumber(lineNumber);
2220             lastLineNumber = lineNumber;
2221         }
2222     }
2223 
2224     int getLastLineNumber() {
2225         return lastLineNumber;
2226     }
2227 
2228     /**
2229      * Load a list of nodes as an array of a specific type
2230      * The array will contain the visited nodes.
2231      *
2232      * @param arrayLiteralNode the array of contents
2233      * @param arrayType        the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
2234      */
2235     private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
2236         assert arrayType == Type.INT_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
2237 
2238         final Expression[]     nodes    = arrayLiteralNode.getValue();
2239         final Object           presets  = arrayLiteralNode.getPresets();
2240         final int[]            postsets = arrayLiteralNode.getPostsets();
2241         final List<Splittable.SplitRange> ranges   = arrayLiteralNode.getSplitRanges();
2242 
2243         loadConstant(presets);
2244 
2245         final Type elementType = arrayType.getElementType();
2246 
2247         if (ranges != null) {
2248 
2249             loadSplitLiteral(new SplitLiteralCreator() {
2250                 @Override
2251                 public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
2252                     for (int i = start; i < end; i++) {
2253                         method.load(type, slot);
2254                         storeElement(nodes, elementType, postsets[i]);
2255                     }
2256                     method.load(type, slot);


2364         } else if (value instanceof Undefined) {
2365             method.loadUndefined(resultBounds.within(Type.OBJECT));
2366         } else if (value instanceof String) {
2367             final String string = (String)value;
2368 
2369             if (string.length() > MethodEmitter.LARGE_STRING_THRESHOLD / 3) { // 3 == max bytes per encoded char
2370                 loadConstant(string);
2371             } else {
2372                 method.load(string);
2373             }
2374         } else if (value instanceof RegexToken) {
2375             loadRegex((RegexToken)value);
2376         } else if (value instanceof Boolean) {
2377             method.load((Boolean)value);
2378         } else if (value instanceof Integer) {
2379             if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
2380                 method.load((Integer)value);
2381                 method.convert(Type.OBJECT);
2382             } else if(!resultBounds.canBeNarrowerThan(Type.NUMBER)) {
2383                 method.load(((Integer)value).doubleValue());


2384             } else {
2385                 method.load((Integer)value);
2386             }









2387         } else if (value instanceof Double) {
2388             if(!resultBounds.canBeNarrowerThan(Type.OBJECT)) {
2389                 method.load((Double)value);
2390                 method.convert(Type.OBJECT);
2391             } else {
2392                 method.load((Double)value);
2393             }
2394         } else if (node instanceof ArrayLiteralNode) {
2395             final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node;
2396             final ArrayType atype = arrayLiteral.getArrayType();
2397             loadArray(arrayLiteral, atype);
2398             globalAllocateArray(atype);
2399         } else {
2400             throw new UnsupportedOperationException("Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value);
2401         }
2402     }
2403 
2404     private MethodEmitter loadRegexToken(final RegexToken value) {
2405         method.load(value.getExpression());
2406         method.load(value.getOptions());


3617             @Override
3618             protected void storeNonDiscard() {
3619                 super.storeNonDiscard();
3620                 if (isPostfix) {
3621                     new OptimisticOperation(unaryNode, typeBounds) {
3622                         @Override
3623                         void loadStack() {
3624                             loadMinusOne();
3625                         }
3626                         @Override
3627                         void consumeStack() {
3628                             doDecInc(getProgramPoint());
3629                         }
3630                     }.emit(1); // 1 for non-incremented result on the top of the stack pushed in evaluate()
3631                 }
3632             }
3633 
3634             private void loadMinusOne() {
3635                 if (type.isInteger()) {
3636                     method.load(isIncrement ? 1 : -1);


3637                 } else {
3638                     method.load(isIncrement ? 1.0 : -1.0);
3639                 }
3640             }
3641 
3642             private void doDecInc(final int programPoint) {
3643                 method.add(programPoint);
3644             }
3645         }.store();
3646     }
3647 
3648     private static int getOptimisticIgnoreCountForSelfModifyingExpression(final Expression target) {
3649         return target instanceof AccessNode ? 1 : target instanceof IndexNode ? 2 : 0;
3650     }
3651 
3652     private void loadAndDiscard(final Expression expr) {
3653         // TODO: move checks for discarding to actual expression load code (e.g. as we do with void). That way we might
3654         // be able to eliminate even more checks.
3655         if(expr instanceof PrimitiveLiteralNode | isLocalVariable(expr)) {
3656             assert !lc.isCurrentDiscard(expr);


3998 
3999     private void loadASSIGN_SAR(final BinaryNode binaryNode) {
4000         new BinarySelfAssignment(binaryNode) {
4001             @Override
4002             protected void op() {
4003                 method.sar();
4004             }
4005         }.store();
4006     }
4007 
4008     private void loadASSIGN_SHL(final BinaryNode binaryNode) {
4009         new BinarySelfAssignment(binaryNode) {
4010             @Override
4011             protected void op() {
4012                 method.shl();
4013             }
4014         }.store();
4015     }
4016 
4017     private void loadASSIGN_SHR(final BinaryNode binaryNode) {
4018         new SelfModifyingStore<BinaryNode>(binaryNode, binaryNode.lhs()) {
4019             @Override
4020             protected void evaluate() {
4021                 new OptimisticOperation(assignNode, new TypeBounds(Type.INT, Type.NUMBER)) {
4022                     @Override
4023                     void loadStack() {
4024                         assert assignNode.getWidestOperandType() == Type.INT;
4025                         if (isRhsZero(binaryNode)) {
4026                             loadExpressionAsType(binaryNode.lhs(), Type.INT);
4027                         } else {
4028                             loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), TypeBounds.INT, true, false);
4029                             method.shr();
4030                         }
4031                     }
4032 
4033                     @Override
4034                     void consumeStack() {
4035                         if (isOptimistic(binaryNode)) {
4036                             toUint32Optimistic(binaryNode.getProgramPoint());
4037                         } else {
4038                             toUint32Double();
4039                         }
4040                     }
4041                 }.emit(getOptimisticIgnoreCountForSelfModifyingExpression(binaryNode.lhs()));
4042                 method.convert(assignNode.getType());
4043             }
4044         }.store();
4045     }
4046 
4047     private void doSHR(final BinaryNode binaryNode) {
4048         new OptimisticOperation(binaryNode, new TypeBounds(Type.INT, Type.NUMBER)) {
4049             @Override
4050             void loadStack() {
4051                 if (isRhsZero(binaryNode)) {
4052                     loadExpressionAsType(binaryNode.lhs(), Type.INT);
4053                 } else {
4054                     loadBinaryOperands(binaryNode);
4055                     method.shr();
4056                 }
4057             }
4058 
4059             @Override
4060             void consumeStack() {
4061                 if (isOptimistic(binaryNode)) {
4062                     toUint32Optimistic(binaryNode.getProgramPoint());
4063                 } else {
4064                     toUint32Double();
4065                 }
4066             }
4067         }.emit();
4068 
4069     }
4070 
4071     private void toUint32Optimistic(final int programPoint) {
4072         method.load(programPoint);
4073         JSType.TO_UINT32_OPTIMISTIC.invoke(method);
4074     }
4075 
4076     private void toUint32Double() {
4077         JSType.TO_UINT32_DOUBLE.invoke(method);
4078     }
4079 
4080     private void loadASSIGN_SUB(final BinaryNode binaryNode) {
4081         new BinaryOptimisticSelfAssignment(binaryNode) {
4082             @Override
4083             protected void op(final OptimisticOperation oo) {
4084                 method.sub(oo.getProgramPoint());
4085             }
4086         }.store();
4087     }
4088 
4089     /**
4090      * Helper class for binary arithmetic ops
4091      */
4092     private abstract class BinaryArith {
4093         protected abstract void op(int programPoint);
4094 
4095         protected void evaluate(final BinaryNode node, final TypeBounds resultBounds) {
4096             final TypeBounds numericBounds = resultBounds.booleanToInt().objectToNumber();
4097             new OptimisticOperation(node, numericBounds) {
4098                 @Override
4099                 void loadStack() {
4100                     final TypeBounds operandBounds;
4101                     boolean forceConversionSeparation = false;
4102                     if(numericBounds.narrowest == Type.NUMBER) {
4103                         // Result should be double always. Propagate it into the operands so we don't have lots of I2D
4104                         // and L2D after operand evaluation.
4105                         assert numericBounds.widest == Type.NUMBER;
4106                         operandBounds = numericBounds;
4107                     } else {
4108                         final boolean isOptimistic = isValid(getProgramPoint());
4109                         if(isOptimistic || node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
4110                             operandBounds = new TypeBounds(node.getType(), Type.NUMBER);
4111                         } else {
4112                             // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
4113                             operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
4114                                     numericBounds.widest), Type.NUMBER);
4115                             forceConversionSeparation = true;
4116                         }
4117                     }
4118                     loadBinaryOperands(node.lhs(), node.rhs(), operandBounds, false, forceConversionSeparation);
4119                 }
4120 
4121                 @Override
4122                 void consumeStack() {
4123                     op(getProgramPoint());
4124                 }
4125             }.emit();
4126         }
4127     }
4128 
4129     private void loadBIT_AND(final BinaryNode binaryNode) {
4130         loadBinaryOperands(binaryNode);
4131         method.and();
4132     }
4133 
4134     private void loadBIT_OR(final BinaryNode binaryNode) {
4135         // Optimize x|0 to (int)x


4197     private void loadMUL(final BinaryNode binaryNode, final TypeBounds resultBounds) {
4198         new BinaryArith() {
4199             @Override
4200             protected void op(final int programPoint) {
4201                 method.mul(programPoint);
4202             }
4203         }.evaluate(binaryNode, resultBounds);
4204     }
4205 
4206     private void loadSAR(final BinaryNode binaryNode) {
4207         loadBinaryOperands(binaryNode);
4208         method.sar();
4209     }
4210 
4211     private void loadSHL(final BinaryNode binaryNode) {
4212         loadBinaryOperands(binaryNode);
4213         method.shl();
4214     }
4215 
4216     private void loadSHR(final BinaryNode binaryNode) {
4217         doSHR(binaryNode);







4218     }
4219 
4220     private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) {
4221         new BinaryArith() {
4222             @Override
4223             protected void op(final int programPoint) {
4224                 method.sub(programPoint);
4225             }
4226         }.evaluate(binaryNode, resultBounds);
4227     }
4228 
4229     @Override
4230     public boolean enterLabelNode(final LabelNode labelNode) {
4231         labeledBlockBreakLiveLocals.push(lc.getUsedSlotCount());
4232         return true;
4233     }
4234 
4235     @Override
4236     protected boolean enterDefault(final Node node) {
4237         throw new AssertionError("Code generator entered node of type " + node.getClass().getName());


4468              */
4469             target.accept(new SimpleNodeVisitor() {
4470                 @Override
4471                 protected boolean enterDefault(final Node node) {
4472                     throw new AssertionError("Unexpected node " + node + " in store epilogue");
4473                 }
4474 
4475                 @Override
4476                 public boolean enterIdentNode(final IdentNode node) {
4477                     final Symbol symbol = node.getSymbol();
4478                     assert symbol != null;
4479                     if (symbol.isScope()) {
4480                         final int flags = getScopeCallSiteFlags(symbol);
4481                         if (isFastScope(symbol)) {
4482                             storeFastScopeVar(symbol, flags);
4483                         } else {
4484                             method.dynamicSet(node.getName(), flags, false);
4485                         }
4486                     } else {
4487                         final Type storeType = assignNode.getType();
4488                         assert storeType != Type.LONG;
4489                         if (symbol.hasSlotFor(storeType)) {
4490                             // Only emit a convert for a store known to be live; converts for dead stores can
4491                             // give us an unnecessary ClassCastException.
4492                             method.convert(storeType);
4493                         }
4494                         storeIdentWithCatchConversion(node, storeType);
4495                     }
4496                     return false;
4497 
4498                 }
4499 
4500                 @Override
4501                 public boolean enterAccessNode(final AccessNode node) {
4502                     method.dynamicSet(node.getProperty(), getCallSiteFlags(), node.isIndex());
4503                     return false;
4504                 }
4505 
4506                 @Override
4507                 public boolean enterIndexNode(final IndexNode node) {
4508                     method.dynamicSetIndex(getCallSiteFlags());


4853                 return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags), msg);
4854             }
4855             return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags), msg);
4856         }
4857 
4858         int getOptimisticFlags(final int flags) {
4859             return flags | CALLSITE_OPTIMISTIC | (optimistic.getProgramPoint() << CALLSITE_PROGRAM_POINT_SHIFT); //encode program point in high bits
4860         }
4861 
4862         int getProgramPoint() {
4863             return isOptimistic ? optimistic.getProgramPoint() : INVALID_PROGRAM_POINT;
4864         }
4865 
4866         void convertOptimisticReturnValue() {
4867             if (isOptimistic) {
4868                 final Type optimisticType = getOptimisticCoercedType();
4869                 if(!optimisticType.isObject()) {
4870                     method.load(optimistic.getProgramPoint());
4871                     if(optimisticType.isInteger()) {
4872                         method.invoke(ENSURE_INT);


4873                     } else if(optimisticType.isNumber()) {
4874                         method.invoke(ENSURE_NUMBER);
4875                     } else {
4876                         throw new AssertionError(optimisticType);
4877                     }
4878                 }
4879             }
4880         }
4881 
4882         void replaceCompileTimeProperty() {
4883             final IdentNode identNode = (IdentNode)expression;
4884             final String name = identNode.getSymbol().getName();
4885             if (CompilerConstants.__FILE__.name().equals(name)) {
4886                 replaceCompileTimeProperty(getCurrentSource().getName());
4887             } else if (CompilerConstants.__DIR__.name().equals(name)) {
4888                 replaceCompileTimeProperty(getCurrentSource().getBase());
4889             } else if (CompilerConstants.__LINE__.name().equals(name)) {
4890                 replaceCompileTimeProperty(getCurrentSource().getLine(identNode.position()));
4891             }
4892         }


< prev index next >