Mercurial > people > rkennke > jdk9-shenandoah-final > nashorn
changeset 246:5a3f7867e19c
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
Reviewed-by: jlaskey, hannesw
line wrap: on
line diff
--- a/bin/jjs Thu May 02 15:01:16 2013 -0300 +++ b/bin/jjs Fri May 03 15:33:54 2013 +0200 @@ -26,4 +26,4 @@ [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; -$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $* +$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Fri May 03 15:33:54 2013 +0200 @@ -31,7 +31,6 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import jdk.nashorn.internal.runtime.Version; -import sun.reflect.Reflection; /** * JSR-223 compliant script engine factory for Nashorn. The engine answers for:
--- a/src/jdk/nashorn/internal/codegen/Attr.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Fri May 03 15:33:54 2013 +0200 @@ -29,17 +29,21 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX; +import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; +import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF; import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; import static jdk.nashorn.internal.ir.Symbol.IS_LET; import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; import static jdk.nashorn.internal.ir.Symbol.IS_THIS; import static jdk.nashorn.internal.ir.Symbol.IS_VAR; import static jdk.nashorn.internal.ir.Symbol.KINDMASK; @@ -51,6 +55,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -90,7 +95,6 @@ import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; -import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; /** @@ -133,9 +137,9 @@ * Constructor. */ Attr() { - localDefs = new ArrayDeque<>(); - localUses = new ArrayDeque<>(); - returnTypes = new ArrayDeque<>(); + this.localDefs = new ArrayDeque<>(); + this.localUses = new ArrayDeque<>(); + this.returnTypes = new ArrayDeque<>(); } @Override @@ -150,67 +154,48 @@ @Override public Node leaveAccessNode(final AccessNode accessNode) { - ensureSymbol(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this - end(accessNode); - return accessNode; + //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this + return end(ensureSymbol(Type.OBJECT, accessNode)); } - private void enterFunctionBody() { + private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) { + initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE); + initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT); - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); - final Block body = getLexicalContext().getCurrentBlock(); - initCallee(body); - initThis(body); if (functionNode.isVarArg()) { - initVarArg(body, functionNode.needsArguments()); + initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY); + if (functionNode.needsArguments()) { + initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); + addLocalDef(ARGUMENTS.symbolName()); + } } initParameters(functionNode, body); - initScope(body); - initReturn(body); + initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); + initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, Type.OBJECT); + } - if (functionNode.isProgram()) { - initFromPropertyMap(body); - } else if(!functionNode.isDeclared()) { - // It's neither declared nor program - it's a function expression then; assign it a self-symbol. - if (functionNode.getSymbol() != null) { - // a temporary left over from an earlier pass when the function was lazy - assert functionNode.getSymbol().isTemp(); - // remove it - functionNode.setSymbol(null); - } - final boolean anonymous = functionNode.isAnonymous(); - final String name = anonymous ? null : functionNode.getIdent().getName(); - if (anonymous || body.getExistingSymbol(name) != null) { - // The function is either anonymous, or another local identifier already trumps its name on entry: - // either it has the same name as one of its parameters, or is named "arguments" and also references the - // "arguments" identifier in its body. - ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode); - } else { - final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode); - assert selfSymbol.isFunctionSelf(); - newType(selfSymbol, Type.OBJECT); - } - } - - /* - * This pushes all declarations (except for non-statements, i.e. for - * node temporaries) to the top of the function scope. This way we can - * get around problems like - * - * while (true) { - * break; - * if (true) { - * var s; - * } - * } - * - * to an arbitrary nesting depth. - * - * @see NASHORN-73 - */ - + /** + * This pushes all declarations (except for non-statements, i.e. for + * node temporaries) to the top of the function scope. This way we can + * get around problems like + * + * while (true) { + * break; + * if (true) { + * var s; + * } + * } + * + * to an arbitrary nesting depth. + * + * see NASHORN-73 + * + * @param functionNode the FunctionNode we are entering + * @param body the body of the FunctionNode we are entering + */ + private void acceptDeclarations(final FunctionNode functionNode, final Block body) { // This visitor will assign symbol to all declared variables, except function declarations (which are taken care // in a separate step above) and "var" declarations in for loop initializers. body.accept(new NodeOperatorVisitor() { @@ -220,27 +205,52 @@ } @Override - public boolean enterVarNode(final VarNode varNode) { - + public Node leaveVarNode(final VarNode varNode) { // any declared symbols that aren't visited need to be typed as well, hence the list - if (varNode.isStatement()) { - - final IdentNode ident = varNode.getName(); - final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident)); + final IdentNode ident = varNode.getName(); + final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR); functionNode.addDeclaredSymbol(symbol); if (varNode.isFunctionDeclaration()) { newType(symbol, FunctionNode.FUNCTION_TYPE); } + return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol)); } - return false; + return varNode; } }); } + private void enterFunctionBody() { + + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + final Block body = getLexicalContext().getCurrentBlock(); + + initFunctionWideVariables(functionNode, body); + + if (functionNode.isProgram()) { + initFromPropertyMap(body); + } else if (!functionNode.isDeclared()) { + // It's neither declared nor program - it's a function expression then; assign it a self-symbol. + assert functionNode.getSymbol() == null; + + final boolean anonymous = functionNode.isAnonymous(); + final String name = anonymous ? null : functionNode.getIdent().getName(); + if (!(anonymous || body.getExistingSymbol(name) != null)) { + assert !anonymous && name != null; + newType(defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF), Type.OBJECT); + } + } + + acceptDeclarations(functionNode, body); + } + @Override public boolean enterBlock(final Block block) { start(block); + //ensure that we don't use information from a previous compile. This is very ugly TODO + //the symbols in the block should really be stateless + block.clearSymbols(); if (getLexicalContext().isFunctionBody()) { enterFunctionBody(); @@ -257,14 +267,13 @@ } @Override - public Node leaveCallNode(final CallNode callNode) { - ensureSymbol(callNode.getType(), callNode); - return end(callNode); + public boolean enterCallNode(final CallNode callNode) { + return start(callNode); } @Override - public boolean enterCallNode(final CallNode callNode) { - return start(callNode); + public Node leaveCallNode(final CallNode callNode) { + return end(ensureSymbol(callNode.getType(), callNode)); } @Override @@ -275,23 +284,31 @@ start(catchNode); // define block-local exception variable - final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET); newType(def, Type.OBJECT); addLocalDef(exception.getName()); return true; } + @Override + public Node leaveCatchNode(final CatchNode catchNode) { + final IdentNode exception = catchNode.getException(); + final Block block = getLexicalContext().getCurrentBlock(); + final Symbol symbol = findSymbol(block, exception.getName()); + assert symbol != null; + return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol))); + } + /** * Declare the definition of a new symbol. * * @param name Name of symbol. * @param symbolFlags Symbol flags. - * @param node Defining Node. * * @return Symbol for given name or null for redefinition. */ - private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { + private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) { int flags = symbolFlags; Symbol symbol = findSymbol(block, name); // Locate symbol. @@ -337,7 +354,7 @@ // Create and add to appropriate block. symbol = new Symbol(name, flags); - symbolBlock.putSymbol(name, symbol); + symbolBlock.putSymbol(getLexicalContext(), symbol); if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { symbol.setNeedsSlot(true); @@ -346,10 +363,6 @@ symbol.setFlags(flags); } - if (node != null) { - node.setSymbol(symbol); - } - return symbol; } @@ -357,30 +370,22 @@ public boolean enterFunctionNode(final FunctionNode functionNode) { start(functionNode, false); + if (functionNode.isLazy()) { + return false; + } + + //an outermost function in our lexical context that is not a program (runScript) + //is possible - it is a function being compiled lazily if (functionNode.isDeclared()) { final Iterator<Block> blocks = getLexicalContext().getBlocks(); if (blocks.hasNext()) { - defineSymbol( - blocks.next(), - functionNode.getIdent().getName(), - IS_VAR, - functionNode); - } else { - // Q: What's an outermost function in a lexical context that is not a program? - // A: It's a function being compiled lazily! - assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram(); + defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR); } } - if (functionNode.isLazy()) { - LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT"); - ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode); - end(functionNode); - return false; - } - returnTypes.push(functionNode.getReturnType()); pushLocalsFunction(); + return true; } @@ -390,8 +395,29 @@ final LexicalContext lc = getLexicalContext(); + final Block body = newFunctionNode.getBody(); + + //look for this function in the parent block + if (functionNode.isDeclared()) { + final Iterator<Block> blocks = getLexicalContext().getBlocks(); + if (blocks.hasNext()) { + newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName())); + } + } else if (!functionNode.isProgram()) { + final boolean anonymous = functionNode.isAnonymous(); + final String name = anonymous ? null : functionNode.getIdent().getName(); + if (anonymous || body.getExistingSymbol(name) != null) { + newFunctionNode = (FunctionNode)Attr.ensureSymbol(lc, body, FunctionNode.FUNCTION_TYPE, newFunctionNode); + } else { + assert name != null; + final Symbol self = body.getExistingSymbol(name); + assert self != null && self.isFunctionSelf(); + newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, body.getExistingSymbol(name)); + } + } + //unknown parameters are promoted to object type. - finalizeParameters(newFunctionNode); + newFunctionNode = finalizeParameters(newFunctionNode); finalizeTypes(newFunctionNode); for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) { if (symbol.getSymbolType().isUnknown()) { @@ -400,8 +426,6 @@ } } - final Block body = newFunctionNode.getBody(); - if (newFunctionNode.hasLazyChildren()) { //the final body has already been assigned as we have left the function node block body by now objectifySymbols(body); @@ -409,7 +433,7 @@ if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) { final IdentNode callee = compilerConstant(CALLEE); - final VarNode selfInit = + VarNode selfInit = new VarNode( newFunctionNode.getSource(), newFunctionNode.getToken(), @@ -420,7 +444,6 @@ LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName()); final List<Node> newStatements = new ArrayList<>(); - newStatements.add(selfInit); assert callee.getSymbol() != null && callee.getSymbol().hasSlot(); final IdentNode name = selfInit.getName(); @@ -428,9 +451,10 @@ assert nameSymbol != null; - name.setSymbol(nameSymbol); - selfInit.setSymbol(nameSymbol); + selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol)); + selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol); + newStatements.add(selfInit); newStatements.addAll(body.getStatements()); newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements)); } @@ -447,34 +471,32 @@ end(newFunctionNode, false); - return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode)); + return newFunctionNode; } @Override public Node leaveCONVERT(final UnaryNode unaryNode) { assert false : "There should be no convert operators in IR during Attribution"; - end(unaryNode); - return unaryNode; + return end(unaryNode); } @Override - public boolean enterIdentNode(final IdentNode identNode) { + public Node leaveIdentNode(final IdentNode identNode) { final String name = identNode.getName(); start(identNode); + final LexicalContext lc = getLexicalContext(); + if (identNode.isPropertyName()) { // assign a pseudo symbol to property name final Symbol pseudoSymbol = pseudoSymbol(name); LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol); LOG.unindent(); - identNode.setSymbol(pseudoSymbol); - return false; + return identNode.setSymbol(lc, pseudoSymbol); } - final LexicalContext lc = getLexicalContext(); - final Block block = lc.getCurrentBlock(); - final Symbol oldSymbol = identNode.getSymbol(); + final Block block = lc.getCurrentBlock(); Symbol symbol = findSymbol(block, name); @@ -495,12 +517,11 @@ } } - identNode.setSymbol(symbol); // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already) maybeForceScope(symbol); } else { LOG.info("No symbol exists. Declare undefined: ", symbol); - symbol = defineSymbol(block, name, IS_GLOBAL, identNode); + symbol = defineSymbol(block, name, IS_GLOBAL); // we have never seen this before, it can be undefined newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? symbol.setCanBeUndefined(); @@ -509,14 +530,14 @@ setBlockScope(name, symbol); - if (symbol != oldSymbol && !identNode.isInitializedHere()) { + if (symbol != null && !identNode.isInitializedHere()) { symbol.increaseUseCount(); } addLocalUse(identNode.getName()); end(identNode); - return false; + return identNode.setSymbol(lc, symbol); } /** @@ -525,7 +546,7 @@ * @param symbol the symbol that might be scoped */ private void maybeForceScope(final Symbol symbol) { - if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) { + if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) { Symbol.setSymbolIsScope(getLexicalContext(), symbol); } } @@ -612,11 +633,11 @@ private Symbol findSymbol(final Block block, final String name) { // Search up block chain to locate symbol. - for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { + for (final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { // Find name. final Symbol symbol = blocks.next().getExistingSymbol(name); // If found then we are good. - if(symbol != null) { + if (symbol != null) { return symbol; } } @@ -625,39 +646,19 @@ @Override public Node leaveIndexNode(final IndexNode indexNode) { - ensureSymbol(Type.OBJECT, indexNode); //TODO - return indexNode; + return end(ensureSymbol(Type.OBJECT, indexNode)); } @SuppressWarnings("rawtypes") @Override - public boolean enterLiteralNode(final LiteralNode literalNode) { - try { - start(literalNode); - assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens - - if (literalNode instanceof ArrayLiteralNode) { - final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; - final Node[] array = arrayLiteralNode.getValue(); - - for (int i = 0; i < array.length; i++) { - final Node element = array[i]; - if (element != null) { - array[i] = element.accept(this); - } - } - arrayLiteralNode.analyze(); - //array literal node now has an element type and all elements are attributed - } else { - assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; - } - - getLexicalContext().getCurrentFunction().newLiteral(literalNode); - } finally { - end(literalNode); + public Node leaveLiteralNode(final LiteralNode literalNode) { + assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens + assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; + final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); + if (literalNode instanceof ArrayLiteralNode) { + ((ArrayLiteralNode)literalNode).analyze(); } - - return false; + return literalNode.setSymbol(getLexicalContext(), symbol); } @Override @@ -667,18 +668,13 @@ @Override public Node leaveObjectNode(final ObjectNode objectNode) { - ensureSymbol(Type.OBJECT, objectNode); - return end(objectNode); + return end(ensureSymbol(Type.OBJECT, objectNode)); } - //TODO is this correct why not leave? @Override - public boolean enterPropertyNode(final PropertyNode propertyNode) { + public Node leavePropertyNode(final PropertyNode propertyNode) { // assign a pseudo symbol to property name, see NASHORN-710 - start(propertyNode); - propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); - end(propertyNode); - return true; + return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); } @Override @@ -763,12 +759,9 @@ final IdentNode ident = varNode.getName(); final String name = ident.getName(); - final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident); + final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR); assert symbol != null; - LOG.info("VarNode ", varNode, " set symbol ", symbol); - varNode.setSymbol(symbol); - // NASHORN-467 - use before definition of vars - conservative if (isLocalUse(ident.getName())) { newType(symbol, Type.OBJECT); @@ -780,22 +773,31 @@ @Override public Node leaveVarNode(final VarNode varNode) { - final Node init = varNode.getInit(); - final IdentNode ident = varNode.getName(); + VarNode newVarNode = varNode; + + final Node init = newVarNode.getInit(); + final IdentNode ident = newVarNode.getName(); final String name = ident.getName(); if (init == null) { // var x; with no init will be treated like a use of x by - // visit(IdentNode) unless we remove the name - // from the localdef list. + // leaveIdentNode unless we remove the name from the localdef list. removeLocalDef(name); - return varNode; + return newVarNode; } addLocalDef(name); - final Symbol symbol = varNode.getSymbol(); - final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56 + final LexicalContext lc = getLexicalContext(); + final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); + assert symbol != null; + + final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol); + + newVarNode = newVarNode.setName(newIdent); + newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol); + + final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { // Forbid integers as local vars for now as we have no way to treat them as undefined newType(symbol, init.getType()); @@ -803,25 +805,19 @@ newType(symbol, Type.OBJECT); } - assert varNode.hasType() : varNode; + assert newVarNode.hasType() : newVarNode + " has no type"; - end(varNode); - - return varNode; + return end(newVarNode); } @Override public Node leaveADD(final UnaryNode unaryNode) { - ensureSymbol(arithType(), unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(arithType(), unaryNode)); } @Override public Node leaveBIT_NOT(final UnaryNode unaryNode) { - ensureSymbol(Type.INT, unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(Type.INT, unaryNode)); } @Override @@ -830,9 +826,7 @@ ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs()); final Type type = arithType(); newType(unaryNode.rhs().getSymbol(), type); - ensureSymbol(type, unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(type, unaryNode)); } @Override @@ -908,23 +902,25 @@ @Override public Node leaveNEW(final UnaryNode unaryNode) { - ensureSymbol(Type.OBJECT, unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(Type.OBJECT, unaryNode)); } @Override public Node leaveNOT(final UnaryNode unaryNode) { - ensureSymbol(Type.BOOLEAN, unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(Type.BOOLEAN, unaryNode)); } private IdentNode compilerConstant(CompilerConstants cc) { final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); - final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); - node.setSymbol(functionNode.compilerConstant(cc)); - return node; + return (IdentNode) + new IdentNode( + functionNode.getSource(), + functionNode.getToken(), + functionNode.getFinish(), + cc.symbolName()). + setSymbol( + getLexicalContext(), + functionNode.compilerConstant(cc)); } @Override @@ -952,15 +948,12 @@ @Override public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { - ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode); - return runtimeNode; + return end(ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode)); } @Override public Node leaveSUB(final UnaryNode unaryNode) { - ensureSymbol(arithType(), unaryNode); - end(unaryNode); - return unaryNode; + return end(ensureSymbol(arithType(), unaryNode)); } @Override @@ -982,18 +975,16 @@ ensureTypeNotUnknown(lhs); ensureTypeNotUnknown(rhs); - ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode); - - end(binaryNode); - - return binaryNode; + //even if we are adding two known types, this can overflow. i.e. + //int and number -> number. + //int and int are also number though. + //something and object is object + return end(ensureSymbol(Type.widest(arithType(), Type.widest(lhs.getType(), rhs.getType())), binaryNode)); } @Override public Node leaveAND(final BinaryNode binaryNode) { - ensureSymbol(Type.OBJECT, binaryNode); - end(binaryNode); - return binaryNode; + return end(ensureSymbol(Type.OBJECT, binaryNode)); } /** @@ -1013,8 +1004,7 @@ Symbol symbol = findSymbol(block, name); if (symbol == null) { - symbol = defineSymbol(block, name, IS_GLOBAL, ident); - binaryNode.setSymbol(symbol); + symbol = defineSymbol(block, name, IS_GLOBAL); } else { maybeForceScope(symbol); } @@ -1025,6 +1015,31 @@ return true; } + + /** + * This assign helper is called after an assignment, when all children of + * the assign has been processed. It fixes the types and recursively makes + * sure that everyhing has slots that should have them in the chain. + * + * @param binaryNode assignment node + */ + private Node leaveAssignmentNode(final BinaryNode binaryNode) { + BinaryNode newBinaryNode = binaryNode; + + final Node lhs = binaryNode.lhs(); + final Node rhs = binaryNode.rhs(); + final Type type; + + if (rhs.getType().isNumeric()) { + type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); + } else { + type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. + } + + newType(lhs.getSymbol(), type); + return end(ensureSymbol(type, newBinaryNode)); + } + private boolean isLocal(FunctionNode function, Symbol symbol) { final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol); // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local @@ -1173,14 +1188,12 @@ @Override public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { - ensureSymbol(binaryNode.rhs().getType(), binaryNode); - return binaryNode; + return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode)); } @Override public Node leaveCOMMALEFT(final BinaryNode binaryNode) { - ensureSymbol(binaryNode.lhs().getType(), binaryNode); - return binaryNode; + return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode)); } @Override @@ -1189,15 +1202,10 @@ } private Node leaveCmp(final BinaryNode binaryNode) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); + ensureTypeNotUnknown(binaryNode.lhs()); + ensureTypeNotUnknown(binaryNode.rhs()); - ensureSymbol(Type.BOOLEAN, binaryNode); - ensureTypeNotUnknown(lhs); - ensureTypeNotUnknown(rhs); - - end(binaryNode); - return binaryNode; + return end(ensureSymbol(Type.BOOLEAN, binaryNode)); } private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) { @@ -1207,11 +1215,9 @@ // as, say, an int : function(x) { return x & 4711 }, and x is not defined in // the function. to make this work, uncomment the following two type inferences // and debug. - //newType(binaryNode.lhs().getSymbol(), operandType); //newType(binaryNode.rhs().getSymbol(), operandType); - ensureSymbol(destType, binaryNode); - return binaryNode; + return ensureSymbol(destType, binaryNode); } private Node coerce(final BinaryNode binaryNode, final Type type) { @@ -1295,9 +1301,7 @@ @Override public Node leaveOR(final BinaryNode binaryNode) { - ensureSymbol(Type.OBJECT, binaryNode); - end(binaryNode); - return binaryNode; + return end(ensureSymbol(Type.OBJECT, binaryNode)); } @Override @@ -1346,50 +1350,13 @@ ensureTypeNotUnknown(rhs); final Type type = Type.widest(lhs.getType(), rhs.getType()); - ensureSymbol(type, ternaryNode); - - end(ternaryNode); - assert ternaryNode.getSymbol() != null; - - return ternaryNode; - } - - private void initThis(final Block block) { - final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null); - newType(thisSymbol, Type.OBJECT); - thisSymbol.setNeedsSlot(true); - } - - private void initScope(final Block block) { - final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null); - newType(scopeSymbol, Type.typeFor(ScriptObject.class)); - scopeSymbol.setNeedsSlot(true); + return end(ensureSymbol(type, ternaryNode)); } - private void initReturn(final Block block) { - final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null); - newType(returnSymbol, Type.OBJECT); - returnSymbol.setNeedsSlot(true); - //return symbol is always object as it's the __return__ thing. What returnType is is another matter though - } - - private void initVarArg(final Block block, final boolean needsArguments) { - final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null); - varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); - varArgsSymbol.setNeedsSlot(true); - - if (needsArguments) { - final Symbol argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null); - newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); - argumentsSymbol.setNeedsSlot(true); - addLocalDef(ARGUMENTS.symbolName()); - } - } - - private void initCallee(final Block block) { - final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null); - newType(calleeSymbol, FunctionNode.FUNCTION_TYPE); - calleeSymbol.setNeedsSlot(true); + private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) { + final Symbol symbol = defineSymbol(block, cc.symbolName(), flags); + newType(symbol, type); + symbol.setNeedsSlot(true); } /** @@ -1399,19 +1366,28 @@ * @param functionNode the function node */ private void initParameters(final FunctionNode functionNode, final Block body) { + int pos = 0; for (final IdentNode param : functionNode.getParameters()) { addLocalDef(param.getName()); - final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param); + + final Type callSiteParamType = functionNode.getHints().getParameterType(pos); + int flags = IS_PARAM; + if (callSiteParamType != null) { + LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that."); + flags |= Symbol.IS_SPECIALIZED_PARAM; + } + + final Symbol paramSymbol = defineSymbol(body, param.getName(), flags); + assert paramSymbol != null; + if (paramSymbol != null) { - final Type callSiteParamType = functionNode.getSpecializedType(param); - if (callSiteParamType != null) { - LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that."); - } newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); } - LOG.info("Initialized param ", paramSymbol); + LOG.info("Initialized param ", pos, "=", paramSymbol); + pos++; } + } /** @@ -1420,14 +1396,19 @@ * * @param functionNode functionNode */ - private static void finalizeParameters(final FunctionNode functionNode) { + private FunctionNode finalizeParameters(final FunctionNode functionNode) { + final List<IdentNode> newParams = new ArrayList<>(); final boolean isVarArg = functionNode.isVarArg(); - for (final IdentNode ident : functionNode.getParameters()) { - final Symbol paramSymbol = ident.getSymbol(); + int pos = 0; + for (final IdentNode param : functionNode.getParameters()) { + final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName()); + assert paramSymbol != null; + assert paramSymbol.isParam(); + newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol)); assert paramSymbol != null; - Type type = functionNode.getSpecializedType(ident); + Type type = functionNode.getHints().getParameterType(pos); if (type == null) { type = Type.OBJECT; } @@ -1436,7 +1417,7 @@ // this function, we can tell the runtime system that no matter what the // call site is, use this information. TODO if (!paramSymbol.getSymbolType().isObject()) { - LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType()); + LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType()); } newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); @@ -1445,7 +1426,11 @@ if (isVarArg) { paramSymbol.setNeedsSlot(false); } + + pos++; } + + return functionNode.setParameters(getLexicalContext(), newParams); } /** @@ -1459,7 +1444,7 @@ for (final Property property : map.getProperties()) { final String key = property.getKey(); - final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null); + final Symbol symbol = defineSymbol(block, key, IS_GLOBAL); newType(symbol, Type.OBJECT); LOG.info("Added global symbol from property map ", symbol); } @@ -1498,7 +1483,7 @@ * objects as parameters, for example +, but not *, which is known * to coerce types into doubles */ - if (node.getType().isUnknown() || symbol.isParam()) { + if (node.getType().isUnknown() || (symbol.isParam() && !symbol.isSpecializedParam())) { newType(symbol, Type.OBJECT); symbol.setCanBeUndefined(); } @@ -1614,29 +1599,6 @@ } while (!changed.isEmpty()); } - /** - * This assign helper is called after an assignment, when all children of - * the assign has been processed. It fixes the types and recursively makes - * sure that everyhing has slots that should have them in the chain. - * - * @param binaryNode assignment node - */ - private Node leaveAssignmentNode(final BinaryNode binaryNode) { - final Node lhs = binaryNode.lhs(); - final Node rhs = binaryNode.rhs(); - - final Type type; - if (rhs.getType().isNumeric()) { - type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); - } else { - type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. - } - ensureSymbol(type, binaryNode); - newType(lhs.getSymbol(), type); - end(binaryNode); - return binaryNode; - } - private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) { return leaveSelfModifyingAssignmentNode(binaryNode, binaryNode.getWidestOperationType()); } @@ -1646,25 +1608,20 @@ final Node lhs = binaryNode.lhs(); newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType - ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine +// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode); - end(binaryNode); - return binaryNode; + return end(ensureSymbol(destType, binaryNode)); } - private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) { - LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type); - return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node); - } - - private Symbol ensureSymbol(final Type type, final Node node) { - return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node); + private Node ensureSymbol(final Type type, final Node node) { + LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type); + return Attr.ensureSymbol(getLexicalContext(), getLexicalContext().getCurrentBlock(), type, node); } private Symbol newInternal(final String name, final Type type) { - final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null); + final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL); iter.setType(type); // NASHORN-73 return iter; } @@ -1721,6 +1678,17 @@ localUses.peek().add(name); } + static Node ensureSymbol(final LexicalContext lc, final Block block, final Type type, final Node node) { + Symbol symbol = node.getSymbol(); + if (symbol != null) { + return node; + } + final String uname = lc.getCurrentFunction().uniqueName(TEMP_PREFIX.symbolName()); + symbol = new Symbol(uname, IS_TEMP, type); + block.putSymbol(lc, symbol); + return node.setSymbol(lc, symbol); + } + /** * Pessimistically promote all symbols in current function node to Object types * This is done when the function contains unevaluated black boxes such as @@ -1731,8 +1699,7 @@ private static void objectifySymbols(final Block body) { body.accept(new NodeVisitor() { private void toObject(final Block block) { - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) { - final Symbol symbol = iter.next(); + for (final Symbol symbol : block.getSymbols()) { if (!symbol.isTemp()) { newType(symbol, Type.OBJECT); }
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri May 03 15:33:54 2013 +0200 @@ -568,8 +568,7 @@ * @param block block containing symbols. */ private void symbolInfo(final Block block) { - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { - final Symbol symbol = iter.next(); + for (final Symbol symbol : block.getSymbols()) { if (symbol.hasSlot()) { method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); } @@ -937,11 +936,10 @@ private static int assignSlots(final Block block, final int firstSlot) { int nextSlot = firstSlot; - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { - final Symbol next = iter.next(); - if (next.hasSlot()) { - next.setSlot(nextSlot); - nextSlot += next.slotCount(); + for (final Symbol symbol : block.getSymbols()) { + if (symbol.hasSlot()) { + symbol.setSlot(nextSlot); + nextSlot += symbol.slotCount(); } } return nextSlot; @@ -1002,10 +1000,7 @@ final boolean hasArguments = function.needsArguments(); - final Iterator<Symbol> symbols = block.symbolIterator(); - - while (symbols.hasNext()) { - final Symbol symbol = symbols.next(); + for (final Symbol symbol : block.getSymbols()) { if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { continue; @@ -1076,12 +1071,7 @@ } } - final Iterator<Symbol> iter = block.symbolIterator(); - final List<Symbol> symbols = new ArrayList<>(); - while (iter.hasNext()) { - symbols.add(iter.next()); - } - initSymbols(symbols); + initSymbols(block.getSymbols()); } // Debugging: print symbols? @see --print-symbols flag @@ -2364,7 +2354,6 @@ public boolean enterDISCARD(final UnaryNode unaryNode) { final Node rhs = unaryNode.rhs(); - // System.err.println("**** Enter discard " + unaryNode); discard.push(rhs); load(rhs); @@ -2373,7 +2362,7 @@ method.pop(); discard.pop(); } - // System.err.println("**** Leave discard " + unaryNode); + return false; }
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri May 03 15:33:54 2013 +0200 @@ -42,7 +42,7 @@ */ LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { @Override - FunctionNode transform(final Compiler compiler, final FunctionNode fn0) { + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { /* * For lazy compilation, we might be given a node previously marked @@ -58,8 +58,7 @@ * function from a trampoline */ - final FunctionNode outermostFunctionNode = compiler.getFunctionNode(); - assert outermostFunctionNode == fn0; + final FunctionNode outermostFunctionNode = fn; final Set<FunctionNode> neverLazy = new HashSet<>(); final Set<FunctionNode> lazy = new HashSet<>(); @@ -172,20 +171,26 @@ ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { @Override FunctionNode transform(final Compiler compiler, final FunctionNode fn) { - return (FunctionNode)initReturnTypes(fn).accept(new Attr()); + return (FunctionNode)enterAttr(fn).accept(new Attr()); } /** * Pessimistically set all lazy functions' return types to Object + * and the function symbols to object * @param functionNode node where to start iterating */ - private FunctionNode initReturnTypes(final FunctionNode functionNode) { + private FunctionNode enterAttr(final FunctionNode functionNode) { return (FunctionNode)functionNode.accept(new NodeVisitor() { @Override public Node leaveFunctionNode(final FunctionNode node) { - return node.isLazy() ? - node.setReturnType(getLexicalContext(), Type.OBJECT) : - node.setReturnType(getLexicalContext(), Type.UNKNOWN); + final LexicalContext lc = getLexicalContext(); + if (node.isLazy()) { + FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT); + return Attr.ensureSymbol(lc, lc.getCurrentBlock(), Type.OBJECT, newNode); + } + //node may have a reference here that needs to be nulled if it was referred to by + //its outer context, if it is lazy and not attributed + return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null); } }); } @@ -207,6 +212,7 @@ FunctionNode transform(final Compiler compiler, final FunctionNode fn) { final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); +// assert fn.isProgram() ; final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; @@ -216,15 +222,6 @@ compiler.setStrictMode(true); } - /* - newFunctionNode.accept(new NodeVisitor() { - @Override - public boolean enterFunctionNode(final FunctionNode functionNode) { - assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit"; - return true; - } - });*/ - return newFunctionNode; }
--- a/src/jdk/nashorn/internal/codegen/Compiler.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Fri May 03 15:33:54 2013 +0200 @@ -77,6 +77,8 @@ /** Name of the objects package */ public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; + private Source source; + private final Map<String, byte[]> bytecode; private final Set<CompileUnit> compileUnits; @@ -87,12 +89,10 @@ private final ScriptEnvironment env; - private final String scriptName; + private String scriptName; private boolean strict; - private FunctionNode functionNode; - private CodeInstaller<ScriptEnvironment> installer; /** logger for compiler, trampolines, splits and related code generation events @@ -168,6 +168,41 @@ } /** + * Environment information known to the compile, e.g. params + */ + public static class Hints { + private final Type[] paramTypes; + + /** singleton empty hints */ + public static final Hints EMPTY = new Hints(); + + private Hints() { + this.paramTypes = null; + } + + /** + * Constructor + * @param paramTypes known parameter types for this callsite + */ + public Hints(final Type[] paramTypes) { + this.paramTypes = paramTypes; + } + + /** + * Get the parameter type for this parameter position, or + * null if now known + * @param pos position + * @return parameter type for this callsite if known + */ + public Type getParameterType(final int pos) { + if (paramTypes != null && pos < paramTypes.length) { + return paramTypes[pos]; + } + return null; + } + } + + /** * Standard (non-lazy) compilation, that basically will take an entire script * and JIT it at once. This can lead to long startup time and fewer type * specializations @@ -207,21 +242,22 @@ * @param strict should this compilation use strict mode semantics */ //TODO support an array of FunctionNodes for batch lazy compilation - Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) { + Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) { this.env = env; - this.functionNode = functionNode; this.sequence = sequence; this.installer = installer; - this.strict = strict || functionNode.isStrict(); this.constantData = new ConstantData(); this.compileUnits = new HashSet<>(); this.bytecode = new HashMap<>(); + } + private void initCompiler(final FunctionNode functionNode) { + this.strict = strict || functionNode.isStrict(); final StringBuilder sb = new StringBuilder(); sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))). append('$'). append(safeSourceName(functionNode.getSource())); - + this.source = functionNode.getSource(); this.scriptName = sb.toString(); } @@ -229,52 +265,43 @@ * Constructor * * @param installer code installer - * @param functionNode function node (in any available {@link CompilationState}) to compile * @param strict should this compilation use strict mode semantics */ - public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) { - this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict); + public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) { + this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict); } /** * Constructor - compilation will use the same strict semantics as in script environment * * @param installer code installer - * @param functionNode function node (in any available {@link CompilationState}) to compile */ - public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) { - this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); + public Compiler(final CodeInstaller<ScriptEnvironment> installer) { + this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); } /** * Constructor - compilation needs no installer, but uses a script environment * Used in "compile only" scenarios * @param env a script environment - * @param functionNode functionNode to compile */ - public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) { - this(env, null, functionNode, sequence(env._lazy_compilation), env._strict); + public Compiler(final ScriptEnvironment env) { + this(env, null, sequence(env._lazy_compilation), env._strict); } /** * Execute the compilation this Compiler was created with - * @params param types if known, for specialization + * @param functionNode function node to compile from its current state * @throws CompilationException if something goes wrong * @return function node that results from code transforms */ - public FunctionNode compile() throws CompilationException { - return compile(null); - } + public FunctionNode compile(final FunctionNode functionNode) throws CompilationException { + FunctionNode newFunctionNode = functionNode; - /** - * Execute the compilation this Compiler was created with - * @param paramTypes param types if known, for specialization - * @throws CompilationException if something goes wrong - * @return function node that results from code transforms - */ - public FunctionNode compile(final Class<?> paramTypes) throws CompilationException { + initCompiler(newFunctionNode); //TODO move this state into functionnode? + for (final String reservedName : RESERVED_NAMES) { - functionNode.uniqueName(reservedName); + newFunctionNode.uniqueName(reservedName); } final boolean fine = !LOG.levelAbove(Level.FINE); @@ -283,7 +310,7 @@ long time = 0L; for (final CompilationPhase phase : sequence) { - this.functionNode = phase.apply(this, functionNode); + newFunctionNode = phase.apply(this, newFunctionNode); final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; time += duration; @@ -293,7 +320,7 @@ sb.append(phase.toString()). append(" done for function '"). - append(functionNode.getName()). + append(newFunctionNode.getName()). append('\''); if (duration > 0L) { @@ -309,7 +336,7 @@ if (info) { final StringBuilder sb = new StringBuilder(); sb.append("Compile job for '"). - append(functionNode.getName()). + append(newFunctionNode.getName()). append("' finished"); if (time > 0L) { @@ -321,16 +348,15 @@ LOG.info(sb); } - return functionNode; + return newFunctionNode; } - private Class<?> install(final String className, final byte[] code) { + private Class<?> install(final FunctionNode functionNode, final String className, final byte[] code) { LOG.fine("Installing class ", className); final Class<?> clazz = installer.install(Compiler.binaryName(className), code); try { - final Source source = getSource(); final Object[] constants = getConstantData().toArray(); // Need doPrivileged because these fields are private AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { @@ -355,9 +381,10 @@ /** * Install compiled classes into a given loader + * @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state * @return root script class - if there are several compile units they will also be installed */ - public Class<?> install() { + public Class<?> install(final FunctionNode functionNode) { final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L; assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; @@ -366,7 +393,7 @@ final String rootClassName = firstCompileUnitName(); final byte[] rootByteCode = bytecode.get(rootClassName); - final Class<?> rootClass = install(rootClassName, rootByteCode); + final Class<?> rootClass = install(functionNode, rootClassName, rootByteCode); int length = rootByteCode.length; @@ -380,7 +407,7 @@ final byte[] code = entry.getValue(); length += code.length; - installedClasses.put(className, install(className, code)); + installedClasses.put(className, install(functionNode, className, code)); } for (final CompileUnit unit : compileUnits) { @@ -430,10 +457,6 @@ this.strict = strict; } - FunctionNode getFunctionNode() { - return functionNode; - } - ConstantData getConstantData() { return constantData; } @@ -442,10 +465,6 @@ return installer; } - Source getSource() { - return functionNode.getSource(); - } - void addClass(final String name, final byte[] code) { bytecode.put(name, code); } @@ -496,7 +515,7 @@ } private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) { - final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict); + final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict); final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); classEmitter.begin();
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Fri May 03 15:33:54 2013 +0200 @@ -30,7 +30,6 @@ import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; @@ -354,13 +353,6 @@ return true; } - /* - @Override - public Node leaveBlock(final Block block) { - final LexicalContext lc = getLexicalContext(); - return block;//.setFlag(lc, lc.getFlags(block)); - }*/ - @Override public Node leaveCatchNode(final CatchNode catchNode) { final Node exceptionCondition = catchNode.getExceptionCondition(); @@ -551,8 +543,7 @@ final boolean allVarsInScope = functionNode.allVarsInScope(); final boolean isVarArg = functionNode.isVarArg(); - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { - final Symbol symbol = iter.next(); + for (final Symbol symbol : block.getSymbols()) { if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { continue; } @@ -812,14 +803,12 @@ LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'"); + assert !node.isTerminal(); + final LexicalContext lc = getLexicalContext(); //This is the only place in this file that can create new temporaries //FinalizeTypes may not introduce ANY node that is not a conversion. - lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode); - - assert !node.isTerminal(); - - return resultNode; + return Attr.ensureSymbol(lc, lc.getCurrentBlock(), to, resultNode); } private static Node discard(final Node node) { @@ -905,7 +894,7 @@ if (literalNode != null) { //inherit literal symbol for attr. - literalNode.setSymbol(parent.getSymbol()); + literalNode = (LiteralNode<?>)literalNode.setSymbol(null, parent.getSymbol()); } return literalNode;
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java Fri May 03 15:33:54 2013 +0200 @@ -27,7 +27,6 @@ import java.util.List; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING; -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING; import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.PropertyMap;
--- a/src/jdk/nashorn/internal/codegen/Splitter.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Fri May 03 15:33:54 2013 +0200 @@ -75,7 +75,7 @@ */ public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { this.compiler = compiler; - this.outermost = functionNode; + this.outermost = functionNode; this.outermostCompileUnit = outermostCompileUnit; } @@ -95,7 +95,7 @@ final LexicalContext lc = getLexicalContext(); long weight = WeighNodes.weigh(functionNode); - final boolean top = compiler.getFunctionNode() == outermost; + final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; if (weight >= SPLIT_THRESHOLD) { LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD); @@ -273,7 +273,9 @@ return literal; } - getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); + + getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT); if (literal instanceof ArrayLiteralNode) { final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
--- a/src/jdk/nashorn/internal/ir/Block.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/Block.java Fri May 03 15:33:54 2013 +0200 @@ -30,7 +30,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -104,18 +103,26 @@ this(source, token, finish, statements.toArray(new Node[statements.size()])); } - private Block(final Block block, final int finish, final List<Node> statements, final int flags) { + private Block(final Block block, final int finish, final List<Node> statements, final int flags, final Map<String, Symbol> symbols) { super(block); this.statements = statements; this.flags = flags; - this.symbols = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now + this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now this.entryLabel = new Label(block.entryLabel); - this.finish = finish; + this.finish = finish; + } + + /** + * Clear the symbols in a block + * TODO: make this immutable + */ + public void clearSymbols() { + symbols.clear(); } @Override public Node ensureUniqueLabels(final LexicalContext lc) { - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols)); } /** @@ -137,15 +144,15 @@ * Get an iterator for all the symbols defined in this block * @return symbol iterator */ - public Iterator<Symbol> symbolIterator() { - return symbols.values().iterator(); + public List<Symbol> getSymbols() { + return Collections.unmodifiableList(new ArrayList<>(symbols.values())); } /** * Retrieves an existing symbol defined in the current block. * @param name the name of the symbol * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't - * define a symbol with this name. + * define a symbol with this name.T */ public Symbol getExistingSymbol(final String name) { return symbols.get(name); @@ -241,17 +248,17 @@ if (!statements.isEmpty()) { lastFinish = statements.get(statements.size() - 1).getFinish(); } - return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags)); + return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols)); } /** * Add or overwrite an existing symbol in the block * - * @param name name of symbol + * @param lc get lexical context * @param symbol symbol */ - public void putSymbol(final String name, final Symbol symbol) { - symbols.put(name, symbol); + public void putSymbol(final LexicalContext lc, final Symbol symbol) { + symbols.put(symbol.getName(), symbol); } /** @@ -268,7 +275,7 @@ if (this.flags == flags) { return this; } - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols)); } @Override @@ -296,7 +303,7 @@ return this; } - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE)); + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols)); } /** @@ -306,13 +313,11 @@ * @return next slot */ public int nextSlot() { - final Iterator<Symbol> iter = symbolIterator(); int next = 0; - while (iter.hasNext()) { - final Symbol symbol = iter.next(); - if (symbol.hasSlot()) { - next += symbol.slotCount(); - } + for (final Symbol symbol : getSymbols()) { + if (symbol.hasSlot()) { + next += symbol.slotCount(); + } } return next; }
--- a/src/jdk/nashorn/internal/ir/CatchNode.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Fri May 03 15:33:54 2013 +0200 @@ -138,7 +138,12 @@ return body; } - private CatchNode setException(final IdentNode exception) { + /** + * Resets the exception of a catch block + * @param exception new exception + * @return new catch node if changed, same otherwise + */ + public CatchNode setException(final IdentNode exception) { if (this.exception == exception) { return this; }
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Fri May 03 15:33:54 2013 +0200 @@ -25,16 +25,12 @@ package jdk.nashorn.internal.ir; -import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX; -import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; -import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; -import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; - import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; + import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; @@ -95,6 +91,10 @@ @Ignore private final IdentNode ident; + /** Parsed version of functionNode */ + @Ignore + private final FunctionNode snapshot; + /** The body of the function node */ private final Block body; @@ -127,6 +127,9 @@ @Ignore private final EnumSet<CompilationState> compilationState; + @Ignore + private final Compiler.Hints hints; + /** Function flags. */ private final int flags; @@ -176,6 +179,9 @@ /** Does this function have nested declarations? */ public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13; + /** Can this function be specialized? */ + public static final int CAN_SPECIALIZE = 1 << 14; + /** Does this function or any nested functions contain an eval? */ private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL; @@ -219,37 +225,52 @@ final int flags) { super(source, token, finish); - this.ident = ident; - this.name = name; - this.kind = kind; - this.parameters = parameters; - this.firstToken = firstToken; - this.lastToken = token; - this.namespace = namespace; - this.compilationState = EnumSet.of(CompilationState.INITIALIZED); - this.declaredSymbols = new HashSet<>(); - this.flags = flags; - this.compileUnit = null; - this.body = null; + this.ident = ident; + this.name = name; + this.kind = kind; + this.parameters = parameters; + this.firstToken = firstToken; + this.lastToken = token; + this.namespace = namespace; + this.compilationState = EnumSet.of(CompilationState.INITIALIZED); + this.declaredSymbols = new HashSet<>(); + this.flags = flags; + this.compileUnit = null; + this.body = null; + this.snapshot = null; + this.hints = null; } - private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) { + private FunctionNode( + final FunctionNode functionNode, + final long lastToken, + final int flags, + final Type returnType, + final CompileUnit compileUnit, + final EnumSet<CompilationState> compilationState, + final Block body, + final List<IdentNode> parameters, + final FunctionNode snapshot, + final Compiler.Hints hints) { super(functionNode); - this.flags = flags; - this.returnType = returnType; - this.compileUnit = compileUnit; - this.lastToken = lastToken; + + this.flags = flags; + this.returnType = returnType; + this.compileUnit = compileUnit; + this.lastToken = lastToken; this.compilationState = compilationState; - this.body = body; + this.body = body; + this.parameters = parameters; + this.snapshot = snapshot; + this.hints = hints; // the fields below never change - they are final and assigned in constructor - this.name = functionNode.name; - this.ident = functionNode.ident; - this.namespace = functionNode.namespace; + this.name = functionNode.name; + this.ident = functionNode.ident; + this.namespace = functionNode.namespace; this.declaredSymbols = functionNode.declaredSymbols; - this.kind = functionNode.kind; - this.parameters = functionNode.parameters; - this.firstToken = functionNode.firstToken; + this.kind = functionNode.kind; + this.firstToken = functionNode.firstToken; } @Override @@ -261,6 +282,36 @@ } /** + * Get the version of this function node's code as it looked upon construction + * i.e typically parsed and nothing else + * @return initial version of function node + */ + public FunctionNode getSnapshot() { + return snapshot; + } + + /** + * Take a snapshot of this function node at a given point in time + * and store it in the function node + * @param lc lexical context + * @return function node + */ + public FunctionNode snapshot(final LexicalContext lc) { + if (this.snapshot == this) { + return this; + } + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints)); + } + + /** + * Can this function node be regenerated with more specific type args? + * @return true if specialization is possible + */ + public boolean canSpecialize() { + return getFlag(CAN_SPECIALIZE); + } + + /** * Get the compilation state of this function * @return the compilation state */ @@ -307,7 +358,28 @@ } final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState); newState.add(state); - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints)); + } + + /** + * Get any compiler hints that may associated with the function + * @return compiler hints + */ + public Compiler.Hints getHints() { + return this.hints == null ? Compiler.Hints.EMPTY : hints; + } + + /** + * Set compiler hints for this function + * @param lc lexical context + * @param hints compiler hints + * @return new function if hints changed + */ + public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) { + if (this.hints == hints) { + return this; + } + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -319,20 +391,6 @@ return namespace.uniqueName(base); } - /** - * Create a virtual symbol for a literal. - * - * @param literalNode Primary node to use symbol. - * - * @return Symbol used. - */ - public Symbol newLiteral(final LiteralNode<?> literalNode) { - final String uname = uniqueName(LITERAL_PREFIX.symbolName()); - final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType()); - literalNode.setSymbol(symbol); - - return symbol; - } @Override public void toString(final StringBuilder sb) { @@ -374,7 +432,7 @@ if (this.flags == flags) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } @Override @@ -483,7 +541,7 @@ if(this.body == body) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -551,7 +609,7 @@ if (this.lastToken == lastToken) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -599,13 +657,17 @@ } /** - * Get a specialized type for an identity, if one exists - * @param node node to check specialized type for - * @return null if no specialization exists, otherwise type + * Reset the compile unit used to compile this function + * @see Compiler + * @param lc lexical context + * @param parameters the compile unit + * @return function node or a new one if state was changed */ - @SuppressWarnings("static-method") - public Type getSpecializedType(final IdentNode node) { - return null; //TODO implement specialized types later + public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) { + if (this.parameters == parameters) { + return this; + } + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -674,7 +736,10 @@ returnType), compileUnit, compilationState, - body)); + body, + parameters, + snapshot, + hints)); } /** @@ -705,7 +770,7 @@ if (this.compileUnit == compileUnit) { return this; } - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); } /** @@ -717,19 +782,6 @@ * * @return Symbol used. */ - public Symbol ensureSymbol(final Block block, final Type type, final Node node) { - Symbol symbol = node.getSymbol(); - - // If no symbol already present. - if (symbol == null) { - final String uname = uniqueName(TEMP_PREFIX.symbolName()); - symbol = new Symbol(uname, IS_TEMP, type); - block.putSymbol(uname, symbol); - node.setSymbol(symbol); - } - - return symbol; - } /** * Get the symbol for a compiler constant, or null if not available (yet)
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Fri May 03 15:33:54 2013 +0200 @@ -64,7 +64,6 @@ for (int i = sp - 1; i >= 0; i--) { if (stack[i] == node) { flags[i] |= flag; - //System.err.println("Setting flag " + node + " " + flag); return; } } @@ -117,8 +116,6 @@ return (FunctionNode)stack[0]; } - - /** * Pushes a new block on top of the context, making it the innermost open block. * @param node the new node
--- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java Fri May 03 15:33:54 2013 +0200 @@ -70,4 +70,16 @@ final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); return lc.pop(newNode); } + + /** + * Set the symbol and replace in lexical context if applicable + * @param lc lexical context + * @param symbol symbol + * @return new node if symbol changed + */ + @Override + public Node setSymbol(final LexicalContext lc, final Symbol symbol) { + return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol)); + } + }
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Fri May 03 15:33:54 2013 +0200 @@ -659,9 +659,12 @@ * Copy constructor * @param node source array literal node */ - protected ArrayLiteralNode(final ArrayLiteralNode node) { - super(node); + private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) { + super(node, value); this.elementType = node.elementType; + this.presets = node.presets; + this.postsets = node.postsets; + this.units = node.units; } /** @@ -750,9 +753,8 @@ break; } - final Symbol symbol = node.getSymbol(); - assert symbol != null; //don't run this on unresolved nodes or you are in trouble - Type symbolType = symbol.getSymbolType(); + assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble + Type symbolType = node.getSymbol().getSymbolType(); if (symbolType.isUnknown()) { symbolType = Type.OBJECT; } @@ -813,7 +815,8 @@ } /** - * Get indices of arrays containing computed post sets + * Get indices of arrays containing computed post sets. post sets + * are things like non literals e.g. "x+y" instead of i or 17 * @return post set indices */ public int[] getPostsets() { @@ -849,17 +852,17 @@ @Override public Node accept(final NodeVisitor visitor) { if (visitor.enterLiteralNode(this)) { - for (int i = 0; i < value.length; i++) { - final Node element = value[i]; - if (element != null) { - value[i] = element.accept(visitor); - } - } - return visitor.leaveLiteralNode(this); + final List<Node> oldValue = Arrays.asList(value); + final List<Node> newValue = Node.accept(visitor, Node.class, oldValue); + return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this); } return this; } + private ArrayLiteralNode setValue(final List<Node> value) { + return new ArrayLiteralNode(this, value.toArray(new Node[value.size()])); + } + @Override public void toString(final StringBuilder sb) { sb.append('[');
--- a/src/jdk/nashorn/internal/ir/Node.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/Node.java Fri May 03 15:33:54 2013 +0200 @@ -252,10 +252,17 @@ * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation * of what a symbol is * + * @param lc lexical context * @param symbol the symbol + * @return new node */ - public void setSymbol(final Symbol symbol) { - this.symbol = symbol; + public Node setSymbol(final LexicalContext lc, final Symbol symbol) { + if (this.symbol == symbol) { + return this; + } + final Node newNode = (Node)clone(); + newNode.symbol = symbol; + return newNode; } /** @@ -274,7 +281,7 @@ final List<T> newList = new ArrayList<>(); for (final Node node : list) { - final T newNode = clazz.cast(node.accept(visitor)); + final T newNode = node == null ? null : clazz.cast(node.accept(visitor)); if (newNode != node) { changed = true; }
--- a/src/jdk/nashorn/internal/ir/Symbol.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Fri May 03 15:33:54 2013 +0200 @@ -67,6 +67,8 @@ public static final int IS_INTERNAL = 1 << 9; /** Is this a function self-reference symbol */ public static final int IS_FUNCTION_SELF = 1 << 10; + /** Is this a specialized param? */ + public static final int IS_SPECIALIZED_PARAM = 1 << 11; /** Null or name identifying symbol. */ private final String name; @@ -384,6 +386,15 @@ } /** + * Check if this symbol is a function parameter of known + * narrowest type + * @return true if parameter + */ + public boolean isSpecializedParam() { + return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM; + } + + /** * Check whether this symbol ever has primitive assignments. Conservative * @return true if primitive assignments exist */
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java Fri May 03 15:33:54 2013 +0200 @@ -794,15 +794,15 @@ RegExpResult match; final int inputLength = string.length(); - int lastLength = -1; - int lastIndex = 0; - int lastLastIndex = 0; + int splitLastLength = -1; + int splitLastIndex = 0; + int splitLastLastIndex = 0; - while ((match = execSplit(string, lastIndex)) != null) { - lastIndex = match.getIndex() + match.length(); + while ((match = execSplit(string, splitLastIndex)) != null) { + splitLastIndex = match.getIndex() + match.length(); - if (lastIndex > lastLastIndex) { - matches.add(string.substring(lastLastIndex, match.getIndex())); + if (splitLastIndex > splitLastLastIndex) { + matches.add(string.substring(splitLastLastIndex, match.getIndex())); final Object[] groups = match.getGroups(); if (groups.length > 1 && match.getIndex() < inputLength) { for (int index = 1; index < groups.length && matches.size() < limit; index++) { @@ -810,7 +810,7 @@ } } - lastLength = match.length(); + splitLastLength = match.length(); if (matches.size() >= limit) { break; @@ -818,10 +818,10 @@ } // bump the index to avoid infinite loop - if (lastIndex == lastLastIndex) { - lastIndex++; + if (splitLastIndex == splitLastLastIndex) { + splitLastIndex++; } else { - lastLastIndex = lastIndex; + splitLastLastIndex = splitLastIndex; } } @@ -829,12 +829,12 @@ // check special case if we need to append an empty string at the // end of the match // if the lastIndex was the entire string - if (lastLastIndex == string.length()) { - if (lastLength > 0 || execSplit("", 0) == null) { + if (splitLastLastIndex == string.length()) { + if (splitLastLength > 0 || execSplit("", 0) == null) { matches.add(""); } } else { - matches.add(string.substring(lastLastIndex, inputLength)); + matches.add(string.substring(splitLastLastIndex, inputLength)); } } @@ -899,10 +899,6 @@ } } - private void setGlobal(final boolean global) { - regexp.setGlobal(global); - } - boolean getGlobal() { return regexp.isGlobal(); }
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java Fri May 03 15:33:54 2013 +0200 @@ -249,6 +249,7 @@ * * @param errorType The error type of the warning * @param message Warning message. + * @param errorToken error token */ protected final void warning(final JSErrorType errorType, final String message, final long errorToken) { errors.warning(error(errorType, message, errorToken));
--- a/src/jdk/nashorn/internal/parser/Parser.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/parser/Parser.java Fri May 03 15:33:54 2013 +0200 @@ -305,6 +305,11 @@ if (isStrictMode) { flags |= FunctionNode.IS_STRICT; } + if (env._specialize_calls != null) { + if (env._specialize_calls.contains(name)) { + flags |= FunctionNode.CAN_SPECIALIZE; + } + } // Start new block. FunctionNode functionNode = @@ -320,11 +325,11 @@ kind, flags); - functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); lc.push(functionNode); // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the // FunctionNode. newBlock(); + return functionNode; } @@ -332,14 +337,19 @@ * Restore the current block. */ private Block restoreBlock(final Block block) { - return lc.pop(block);//.setFlag(lc, flags); + return lc.pop(block); } + private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) { final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); - return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken); - } + return lc.pop(functionNode). + setBody(lc, newBody). + setLastToken(lc, lastToken). + setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED). + snapshot(lc); + } /** * Get the statements in a block. @@ -529,6 +539,7 @@ script = restoreFunctionNode(script, token); //commit code script = script.setBody(lc, script.getBody().setNeedsScope(lc)); + return script; } @@ -800,7 +811,6 @@ * @param ident Identifier that is verified * @param contextString String used in error message to give context to the user */ - @SuppressWarnings("fallthrough") private void verifyStrictIdent(final IdentNode ident, final String contextString) { if (isStrictMode) { switch (ident.getName()) {
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Fri May 03 15:33:54 2013 +0200 @@ -88,7 +88,7 @@ int weight = Type.typeFor(type.returnType()).getWeight(); for (final Class<?> paramType : type.parameterArray()) { - final int pweight = Type.typeFor(paramType).getWeight(); + final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized weight += pweight; } return weight;
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Fri May 03 15:33:54 2013 +0200 @@ -69,5 +69,4 @@ return best(type).moreGenericThan(type); } - }
--- a/src/jdk/nashorn/internal/runtime/Context.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/Context.java Fri May 03 15:33:54 2013 +0200 @@ -411,7 +411,7 @@ return ScriptRuntime.apply(func, evalThis); } - private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) { + private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) { if (srcStr.startsWith(prefix)) { final String resource = resourcePath + srcStr.substring(prefix.length()); // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme @@ -759,10 +759,10 @@ final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs); - final Compiler compiler = new Compiler(installer, functionNode, strict); + final Compiler compiler = new Compiler(installer, strict); - compiler.compile(); - script = compiler.install(); + final FunctionNode newFunctionNode = compiler.compile(functionNode); + script = compiler.install(newFunctionNode); if (global != null) { global.cacheClass(source, script);
--- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java Fri May 03 15:33:54 2013 +0200 @@ -25,8 +25,6 @@ package jdk.nashorn.internal.runtime; -import static jdk.nashorn.internal.runtime.ScriptObject.isArray; - import java.lang.invoke.MethodHandle; import java.util.Iterator; import java.util.List;
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri May 03 15:33:54 2013 +0200 @@ -30,9 +30,12 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.LinkedList; + import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.FunctionSignature; +import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.parser.Token; @@ -148,10 +151,10 @@ if (functionNode.isLazy()) { Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); - final Compiler compiler = new Compiler(installer, functionNode); - functionNode = compiler.compile(); + final Compiler compiler = new Compiler(installer); + functionNode = compiler.compile(functionNode); assert !functionNode.isLazy(); - compiler.install(); + compiler.install(functionNode); // we don't need to update any flags - varArgs and needsCallee are instrincic // in the function world we need to get a destination node from the compile instead @@ -164,23 +167,114 @@ assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); // code exists - look it up and add it into the automatically sorted invoker list - code.add( - new CompiledFunction( - MH.findStatic( + addCode(functionNode, null, null); + } + + private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) { + final MethodHandle target = + MH.findStatic( LOOKUP, - functionNode.getCompileUnit().getCode(), - functionNode.getName(), - new FunctionSignature(functionNode). - getMethodType()))); + fn.getCompileUnit().getCode(), + fn.getName(), + new FunctionSignature(fn). + getMethodType()); + MethodHandle mh = target; + if (guard != null) { + try { + mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + final CompiledFunction cf = new CompiledFunction(mh); + code.add(cf); + + return cf.getInvoker(); } + private static Type runtimeType(final Object arg) { + if (arg == null) { + return Type.OBJECT; + } + + final Class<?> clazz = arg.getClass(); + assert !clazz.isPrimitive() : "always boxed"; + if (clazz == Double.class) { + return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER; + } else if (clazz == Integer.class) { + return Type.INT; + } else if (clazz == Long.class) { + return Type.LONG; + } else if (clazz == String.class) { + return Type.STRING; + } + return Type.OBJECT; + } + + @SuppressWarnings("unused") + private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) { + //System.err.println("Param type guard " + Arrays.asList(args)); + return false; + } + + private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class); + @Override MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { final MethodHandle mh = super.getBestInvoker(callSiteType, args); - if (code.isLessSpecificThan(callSiteType)) { - // opportunity for code specialization - we can regenerate a better version of this method + + if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) { + return mh; + } + + final FunctionNode snapshot = functionNode.getSnapshot(); + int i; + + //classes known at runtime + final LinkedList<Type> runtimeArgs = new LinkedList<>(); + for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) { + runtimeArgs.addLast(runtimeType(args[i])); + } + + //classes known at compile time + final LinkedList<Type> compileTimeArgs = new LinkedList<>(); + for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) { + compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i))); } - return mh; + + //the classes known at compile time are a safe to generate as primitives without parameter guards + //the classes known at runtime are safe to generate as primitives IFF there are parameter guards + MethodHandle guard = null; + for (i = 0; i < compileTimeArgs.size(); i++) { + final Type runtimeType = runtimeArgs.get(i); + final Type compileType = compileTimeArgs.get(i); + + if (compileType.isObject() && !runtimeType.isObject()) { + if (guard == null) { + guard = PARAM_TYPE_GUARD; + guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()])); + } + } + } + + //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs); + + assert snapshot != null; + assert snapshot != functionNode; + + final Compiler compiler = new Compiler(installer); + final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()])))); + + compiler.install(compiledSnapshot); + + final MethodHandle nmh = addCode(compiledSnapshot, guard, mh); + + return nmh; + } + + private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { + return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types)); } }
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri May 03 15:33:54 2013 +0200 @@ -26,9 +26,13 @@ package jdk.nashorn.internal.runtime; import java.io.PrintWriter; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Set; +import java.util.StringTokenizer; import java.util.TimeZone; + import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.options.KeyValueOption; @@ -151,6 +155,9 @@ /** is this environment in scripting mode? */ public final boolean _scripting; + /** is the JIT allowed to specializ calls based on callsite types? */ + public final Set<String> _specialize_calls; + /** is this environment in strict mode? */ public final boolean _strict; @@ -213,6 +220,17 @@ _version = options.getBoolean("version"); _verify_code = options.getBoolean("verify.code"); + final String specialize = options.getString("specialize.calls"); + if (specialize == null) { + _specialize_calls = null; + } else { + _specialize_calls = new HashSet<>(); + final StringTokenizer st = new StringTokenizer(specialize, ","); + while (st.hasMoreElements()) { + _specialize_calls.add(st.nextToken()); + } + } + int callSiteFlags = 0; if (options.getBoolean("profile.callsites")) { callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE; @@ -247,6 +265,18 @@ } /** + * Can we specialize a particular method name? + * @param functionName method name + * @return true if we are allowed to generate versions of this method + */ + public boolean canSpecialize(final String functionName) { + if (_specialize_calls == null) { + return false; + } + return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName); + } + + /** * Get the output stream for this environment * @return output print writer */
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri May 03 15:33:54 2013 +0200 @@ -662,9 +662,9 @@ } if (deep) { - final ScriptObject proto = getProto(); - if(proto != null) { - return proto.findProperty(key, deep, stopOnNonScope, start); + final ScriptObject myProto = getProto(); + if (myProto != null) { + return myProto.findProperty(key, deep, stopOnNonScope, start); } }
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Fri May 03 15:33:54 2013 +0200 @@ -107,16 +107,16 @@ class DefaultMatcher implements RegExpMatcher { final String input; - final Matcher matcher; + final Matcher defaultMatcher; DefaultMatcher(final String input) { this.input = input; - this.matcher = pattern.matcher(input); + this.defaultMatcher = pattern.matcher(input); } @Override public boolean search(final int start) { - return matcher.find(start); + return defaultMatcher.find(start); } @Override @@ -126,37 +126,37 @@ @Override public int start() { - return matcher.start(); + return defaultMatcher.start(); } @Override public int start(final int group) { - return matcher.start(group); + return defaultMatcher.start(group); } @Override public int end() { - return matcher.end(); + return defaultMatcher.end(); } @Override public int end(final int group) { - return matcher.end(group); + return defaultMatcher.end(group); } @Override public String group() { - return matcher.group(); + return defaultMatcher.group(); } @Override public String group(final int group) { - return matcher.group(group); + return defaultMatcher.group(group); } @Override public int groupCount() { - return matcher.groupCount(); + return defaultMatcher.groupCount(); } }
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Fri May 03 15:33:54 2013 +0200 @@ -121,16 +121,16 @@ class JoniMatcher implements RegExpMatcher { final String input; - final Matcher matcher; + final Matcher joniMatcher; JoniMatcher(final String input) { this.input = input; - this.matcher = regex.matcher(input.toCharArray()); + this.joniMatcher = regex.matcher(input.toCharArray()); } @Override public boolean search(final int start) { - return matcher.search(start, input.length(), Option.NONE) > -1; + return joniMatcher.search(start, input.length(), Option.NONE) > -1; } @Override @@ -140,27 +140,27 @@ @Override public int start() { - return matcher.getBegin(); + return joniMatcher.getBegin(); } @Override public int start(final int group) { - return group == 0 ? start() : matcher.getRegion().beg[group]; + return group == 0 ? start() : joniMatcher.getRegion().beg[group]; } @Override public int end() { - return matcher.getEnd(); + return joniMatcher.getEnd(); } @Override public int end(final int group) { - return group == 0 ? end() : matcher.getRegion().end[group]; + return group == 0 ? end() : joniMatcher.getRegion().end[group]; } @Override public String group() { - return input.substring(matcher.getBegin(), matcher.getEnd()); + return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd()); } @Override @@ -168,13 +168,13 @@ if (group == 0) { return group(); } - final Region region = matcher.getRegion(); + final Region region = joniMatcher.getRegion(); return input.substring(region.beg[group], region.end[group]); } @Override public int groupCount() { - final Region region = matcher.getRegion(); + final Region region = joniMatcher.getRegion(); return region == null ? 0 : region.numRegs - 1; } }
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Fri May 03 15:33:54 2013 +0200 @@ -934,7 +934,7 @@ return true; } - private void unicode(final int value, final StringBuilder buffer) { + private static void unicode(final int value, final StringBuilder buffer) { final String hex = Integer.toHexString(value); buffer.append('u'); for (int i = 0; i < 4 - hex.length(); i++) { @@ -944,7 +944,7 @@ } // Convert what would have been a backreference into a unicode escape, or a number literal, or both. - private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) { + private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) { final int length = numberLiteral.length(); int octalValue = 0; int pos = 0;
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri May 03 15:33:54 2013 +0200 @@ -288,12 +288,12 @@ dependency="--anon-functions=true" \ } -nashorn.option.timezone = { \ - name="-timezone", \ - short_name="-t", \ - params="<timezone>", \ - desc="Set timezone for script execution.", \ - type=TimeZone \ +nashorn.option.specialize.calls = { \ + name="--specialize-calls", \ + is_undocumented=true, \ + type=String, \ + params="[=function_1,...,function_n]", \ + desc="Specialize all or a set of method according to callsite parameter types" \ } nashorn.option.stdout = { \ @@ -312,6 +312,14 @@ desc="Redirect stderr to a filename or to another tty, e.g. stdout" \ } +nashorn.option.timezone = { \ + name="-timezone", \ + short_name="-t", \ + params="<timezone>", \ + desc="Set timezone for script execution.", \ + type=TimeZone \ +} + nashorn.option.trace.callsites = { \ name="--trace-callsites", \ short_name="-tcs", \
--- a/src/jdk/nashorn/tools/Shell.java Thu May 02 15:01:16 2013 -0300 +++ b/src/jdk/nashorn/tools/Shell.java Fri May 03 15:33:54 2013 +0200 @@ -270,7 +270,7 @@ } //null - pass no code installer - this is compile only - new Compiler(env, functionNode).compile(); + new Compiler(env).compile(functionNode); } } finally { env.getOut().flush();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/paramspec.js Fri May 03 15:33:54 2013 +0200 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * paramspec - test that Attr doesn't break parameters when specializing + * + * @run + * @test + */ + +function f(a) { + var b = ~a; + return b == ~17; +} + +print(f("17")); +print(f(17)); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/paramspec.js.EXPECTED Fri May 03 15:33:54 2013 +0200 @@ -0,0 +1,2 @@ +true +true
--- a/test/script/basic/runsunspider.js Thu May 02 15:01:16 2013 -0300 +++ b/test/script/basic/runsunspider.js Fri May 03 15:33:54 2013 +0200 @@ -86,7 +86,7 @@ changed = true; } } catch (e) { - print("error: " + e); + print("error: " + e.printStackTrace()); if (e.toString().indexOf(tests) == 1) { throw e; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/currently-failing/logcoverage.js Fri May 03 15:33:54 2013 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * mh_coverage.js + * Screen scrape various logs to ensure that we cover enough functionality, + * e.g. method handle instrumentation + * + * @test + * @run + */ + +/* + * creates new script engine initialized with given options and + * runs given code on it. Returns standard output captured. + */ + +function runScriptEngine(opts, name) { + var imports = new JavaImporter( + Packages.jdk.nashorn.api.scripting, + java.io, java.lang, java.util); + + with(imports) { + var fac = new NashornScriptEngineFactory(); + // get current System.err + var oldErr = System.err; + var oldOut = System.out; + var baosErr = new ByteArrayOutputStream(); + var newErr = new PrintStream(baosErr); + var baosOut = new ByteArrayOutputStream(); + var newOut = new PrintStream(baosOut); + try { + // set new standard err + System.setErr(newErr); + System.setOut(newOut); + var strType = Java.type("java.lang.String"); + var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); + var reader = new java.io.FileReader(name); + engine.eval(reader); + newErr.flush(); + newOut.flush(); + return new java.lang.String(baosErr.toByteArray()); + } finally { + // restore System.err to old value + System.setErr(oldErr); + System.setOut(oldOut); + } + } +} + +var str; + +var methodsCalled = [ + 'asCollector', + 'asType', + 'bindTo', + 'dropArguments', + 'explicitCastArguments', + 'filterArguments', + 'filterReturnValue', + 'findStatic', + 'findVirtual', + 'foldArguments', + 'getter', + 'guardWithTest', + 'insertArguments', + 'methodType', + 'setter' +]; + +function check(str, strs) { + for each (s in strs) { + if (str.indexOf(s) !== -1) { + continue; + } + print(s + " not found"); + return; + } + print("check ok!"); +} + +str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js"); +str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js"); + +check(str, methodsCalled); +check(str, ['return', 'get', 'set', '[fields]']); +check(str, ['codegen']); + +print("hello, world!");
--- a/test/script/trusted/logcoverage.js Thu May 02 15:01:16 2013 -0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * mh_coverage.js - * Screen scrape various logs to ensure that we cover enough functionality, - * e.g. method handle instrumentation - * - * @test - * @run - */ - -/* - * creates new script engine initialized with given options and - * runs given code on it. Returns standard output captured. - */ - -function runScriptEngine(opts, name) { - var imports = new JavaImporter( - Packages.jdk.nashorn.api.scripting, - java.io, java.lang, java.util); - - with(imports) { - var fac = new NashornScriptEngineFactory(); - // get current System.err - var oldErr = System.err; - var oldOut = System.out; - var baosErr = new ByteArrayOutputStream(); - var newErr = new PrintStream(baosErr); - var baosOut = new ByteArrayOutputStream(); - var newOut = new PrintStream(baosOut); - try { - // set new standard err - System.setErr(newErr); - System.setOut(newOut); - var strType = Java.type("java.lang.String"); - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); - var reader = new java.io.FileReader(name); - engine.eval(reader); - newErr.flush(); - newOut.flush(); - return new java.lang.String(baosErr.toByteArray()); - } finally { - // restore System.err to old value - System.setErr(oldErr); - System.setOut(oldOut); - } - } -} - -var str; - -var methodsCalled = [ - 'asCollector', - 'asType', - 'bindTo', - 'dropArguments', - 'explicitCastArguments', - 'filterArguments', - 'filterReturnValue', - 'findStatic', - 'findVirtual', - 'foldArguments', - 'getter', - 'guardWithTest', - 'insertArguments', - 'methodType', - 'setter' -]; - -function check(str, strs) { - for each (s in strs) { - if (s.indexOf(str) !== -1) { - continue; - } - print(method + "not found"); - return; - } - print("check ok!"); -} - -str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js"); - -check(str, methodsCalled); -check(str, ['return', 'get', 'set', '[fields]']); -check(str, ['codegen']); - -print("hello, world!");