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
--- a/nashorn/bin/jjs Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/Block.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/Node.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/parser/Parser.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/Context.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/src/jdk/nashorn/tools/Shell.java Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/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/nashorn/test/script/basic/paramspec.js.EXPECTED Fri May 03 15:33:54 2013 +0200
@@ -0,0 +1,2 @@
+true
+true
--- a/nashorn/test/script/basic/runsunspider.js Thu May 02 15:01:16 2013 -0300
+++ b/nashorn/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/nashorn/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/nashorn/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!");