< prev index next >

src/jdk.scripting.nashorn/share/classes/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());


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


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


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


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


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









4040             }
4041 











4042         }.store();
4043     }
4044 
4045     private void doSHR() {
4046         // TODO: make SHR optimistic






4047         method.shr();
4048         toUint();

















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


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


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

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


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




 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());


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


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


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


2390             } else {
2391                 method.load((Integer)value);
2392             }









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


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


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


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


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







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


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


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


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


< prev index next >