aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlana <none@none>2013-05-17 10:14:03 -0700
committerlana <none@none>2013-05-17 10:14:03 -0700
commitd0aa59aefe26c749800f2928e11528d581e6c9d7 (patch)
treeba20ff66a411d9e212a6f8413d0f04587bea014b
parent1451d1a57848f90f9d82e003abf7b90c743e45ac (diff)
parent4fcbed61c2a20e92468f29c51902eec8682448f9 (diff)
downloadnashorn-d0aa59aefe26c749800f2928e11528d581e6c9d7.tar.gz
-rw-r--r--.hgignore1
-rw-r--r--bin/jjs2
-rw-r--r--make/project.properties4
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngine.java3
-rw-r--r--src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java1
-rw-r--r--src/jdk/nashorn/internal/codegen/Attr.java667
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java97
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilationPhase.java39
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java155
-rw-r--r--src/jdk/nashorn/internal/codegen/CompilerConstants.java14
-rw-r--r--src/jdk/nashorn/internal/codegen/FinalizeTypes.java98
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java53
-rw-r--r--src/jdk/nashorn/internal/codegen/Label.java102
-rw-r--r--src/jdk/nashorn/internal/codegen/Lower.java116
-rw-r--r--src/jdk/nashorn/internal/codegen/MapCreator.java6
-rw-r--r--src/jdk/nashorn/internal/codegen/MethodEmitter.java132
-rw-r--r--src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java10
-rw-r--r--src/jdk/nashorn/internal/codegen/ObjectCreator.java12
-rw-r--r--src/jdk/nashorn/internal/codegen/Splitter.java53
-rw-r--r--src/jdk/nashorn/internal/ir/AccessNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/BaseNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/BinaryNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/Block.java66
-rw-r--r--src/jdk/nashorn/internal/ir/BlockLexicalContext.java34
-rw-r--r--src/jdk/nashorn/internal/ir/BreakNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/BreakableNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/CallNode.java19
-rw-r--r--src/jdk/nashorn/internal/ir/CaseNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/CatchNode.java18
-rw-r--r--src/jdk/nashorn/internal/ir/ContinueNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/EmptyNode.java11
-rw-r--r--src/jdk/nashorn/internal/ir/ExecuteNode.java19
-rw-r--r--src/jdk/nashorn/internal/ir/ForNode.java21
-rw-r--r--src/jdk/nashorn/internal/ir/FunctionNode.java228
-rw-r--r--src/jdk/nashorn/internal/ir/IdentNode.java10
-rw-r--r--src/jdk/nashorn/internal/ir/IfNode.java19
-rw-r--r--src/jdk/nashorn/internal/ir/IndexNode.java24
-rw-r--r--src/jdk/nashorn/internal/ir/LabelNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java21
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContextNode.java25
-rw-r--r--src/jdk/nashorn/internal/ir/LiteralNode.java131
-rw-r--r--src/jdk/nashorn/internal/ir/Location.java134
-rw-r--r--src/jdk/nashorn/internal/ir/LoopNode.java15
-rw-r--r--src/jdk/nashorn/internal/ir/Node.java110
-rw-r--r--src/jdk/nashorn/internal/ir/ObjectNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/PropertyNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/ReturnNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/RuntimeNode.java13
-rw-r--r--src/jdk/nashorn/internal/ir/SplitNode.java5
-rw-r--r--src/jdk/nashorn/internal/ir/Statement.java (renamed from src/jdk/nashorn/internal/ir/LineNumberNode.java)69
-rw-r--r--src/jdk/nashorn/internal/ir/SwitchNode.java7
-rw-r--r--src/jdk/nashorn/internal/ir/Symbol.java133
-rw-r--r--src/jdk/nashorn/internal/ir/TemporarySymbols.java169
-rw-r--r--src/jdk/nashorn/internal/ir/TernaryNode.java6
-rw-r--r--src/jdk/nashorn/internal/ir/ThrowNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/TryNode.java17
-rw-r--r--src/jdk/nashorn/internal/ir/TypeOverride.java6
-rw-r--r--src/jdk/nashorn/internal/ir/UnaryNode.java12
-rw-r--r--src/jdk/nashorn/internal/ir/VarNode.java33
-rw-r--r--src/jdk/nashorn/internal/ir/WhileNode.java27
-rw-r--r--src/jdk/nashorn/internal/ir/WithNode.java9
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java113
-rw-r--r--src/jdk/nashorn/internal/ir/debug/JSONWriter.java36
-rw-r--r--src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java457
-rw-r--r--src/jdk/nashorn/internal/ir/debug/PrintVisitor.java50
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java2
-rw-r--r--src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java21
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java19
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDebug.java60
-rw-r--r--src/jdk/nashorn/internal/objects/NativeJSAdapter.java6
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRegExp.java32
-rw-r--r--src/jdk/nashorn/internal/parser/AbstractParser.java15
-rw-r--r--src/jdk/nashorn/internal/parser/JSONParser.java14
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java214
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java15
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunction.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunctions.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java13
-rw-r--r--src/jdk/nashorn/internal/runtime/JSONFunctions.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java23
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyHashMap.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java187
-rw-r--r--src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java124
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptEnvironment.java34
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java299
-rw-r--r--src/jdk/nashorn/internal/runtime/SetMethodCreator.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/SpillProperty.java85
-rw-r--r--src/jdk/nashorn/internal/runtime/StructureLoader.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/UserAccessorProperty.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/NashornLinker.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/options/Options.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java20
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java20
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Options.properties26
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js2
-rw-r--r--src/jdk/nashorn/internal/scripts/JO.java3
-rw-r--r--src/jdk/nashorn/tools/Shell.java8
-rw-r--r--test/script/basic/JDK-8013729.js49
-rw-r--r--test/script/basic/JDK-8013729.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8013873.js40
-rw-r--r--test/script/basic/JDK-8013873.js.EXPECTED7
-rw-r--r--test/script/basic/JDK-8013874.js66
-rw-r--r--test/script/basic/JDK-8013874.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8013878.js53
-rw-r--r--test/script/basic/JDK-8013878.js.EXPECTED24
-rw-r--r--test/script/basic/no_line_numbers.js125
-rw-r--r--test/script/basic/no_line_numbers.js.EXPECTED12
-rw-r--r--test/script/basic/paramspec.js38
-rw-r--r--test/script/basic/paramspec.js.EXPECTED2
-rw-r--r--test/script/basic/runsunspider.js2
-rw-r--r--test/script/currently-failing/logcoverage.js (renamed from test/script/trusted/logcoverage.js)5
-rw-r--r--test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java2
-rw-r--r--test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java59
-rw-r--r--test/src/jdk/nashorn/internal/test/framework/TestConfig.java3
-rw-r--r--test/src/jdk/nashorn/internal/test/framework/TestFinder.java19
118 files changed, 3433 insertions, 2140 deletions
diff --git a/.hgignore b/.hgignore
index d07a19d7..56e01bae 100644
--- a/.hgignore
+++ b/.hgignore
@@ -8,6 +8,7 @@ private.xml
private.properties
webrev/*
webrev.zip
+.classpath
*.class
*.clazz
*.log
diff --git a/bin/jjs b/bin/jjs
index fe6665c3..f89a07c2 100644
--- a/bin/jjs
+++ b/bin/jjs
@@ -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 $*
diff --git a/make/project.properties b/make/project.properties
index e2f39bb7..2d66dfef 100644
--- a/make/project.properties
+++ b/make/project.properties
@@ -194,6 +194,8 @@ test262-test-sys-prop.test.js.enable.strict.mode=true
test262-test-sys-prop.test.js.exclude.dir=\
${test262.suite.dir}/intl402/
+test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
+
# test262 test frameworks
test262-test-sys-prop.test.js.framework=\
-timezone=PST \
@@ -214,7 +216,7 @@ run.test.xms=2G
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
-run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
+run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index 197a6da4..283e36e9 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -78,7 +78,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
this(factory, DEFAULT_OPTIONS, appLoader);
}
- @SuppressWarnings("LeakingThisInConstructor")
NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
this.factory = factory;
final Options options = new Options("nashorn");
@@ -102,7 +101,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
});
// create new global object
- this.global = createNashornGlobal();
+ this.global = createNashornGlobal();
// set the default engine scope for the default context
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
diff --git a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
index 1ca6dcdd..c1005415 100644
--- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
+++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java
@@ -31,7 +31,6 @@ import java.util.List;
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:
diff --git a/src/jdk/nashorn/internal/codegen/Attr.java b/src/jdk/nashorn/internal/codegen/Attr.java
index 9b17c47f..4e47892f 100644
--- a/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/src/jdk/nashorn/internal/codegen/Attr.java
@@ -29,11 +29,13 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
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.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;
@@ -73,8 +75,10 @@ import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
@@ -90,7 +94,6 @@ import jdk.nashorn.internal.runtime.ECMAException;
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;
/**
@@ -129,13 +132,16 @@ final class Attr extends NodeOperatorVisitor {
private static final DebugLogger LOG = new DebugLogger("attr");
private static final boolean DEBUG = LOG.isEnabled();
+ private final TemporarySymbols temporarySymbols;
+
/**
* Constructor.
*/
- Attr() {
- localDefs = new ArrayDeque<>();
- localUses = new ArrayDeque<>();
- returnTypes = new ArrayDeque<>();
+ Attr(final TemporarySymbols temporarySymbols) {
+ this.temporarySymbols = temporarySymbols;
+ this.localDefs = new ArrayDeque<>();
+ this.localUses = new ArrayDeque<>();
+ this.returnTypes = new ArrayDeque<>();
}
@Override
@@ -150,67 +156,50 @@ final class Attr extends NodeOperatorVisitor {
@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, that
+ //is why we can't set the access node base to be an object here, that will ruin access specialization
+ //for example for a.x | 17.
+ 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);
-
- 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);
- }
- }
+ initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class));
+ initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, 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 +209,52 @@ final class Attr extends NodeOperatorVisitor {
}
@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 +271,13 @@ final class Attr extends NodeOperatorVisitor {
}
@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 +288,31 @@ final class Attr extends NodeOperatorVisitor {
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 +358,7 @@ final class Attr extends NodeOperatorVisitor {
// 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 +367,6 @@ final class Attr extends NodeOperatorVisitor {
symbol.setFlags(flags);
}
- if (node != null) {
- node.setSymbol(symbol);
- }
-
return symbol;
}
@@ -357,30 +374,22 @@ final class Attr extends NodeOperatorVisitor {
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,9 +399,30 @@ final class Attr extends NodeOperatorVisitor {
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)ensureSymbol(lc, 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);
- finalizeTypes(newFunctionNode);
+ newFunctionNode = finalizeParameters(newFunctionNode);
+ newFunctionNode = finalizeTypes(newFunctionNode);
for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
if (symbol.getSymbolType().isUnknown()) {
symbol.setType(Type.OBJECT);
@@ -400,8 +430,6 @@ final class Attr extends NodeOperatorVisitor {
}
}
- 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,9 +437,9 @@ final class Attr extends NodeOperatorVisitor {
if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
final IdentNode callee = compilerConstant(CALLEE);
- final VarNode selfInit =
+ VarNode selfInit =
new VarNode(
- newFunctionNode.getSource(),
+ newFunctionNode.getLineNumber(),
newFunctionNode.getToken(),
newFunctionNode.getFinish(),
newFunctionNode.getIdent(),
@@ -419,8 +447,7 @@ final class Attr extends NodeOperatorVisitor {
LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
- final List<Node> newStatements = new ArrayList<>();
- newStatements.add(selfInit);
+ final List<Statement> newStatements = new ArrayList<>();
assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
final IdentNode name = selfInit.getName();
@@ -428,9 +455,10 @@ final class Attr extends NodeOperatorVisitor {
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 +475,32 @@ final class Attr extends NodeOperatorVisitor {
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 end(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 +521,11 @@ final class Attr extends NodeOperatorVisitor {
}
}
- 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 +534,12 @@ final class Attr extends NodeOperatorVisitor {
setBlockScope(name, symbol);
- if (symbol != oldSymbol && !identNode.isInitializedHere()) {
+ if (!identNode.isInitializedHere()) {
symbol.increaseUseCount();
}
addLocalUse(identNode.getName());
- end(identNode);
-
- return false;
+ return end(identNode.setSymbol(lc, symbol));
}
/**
@@ -525,7 +548,7 @@ final class Attr extends NodeOperatorVisitor {
* @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 +635,11 @@ final class Attr extends NodeOperatorVisitor {
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 +648,19 @@ final class Attr extends NodeOperatorVisitor {
@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 end(literalNode.setSymbol(getLexicalContext(), symbol));
}
@Override
@@ -667,18 +670,13 @@ final class Attr extends NodeOperatorVisitor {
@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 +761,9 @@ final class Attr extends NodeOperatorVisitor {
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 +775,32 @@ final class Attr extends NodeOperatorVisitor {
@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();
+ final LexicalContext lc = getLexicalContext();
+ final Symbol symbol = findSymbol(lc.getCurrentBlock(), 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 end(newVarNode.setSymbol(lc, symbol));
}
addLocalDef(name);
- final Symbol symbol = varNode.getSymbol();
- final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56
+ 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,36 +808,28 @@ final class Attr extends NodeOperatorVisitor {
newType(symbol, Type.OBJECT);
}
- assert varNode.hasType() : varNode;
-
- end(varNode);
+ assert newVarNode.hasType() : newVarNode + " has no type";
- 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
public Node leaveDECINC(final UnaryNode unaryNode) {
// @see assignOffset
- ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs());
+ final UnaryNode newUnaryNode = unaryNode.setRHS(ensureAssignmentSlots(unaryNode.rhs()));
final Type type = arithType();
- newType(unaryNode.rhs().getSymbol(), type);
- ensureSymbol(type, unaryNode);
- end(unaryNode);
- return unaryNode;
+ newType(newUnaryNode.rhs().getSymbol(), type);
+ return end(ensureSymbol(type, newUnaryNode));
}
@Override
@@ -908,23 +905,24 @@ final class Attr extends NodeOperatorVisitor {
@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.getToken(),
+ functionNode.getFinish(),
+ cc.symbolName()).
+ setSymbol(
+ getLexicalContext(),
+ functionNode.compilerConstant(cc));
}
@Override
@@ -952,15 +950,12 @@ final class Attr extends NodeOperatorVisitor {
@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 +977,16 @@ final class Attr extends NodeOperatorVisitor {
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 +1006,7 @@ final class Attr extends NodeOperatorVisitor {
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 +1017,31 @@ final class Attr extends NodeOperatorVisitor {
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 +1190,12 @@ final class Attr extends NodeOperatorVisitor {
@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 +1204,10 @@ final class Attr extends NodeOperatorVisitor {
}
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 +1217,9 @@ final class Attr extends NodeOperatorVisitor {
// 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 +1303,7 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveOR(final BinaryNode binaryNode) {
- ensureSymbol(Type.OBJECT, binaryNode);
- end(binaryNode);
- return binaryNode;
+ return end(ensureSymbol(Type.OBJECT, binaryNode));
}
@Override
@@ -1346,50 +1352,13 @@ final class Attr extends NodeOperatorVisitor {
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 +1368,26 @@ final class Attr extends NodeOperatorVisitor {
* @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);
- 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);
+
+ 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;
}
- LOG.info("Initialized param ", paramSymbol);
+ final Symbol paramSymbol = defineSymbol(body, param.getName(), flags);
+ assert paramSymbol != null;
+
+ newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
+
+ LOG.info("Initialized param ", pos, "=", paramSymbol);
+ pos++;
}
+
}
/**
@@ -1420,23 +1396,34 @@ final class Attr extends NodeOperatorVisitor {
*
* @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();
+ final int nparams = functionNode.getParameters().size();
- for (final IdentNode ident : functionNode.getParameters()) {
- final Symbol paramSymbol = ident.getSymbol();
+ int specialize = 0;
+ 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;
}
// if we know that a parameter is only used as a certain type throughout
// 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());
+ // call site is, use this information:
+ // we also need more than half of the parameters to be specializable
+ // for the heuristic to be worth it, and we need more than one use of
+ // the parameter to consider it, i.e. function(x) { call(x); } doens't count
+ if (paramSymbol.getUseCount() > 1 && !paramSymbol.getSymbolType().isObject()) {
+ LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType());
+ specialize++;
}
newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType()));
@@ -1445,7 +1432,17 @@ final class Attr extends NodeOperatorVisitor {
if (isVarArg) {
paramSymbol.setNeedsSlot(false);
}
+
+ pos++;
}
+
+ FunctionNode newFunctionNode = functionNode;
+
+ if (nparams == 0 || (specialize * 2) < nparams) {
+ newFunctionNode = newFunctionNode.clearSnapshot(getLexicalContext());
+ }
+
+ return newFunctionNode.setParameters(getLexicalContext(), newParams);
}
/**
@@ -1459,7 +1456,7 @@ final class Attr extends NodeOperatorVisitor {
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 +1495,7 @@ final class Attr extends NodeOperatorVisitor {
* 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();
}
@@ -1520,19 +1517,25 @@ final class Attr extends NodeOperatorVisitor {
*
* see NASHORN-258
*
- * @param functionNode the current function node (has to be passed as it changes in the visitor below)
* @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
*/
- private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
- assignmentDest.accept(new NodeVisitor() {
+ private Node ensureAssignmentSlots(final Node assignmentDest) {
+ final LexicalContext attrLexicalContext = getLexicalContext();
+ return assignmentDest.accept(new NodeVisitor() {
@Override
public Node leaveIndexNode(final IndexNode indexNode) {
assert indexNode.getSymbol().isTemp();
final Node index = indexNode.getIndex();
//only temps can be set as needing slots. the others will self resolve
//it is illegal to take a scope var and force it to be a slot, that breaks
- if (index.getSymbol().isTemp() && !index.getSymbol().isConstant()) {
- index.getSymbol().setNeedsSlot(true);
+ Symbol indexSymbol = index.getSymbol();
+ if (indexSymbol.isTemp() && !indexSymbol.isConstant() && !indexSymbol.hasSlot()) {
+ if(indexSymbol.isShared()) {
+ indexSymbol = temporarySymbols.createUnshared(indexSymbol);
+ }
+ indexSymbol.setNeedsSlot(true);
+ attrLexicalContext.getCurrentBlock().putSymbol(attrLexicalContext, indexSymbol);
+ return indexNode.setIndex(index.setSymbol(attrLexicalContext, indexSymbol));
}
return indexNode;
}
@@ -1557,22 +1560,30 @@ final class Attr extends NodeOperatorVisitor {
*
* @param functionNode
*/
- private static void finalizeTypes(final FunctionNode functionNode) {
+ private FunctionNode finalizeTypes(final FunctionNode functionNode) {
final Set<Node> changed = new HashSet<>();
+ FunctionNode currentFunctionNode = functionNode;
do {
changed.clear();
- functionNode.accept(new NodeVisitor() {
+ final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() {
- private void widen(final Node node, final Type to) {
+ private Node widen(final Node node, final Type to) {
if (node instanceof LiteralNode) {
- return;
+ return node;
}
Type from = node.getType();
if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
- LOG.fine("Had to post pass widen '", node, "' " + Debug.id(node), " from ", node.getType(), " to ", to);
- newType(node.getSymbol(), to);
- changed.add(node);
+ LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
+ Symbol symbol = node.getSymbol();
+ if(symbol.isShared() && symbol.wouldChangeType(to)) {
+ symbol = temporarySymbols.getTypedTemporarySymbol(to);
+ }
+ newType(symbol, to);
+ final Node newNode = node.setSymbol(getLexicalContext(), symbol);
+ changed.add(newNode);
+ return newNode;
}
+ return node;
}
@Override
@@ -1598,43 +1609,23 @@ final class Attr extends NodeOperatorVisitor {
@Override
public Node leaveBinaryNode(final BinaryNode binaryNode) {
final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ BinaryNode newBinaryNode = binaryNode;
switch (binaryNode.tokenType()) {
default:
if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) {
break;
}
- widen(binaryNode.lhs(), widest);
+ newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest));
case ADD:
- widen(binaryNode, widest);
- break;
+ newBinaryNode = (BinaryNode)widen(newBinaryNode, widest);
}
- return binaryNode;
+ return newBinaryNode;
}
});
+ getLexicalContext().replace(currentFunctionNode, newFunctionNode);
+ currentFunctionNode = newFunctionNode;
} 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;
+ return currentFunctionNode;
}
private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) {
@@ -1646,25 +1637,18 @@ final class Attr extends NodeOperatorVisitor {
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;
- }
-
- 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);
+ return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
}
- 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 ensureSymbol(getLexicalContext(), 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 +1705,10 @@ final class Attr extends NodeOperatorVisitor {
localUses.peek().add(name);
}
+ private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
+ return temporarySymbols.ensureSymbol(lc, type, node);
+ }
+
/**
* 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 +1719,7 @@ final class Attr extends NodeOperatorVisitor {
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);
}
@@ -1788,6 +1775,10 @@ final class Attr extends NodeOperatorVisitor {
}
private Node end(final Node node, final boolean printNode) {
+ if(node instanceof Statement) {
+ // If we're done with a statement, all temporaries can be reused.
+ temporarySymbols.reuse();
+ }
if (DEBUG) {
final StringBuilder sb = new StringBuilder();
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 5d4b8f98..1fae1294 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -63,6 +63,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
+
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode;
@@ -88,7 +89,6 @@ import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
@@ -100,6 +100,7 @@ import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TernaryNode;
@@ -191,6 +192,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** Current compile unit */
private CompileUnit unit;
+ private int lastLineNumber = -1;
+
/** When should we stop caching regexp expressions in fields to limit bytecode size? */
private static final int MAX_REGEX_FIELDS = 2 * 1024;
@@ -261,14 +264,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
return method.load(symbol);
}
- final String name = symbol.getName();
+ final String name = symbol.getName();
+ final Source source = getLexicalContext().getCurrentFunction().getSource();
if (CompilerConstants.__FILE__.name().equals(name)) {
- return method.load(identNode.getSource().getName());
+ return method.load(source.getName());
} else if (CompilerConstants.__DIR__.name().equals(name)) {
- return method.load(identNode.getSource().getBase());
+ return method.load(source.getBase());
} else if (CompilerConstants.__LINE__.name().equals(name)) {
- return method.load(identNode.getSource().getLine(identNode.position())).convert(Type.OBJECT);
+ return method.load(source.getLine(identNode.position())).convert(Type.OBJECT);
} else {
assert identNode.getSymbol().isScope() : identNode + " is not in scope!";
@@ -568,8 +572,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @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());
}
@@ -619,6 +622,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterBreakNode(final BreakNode breakNode) {
+ lineNumber(breakNode);
+
final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
closeWith();
@@ -663,6 +668,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterCallNode(final CallNode callNode) {
+ lineNumber(callNode);
+
final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction();
final Block currentBlock = getLexicalContext().getCurrentBlock();
@@ -836,6 +843,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterContinueNode(final ContinueNode continueNode) {
+ lineNumber(continueNode);
+
final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
closeWith();
@@ -847,11 +856,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterEmptyNode(final EmptyNode emptyNode) {
+ lineNumber(emptyNode);
+
return false;
}
@Override
public boolean enterExecuteNode(final ExecuteNode executeNode) {
+ lineNumber(executeNode);
+
final Node expression = executeNode.getExpression();
expression.accept(this);
@@ -860,6 +873,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterForNode(final ForNode forNode) {
+ lineNumber(forNode);
+
final Node test = forNode.getTest();
final Block body = forNode.getBody();
final Node modify = forNode.getModify();
@@ -937,11 +952,10 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 +1016,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 +1087,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
}
- 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
@@ -1157,6 +1163,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterIfNode(final IfNode ifNode) {
+ lineNumber(ifNode);
+
final Node test = ifNode.getTest();
final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail();
@@ -1196,12 +1204,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
return false;
}
- @Override
- public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- final Label label = new Label((String)null);
- method.label(label);
- method.lineNumber(lineNumberNode.getLineNumber(), label);
- return false;
+ private void lineNumber(final Statement statement) {
+ final int lineNumber = statement.getLineNumber();
+ if (lineNumber != lastLineNumber) {
+ method.lineNumber(statement.getLineNumber());
+ }
+ lastLineNumber = lineNumber;
}
/**
@@ -1533,6 +1541,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterReturnNode(final ReturnNode returnNode) {
+ lineNumber(returnNode);
+
method.registerReturn();
final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
@@ -1742,6 +1752,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterSplitNode(final SplitNode splitNode) {
+ lineNumber(splitNode);
+
final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
final FunctionNode fn = getLexicalContext().getCurrentFunction();
@@ -1885,6 +1897,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterSwitchNode(final SwitchNode switchNode) {
+ lineNumber(switchNode);
+
final Node expression = switchNode.getExpression();
final Symbol tag = switchNode.getTag();
final boolean allInteger = tag.getSymbolType().isInteger();
@@ -1967,7 +1981,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.tableswitch(lo, hi, defaultLabel, table);
} else {
final int[] ints = new int[size];
-
for (int i = 0; i < size; i++) {
ints[i] = values[i];
}
@@ -2013,10 +2026,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterThrowNode(final ThrowNode throwNode) {
+ lineNumber(throwNode);
+
method._new(ECMAException.class).dup();
+ final Source source = getLexicalContext().getCurrentFunction().getSource();
+
final Node expression = throwNode.getExpression();
- final Source source = throwNode.getSource();
final int position = throwNode.position();
final int line = source.getLine(position);
final int column = source.getColumn(position);
@@ -2036,6 +2052,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterTryNode(final TryNode tryNode) {
+ lineNumber(tryNode);
+
final Block body = tryNode.getBody();
final List<Block> catchBlocks = tryNode.getCatchBlocks();
final Symbol symbol = tryNode.getException();
@@ -2132,12 +2150,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterVarNode(final VarNode varNode) {
+
final Node init = varNode.getInit();
if (init == null) {
return false;
}
+ lineNumber(varNode);
+
final Symbol varSymbol = varNode.getSymbol();
assert varSymbol != null : "variable node " + varNode + " requires a symbol";
@@ -2170,6 +2191,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override
public boolean enterWhileNode(final WhileNode whileNode) {
+ lineNumber(whileNode);
+
final Node test = whileNode.getTest();
final Block body = whileNode.getBody();
final Label breakLabel = whileNode.getBreakLabel();
@@ -2192,7 +2215,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
private void closeWith() {
- if(method.hasScope()) {
+ if (method.hasScope()) {
method.loadCompilerConstant(SCOPE);
method.invoke(ScriptRuntime.CLOSE_WITH);
method.storeCompilerConstant(SCOPE);
@@ -2235,7 +2258,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Always process body
body.accept(this);
- if(hasScope) {
+ if (hasScope) {
// Ensure we always close the WithObject
final Label endLabel = new Label("with_end");
final Label catchLabel = new Label("with_catch");
@@ -2364,7 +2387,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterDISCARD(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
- // System.err.println("**** Enter discard " + unaryNode);
discard.push(rhs);
load(rhs);
@@ -2373,7 +2395,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.pop();
discard.pop();
}
- // System.err.println("**** Leave discard " + unaryNode);
+
return false;
}
@@ -3019,12 +3041,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @param block the block we are in
* @param ident identifier for block or function where applicable
*/
+ @SuppressWarnings("resource")
private void printSymbols(final Block block, final String ident) {
if (!compiler.getEnv()._print_symbols) {
return;
}
- @SuppressWarnings("resource")
final PrintWriter out = compiler.getEnv().getErr();
out.println("[BLOCK in '" + ident + "']");
if (!block.printSymbols(out)) {
@@ -3200,9 +3222,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
return;
}
- //System.err.println("Store with out discard that shouldn't just return " + assignNode);
- //new Throwable().printStackTrace();
-
final Symbol symbol = assignNode.getSymbol();
if (symbol.hasSlot()) {
method.dup().store(symbol);
@@ -3298,7 +3317,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded
// visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their
// static method's parameter list.
- if(lc.getOutermostFunction() == functionNode ||
+ if (lc.getOutermostFunction() == functionNode ||
(!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) {
return;
}
diff --git a/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index 884a68bf..bfc71cc2 100644
--- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -21,6 +21,7 @@ import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
@@ -42,7 +43,7 @@ enum CompilationPhase {
*/
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 +59,7 @@ enum CompilationPhase {
* 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 +172,31 @@ enum CompilationPhase {
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());
+ final TemporarySymbols ts = compiler.getTemporarySymbols();
+ final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
+ if(compiler.getEnv()._print_mem_usage) {
+ Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
+ }
+ return newFunctionNode;
}
/**
* 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, final TemporarySymbols ts) {
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 ts.ensureSymbol(lc, 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 +218,7 @@ enum CompilationPhase {
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 +228,6 @@ enum CompilationPhase {
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;
}
@@ -252,7 +255,7 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv();
- final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes());
+ final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes(compiler.getTemporarySymbols()));
if (env._print_lower_ast) {
env.getErr().println(new ASTWriter(newFunctionNode));
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index b1e47d02..81a76186 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -36,26 +36,32 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
+import jdk.nashorn.internal.ir.TemporarySymbols;
+
import java.io.File;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
-
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
+import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -77,6 +83,8 @@ public final class Compiler {
/** 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,14 +95,14 @@ public final class Compiler {
private final ScriptEnvironment env;
- private final String scriptName;
+ private String scriptName;
private boolean strict;
- private FunctionNode functionNode;
-
private CodeInstaller<ScriptEnvironment> installer;
+ private final TemporarySymbols temporarySymbols = new TemporarySymbols();
+
/** logger for compiler, trampolines, splits and related code generation events
* that affect classes */
public static final DebugLogger LOG = new DebugLogger("compiler");
@@ -168,6 +176,41 @@ public final class Compiler {
}
/**
+ * 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 +250,22 @@ public final class Compiler {
* @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 +273,79 @@ public final class Compiler {
* 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
- * @throws CompilationException if something goes wrong
- * @return function node that results from code transforms
- */
- public FunctionNode compile() throws CompilationException {
- return compile(null);
+ private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
+ LOG.info(phaseName + " finished. Doing IR size calculation...");
+
+ final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
+ osc.calculateObjectSize(functionNode);
+
+ final List<ClassHistogramElement> list = osc.getClassHistogram();
+
+ final StringBuilder sb = new StringBuilder();
+ final long totalSize = osc.calculateObjectSize(functionNode);
+ sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
+ LOG.info(sb);
+
+ Collections.sort(list, new Comparator<ClassHistogramElement>() {
+ @Override
+ public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
+ final long diff = o1.getBytes() - o2.getBytes();
+ if (diff < 0) {
+ return 1;
+ } else if (diff > 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ for (final ClassHistogramElement e : list) {
+ final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
+ LOG.info(line);
+ if (e.getBytes() < totalSize / 200) {
+ LOG.info(" ...");
+ break; // never mind, so little memory anyway
+ }
+ }
}
/**
* Execute the compilation this Compiler was created with
- * @param paramTypes 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(final Class<?> paramTypes) throws CompilationException {
+ public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
+ FunctionNode newFunctionNode = functionNode;
+
+ 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 +354,11 @@ public final class Compiler {
long time = 0L;
for (final CompilationPhase phase : sequence) {
- this.functionNode = phase.apply(this, functionNode);
+ newFunctionNode = phase.apply(this, newFunctionNode);
+
+ if (env._print_mem_usage) {
+ printMemoryUsage(phase.toString(), newFunctionNode);
+ }
final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
time += duration;
@@ -293,7 +368,7 @@ public final class Compiler {
sb.append(phase.toString()).
append(" done for function '").
- append(functionNode.getName()).
+ append(newFunctionNode.getName()).
append('\'');
if (duration > 0L) {
@@ -309,7 +384,7 @@ public final class Compiler {
if (info) {
final StringBuilder sb = new StringBuilder();
sb.append("Compile job for '").
- append(functionNode.getName()).
+ append(newFunctionNode.getName()).
append("' finished");
if (time > 0L) {
@@ -321,7 +396,7 @@ public final class Compiler {
LOG.info(sb);
}
- return functionNode;
+ return newFunctionNode;
}
private Class<?> install(final String className, final byte[] code) {
@@ -330,7 +405,6 @@ public final class Compiler {
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 +429,10 @@ public final class Compiler {
/**
* 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";
@@ -430,10 +505,6 @@ public final class Compiler {
this.strict = strict;
}
- FunctionNode getFunctionNode() {
- return functionNode;
- }
-
ConstantData getConstantData() {
return constantData;
}
@@ -442,8 +513,8 @@ public final class Compiler {
return installer;
}
- Source getSource() {
- return functionNode.getSource();
+ TemporarySymbols getTemporarySymbols() {
+ return temporarySymbols;
}
void addClass(final String name, final byte[] code) {
@@ -496,7 +567,7 @@ public final class Compiler {
}
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();
@@ -550,6 +621,4 @@ public final class Compiler {
USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic");
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
}
-
-
}
diff --git a/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
index dfc9198c..6912534d 100644
--- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java
+++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java
@@ -105,25 +105,25 @@ public enum CompilerConstants {
ARGUMENTS("arguments", Object.class, 2),
/** prefix for iterators for for (x in ...) */
- ITERATOR_PREFIX(":iter"),
+ ITERATOR_PREFIX(":i"),
/** prefix for tag variable used for switch evaluation */
- SWITCH_TAG_PREFIX(":tag"),
+ SWITCH_TAG_PREFIX(":s"),
/** prefix for all exceptions */
- EXCEPTION_PREFIX(":exception"),
+ EXCEPTION_PREFIX(":e"),
/** prefix for quick slots generated in Store */
- QUICK_PREFIX(":quick"),
+ QUICK_PREFIX(":q"),
/** prefix for temporary variables */
- TEMP_PREFIX(":temp"),
+ TEMP_PREFIX(":t"),
/** prefix for literals */
- LITERAL_PREFIX(":lit"),
+ LITERAL_PREFIX(":l"),
/** prefix for regexps */
- REGEX_PREFIX(":regex"),
+ REGEX_PREFIX(":r"),
/** "this" used in non-static Java methods; always in slot 0 */
JAVA_THIS(null, 0),
diff --git a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
index 5f6a63dc..e94dab7c 100644
--- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
+++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
@@ -30,7 +30,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
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;
@@ -56,6 +55,7 @@ import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TypeOverride;
@@ -88,7 +88,10 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private static final DebugLogger LOG = new DebugLogger("finalize");
- FinalizeTypes() {
+ private final TemporarySymbols temporarySymbols;
+
+ FinalizeTypes(final TemporarySymbols temporarySymbols) {
+ this.temporarySymbols = temporarySymbols;
}
@Override
@@ -228,21 +231,27 @@ final class FinalizeTypes extends NodeOperatorVisitor {
return leaveASSIGN(binaryNode);
}
+ private boolean symbolIsInteger(Node node) {
+ final Symbol symbol = node.getSymbol();
+ assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource();
+ return true;
+ }
+
@Override
- public Node leaveBIT_AND(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+ public Node leaveBIT_AND(final BinaryNode binaryNode) {
+ assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@Override
- public Node leaveBIT_OR(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+ public Node leaveBIT_OR(final BinaryNode binaryNode) {
+ assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@Override
- public Node leaveBIT_XOR(BinaryNode binaryNode) {
- assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
+ public Node leaveBIT_XOR(final BinaryNode binaryNode) {
+ assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT);
}
@@ -252,8 +261,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
// AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(newBinaryNode, newBinaryNode.lhs().getType());
- return newBinaryNode;
+ return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
}
@Override
@@ -262,8 +270,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
// AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(newBinaryNode, newBinaryNode.rhs().getType());
- return newBinaryNode;
+ return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
}
@Override
@@ -354,13 +361,6 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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();
@@ -372,6 +372,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveExecuteNode(final ExecuteNode executeNode) {
+ temporarySymbols.reuse();
return executeNode.setExpression(discard(executeNode.getExpression()));
}
@@ -497,8 +498,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveVarNode(final VarNode varNode) {
- final Node rhs = varNode.getInit();
- if (rhs != null) {
+ final Node init = varNode.getInit();
+ if (init != null) {
final SpecializedNode specialized = specialize(varNode);
final VarNode specVarNode = (VarNode)specialized.node;
Type destType = specialized.type;
@@ -506,8 +507,11 @@ final class FinalizeTypes extends NodeOperatorVisitor {
destType = specVarNode.getType();
}
assert specVarNode.hasType() : specVarNode + " doesn't have a type";
- return specVarNode.setInit(convert(rhs, destType));
+ final Node convertedInit = convert(init, destType);
+ temporarySymbols.reuse();
+ return specVarNode.setInit(convertedInit);
}
+ temporarySymbols.reuse();
return varNode;
}
@@ -551,8 +555,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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;
}
@@ -687,7 +690,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
- private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
+ <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
final Node node = ((Node)assignment);
final T lhs = assignment.getAssignmentDest();
final Node rhs = assignment.getAssignmentSource();
@@ -709,9 +712,9 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
- propagateType(newNode, to);
+ final Node typePropagatedNode = propagateType(newNode, to);
- return new SpecializedNode(newNode, to);
+ return new SpecializedNode(typePropagatedNode, to);
}
@@ -750,7 +753,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @param to new type
*/
@SuppressWarnings("unchecked")
- private static <T extends Node> T setTypeOverride(final T node, final Type to) {
+ <T extends Node> T setTypeOverride(final T node, final Type to) {
final Type from = node.getType();
if (!node.getType().equals(to)) {
LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
@@ -759,7 +762,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
LOG.info("Type override for lhs in '", node, "' => ", to);
- return ((TypeOverride<T>)node).setType(to);
+ return ((TypeOverride<T>)node).setType(temporarySymbols, getLexicalContext(), to);
}
/**
@@ -782,7 +785,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private Node convert(final Node node, final Type to) {
assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
assert node != null : "node is null";
- assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction() + " " + node.getSource();
+ assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction();
assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
final Type from = node.getType();
@@ -807,24 +810,22 @@ final class FinalizeTypes extends NodeOperatorVisitor {
assert node instanceof TypeOverride;
return setTypeOverride(node, to);
}
- resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
+ resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node);
}
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 temporarySymbols.ensureSymbol(lc, to, resultNode);
}
private static Node discard(final Node node) {
if (node.getSymbol() != null) {
- final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node);
+ final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
//discard never has a symbol in the discard node - then it would be a nop
assert !node.isTerminal();
return discard;
@@ -847,12 +848,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @param node
* @param to
*/
- private static void propagateType(final Node node, final Type to) {
- final Symbol symbol = node.getSymbol();
- if (symbol.isTemp()) {
- symbol.setTypeOverride(to);
+ private Node propagateType(final Node node, final Type to) {
+ Symbol symbol = node.getSymbol();
+ if (symbol.isTemp() && symbol.getSymbolType() != to) {
+ symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
LOG.info("Type override for temporary in '", node, "' => ", to);
}
+ return node.setSymbol(getLexicalContext(), symbol);
}
/**
@@ -877,7 +879,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* Whenever an explicit conversion is needed and the convertee is a literal, we can
* just change the literal
*/
- static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
+ class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
private final Type type;
LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
@@ -892,20 +894,20 @@ final class FinalizeTypes extends NodeOperatorVisitor {
LiteralNode<?> literalNode = null;
if (type.isString()) {
- literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value));
+ literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
} else if (type.isBoolean()) {
- literalNode = LiteralNode.newInstance(source, token, finish, JSType.toBoolean(value));
+ literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value));
} else if (type.isInteger()) {
- literalNode = LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
+ literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value));
} else if (type.isLong()) {
- literalNode = LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
+ literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value));
} else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
- literalNode = LiteralNode.newInstance(source, token, finish, JSType.toNumber(value));
+ literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value));
}
if (literalNode != null) {
//inherit literal symbol for attr.
- literalNode.setSymbol(parent.getSymbol());
+ literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol());
}
return literalNode;
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 03accb4b..686c9836 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -41,7 +41,6 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
/**
* Simple constant folding pass, executed before IR is starting to be lowered.
@@ -89,7 +88,7 @@ final class FoldConstants extends NodeVisitor {
if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
if (shortCut != null) {
- return new ExecuteNode(shortCut);
+ return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
}
return new EmptyNode(ifNode);
}
@@ -112,13 +111,11 @@ final class FoldConstants extends NodeVisitor {
*/
abstract static class ConstantEvaluator<T extends Node> {
protected T parent;
- protected final Source source;
protected final long token;
protected final int finish;
protected ConstantEvaluator(final T parent) {
this.parent = parent;
- this.source = parent.getSource();
this.token = parent.getToken();
this.finish = parent.getFinish();
}
@@ -152,23 +149,23 @@ final class FoldConstants extends NodeVisitor {
switch (parent.tokenType()) {
case ADD:
if (rhsInteger) {
- literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32());
+ literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
} else {
- literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber());
+ literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
}
break;
case SUB:
if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
- literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getInt32());
+ literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
} else {
- literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber());
+ literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
}
break;
case NOT:
- literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean());
+ literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
break;
case BIT_NOT:
- literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32());
+ literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
break;
default:
return null;
@@ -234,7 +231,7 @@ final class FoldConstants extends NodeVisitor {
break;
}
assert res instanceof CharSequence : res + " was not a CharSequence, it was a " + res.getClass();
- return LiteralNode.newInstance(source, token, finish, res.toString());
+ return LiteralNode.newInstance(token, finish, res.toString());
}
return null;
case MUL:
@@ -247,33 +244,33 @@ final class FoldConstants extends NodeVisitor {
value = lhs.getNumber() - rhs.getNumber();
break;
case SHR:
- return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
+ return LiteralNode.newInstance(token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
case SAR:
- return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
case SHL:
- return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, lhs.getInt32() << rhs.getInt32());
case BIT_XOR:
- return LiteralNode.newInstance(source, token, finish, lhs.getInt32() ^ rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, lhs.getInt32() ^ rhs.getInt32());
case BIT_AND:
- return LiteralNode.newInstance(source, token, finish, lhs.getInt32() & rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, lhs.getInt32() & rhs.getInt32());
case BIT_OR:
- return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32());
+ return LiteralNode.newInstance(token, finish, lhs.getInt32() | rhs.getInt32());
case GE:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
case LE:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
case GT:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
case LT:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
case NE:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
case NE_STRICT:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
case EQ:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
case EQ_STRICT:
- return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
+ return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
default:
return null;
}
@@ -282,12 +279,12 @@ final class FoldConstants extends NodeVisitor {
isLong &= value != 0.0 && JSType.isRepresentableAsLong(value);
if (isInteger) {
- return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
+ return LiteralNode.newInstance(token, finish, JSType.toInt32(value));
} else if (isLong) {
- return LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
+ return LiteralNode.newInstance(token, finish, JSType.toLong(value));
}
- return LiteralNode.newInstance(source, token, finish, value);
+ return LiteralNode.newInstance(token, finish, value);
}
}
}
diff --git a/src/jdk/nashorn/internal/codegen/Label.java b/src/jdk/nashorn/internal/codegen/Label.java
index 9d28caaf..be1e126f 100644
--- a/src/jdk/nashorn/internal/codegen/Label.java
+++ b/src/jdk/nashorn/internal/codegen/Label.java
@@ -24,9 +24,8 @@
*/
package jdk.nashorn.internal.codegen;
-import java.util.ArrayDeque;
-
import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.runtime.Debug;
/**
* Abstraction for labels, separating a label from the underlying
@@ -35,12 +34,87 @@ import jdk.nashorn.internal.codegen.types.Type;
*
* see -Dnashorn.codegen.debug, --log=codegen
*/
-public class Label extends jdk.internal.org.objectweb.asm.Label {
+public final class Label {
+ //byte code generation evaluation type stack for consistency check
+ //and correct opcode selection. one per label as a label may be a
+ //join point
+ static final class Stack {
+ Type[] data = new Type[8];
+ int sp = 0;
+
+ Stack() {
+ }
+
+ private Stack(final Type[] type, final int sp) {
+ this();
+ this.data = new Type[type.length];
+ this.sp = sp;
+ for (int i = 0; i < sp; i++) {
+ data[i] = type[i];
+ }
+ }
+
+ boolean isEmpty() {
+ return sp == 0;
+ }
+
+ int size() {
+ return sp;
+ }
+
+ boolean isEquivalentTo(final Stack other) {
+ if (sp != other.sp) {
+ return false;
+ }
+ for (int i = 0; i < sp; i++) {
+ if (!data[i].isEquivalentTo(other.data[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void clear() {
+ sp = 0;
+ }
+
+ void push(final Type type) {
+ if (data.length == sp) {
+ final Type[] newData = new Type[sp * 2];
+ for (int i = 0; i < sp; i++) {
+ newData[i] = data[i];
+ }
+ data = newData;
+ }
+ data[sp++] = type;
+ }
+
+ Type peek() {
+ return peek(0);
+ }
+
+ Type peek(final int n) {
+ int pos = sp - 1 - n;
+ return pos < 0 ? null : data[pos];
+ }
+
+ Type pop() {
+ return data[--sp];
+ }
+
+ Stack copy() {
+ return new Stack(data, sp);
+ }
+ }
+
/** Name of this label */
private final String name;
/** Type stack at this label */
- private ArrayDeque<Type> stack;
+ private Label.Stack stack;
+
+ /** ASM representation of this label */
+ private jdk.internal.org.objectweb.asm.Label label;
/**
* Constructor
@@ -62,22 +136,24 @@ public class Label extends jdk.internal.org.objectweb.asm.Label {
this.name = label.name;
}
- ArrayDeque<Type> getStack() {
+
+ jdk.internal.org.objectweb.asm.Label getLabel() {
+ if (this.label == null) {
+ this.label = new jdk.internal.org.objectweb.asm.Label();
+ }
+ return label;
+ }
+
+ Label.Stack getStack() {
return stack;
}
- void setStack(final ArrayDeque<Type> stack) {
+ void setStack(final Label.Stack stack) {
this.stack = stack;
}
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- String s = super.toString();
- s = s.substring(1, s.length());
- sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s)));
-
- return sb.toString();
+ return name + '_' + Debug.id(this);
}
}
-
diff --git a/src/jdk/nashorn/internal/codegen/Lower.java b/src/jdk/nashorn/internal/codegen/Lower.java
index d6209e4f..23e91b63 100644
--- a/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk/nashorn/internal/codegen/Lower.java
@@ -32,6 +32,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
@@ -49,16 +50,15 @@ import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ReturnNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode;
-import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
@@ -93,21 +93,25 @@ final class Lower extends NodeOperatorVisitor {
super(new BlockLexicalContext() {
@Override
- public List<Node> popStatements() {
- List<Node> newStatements = new ArrayList<>();
+ public List<Statement> popStatements() {
+ final List<Statement> newStatements = new ArrayList<>();
boolean terminated = false;
- final List<Node> statements = super.popStatements();
- for (final Node statement : statements) {
+ final List<Statement> statements = super.popStatements();
+ for (final Statement statement : statements) {
if (!terminated) {
newStatements.add(statement);
- if (statement.isTerminal()) {
+ if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why?
terminated = true;
}
} else {
- if (statement instanceof VarNode) {
- newStatements.add(((VarNode)statement).setInit(null));
- }
+ statement.accept(new NodeVisitor() {
+ @Override
+ public boolean enterVarNode(final VarNode varNode) {
+ newStatements.add(varNode.setInit(null));
+ return false;
+ }
+ });
}
}
return newStatements;
@@ -118,8 +122,9 @@ final class Lower extends NodeOperatorVisitor {
@Override
public boolean enterBlock(final Block block) {
final LexicalContext lc = getLexicalContext();
- if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) {
- new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+ final FunctionNode function = lc.getCurrentFunction();
+ if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
+ new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
}
return true;
}
@@ -131,20 +136,20 @@ final class Lower extends NodeOperatorVisitor {
final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
- Node last = lc.getLastStatement();
+ Statement last = lc.getLastStatement();
if (lc.isFunctionBody()) {
final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
final boolean isProgram = currentFunction.isProgram();
final ReturnNode returnNode = new ReturnNode(
- currentFunction.getSource(),
+ last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
currentFunction.getToken(),
currentFunction.getFinish(),
isProgram ?
compilerConstant(RETURN) :
LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
- last = returnNode.accept(this);
+ last = (Statement)returnNode.accept(this);
}
if (last != null && last.isTerminal()) {
@@ -193,7 +198,6 @@ final class Lower extends NodeOperatorVisitor {
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
node = executeNode.setExpression(
new BinaryNode(
- executeNode.getSource(),
Token.recast(
executeNode.getToken(),
TokenType.ASSIGN),
@@ -240,12 +244,6 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
- public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- addStatement(lineNumberNode); // don't put it in lastStatement cache
- return false;
- }
-
- @Override
public Node leaveReturnNode(final ReturnNode returnNode) {
addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
return returnNode;
@@ -272,10 +270,10 @@ final class Lower extends NodeOperatorVisitor {
});
}
- private static List<Node> copyFinally(final Block finallyBody) {
- final List<Node> newStatements = new ArrayList<>();
- for (final Node statement : finallyBody.getStatements()) {
- newStatements.add(ensureUniqueLabelsIn(statement));
+ private static List<Statement> copyFinally(final Block finallyBody) {
+ final List<Statement> newStatements = new ArrayList<>();
+ for (final Statement statement : finallyBody.getStatements()) {
+ newStatements.add((Statement)ensureUniqueLabelsIn(statement));
if (statement.hasTerminalFlags()) {
return newStatements;
}
@@ -284,17 +282,17 @@ final class Lower extends NodeOperatorVisitor {
}
private Block catchAllBlock(final TryNode tryNode) {
- final Source source = tryNode.getSource();
- final long token = tryNode.getToken();
- final int finish = tryNode.getFinish();
+ final int lineNumber = tryNode.getLineNumber();
+ final long token = tryNode.getToken();
+ final int finish = tryNode.getFinish();
- final IdentNode exception = new IdentNode(source, token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
+ final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
- final Block catchBody = new Block(source, token, finish, new ThrowNode(source, token, finish, new IdentNode(exception))).
+ final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))).
setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
- final CatchNode catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
- final Block catchAllBlock = new Block(source, token, finish, catchAllNode);
+ final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody);
+ final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
//catchallblock -> catchallnode (catchnode) -> exception -> throw
@@ -303,10 +301,10 @@ final class Lower extends NodeOperatorVisitor {
private IdentNode compilerConstant(final CompilerConstants cc) {
final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
- return new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
+ return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
}
- private static boolean isTerminal(final List<Node> statements) {
+ private static boolean isTerminal(final List<Statement> statements) {
return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags();
}
@@ -318,8 +316,7 @@ final class Lower extends NodeOperatorVisitor {
* @return new try node after splicing finally code (same if nop)
*/
private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
- final Source source = tryNode.getSource();
- final int finish = tryNode.getFinish();
+ final int finish = tryNode.getFinish();
assert tryNode.getFinallyBody() == null;
@@ -341,11 +338,11 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveThrowNode(final ThrowNode throwNode) {
if (rethrows.contains(throwNode)) {
- final List<Node> newStatements = copyFinally(finallyBody);
+ final List<Statement> newStatements = copyFinally(finallyBody);
if (!isTerminal(newStatements)) {
newStatements.add(throwNode);
}
- return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements);
+ return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
}
return throwNode;
}
@@ -363,14 +360,14 @@ final class Lower extends NodeOperatorVisitor {
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
- final List<Node> newStatements = new ArrayList<>();
+ final List<Statement> newStatements = new ArrayList<>();
final Node resultNode;
if (expr != null) {
//we need to evaluate the result of the return in case it is complex while
//still in the try block, store it in a result value and return it afterwards
resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
- newStatements.add(new ExecuteNode(new BinaryNode(source, Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+ newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
} else {
resultNode = null;
}
@@ -380,16 +377,16 @@ final class Lower extends NodeOperatorVisitor {
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
}
- return new ExecuteNode(new Block(source, returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
+ return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
}
- private Node copy(final Node endpoint, final Node targetNode) {
+ private Node copy(final Statement endpoint, final Node targetNode) {
if (!insideTry.contains(targetNode)) {
- final List<Node> newStatements = copyFinally(finallyBody);
+ final List<Statement> newStatements = copyFinally(finallyBody);
if (!isTerminal(newStatements)) {
newStatements.add(endpoint);
}
- return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements));
+ return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
}
return endpoint;
}
@@ -397,7 +394,7 @@ final class Lower extends NodeOperatorVisitor {
addStatement(newTryNode);
for (final Node statement : finallyBody.getStatements()) {
- addStatement(statement);
+ addStatement((Statement)statement);
}
return newTryNode;
@@ -451,7 +448,7 @@ final class Lower extends NodeOperatorVisitor {
if (tryNode.getCatchBlocks().isEmpty()) {
newTryNode = tryNode.setFinallyBody(null);
} else {
- Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Node>(Arrays.asList(tryNode.setFinallyBody(null))));
+ Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
}
@@ -468,19 +465,19 @@ final class Lower extends NodeOperatorVisitor {
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
- new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+ new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
}
return varNode;
}
@Override
public Node leaveWhileNode(final WhileNode whileNode) {
- final Node test = whileNode.getTest();
+ final Node test = whileNode.getTest();
final Block body = whileNode.getBody();
if (conservativeAlwaysTrue(test)) {
//turn it into a for node without a test.
- final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
+ final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
getLexicalContext().replace(whileNode, forNode);
return forNode;
}
@@ -493,16 +490,6 @@ final class Lower extends NodeOperatorVisitor {
return addStatement(withNode);
}
- @Override
- public Node leaveDELETE(final UnaryNode unaryNode) {
- final Node rhs = unaryNode.rhs();
- if (rhs instanceof IdentNode || rhs instanceof BaseNode) {
- return unaryNode;
- }
- addStatement(new ExecuteNode(rhs));
- return LiteralNode.newInstance(unaryNode, true);
- }
-
/**
* Given a function node that is a callee in a CallNode, replace it with
* the appropriate marker function. This is used by {@link CodeGenerator}
@@ -525,11 +512,12 @@ final class Lower extends NodeOperatorVisitor {
* @param node a node
* @return eval location
*/
- private static String evalLocation(final IdentNode node) {
+ private String evalLocation(final IdentNode node) {
+ final Source source = getLexicalContext().getCurrentFunction().getSource();
return new StringBuilder().
- append(node.getSource().getName()).
+ append(source.getName()).
append('#').
- append(node.getSource().getLine(node.position())).
+ append(source.getLine(node.position())).
append("<eval>").
toString();
}
@@ -618,7 +606,7 @@ final class Lower extends NodeOperatorVisitor {
}
- private Node addStatement(final Node statement) {
+ private Node addStatement(final Statement statement) {
((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
return statement;
}
diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java
index 00f3f80f..153e0367 100644
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -65,10 +65,12 @@ public class MapCreator {
* Constructs a property map based on a set of fields.
*
* @param hasArguments does the created object have an "arguments" property
+ * @param fieldCount Number of fields in use.
+ * @param fieldMaximum Number of fields available.
*
* @return New map populated with accessor properties.
*/
- PropertyMap makeMap(final boolean hasArguments) {
+ PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
final List<Property> properties = new ArrayList<>();
assert keys != null;
@@ -82,7 +84,7 @@ public class MapCreator {
}
}
- return PropertyMap.newMap(structure, properties);
+ return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
}
/**
diff --git a/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index 4fbb57a6..c156c865 100644
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -67,10 +67,9 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
import java.io.PrintStream;
import java.lang.reflect.Array;
-import java.util.ArrayDeque;
import java.util.EnumSet;
-import java.util.Iterator;
import java.util.List;
+
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -114,7 +113,7 @@ public class MethodEmitter implements Emitter {
private final MethodVisitor method;
/** Current type stack for current evaluation */
- private ArrayDeque<Type> stack;
+ private Label.Stack stack;
/** Parent classEmitter representing the class of this method */
private final ClassEmitter classEmitter;
@@ -189,7 +188,7 @@ public class MethodEmitter implements Emitter {
@Override
public void begin() {
classEmitter.beginMethod(this);
- stack = new ArrayDeque<>();
+ newStack();
method.visitCode();
}
@@ -205,6 +204,10 @@ public class MethodEmitter implements Emitter {
classEmitter.endMethod(this);
}
+ private void newStack() {
+ stack = new Label.Stack();
+ }
+
@Override
public String toString() {
return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
@@ -288,11 +291,7 @@ public class MethodEmitter implements Emitter {
* @return the type at position "pos" on the stack
*/
final Type peekType(final int pos) {
- final Iterator<Type> iter = stack.iterator();
- for (int i = 0; i < pos; i++) {
- iter.next();
- }
- return iter.next();
+ return stack.peek(pos);
}
/**
@@ -484,7 +483,7 @@ public class MethodEmitter implements Emitter {
name = THIS_DEBUGGER.symbolName();
}
- method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
+ method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
}
/**
@@ -509,17 +508,6 @@ public class MethodEmitter implements Emitter {
}
/**
- * Associate a variable with a given range
- *
- * @param name name of the variable
- * @param start start
- * @param end end
- */
- void markerVariable(final String name, final Label start, final Label end) {
- method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0);
- }
-
- /**
* Pops two integer types from the stack, performs a bitwise and and pushes
* the result
*
@@ -626,7 +614,7 @@ public class MethodEmitter implements Emitter {
* @param typeDescriptor type descriptor for exception
*/
void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
- method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor);
+ method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
}
/**
@@ -638,7 +626,7 @@ public class MethodEmitter implements Emitter {
* @param clazz exception class
*/
void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
- method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz));
+ method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
}
/**
@@ -871,7 +859,7 @@ public class MethodEmitter implements Emitter {
}
private boolean isThisSlot(final int slot) {
- if(functionNode == null) {
+ if (functionNode == null) {
return slot == CompilerConstants.JAVA_THIS.slot();
}
final int thisSlot = compilerConstant(THIS).getSlot();
@@ -915,7 +903,6 @@ public class MethodEmitter implements Emitter {
dup();
return this;
}
- debug("load compiler constant ", symbol);
return load(symbol);
}
@@ -1228,6 +1215,14 @@ public class MethodEmitter implements Emitter {
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
}
+ static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
+ final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
+ for (int i = 0; i < table.length; i++) {
+ internalLabels[i] = table[i].getLabel();
+ }
+ return internalLabels;
+ }
+
/**
* Generate a lookup switch, popping the switch value from the stack
*
@@ -1235,10 +1230,10 @@ public class MethodEmitter implements Emitter {
* @param values case values for the table
* @param table default label
*/
- void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) {
+ void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
debug("lookupswitch", peekType());
popType(Type.INT);
- method.visitLookupSwitchInsn(defaultLabel, values, table);
+ method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
}
/**
@@ -1248,10 +1243,10 @@ public class MethodEmitter implements Emitter {
* @param defaultLabel default label
* @param table label table
*/
- void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) {
+ void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
debug("tableswitch", peekType());
popType(Type.INT);
- method.visitTableSwitchInsn(lo, hi, defaultLabel, table);
+ method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
}
/**
@@ -1358,7 +1353,7 @@ public class MethodEmitter implements Emitter {
popType();
}
mergeStackTo(label);
- method.visitJumpInsn(opcode, label);
+ method.visitJumpInsn(opcode, label.getLabel());
}
/**
@@ -1487,9 +1482,9 @@ public class MethodEmitter implements Emitter {
* @param label destination label
*/
void _goto(final Label label) {
- debug("goto", label);
+ //debug("goto", label);
jump(GOTO, label, 0);
- stack = null;
+ stack = null; //whoever reaches the point after us provides the stack, because we don't
}
/**
@@ -1500,38 +1495,31 @@ public class MethodEmitter implements Emitter {
*
* @return true if stacks are equivalent, false otherwise
*/
- private boolean stacksEquivalent(final ArrayDeque<Type> s0, final ArrayDeque<Type> s1) {
- if (s0.size() != s1.size()) {
- debug("different stack sizes", s0, s1);
- return false;
- }
-
- final Type[] s0a = s0.toArray(new Type[s0.size()]);
- final Type[] s1a = s1.toArray(new Type[s1.size()]);
- for (int i = 0; i < s0.size(); i++) {
- if (!s0a[i].isEquivalentTo(s1a[i])) {
- debug("different stack element", s0a[i], s1a[i]);
- return false;
- }
- }
-
- return true;
- }
-
/**
* A join in control flow - helper function that makes sure all entry stacks
* discovered for the join point so far are equivalent
- * @param label
+ *
+ * MergeStack: we are about to enter a label. If its stack, label.getStack() is null
+ * we have never been here before. Then we are expected to carry a stack with us.
+ *
+ * @param label label
*/
private void mergeStackTo(final Label label) {
- final ArrayDeque<Type> labelStack = label.getStack();
- //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
+ //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
+ //see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
+ //by Lower removing everything after an unconditionally executed terminating statement OR a break
+ //or continue in a block. Previously code left over after breaks and continues was still there
+ //and caused bytecode to be generated - which crashed on stack not being there, as the merge
+ //was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
+ //ATHROW sequences instead of no code being generated at all. This should now be fixed.
+ assert stack != null : label + " entered with no stack. deadcode that remains?";
+
+ final Label.Stack labelStack = label.getStack();
if (labelStack == null) {
- assert stack != null;
- label.setStack(stack.clone());
+ label.setStack(stack.copy());
return;
}
- assert stacksEquivalent(stack, labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
+ assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
}
/**
@@ -1548,14 +1536,14 @@ public class MethodEmitter implements Emitter {
if (stack == null) {
stack = label.getStack();
if (stack == null) {
- stack = new ArrayDeque<>(); //we don't have a stack at this point.
+ newStack();
}
}
debug_label(label);
mergeStackTo(label); //we have to merge our stack to whatever is in the label
- method.visitLabel(label);
+ method.visitLabel(label.getLabel());
}
/**
@@ -1675,11 +1663,10 @@ public class MethodEmitter implements Emitter {
* @return array of Types
*/
protected Type[] getTypesFromStack(final int count) {
- final Iterator<Type> iter = stack.iterator();
- final Type[] types = new Type[count];
-
+ final Type[] types = new Type[count];
+ int pos = 0;
for (int i = count - 1; i >= 0; i--) {
- types[i] = iter.next();
+ types[i] = stack.peek(pos++);
}
return types;
@@ -1695,11 +1682,11 @@ public class MethodEmitter implements Emitter {
* @return function signature for stack contents
*/
private String getDynamicSignature(final Type returnType, final int argCount) {
- final Iterator<Type> iter = stack.iterator();
final Type[] paramTypes = new Type[argCount];
+ int pos = 0;
for (int i = argCount - 1; i >= 0; i--) {
- paramTypes[i] = iter.next();
+ paramTypes[i] = stack.peek(pos++);
}
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
for (int i = 0; i < argCount; i++) {
@@ -2018,8 +2005,13 @@ public class MethodEmitter implements Emitter {
* @param line line number
* @param label label
*/
- void lineNumber(final int line, final Label label) {
- method.visitLineNumber(line, label);
+ void lineNumber(final int line) {
+ if (env._debug_lines) {
+ debug_label("[LINE]", line);
+ final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
+ method.visitLabel(l);
+ method.visitLineNumber(line, l);
+ }
}
/*
@@ -2116,12 +2108,12 @@ public class MethodEmitter implements Emitter {
pad--;
}
- if (!stack.isEmpty()) {
+ if (stack != null && !stack.isEmpty()) {
sb.append("{");
sb.append(stack.size());
sb.append(":");
- for (final Iterator<Type> iter = stack.iterator(); iter.hasNext();) {
- final Type t = iter.next();
+ for (int pos = 0; pos < stack.size(); pos++) {
+ final Type t = stack.peek(pos);
if (t == Type.SCOPE) {
sb.append("scope");
@@ -2147,7 +2139,7 @@ public class MethodEmitter implements Emitter {
sb.append(t.getDescriptor());
}
- if (iter.hasNext()) {
+ if (pos + 1 < stack.size()) {
sb.append(' ');
}
}
diff --git a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
index b7514526..172c1035 100644
--- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
@@ -69,6 +69,16 @@ public final class ObjectClassGenerator {
static final String SCOPE_MARKER = "P";
/**
+ * Minimum number of extra fields in an object.
+ */
+ static final int FIELD_PADDING = 4;
+
+ /**
+ * Rounding when calculating the number of fields.
+ */
+ static final int FIELD_ROUNDING = 4;
+
+ /**
* Debug field logger
* Should we print debugging information for fields when they are generated and getters/setters are called?
*/
diff --git a/src/jdk/nashorn/internal/codegen/ObjectCreator.java b/src/jdk/nashorn/internal/codegen/ObjectCreator.java
index a9c494cc..b0e5a773 100644
--- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.codegen;
import java.util.List;
+import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -50,6 +51,7 @@ public abstract class ObjectCreator {
private final boolean isScope;
private final boolean hasArguments;
private int fieldCount;
+ private int paddedFieldCount;
private int paramCount;
private String fieldObjectClassName;
private Class<?> fieldObjectClass;
@@ -88,6 +90,8 @@ public abstract class ObjectCreator {
}
}
}
+
+ paddedFieldCount = fieldCount + FIELD_PADDING;
}
/**
@@ -96,7 +100,7 @@ public abstract class ObjectCreator {
private void findClass() {
fieldObjectClassName = isScope() ?
ObjectClassGenerator.getClassName(fieldCount, paramCount) :
- ObjectClassGenerator.getClassName(fieldCount);
+ ObjectClassGenerator.getClassName(paddedFieldCount);
try {
this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
@@ -125,11 +129,7 @@ public abstract class ObjectCreator {
* @return the newly created property map
*/
protected PropertyMap makeMap() {
- if (keys.isEmpty()) { //empty map
- propertyMap = PropertyMap.newMap(fieldObjectClass);
- } else {
- propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments());
- }
+ propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount);
return propertyMap;
}
diff --git a/src/jdk/nashorn/internal/codegen/Splitter.java b/src/jdk/nashorn/internal/codegen/Splitter.java
index f482e4df..f18f686e 100644
--- a/src/jdk/nashorn/internal/codegen/Splitter.java
+++ b/src/jdk/nashorn/internal/codegen/Splitter.java
@@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -40,9 +41,9 @@ import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
-import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options;
/**
@@ -75,7 +76,7 @@ final class Splitter extends NodeVisitor {
*/
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 +96,7 @@ final class Splitter extends NodeVisitor {
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);
@@ -127,18 +128,18 @@ final class Splitter extends NodeVisitor {
final List<FunctionNode> dc = directChildren(functionNode);
final Block newBody = (Block)body.accept(new NodeVisitor() {
- @Override
- public boolean enterFunctionNode(final FunctionNode nestedFunction) {
- return dc.contains(nestedFunction);
- }
+ @Override
+ public boolean enterFunctionNode(final FunctionNode nestedFunction) {
+ return dc.contains(nestedFunction);
+ }
- @Override
- public Node leaveFunctionNode(final FunctionNode nestedFunction) {
- FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
- getLexicalContext().replace(nestedFunction, split);
- return split;
- }
- });
+ @Override
+ public Node leaveFunctionNode(final FunctionNode nestedFunction) {
+ FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
+ getLexicalContext().replace(nestedFunction, split);
+ return split;
+ }
+ });
functionNode = functionNode.setBody(lc, newBody);
assert functionNode.getCompileUnit() != null;
@@ -182,11 +183,11 @@ final class Splitter extends NodeVisitor {
private Block splitBlock(final Block block, final FunctionNode function) {
getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
- final List<Node> splits = new ArrayList<>();
- List<Node> statements = new ArrayList<>();
+ final List<Statement> splits = new ArrayList<>();
+ List<Statement> statements = new ArrayList<>();
long statementsWeight = 0;
- for (final Node statement : block.getStatements()) {
+ for (final Statement statement : block.getStatements()) {
final long weight = WeighNodes.weigh(statement, weightCache);
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
@@ -220,15 +221,15 @@ final class Splitter extends NodeVisitor {
*
* @return New split node.
*/
- private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
- final Source source = parent.getSource();
- final long token = parent.getToken();
- final int finish = parent.getFinish();
- final String name = function.uniqueName(SPLIT_PREFIX.symbolName());
+ private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
+ final int lineNumber = parent.getLineNumber();
+ final long token = parent.getToken();
+ final int finish = parent.getFinish();
+ final String name = function.uniqueName(SPLIT_PREFIX.symbolName());
- final Block newBlock = new Block(source, token, finish, statements);
+ final Block newBlock = new Block(lineNumber, token, finish, statements);
- return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
+ return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
}
@Override
@@ -273,7 +274,9 @@ final class Splitter extends NodeVisitor {
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;
diff --git a/src/jdk/nashorn/internal/ir/AccessNode.java b/src/jdk/nashorn/internal/ir/AccessNode.java
index 2f739bf0..28b09a6c 100644
--- a/src/jdk/nashorn/internal/ir/AccessNode.java
+++ b/src/jdk/nashorn/internal/ir/AccessNode.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of a property access (period operator.)
@@ -41,14 +40,13 @@ public final class AccessNode extends BaseNode {
/**
* Constructor
*
- * @param source source code
* @param token token
* @param finish finish
* @param base base node
* @param property property
*/
- public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) {
- super(source, token, finish, base, false, false);
+ public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
+ super(token, finish, base, false, false);
this.property = property.setIsPropertyName();
}
@@ -121,10 +119,10 @@ public final class AccessNode extends BaseNode {
}
@Override
- public AccessNode setType(final Type type) {
+ public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
logTypeChange(type);
- getSymbol().setTypeOverride(type); //always a temp so this is fine.
- return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType());
+ final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
+ return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/BaseNode.java b/src/jdk/nashorn/internal/ir/BaseNode.java
index 5e5bfb13..a1b7c0ee 100644
--- a/src/jdk/nashorn/internal/ir/BaseNode.java
+++ b/src/jdk/nashorn/internal/ir/BaseNode.java
@@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR base for accessing/indexing nodes.
@@ -50,15 +49,14 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
/**
* Constructor
*
- * @param source source code
* @param token token
* @param finish finish
* @param base base node
* @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type
*/
- public BaseNode(final Source source, final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
- super(source, token, base.getStart(), finish);
+ public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+ super(token, base.getStart(), finish);
this.base = base;
this.isFunction = isFunction;
this.hasCallSiteType = hasCallSiteType;
diff --git a/src/jdk/nashorn/internal/ir/BinaryNode.java b/src/jdk/nashorn/internal/ir/BinaryNode.java
index 28df8edf..61454fef 100644
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java
@@ -29,7 +29,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
/**
* BinaryNode nodes represent two operand operations.
@@ -44,13 +43,12 @@ public final class BinaryNode extends Node implements Assignment<Node> {
/**
* Constructor
*
- * @param source source code
* @param token token
* @param lhs left hand side
* @param rhs right hand side
*/
- public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) {
- super(source, token, lhs.getStart(), rhs.getFinish());
+ public BinaryNode(final long token, final Node lhs, final Node rhs) {
+ super(token, lhs.getStart(), rhs.getFinish());
this.lhs = lhs;
this.rhs = rhs;
}
diff --git a/src/jdk/nashorn/internal/ir/Block.java b/src/jdk/nashorn/internal/ir/Block.java
index 48b9ed69..a0fa9372 100644
--- a/src/jdk/nashorn/internal/ir/Block.java
+++ b/src/jdk/nashorn/internal/ir/Block.java
@@ -30,14 +30,12 @@ import java.util.ArrayList;
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;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a list of statements and functions. All provides the
@@ -46,7 +44,7 @@ import jdk.nashorn.internal.runtime.Source;
@Immutable
public class Block extends BreakableNode implements Flags<Block> {
/** List of statements */
- protected final List<Node> statements;
+ protected final List<Statement> statements;
/** Symbol table - keys must be returned in the order they were put in. */
protected final Map<String, Symbol> symbols;
@@ -78,13 +76,13 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
- * @param source source code
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
- public Block(final Source source, final long token, final int finish, final Node... statements) {
- super(source, token, finish, new Label("block_break"));
+ public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
+ super(lineNumber, token, finish, new Label("block_break"));
this.statements = Arrays.asList(statements);
this.symbols = new LinkedHashMap<>();
@@ -95,27 +93,35 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
- * @param source source code
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
- public Block(final Source source, final long token, final int finish, final List<Node> statements) {
- this(source, token, finish, statements.toArray(new Node[statements.size()]));
+ public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
+ this(lineNumber, token, finish, statements.toArray(new Statement[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<Statement> 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));
}
/**
@@ -127,7 +133,7 @@ public class Block extends BreakableNode implements Flags<Block> {
@Override
public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
if (visitor.enterBlock(this)) {
- return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
+ return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements)));
}
return this;
@@ -137,15 +143,15 @@ public class Block extends BreakableNode implements Flags<Block> {
* 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);
@@ -222,7 +228,7 @@ public class Block extends BreakableNode implements Flags<Block> {
*
* @return a list of statements
*/
- public List<Node> getStatements() {
+ public List<Statement> getStatements() {
return Collections.unmodifiableList(statements);
}
@@ -233,7 +239,7 @@ public class Block extends BreakableNode implements Flags<Block> {
* @param statements new statement list
* @return new block if statements changed, identity of statements == block.statements
*/
- public Block setStatements(final LexicalContext lc, final List<Node> statements) {
+ public Block setStatements(final LexicalContext lc, final List<Statement> statements) {
if (this.statements == statements) {
return this;
}
@@ -241,17 +247,17 @@ public class Block extends BreakableNode implements Flags<Block> {
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 +274,7 @@ public class Block extends BreakableNode implements Flags<Block> {
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 +302,7 @@ public class Block extends BreakableNode implements Flags<Block> {
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 +312,11 @@ public class Block extends BreakableNode implements Flags<Block> {
* @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;
}
diff --git a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
index 38186f56..71c80a6b 100644
--- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
@@ -41,16 +41,16 @@ import java.util.ListIterator;
public class BlockLexicalContext extends LexicalContext {
/** statement stack, each block on the lexical context maintains one of these, which is
* committed to the block on pop */
- private Deque<List<Node>> sstack = new ArrayDeque<>();
+ private Deque<List<Statement>> sstack = new ArrayDeque<>();
/** Last non debug statement emitted in this context */
- protected Node lastStatement;
+ protected Statement lastStatement;
@Override
public <T extends LexicalContextNode> T push(final T node) {
T pushed = super.push(node);
if (node instanceof Block) {
- sstack.push(new ArrayList<Node>());
+ sstack.push(new ArrayList<Statement>());
}
return pushed;
}
@@ -59,16 +59,16 @@ public class BlockLexicalContext extends LexicalContext {
* Get the statement list from the stack, possibly filtered
* @return statement list
*/
- protected List<Node> popStatements() {
+ protected List<Statement> popStatements() {
return sstack.pop();
}
- @Override
@SuppressWarnings("unchecked")
+ @Override
public <T extends LexicalContextNode> T pop(final T node) {
T expected = node;
if (node instanceof Block) {
- final List<Node> newStatements = popStatements();
+ final List<Statement> newStatements = popStatements();
expected = (T)((Block)node).setStatements(this, newStatements);
if (!sstack.isEmpty()) {
lastStatement = lastStatement(sstack.peek());
@@ -81,12 +81,10 @@ public class BlockLexicalContext extends LexicalContext {
* Append a statement to the block being generated
* @param statement statement to add
*/
- public void appendStatement(final Node statement) {
+ public void appendStatement(final Statement statement) {
assert statement != null;
sstack.peek().add(statement);
- if (!statement.isDebug()) {
- lastStatement = statement;
- }
+ lastStatement = statement;
}
/**
@@ -94,26 +92,24 @@ public class BlockLexicalContext extends LexicalContext {
* @param statement statement to prepend
* @return the prepended statement
*/
- public Node prependStatement(final Node statement) {
+ public Node prependStatement(final Statement statement) {
assert statement != null;
sstack.peek().add(0, statement);
return statement;
}
/**
- * Get the last (non debug) statement that was emitted into a block
+ * Get the last statement that was emitted into a block
* @return the last statement emitted
*/
- public Node getLastStatement() {
+ public Statement getLastStatement() {
return lastStatement;
}
- private static Node lastStatement(final List<Node> statements) {
- for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
- final Node node = iter.previous();
- if (!node.isDebug()) {
- return node;
- }
+ private static Statement lastStatement(final List<Statement> statements) {
+ for (final ListIterator<Statement> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
+ final Statement node = iter.previous();
+ return node;
}
return null;
}
diff --git a/src/jdk/nashorn/internal/ir/BreakNode.java b/src/jdk/nashorn/internal/ir/BreakNode.java
index f0966b46..f1b9cb98 100644
--- a/src/jdk/nashorn/internal/ir/BreakNode.java
+++ b/src/jdk/nashorn/internal/ir/BreakNode.java
@@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for {@code break} statements.
*/
@Immutable
-public final class BreakNode extends Node {
+public final class BreakNode extends Statement {
private final IdentNode label;
/**
* Constructor
*
- * @param source source code
- * @param token token
- * @param finish finish
- * @param label label for break or null if none
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param label label for break or null if none
*/
- public BreakNode(final Source source, final long token, final int finish, final IdentNode label) {
- super(source, token, finish);
+ public BreakNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+ super(lineNumber, token, finish);
this.label = label;
}
diff --git a/src/jdk/nashorn/internal/ir/BreakableNode.java b/src/jdk/nashorn/internal/ir/BreakableNode.java
index 3662bfa7..ea07cb4b 100644
--- a/src/jdk/nashorn/internal/ir/BreakableNode.java
+++ b/src/jdk/nashorn/internal/ir/BreakableNode.java
@@ -30,7 +30,6 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.runtime.Source;
/**
* This class represents a node from which control flow can execute
@@ -45,13 +44,13 @@ public abstract class BreakableNode extends LexicalContextNode {
/**
* Constructor
*
- * @param source source code
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param breakLabel break label
*/
- protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) {
- super(source, token, finish);
+ protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
+ super(lineNumber, token, finish);
this.breakLabel = breakLabel;
}
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java
index 9a730aa8..46cf4588 100644
--- a/src/jdk/nashorn/internal/ir/CallNode.java
+++ b/src/jdk/nashorn/internal/ir/CallNode.java
@@ -31,7 +31,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a function call.
@@ -137,14 +136,14 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
/**
* Constructors
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param function the function to call
- * @param args args to the call
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param function the function to call
+ * @param args args to the call
*/
- public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) {
- super(source, token, finish);
+ public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
+ super(lineNumber, token, finish);
this.function = function;
this.args = args;
@@ -171,7 +170,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
}
@Override
- public CallNode setType(final Type type) {
+ public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
if (this.type == type) {
return this;
}
@@ -201,7 +200,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
setFunction(function.accept(visitor)).
setArgs(Node.accept(visitor, Node.class, args)).
setFlags(flags).
- setType(type).
+ setType(null, lc, type).
setEvalArgs(evalArgs == null ?
null :
evalArgs.setCode(evalArgs.getCode().accept(visitor)).
diff --git a/src/jdk/nashorn/internal/ir/CaseNode.java b/src/jdk/nashorn/internal/ir/CaseNode.java
index 237536cc..8a438f8f 100644
--- a/src/jdk/nashorn/internal/ir/CaseNode.java
+++ b/src/jdk/nashorn/internal/ir/CaseNode.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of CASE clause.
@@ -48,14 +47,13 @@ public final class CaseNode extends Node {
/**
* Constructors
*
- * @param source the source
* @param token token
* @param finish finish
* @param test case test node, can be any node in JavaScript
* @param body case body
*/
- public CaseNode(final Source source, final long token, final int finish, final Node test, final Block body) {
- super(source, token, finish);
+ public CaseNode(final long token, final int finish, final Node test, final Block body) {
+ super(token, finish);
this.test = test;
this.body = body;
diff --git a/src/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk/nashorn/internal/ir/CatchNode.java
index 5e1b4111..c4551492 100644
--- a/src/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk/nashorn/internal/ir/CatchNode.java
@@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of a catch clause.
*/
@Immutable
-public final class CatchNode extends Node {
+public final class CatchNode extends Statement {
/** Exception identifier. */
private final IdentNode exception;
@@ -46,16 +45,15 @@ public final class CatchNode extends Node {
/**
* Constructors
*
- * @param source the source
+ * @param lineNumber lineNumber
* @param token token
* @param finish finish
* @param exception variable name of exception
* @param exceptionCondition exception condition
* @param body catch body
*/
- public CatchNode(final Source source, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
- super(source, token, finish);
-
+ public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
+ super(lineNumber, token, finish);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
this.body = body;
@@ -63,7 +61,6 @@ public final class CatchNode extends Node {
private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
super(catchNode);
-
this.exception = exception;
this.exceptionCondition = exceptionCondition;
this.body = body;
@@ -138,7 +135,12 @@ public final class CatchNode extends Node {
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;
}
diff --git a/src/jdk/nashorn/internal/ir/ContinueNode.java b/src/jdk/nashorn/internal/ir/ContinueNode.java
index c8cc309d..c82813b4 100644
--- a/src/jdk/nashorn/internal/ir/ContinueNode.java
+++ b/src/jdk/nashorn/internal/ir/ContinueNode.java
@@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for CONTINUE statements.
*/
@Immutable
-public class ContinueNode extends Node {
+public class ContinueNode extends Statement {
private IdentNode label;
/**
* Constructor
*
- * @param source source code
- * @param token token
- * @param finish finish
- * @param label label for break or null if none
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param label label for break or null if none
*/
- public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) {
- super(source, token, finish);
+ public ContinueNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
+ super(lineNumber, token, finish);
this.label = label;
}
diff --git a/src/jdk/nashorn/internal/ir/EmptyNode.java b/src/jdk/nashorn/internal/ir/EmptyNode.java
index 67516127..9f53a602 100644
--- a/src/jdk/nashorn/internal/ir/EmptyNode.java
+++ b/src/jdk/nashorn/internal/ir/EmptyNode.java
@@ -27,32 +27,31 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for an empty statement.
*/
@Immutable
-public final class EmptyNode extends Node {
+public final class EmptyNode extends Statement {
/**
* Constructor
*
* @param node node to wrap
*/
- public EmptyNode(final Node node) {
+ public EmptyNode(final Statement node) {
super(node);
}
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
*/
- public EmptyNode(final Source source, final long token, final int finish) {
- super(source, token, finish);
+ public EmptyNode(final int lineNumber, final long token, final int finish) {
+ super(lineNumber, token, finish);
}
diff --git a/src/jdk/nashorn/internal/ir/ExecuteNode.java b/src/jdk/nashorn/internal/ir/ExecuteNode.java
index f6dd7d1b..300254dd 100644
--- a/src/jdk/nashorn/internal/ir/ExecuteNode.java
+++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for executing bare expressions. Basically, an expression
@@ -35,20 +34,20 @@ import jdk.nashorn.internal.runtime.Source;
* statements being added to the IR
*/
@Immutable
-public final class ExecuteNode extends Node {
+public final class ExecuteNode extends Statement {
/** Expression to execute. */
private final Node expression;
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param expression the expression to execute
*/
- public ExecuteNode(final Source source, final long token, final int finish, final Node expression) {
- super(source, token, finish);
+ public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ super(lineNumber, token, finish);
this.expression = expression;
}
@@ -57,16 +56,6 @@ public final class ExecuteNode extends Node {
this.expression = expression;
}
- /**
- * Constructor
- *
- * @param expression an expression to wrap, from which source, tokens and finish are also inherited
- */
- public ExecuteNode(final Node expression) {
- super(expression.getSource(), expression.getToken(), expression.getFinish());
- this.expression = expression;
- }
-
@Override
public boolean isTerminal() {
return expression.isTerminal();
diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java
index 057b8464..3d0ea364 100644
--- a/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/src/jdk/nashorn/internal/ir/ForNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representing a FOR statement.
@@ -57,17 +56,17 @@ public final class ForNode extends LoopNode {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param init init
- * @param test test
- * @param body body
- * @param modify modify
- * @param flags flags
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param init initialization expression
+ * @param test test
+ * @param body body
+ * @param modify modify
+ * @param flags flags
*/
- public ForNode(final Source source, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
- super(source, token, finish, test, body, false);
+ public ForNode(final int lineNumber, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
+ super(lineNumber, token, finish, test, body, false);
this.init = init;
this.modify = modify;
this.flags = flags;
diff --git a/src/jdk/nashorn/internal/ir/FunctionNode.java b/src/jdk/nashorn/internal/ir/FunctionNode.java
index 60fe64ff..2b6d19bf 100644
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -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;
@@ -90,11 +86,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** method has been emitted to bytecode */
EMITTED
}
+ /** Source of entity. */
+ private final Source source;
/** External function identifier. */
@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 +129,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
@Ignore
private final EnumSet<CompilationState> compilationState;
+ @Ignore
+ private final Compiler.Hints hints;
+
/** Function flags. */
private final int flags;
@@ -176,6 +181,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** 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;
@@ -196,6 +204,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
* Constructor
*
* @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param firstToken first token of the funtion node (including the function declaration)
@@ -208,6 +217,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
*/
public FunctionNode(
final Source source,
+ final int lineNumber,
final long token,
final int finish,
final long firstToken,
@@ -217,39 +227,56 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
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;
- }
-
- private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
+ super(lineNumber, token, finish);
+
+ this.source = source;
+ 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,
+ 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.source = functionNode.source;
+ 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 +288,61 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
+ * Get the source for this function
+ * @return the source
+ */
+ public Source getSource() {
+ return source;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Throw away the snapshot, if any, to save memory. Used when heuristic
+ * determines that a method is not worth specializing
+ *
+ * @param lc lexical context
+ * @return new function node if a snapshot was present, now with snapsnot null
+ */
+ public FunctionNode clearSnapshot(final LexicalContext lc) {
+ if (this.snapshot == null) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints));
+ }
+
+ /**
+ * 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;
+ }
+ if (isProgram() || parameters.isEmpty()) {
+ return this; //never specialize anything that won't be recompiled
+ }
+ 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 +389,28 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
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 +422,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
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 +463,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
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 +572,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
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 +640,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
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 +688,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
- * 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 +767,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
returnType),
compileUnit,
compilationState,
- body));
+ body,
+ parameters,
+ snapshot,
+ hints));
}
/**
@@ -705,7 +801,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
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 +813,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
*
* @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)
@@ -739,5 +822,4 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
public Symbol compilerConstant(final CompilerConstants cc) {
return body.getExistingSymbol(cc.symbolName());
}
-
}
diff --git a/src/jdk/nashorn/internal/ir/IdentNode.java b/src/jdk/nashorn/internal/ir/IdentNode.java
index daf79ee3..2fb769a9 100644
--- a/src/jdk/nashorn/internal/ir/IdentNode.java
+++ b/src/jdk/nashorn/internal/ir/IdentNode.java
@@ -34,7 +34,6 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for an identifier.
@@ -56,14 +55,13 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish position
* @param name name of identifier
*/
- public IdentNode(final Source source, final long token, final int finish, final String name) {
- super(source, token, finish);
- this.name = name;
+ public IdentNode(final long token, final int finish, final String name) {
+ super(token, finish);
+ this.name = name.intern();
this.callSiteType = null;
this.flags = 0;
}
@@ -103,7 +101,7 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
}
@Override
- public IdentNode setType(final Type type) {
+ public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
// do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
if (this.callSiteType == type) {
return this;
diff --git a/src/jdk/nashorn/internal/ir/IfNode.java b/src/jdk/nashorn/internal/ir/IfNode.java
index 027e1a84..7731b302 100644
--- a/src/jdk/nashorn/internal/ir/IfNode.java
+++ b/src/jdk/nashorn/internal/ir/IfNode.java
@@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for an IF statement.
*/
@Immutable
-public final class IfNode extends Node {
+public final class IfNode extends Statement {
/** Test expression. */
private final Node test;
@@ -46,15 +45,15 @@ public final class IfNode extends Node {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param test test
- * @param pass block to execute when test passes
- * @param fail block to execute when test fails or null
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param test test
+ * @param pass block to execute when test passes
+ * @param fail block to execute when test fails or null
*/
- public IfNode(final Source source, final long token, final int finish, final Node test, final Block pass, final Block fail) {
- super(source, token, finish);
+ public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
+ super(lineNumber, token, finish);
this.test = test;
this.pass = pass;
this.fail = fail;
diff --git a/src/jdk/nashorn/internal/ir/IndexNode.java b/src/jdk/nashorn/internal/ir/IndexNode.java
index 764ee38c..a22c6179 100644
--- a/src/jdk/nashorn/internal/ir/IndexNode.java
+++ b/src/jdk/nashorn/internal/ir/IndexNode.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of an indexed access (brackets operator.)
@@ -41,14 +40,13 @@ public final class IndexNode extends BaseNode {
/**
* Constructors
*
- * @param source the source
* @param token token
* @param finish finish
* @param base base node for access
* @param index index for access
*/
- public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) {
- super(source, token, finish, base, false, false);
+ public IndexNode(final long token, final int finish, final Node base, final Node index) {
+ super(token, finish, base, false, false);
this.index = index;
}
@@ -108,6 +106,18 @@ public final class IndexNode extends BaseNode {
return index;
}
+ /**
+ * Set the index expression for this node
+ * @param index new index expression
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public IndexNode setIndex(Node index) {
+ if(this.index == index) {
+ return this;
+ }
+ return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
+ }
+
@Override
public BaseNode setIsFunction() {
if (isFunction()) {
@@ -117,10 +127,10 @@ public final class IndexNode extends BaseNode {
}
@Override
- public IndexNode setType(final Type type) {
+ public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
logTypeChange(type);
- getSymbol().setTypeOverride(type); //always a temp so this is fine.
- return new IndexNode(this, base, index, isFunction(), true);
+ final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
+ return new IndexNode(newIndexNode, base, index, isFunction(), true);
}
}
diff --git a/src/jdk/nashorn/internal/ir/LabelNode.java b/src/jdk/nashorn/internal/ir/LabelNode.java
index bf932db8..d791f3fa 100644
--- a/src/jdk/nashorn/internal/ir/LabelNode.java
+++ b/src/jdk/nashorn/internal/ir/LabelNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a labeled statement.
@@ -43,14 +42,14 @@ public final class LabelNode extends LexicalContextNode {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param label label identifier
- * @param body body of label node
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param label label identifier
+ * @param body body of label node
*/
- public LabelNode(final Source source, final long token, final int finish, final IdentNode label, final Block body) {
- super(source, token, finish);
+ public LabelNode(final int lineNumber, final long token, final int finish, final IdentNode label, final Block body) {
+ super(lineNumber, token, finish);
this.label = label;
this.body = body;
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java
index c3f096f5..13eb0aa8 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContext.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContext.java
@@ -64,7 +64,6 @@ public class LexicalContext {
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 @@ public class LexicalContext {
return (FunctionNode)stack[0];
}
-
-
/**
* Pushes a new block on top of the context, making it the innermost open block.
* @param node the new node
@@ -395,8 +392,7 @@ public class LexicalContext {
*/
public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) {
final LexicalContextNode parent = stack[sp - 2];
- if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
- assert functionNode.getSource() == peek().getSource();
+ if (parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
return true;
}
return false;
@@ -543,13 +539,16 @@ public class LexicalContext {
sb.append('@');
sb.append(Debug.id(node));
sb.append(':');
- final Source source = node.getSource();
- String src = source.toString();
- if (src.indexOf(File.pathSeparator) != -1) {
- src = src.substring(src.lastIndexOf(File.pathSeparator));
+ if (node instanceof FunctionNode) {
+ final Source source = ((FunctionNode)node).getSource();
+ String src = source.toString();
+ if (src.indexOf(File.pathSeparator) != -1) {
+ src = src.substring(src.lastIndexOf(File.pathSeparator));
+ }
+ src += ' ';
+ src += source.getLine(node.getStart());
+ sb.append(src);
}
- src += ' ';
- src += source.getLine(node.getStart());
sb.append(' ');
}
sb.append(" ==> ]");
diff --git a/src/jdk/nashorn/internal/ir/LexicalContextNode.java b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
index e48c6e0b..52f62f09 100644
--- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java
+++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java
@@ -25,22 +25,21 @@
package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* Superclass for nodes that can be part of the lexical context
* @see LexicalContext
*/
-public abstract class LexicalContextNode extends Node {
+public abstract class LexicalContextNode extends Statement {
/**
* Constructor
*
- * @param source source
- * @param token token
- * @param finish finish
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
*/
- protected LexicalContextNode(final Source source, final long token, final int finish) {
- super(source, token, finish);
+ protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
+ super(lineNumber, token, finish);
}
/**
@@ -70,4 +69,16 @@ public abstract class LexicalContextNode extends Node {
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));
+ }
+
}
diff --git a/src/jdk/nashorn/internal/ir/LiteralNode.java b/src/jdk/nashorn/internal/ir/LiteralNode.java
index ae80214c..4c2f932c 100644
--- a/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -37,7 +37,6 @@ import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.Undefined;
/**
@@ -50,16 +49,15 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** Literal value */
protected final T value;
- /**
+ /**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param value the value of the literal
*/
- protected LiteralNode(final Source source, final long token, final int finish, final T value) {
- super(source, token, finish);
+ protected LiteralNode(final long token, final int finish, final T value) {
+ super(token, finish);
this.value = value;
}
@@ -238,14 +236,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new null literal
*
- * @param source the source
* @param token token
* @param finish finish
*
* @return the new literal node
*/
- public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) {
- return new NodeLiteralNode(source, token, finish);
+ public static LiteralNode<Node> newInstance(final long token, final int finish) {
+ return new NodeLiteralNode(token, finish);
}
/**
@@ -256,14 +253,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent) {
- return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
+ return new NodeLiteralNode(parent.getToken(), parent.getFinish());
}
@Immutable
private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
- private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) {
- super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
+ private BooleanLiteralNode(final long token, final int finish, final boolean value) {
+ super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
}
private BooleanLiteralNode(final BooleanLiteralNode literalNode) {
@@ -289,15 +286,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new boolean literal
*
- * @param source the source
* @param token token
* @param finish finish
* @param value true or false
*
* @return the new literal node
*/
- public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) {
- return new BooleanLiteralNode(source, token, finish, value);
+ public static LiteralNode<Boolean> newInstance(final long token, final int finish, final boolean value) {
+ return new BooleanLiteralNode(token, finish, value);
}
/**
@@ -309,7 +305,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final boolean value) {
- return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+ return new BooleanLiteralNode(parent.getToken(), parent.getFinish(), value);
}
@Immutable
@@ -317,8 +313,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
private final Type type = numberGetType(value);
- private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) {
- super(source, Token.recast(token, TokenType.DECIMAL), finish, value);
+ private NumberLiteralNode(final long token, final int finish, final Number value) {
+ super(Token.recast(token, TokenType.DECIMAL), finish, value);
}
private NumberLiteralNode(final NumberLiteralNode literalNode) {
@@ -353,15 +349,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new number literal
*
- * @param source the source
* @param token token
* @param finish finish
* @param value literal value
*
* @return the new literal node
*/
- public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) {
- return new NumberLiteralNode(source, token, finish, value);
+ public static LiteralNode<Number> newInstance(final long token, final int finish, final Number value) {
+ return new NumberLiteralNode(token, finish, value);
}
/**
@@ -373,12 +368,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final Number value) {
- return new NumberLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+ return new NumberLiteralNode(parent.getToken(), parent.getFinish(), value);
}
private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
- private UndefinedLiteralNode(final Source source, final long token, final int finish) {
- super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
+ private UndefinedLiteralNode(final long token, final int finish) {
+ super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
}
private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
@@ -389,15 +384,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new undefined literal
*
- * @param source the source
* @param token token
* @param finish finish
* @param value undefined value, passed only for polymorphisism discrimination
*
* @return the new literal node
*/
- public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) {
- return new UndefinedLiteralNode(source, token, finish);
+ public static LiteralNode<Undefined> newInstance(final long token, final int finish, final Undefined value) {
+ return new UndefinedLiteralNode(token, finish);
}
/**
@@ -409,13 +403,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final Undefined value) {
- return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
+ return new UndefinedLiteralNode(parent.getToken(), parent.getFinish());
}
@Immutable
private static class StringLiteralNode extends LiteralNode<String> {
- private StringLiteralNode(final Source source, final long token, final int finish, final String value) {
- super(source, Token.recast(token, TokenType.STRING), finish, value);
+ private StringLiteralNode(final long token, final int finish, final String value) {
+ super(Token.recast(token, TokenType.STRING), finish, value);
}
private StringLiteralNode(final StringLiteralNode literalNode) {
@@ -433,15 +427,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new string literal
*
- * @param source the source
* @param token token
* @param finish finish
* @param value string value
*
* @return the new literal node
*/
- public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) {
- return new StringLiteralNode(source, token, finish, value);
+ public static LiteralNode<String> newInstance(final long token, final int finish, final String value) {
+ return new StringLiteralNode(token, finish, value);
}
/**
@@ -453,13 +446,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final String value) {
- return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+ return new StringLiteralNode(parent.getToken(), parent.getFinish(), value);
}
@Immutable
private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
- private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) {
- super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
+ private LexerTokenLiteralNode(final long token, final int finish, final LexerToken value) {
+ super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
}
private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) {
@@ -480,15 +473,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new literal node for a lexer token
*
- * @param source the source
* @param token token
* @param finish finish
* @param value lexer token value
*
* @return the new literal node
*/
- public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) {
- return new LexerTokenLiteralNode(source, token, finish, value);
+ public static LiteralNode<LexerToken> newInstance(final long token, final int finish, final LexerToken value) {
+ return new LexerTokenLiteralNode(token, finish, value);
}
/**
@@ -500,17 +492,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) {
- return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+ return new LexerTokenLiteralNode(parent.getToken(), parent.getFinish(), value);
}
private static final class NodeLiteralNode extends LiteralNode<Node> {
- private NodeLiteralNode(final Source source, final long token, final int finish) {
- this(source, token, finish, null);
+ private NodeLiteralNode(final long token, final int finish) {
+ this(token, finish, null);
}
- private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) {
- super(source, Token.recast(token, TokenType.OBJECT), finish, value);
+ private NodeLiteralNode(final long token, final int finish, final Node value) {
+ super(Token.recast(token, TokenType.OBJECT), finish, value);
}
private NodeLiteralNode(final LiteralNode<Node> literalNode) {
@@ -550,15 +542,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new node literal for an arbitrary node
*
- * @param source the source
* @param token token
* @param finish finish
* @param value the literal value node
*
* @return the new literal node
*/
- public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) {
- return new NodeLiteralNode(source, token, finish, value);
+ public static LiteralNode<Node> newInstance(final long token, final int finish, final Node value) {
+ return new NodeLiteralNode(token, finish, value);
}
/**
@@ -570,7 +561,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final Node value) {
- return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
+ return new NodeLiteralNode(parent.getToken(), parent.getFinish(), value);
}
/**
@@ -645,13 +636,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param value array literal value, a Node array
*/
- protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) {
- super(source, Token.recast(token, TokenType.ARRAY), finish, value);
+ protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
+ super(Token.recast(token, TokenType.ARRAY), finish, value);
this.elementType = Type.UNKNOWN;
}
@@ -659,9 +649,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* 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 +743,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
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 +805,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
/**
- * 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 +842,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@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('[');
@@ -883,15 +876,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Create a new array literal of Nodes from a list of Node values
*
- * @param source the source
* @param token token
* @param finish finish
* @param value literal value list
*
* @return the new literal node
*/
- public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) {
- return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()]));
+ public static LiteralNode<Node[]> newInstance(final long token, final int finish, final List<Node> value) {
+ return new ArrayLiteralNode(token, finish, value.toArray(new Node[value.size()]));
}
@@ -904,20 +896,19 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) {
- return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
+ return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
}
/**
* Create a new array literal of Nodes
*
- * @param source the source
* @param token token
* @param finish finish
* @param value literal value array
*
* @return the new literal node
*/
- public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) {
- return new ArrayLiteralNode(source, token, finish, value);
+ public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
+ return new ArrayLiteralNode(token, finish, value);
}
}
diff --git a/src/jdk/nashorn/internal/ir/Location.java b/src/jdk/nashorn/internal/ir/Location.java
deleted file mode 100644
index cd9edb5b..00000000
--- a/src/jdk/nashorn/internal/ir/Location.java
+++ /dev/null
@@ -1,134 +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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package jdk.nashorn.internal.ir;
-
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * Used to locate an entity back to it's source file.
- */
-public class Location implements Cloneable {
- /** Source of entity. */
- private final Source source;
-
- /** Token descriptor. */
- private final long token;
-
- /**
- * Constructor
- *
- * @param source the source
- * @param token token
- */
- public Location(final Source source, final long token) {
- this.source = source;
- this.token = token;
- }
-
- /**
- * Copy constructor
- *
- * @param location source node
- */
- protected Location(final Location location) {
- this.source = location.source;
- this.token = location.token;
- }
-
- @Override
- protected Object clone() {
- try {
- return super.clone();
- } catch(CloneNotSupportedException e) {
- throw new AssertionError(e);
- }
- }
-
- @Override
- public final boolean equals(final Object other) {
- return super.equals(other);
- }
-
- @Override
- public final int hashCode() {
- return super.hashCode();
- }
-
- /**
- * Return token position from a token descriptor.
- *
- * @return Start position of the token in the source.
- */
- public int position() {
- return Token.descPosition(token);
- }
-
- /**
- * Return token length from a token descriptor.
- *
- * @return Length of the token.
- */
- public int length() {
- return Token.descLength(token);
- }
-
- /**
- * Return token tokenType from a token descriptor.
- *
- * @return Type of token.
- */
- public TokenType tokenType() {
- return Token.descType(token);
- }
-
- /**
- * Test token tokenType.
- *
- * @param type a type to check this token against
- * @return true if token types match.
- */
- public boolean isTokenType(final TokenType type) {
- return Token.descType(token) == type;
- }
-
- /**
- * Get the source for this location
- * @return the source
- */
- public Source getSource() {
- return source;
- }
-
- /**
- * Get the token for this location
- * @return the token
- */
- public long getToken() {
- return token;
- }
-}
diff --git a/src/jdk/nashorn/internal/ir/LoopNode.java b/src/jdk/nashorn/internal/ir/LoopNode.java
index b3909dc2..4a4fd3be 100644
--- a/src/jdk/nashorn/internal/ir/LoopNode.java
+++ b/src/jdk/nashorn/internal/ir/LoopNode.java
@@ -29,7 +29,6 @@ import java.util.Arrays;
import java.util.List;
import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.runtime.Source;
/**
* A loop node, for example a while node, do while node or for node
@@ -50,15 +49,15 @@ public abstract class LoopNode extends BreakableNode {
/**
* Constructor
*
- * @param source source
- * @param token token
- * @param finish finish
- * @param test test, or null if infinite loop
- * @param body loop body
+ * @param lineNumber lineNumber
+ * @param token token
+ * @param finish finish
+ * @param test test, or null if infinite loop
+ * @param body loop body
* @param controlFlowEscapes controlFlowEscapes
*/
- protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
- super(source, token, finish, new Label("while_break"));
+ protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
+ super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = test;
this.body = body;
diff --git a/src/jdk/nashorn/internal/ir/Node.java b/src/jdk/nashorn/internal/ir/Node.java
index dfed903d..0fb95cc3 100644
--- a/src/jdk/nashorn/internal/ir/Node.java
+++ b/src/jdk/nashorn/internal/ir/Node.java
@@ -27,16 +27,15 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.List;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.parser.TokenType;
/**
* Nodes are used to compose Abstract Syntax Trees.
*/
-public abstract class Node extends Location {
+public abstract class Node implements Cloneable {
/** Node symbol. */
private Symbol symbol;
@@ -46,16 +45,17 @@ public abstract class Node extends Location {
/** End of source range. */
protected int finish;
+ /** Token descriptor. */
+ private final long token;
+
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
*/
- public Node(final Source source, final long token, final int finish) {
- super(source, token);
-
+ public Node(final long token, final int finish) {
+ this.token = token;
this.start = Token.descPosition(token);
this.finish = finish;
}
@@ -63,16 +63,14 @@ public abstract class Node extends Location {
/**
* Constructor
*
- * @param source source
* @param token token
* @param start start
* @param finish finish
*/
- protected Node(final Source source, final long token, final int start, final int finish) {
- super(source, token);
-
+ protected Node(final long token, final int start, final int finish) {
this.start = start;
this.finish = finish;
+ this.token = token;
}
/**
@@ -81,8 +79,7 @@ public abstract class Node extends Location {
* @param node source node
*/
protected Node(final Node node) {
- super(node);
-
+ this.token = node.token;
this.symbol = node.symbol;
this.start = node.start;
this.finish = node.finish;
@@ -156,15 +153,6 @@ public abstract class Node extends Location {
}
/**
- * Is this a debug info node like LineNumberNode etc?
- *
- * @return true if this is a debug node
- */
- public boolean isDebug() {
- return false;
- }
-
- /**
* For reference copies - ensure that labels in the copy node are unique
* using an appropriate copy constructor
* @param lc lexical context
@@ -248,14 +236,86 @@ public abstract class Node extends Location {
return symbol;
}
+ @Override
+ protected Object clone() {
+ try {
+ return super.clone();
+ } catch (final CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
/**
* 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 Node setSymbol(final LexicalContext lc, final Symbol symbol) {
+ if (this.symbol == symbol) {
+ return this;
+ }
+ final Node newNode = (Node)clone();
+ newNode.symbol = symbol;
+ return newNode;
+ }
+
+
+ @Override
+ public final boolean equals(final Object other) {
+ return super.equals(other);
+ }
+
+ @Override
+ public final int hashCode() {
+ return super.hashCode();
+ }
+
+ /**
+ * Return token position from a token descriptor.
+ *
+ * @return Start position of the token in the source.
+ */
+ public int position() {
+ return Token.descPosition(token);
+ }
+
+ /**
+ * Return token length from a token descriptor.
+ *
+ * @return Length of the token.
+ */
+ public int length() {
+ return Token.descLength(token);
+ }
+
+ /**
+ * Return token tokenType from a token descriptor.
+ *
+ * @return Type of token.
+ */
+ public TokenType tokenType() {
+ return Token.descType(token);
+ }
+
+ /**
+ * Test token tokenType.
+ *
+ * @param type a type to check this token against
+ * @return true if token types match.
+ */
+ public boolean isTokenType(final TokenType type) {
+ return Token.descType(token) == type;
+ }
+
+ /**
+ * Get the token for this location
+ * @return the token
*/
- public void setSymbol(final Symbol symbol) {
- this.symbol = symbol;
+ public long getToken() {
+ return token;
}
/**
@@ -274,7 +334,7 @@ public abstract class Node extends Location {
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;
}
diff --git a/src/jdk/nashorn/internal/ir/ObjectNode.java b/src/jdk/nashorn/internal/ir/ObjectNode.java
index 744a44d7..34069725 100644
--- a/src/jdk/nashorn/internal/ir/ObjectNode.java
+++ b/src/jdk/nashorn/internal/ir/ObjectNode.java
@@ -30,7 +30,6 @@ import java.util.List;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of an object literal.
@@ -44,13 +43,12 @@ public final class ObjectNode extends Node {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param elements the elements used to initialize this ObjectNode
*/
- public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) {
- super(source, token, finish);
+ public ObjectNode(final long token, final int finish, final List<Node> elements) {
+ super(token, finish);
this.elements = elements;
}
diff --git a/src/jdk/nashorn/internal/ir/PropertyNode.java b/src/jdk/nashorn/internal/ir/PropertyNode.java
index 635e1aa3..7040d414 100644
--- a/src/jdk/nashorn/internal/ir/PropertyNode.java
+++ b/src/jdk/nashorn/internal/ir/PropertyNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of an object literal property.
@@ -50,7 +49,6 @@ public final class PropertyNode extends Node {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param key the key of this property
@@ -58,8 +56,8 @@ public final class PropertyNode extends Node {
* @param getter getter function body
* @param setter setter function body
*/
- public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
- super(source, token, finish);
+ public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
+ super(token, finish);
this.key = key;
this.value = value;
this.getter = getter;
diff --git a/src/jdk/nashorn/internal/ir/ReturnNode.java b/src/jdk/nashorn/internal/ir/ReturnNode.java
index dafc956d..c0091eb4 100644
--- a/src/jdk/nashorn/internal/ir/ReturnNode.java
+++ b/src/jdk/nashorn/internal/ir/ReturnNode.java
@@ -29,26 +29,25 @@ import static jdk.nashorn.internal.parser.TokenType.RETURN;
import static jdk.nashorn.internal.parser.TokenType.YIELD;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for RETURN or YIELD statements.
*/
@Immutable
-public class ReturnNode extends Node {
+public class ReturnNode extends Statement {
/** Optional expression. */
private final Node expression;
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param expression expression to return
*/
- public ReturnNode(final Source source, final long token, final int finish, final Node expression) {
- super(source, token, finish);
+ public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ super(lineNumber, token, finish);
this.expression = expression;
}
@@ -101,9 +100,9 @@ public class ReturnNode extends Node {
@Override
public void toString(final StringBuilder sb) {
- sb.append(isYield() ? "yield" : "return ");
-
+ sb.append(isYield() ? "yield" : "return");
if (expression != null) {
+ sb.append(' ');
expression.toString(sb);
}
}
diff --git a/src/jdk/nashorn/internal/ir/RuntimeNode.java b/src/jdk/nashorn/internal/ir/RuntimeNode.java
index 7bdb6c0a..47509be1 100644
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java
@@ -33,7 +33,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a runtime call.
@@ -280,14 +279,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final Source source, final long token, final int finish, final Request request, final List<Node> args) {
- super(source, token, finish);
+ public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
+ super(token, finish);
this.request = request;
this.args = args;
@@ -307,14 +305,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param finish finish
* @param request the request
* @param args arguments to request
*/
- public RuntimeNode(final Source source, final long token, final int finish, final Request request, final Node... args) {
- this(source, token, finish, request, Arrays.asList(args));
+ public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
+ this(token, finish, request, Arrays.asList(args));
}
/**
@@ -393,7 +390,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
}
@Override
- public RuntimeNode setType(final Type type) {
+ public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
if (this.callSiteType == type) {
return this;
}
diff --git a/src/jdk/nashorn/internal/ir/SplitNode.java b/src/jdk/nashorn/internal/ir/SplitNode.java
index 49c4092f..ee6e023c 100644
--- a/src/jdk/nashorn/internal/ir/SplitNode.java
+++ b/src/jdk/nashorn/internal/ir/SplitNode.java
@@ -46,12 +46,13 @@ public class SplitNode extends LexicalContextNode {
/**
* Constructor
*
+ * @param lineNumber lineNumber
* @param name name of split node
* @param body body of split code
* @param compileUnit compile unit to use for the body
*/
- public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
- super(body.getSource(), body.getToken(), body.getFinish());
+ public SplitNode(final int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
+ super(lineNumber, body.getToken(), body.getFinish());
this.name = name;
this.body = body;
this.compileUnit = compileUnit;
diff --git a/src/jdk/nashorn/internal/ir/LineNumberNode.java b/src/jdk/nashorn/internal/ir/Statement.java
index 63f04594..6b171cb9 100644
--- a/src/jdk/nashorn/internal/ir/LineNumberNode.java
+++ b/src/jdk/nashorn/internal/ir/Statement.java
@@ -25,67 +25,56 @@
package jdk.nashorn.internal.ir;
-import jdk.nashorn.internal.ir.annotations.Immutable;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.parser.Token;
-import jdk.nashorn.internal.runtime.Source;
-
/**
- * IR Node representing a line number
+ * Statement is something that becomes code and can be stepped past. A block is
+ * made up of statements. The only node subclass that needs to keep token and
+ * location information is the Statement
*/
-@Immutable
-public final class LineNumberNode extends Node {
- /** Line number */
+public abstract class Statement extends Node {
+
private final int lineNumber;
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
- * @param lineNumber the line number
+ * @param finish finish
*/
- public LineNumberNode(final Source source, final long token, final int lineNumber) {
- super(source, token, Token.descPosition(token));
+ public Statement(final int lineNumber, final long token, final int finish) {
+ super(token, finish);
this.lineNumber = lineNumber;
}
- private LineNumberNode(final LineNumberNode lineNumberNode) {
- super(lineNumberNode);
- this.lineNumber = lineNumberNode.getLineNumber();
- }
-
- @Override
- public Node accept(final NodeVisitor visitor) {
- if (visitor.enterLineNumberNode(this)) {
- return visitor.leaveLineNumberNode(this);
- }
-
- return this;
- }
-
- @Override
- public void toString(final StringBuilder sb) {
- sb.append("[|");
- sb.append(lineNumber);
- sb.append("|]");
+ /**
+ * Constructor
+ *
+ * @param lineNumber line number
+ * @param token token
+ * @param start start
+ * @param finish finish
+ */
+ protected Statement(final int lineNumber, final long token, final int start, final int finish) {
+ super(token, start, finish);
+ this.lineNumber = lineNumber;
}
- @Override
- public boolean isAtom() {
- return true;
+ /**
+ * Copy constructor
+ *
+ * @param node source node
+ */
+ protected Statement(final Statement node) {
+ super(node);
+ this.lineNumber = node.lineNumber;
}
/**
- * Get the line number
+ * Return the line number
* @return line number
*/
public int getLineNumber() {
return lineNumber;
}
- @Override
- public boolean isDebug() {
- return true;
- }
}
diff --git a/src/jdk/nashorn/internal/ir/SwitchNode.java b/src/jdk/nashorn/internal/ir/SwitchNode.java
index 7864a10d..bfc03108 100644
--- a/src/jdk/nashorn/internal/ir/SwitchNode.java
+++ b/src/jdk/nashorn/internal/ir/SwitchNode.java
@@ -32,7 +32,6 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of a SWITCH statement.
@@ -54,15 +53,15 @@ public final class SwitchNode extends BreakableNode {
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber lineNumber
* @param token token
* @param finish finish
* @param expression switch expression
* @param cases cases
* @param defaultCase the default case node - null if none, otherwise has to be present in cases list
*/
- public SwitchNode(final Source source, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
- super(source, token, finish, new Label("switch_break"));
+ public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
+ super(lineNumber, token, finish, new Label("switch_break"));
this.expression = expression;
this.cases = cases;
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
diff --git a/src/jdk/nashorn/internal/ir/Symbol.java b/src/jdk/nashorn/internal/ir/Symbol.java
index da22f64d..05495152 100644
--- a/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/src/jdk/nashorn/internal/ir/Symbol.java
@@ -29,7 +29,6 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
@@ -67,6 +66,10 @@ public final class Symbol implements Comparable<Symbol> {
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;
+ /** Is this symbol a shared temporary? */
+ public static final int IS_SHARED = 1 << 12;
/** Null or name identifying symbol. */
private final String name;
@@ -152,6 +155,16 @@ public final class Symbol implements Comparable<Symbol> {
this(name, flags, type, -1);
}
+ private Symbol(final Symbol base, final String name, final int flags) {
+ this.flags = flags;
+ this.name = name;
+
+ this.fieldIndex = base.fieldIndex;
+ this.slot = base.slot;
+ this.type = base.type;
+ this.useCount = base.useCount;
+ }
+
private static String align(final String string, final int max) {
final StringBuilder sb = new StringBuilder();
sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -261,32 +274,14 @@ public final class Symbol implements Comparable<Symbol> {
return type.isCategory2() ? 2 : 1;
}
- private static String type(final String desc) {
- switch (desc.charAt(desc.length() - 1)) {
- case ';':
- return desc;//"obj";
- case 'D':
- return "double";
- case 'I':
- return "int";
- case 'J':
- return "long";
- case 'Z':
- return "boolean";
- default:
- return "UNKNOWN";
- }
- }
-
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- final String desc = getSymbolType().getDescriptor();
sb.append(name).
append(' ').
append('(').
- append(type(desc)).
+ append(getSymbolType().getTypeClass().getSimpleName()).
append(')');
if (hasSlot()) {
@@ -347,6 +342,24 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * Returns true if this symbol is a temporary that is being shared across expressions.
+ * @return true if this symbol is a temporary that is being shared across expressions.
+ */
+ public boolean isShared() {
+ return (flags & IS_SHARED) == IS_SHARED;
+ }
+
+ /**
+ * Creates an unshared copy of a symbol. The symbol must be currently shared.
+ * @param newName the name for the new symbol.
+ * @return a new, unshared symbol.
+ */
+ public Symbol createUnshared(final String newName) {
+ assert isShared();
+ return new Symbol(this, newName, flags & ~IS_SHARED);
+ }
+
+ /**
* Flag this symbol as scope as described in {@link Symbol#isScope()}
*/
/**
@@ -355,10 +368,23 @@ public final class Symbol implements Comparable<Symbol> {
public void setIsScope() {
if (!isScope()) {
trace("SET IS SCOPE");
+ assert !isShared();
+ flags |= IS_SCOPE;
}
- flags |= IS_SCOPE;
}
+ /**
+ * Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary.
+ */
+ public void setIsShared() {
+ if(!isShared()) {
+ assert isTemp();
+ trace("SET IS SHARED");
+ flags |= IS_SHARED;
+ }
+ }
+
+
/**
* Check if this symbol is a variable
* @return true if variable
@@ -384,6 +410,15 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * 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
*/
@@ -404,7 +439,10 @@ public final class Symbol implements Comparable<Symbol> {
*/
public void setCanBeUndefined() {
assert type.isObject() : type;
- flags |= CAN_BE_UNDEFINED;
+ if(!canBeUndefined()) {
+ assert !isShared();
+ flags |= CAN_BE_UNDEFINED;
+ }
}
/**
@@ -412,7 +450,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param type the primitive type it occurs with, currently unused but can be used for width guesses
*/
public void setCanBePrimitive(final Type type) {
- flags |= CAN_BE_PRIMITIVE;
+ if(!canBePrimitive()) {
+ assert !isShared();
+ flags |= CAN_BE_PRIMITIVE;
+ }
}
/**
@@ -452,7 +493,10 @@ public final class Symbol implements Comparable<Symbol> {
* Flag this symbol as a let
*/
public void setIsLet() {
- flags |= IS_LET;
+ if(!isLet()) {
+ assert !isShared();
+ flags |= IS_LET;
+ }
}
/**
@@ -481,7 +525,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param fieldIndex field index - a positive integer
*/
public void setFieldIndex(final int fieldIndex) {
- this.fieldIndex = fieldIndex;
+ if(this.fieldIndex != fieldIndex) {
+ assert !isShared();
+ this.fieldIndex = fieldIndex;
+ }
}
/**
@@ -497,7 +544,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param flags flags
*/
public void setFlags(final int flags) {
- this.flags = flags;
+ if(this.flags != flags) {
+ assert !isShared();
+ this.flags = flags;
+ }
}
/**
@@ -537,6 +587,7 @@ public final class Symbol implements Comparable<Symbol> {
*/
public void setSlot(final int slot) {
if (slot != this.slot) {
+ assert !isShared();
trace("SET SLOT " + slot);
this.slot = slot;
}
@@ -562,6 +613,15 @@ public final class Symbol implements Comparable<Symbol> {
}
/**
+ * Returns true if calling {@link #setType(Type)} on this symbol would effectively change its type.
+ * @param newType the new type to test for
+ * @return true if setting this symbols type to a new value would effectively change its type.
+ */
+ public boolean wouldChangeType(final Type newType) {
+ return Type.widest(this.type, newType) != this.type;
+ }
+
+ /**
* Only use this if you know about an existing type
* constraint - otherwise a type can only be
* widened
@@ -571,12 +631,33 @@ public final class Symbol implements Comparable<Symbol> {
public void setTypeOverride(final Type type) {
final Type old = this.type;
if (old != type) {
+ assert !isShared();
trace("TYPE CHANGE: " + old + "=>" + type + " == " + type);
this.type = type;
}
}
/**
+ * Sets the type of the symbol to the specified type. If the type would be changed, but this symbol is a shared
+ * temporary, it will instead return a different temporary symbol of the requested type from the passed temporary
+ * symbols. That way, it never mutates the type of a shared temporary.
+ * @param type the new type for the symbol
+ * @param ts a holder of temporary symbols
+ * @return either this symbol, or a different symbol if this symbol is a shared temporary and it type would have to
+ * be changed.
+ */
+ public Symbol setTypeOverrideShared(final Type type, final TemporarySymbols ts) {
+ if(getSymbolType() != type) {
+ if(isShared()) {
+ assert !hasSlot();
+ return ts.getTypedTemporarySymbol(type);
+ }
+ setTypeOverride(type);
+ }
+ return this;
+ }
+
+ /**
* From a lexical context, set this symbol as needing scope, which
* will set flags for the defining block that will be written when
* block is popped from the lexical context stack, used by codegen
diff --git a/src/jdk/nashorn/internal/ir/TemporarySymbols.java b/src/jdk/nashorn/internal/ir/TemporarySymbols.java
new file mode 100644
index 00000000..ee8069e1
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/TemporarySymbols.java
@@ -0,0 +1,169 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
+import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
+
+import java.util.HashMap;
+import java.util.Map;
+import jdk.nashorn.internal.codegen.types.Type;
+
+/**
+ * Class that holds reusable temporary symbols by type.
+ *
+ */
+public class TemporarySymbols {
+ private static final String prefix = TEMP_PREFIX.symbolName() + "$";
+
+ private int totalSymbolCount;
+ private final Map<Type, TypedTemporarySymbols> temporarySymbolsByType = new HashMap<>();
+
+ /**
+ * Associates a temporary symbol of a given type with a node, if the node doesn't already have any symbol.
+ * @param lc the current lexical context
+ * @param type the type of the temporary symbol
+ * @param node the node
+ * @return the node that is guaranteed to have a symbol.
+ */
+ public Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
+ final Symbol symbol = node.getSymbol();
+ if (symbol != null) {
+ return node;
+ }
+ return node.setSymbol(lc, getTypedTemporarySymbol(type));
+ }
+
+ /**
+ * Given a type, returns a temporary symbol of that type.
+ * @param type the required type of the symbol.
+ * @return a temporary symbol of the required type.
+ */
+ public Symbol getTypedTemporarySymbol(final Type type) {
+ return getTypedTemporarySymbols(type).getTemporarySymbol(type);
+ }
+
+ private TypedTemporarySymbols getTypedTemporarySymbols(final Type type) {
+ TypedTemporarySymbols temporarySymbols = temporarySymbolsByType.get(type);
+ if(temporarySymbols == null) {
+ temporarySymbols = new TypedTemporarySymbols();
+ temporarySymbolsByType.put(type, temporarySymbols);
+ }
+ return temporarySymbols;
+ }
+
+ /**
+ * This method is called to signal to this object that all the symbols it holds can be reused now.
+ */
+ public void reuse() {
+ for(TypedTemporarySymbols ts: temporarySymbolsByType.values()) {
+ ts.reuse();
+ }
+ }
+
+ /**
+ * Given a shared symbol, creates an unshared copy of it with a unique name.
+ * @param symbol the shared symbol
+ * @return the unshared, uniquely named copy of the symbol
+ */
+ public Symbol createUnshared(Symbol symbol) {
+ return symbol.createUnshared(getUniqueName());
+ }
+
+ private String getUniqueName() {
+ return prefix + (++totalSymbolCount);
+ }
+
+ /**
+ * Returns the total number of symbols this object created during its lifetime.
+ * @return the total number of symbols this object created during its lifetime.
+ */
+ public int getTotalSymbolCount() {
+ return totalSymbolCount;
+ }
+
+ private class TypedTemporarySymbols {
+ private Symbol[] symbols = new Symbol[16];
+ private int nextFreeSymbol = 0;
+ private int symbolCount = 0;
+
+ Symbol getTemporarySymbol(final Type type) {
+ while(nextFreeSymbol < symbolCount) {
+ final Symbol nextSymbol = symbols[nextFreeSymbol];
+ assert nextSymbol != null;
+ // If it has a slot, we can't reuse it.
+ if(!nextSymbol.hasSlot()) {
+ final Type symbolType = nextSymbol.getSymbolType();
+ if(symbolType == type) {
+ assert nextSymbol.isTemp();
+ assert !nextSymbol.isScope();
+ // If types match, we can reuse it.
+ nextSymbol.setIsShared();
+ nextFreeSymbol++;
+ return nextSymbol;
+ }
+ // If its type changed, but it doesn't have a slot then move it to its new home according to its
+ // new type.
+ getTypedTemporarySymbols(symbolType).addSymbol(nextSymbol);
+ }
+ // If we can move another symbol into its place, do that and repeat the analysis for this symbol.
+ --symbolCount;
+ if(symbolCount != nextFreeSymbol) {
+ final Symbol lastFreeSymbol = symbols[symbolCount];
+ symbols[nextFreeSymbol] = lastFreeSymbol;
+ }
+ symbols[symbolCount] = null;
+ }
+ return createNewSymbol(type);
+ }
+
+ private Symbol createNewSymbol(final Type type) {
+ ensureCapacity();
+ final Symbol symbol = symbols[nextFreeSymbol] = new Symbol(getUniqueName(), IS_TEMP, type);
+ nextFreeSymbol++;
+ symbolCount++;
+ return symbol;
+ }
+
+ private void addSymbol(Symbol symbol) {
+ ensureCapacity();
+ symbols[symbolCount++] = symbol;
+ }
+
+ void reuse() {
+ nextFreeSymbol = 0;
+ }
+
+ private void ensureCapacity() {
+ if(symbolCount == symbols.length) {
+ final Symbol[] newSymbols = new Symbol[symbolCount * 2];
+ System.arraycopy(symbols, 0, newSymbols, 0, symbolCount);
+ symbols = newSymbols;
+ }
+ }
+ }
+
+}
diff --git a/src/jdk/nashorn/internal/ir/TernaryNode.java b/src/jdk/nashorn/internal/ir/TernaryNode.java
index e2ccdb91..25ac1a4d 100644
--- a/src/jdk/nashorn/internal/ir/TernaryNode.java
+++ b/src/jdk/nashorn/internal/ir/TernaryNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* TernaryNode nodes represent three operand operations (?:).
@@ -44,14 +43,13 @@ public final class TernaryNode extends Node {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param lhs left hand side node
* @param rhs right hand side node
* @param third third node
*/
- public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) {
- super(source, token, third.getFinish());
+ public TernaryNode(final long token, final Node lhs, final Node rhs, final Node third) {
+ super(token, third.getFinish());
this.lhs = lhs;
this.rhs = rhs;
this.third = third;
diff --git a/src/jdk/nashorn/internal/ir/ThrowNode.java b/src/jdk/nashorn/internal/ir/ThrowNode.java
index 7a10a6ad..e37302e6 100644
--- a/src/jdk/nashorn/internal/ir/ThrowNode.java
+++ b/src/jdk/nashorn/internal/ir/ThrowNode.java
@@ -27,31 +27,29 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for THROW statements.
*/
@Immutable
-public final class ThrowNode extends Node {
+public final class ThrowNode extends Statement {
/** Exception expression. */
private final Node expression;
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
* @param expression expression to throw
*/
- public ThrowNode(final Source source, final long token, final int finish, final Node expression) {
- super(source, token, finish);
-
+ public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) {
+ super(lineNumber, token, finish);
this.expression = expression;
}
- private ThrowNode(final Node node, final Node expression) {
+ private ThrowNode(final ThrowNode node, final Node expression) {
super(node);
this.expression = expression;
}
diff --git a/src/jdk/nashorn/internal/ir/TryNode.java b/src/jdk/nashorn/internal/ir/TryNode.java
index 5e3ff7af..01ea75c7 100644
--- a/src/jdk/nashorn/internal/ir/TryNode.java
+++ b/src/jdk/nashorn/internal/ir/TryNode.java
@@ -32,13 +32,12 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation of a TRY statement.
*/
@Immutable
-public final class TryNode extends Node {
+public final class TryNode extends Statement {
/** Try statements. */
private final Block body;
@@ -60,27 +59,27 @@ public final class TryNode extends Node {
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber lineNumber
* @param token token
* @param finish finish
* @param body try node body
* @param catchBlocks list of catch blocks in order
* @param finallyBody body of finally block or null if none
*/
- public TryNode(final Source source, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
- super(source, token, finish);
- this.body = body;
+ public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
+ super(lineNumber, token, finish);
+ this.body = body;
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
- this.exit = new Label("exit");
+ this.exit = new Label("exit");
}
private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
super(tryNode);
- this.body = body;
+ this.body = body;
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
- this.exit = new Label(tryNode.exit);
+ this.exit = new Label(tryNode.exit);
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/TypeOverride.java b/src/jdk/nashorn/internal/ir/TypeOverride.java
index 61c1fe20..929d0128 100644
--- a/src/jdk/nashorn/internal/ir/TypeOverride.java
+++ b/src/jdk/nashorn/internal/ir/TypeOverride.java
@@ -43,10 +43,12 @@ public interface TypeOverride<T extends Node> {
/**
* Set the override type
*
- * @param type the type
+ * @param ts temporary symbols
+ * @param lc the current lexical context
+ * @param type the type
* @return a node equivalent to this one except for the requested change.
*/
- public T setType(final Type type);
+ public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
/**
* Returns true if this node can have a callsite override, e.g. all scope ident nodes
diff --git a/src/jdk/nashorn/internal/ir/UnaryNode.java b/src/jdk/nashorn/internal/ir/UnaryNode.java
index fed5e408..ed1d8a9b 100644
--- a/src/jdk/nashorn/internal/ir/UnaryNode.java
+++ b/src/jdk/nashorn/internal/ir/UnaryNode.java
@@ -35,7 +35,6 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.Source;
/**
* UnaryNode nodes represent single operand operations.
@@ -48,24 +47,23 @@ public final class UnaryNode extends Node implements Assignment<Node> {
/**
* Constructor
*
- * @param source the source
* @param token token
* @param rhs expression
*/
- public UnaryNode(final Source source, final long token, final Node rhs) {
- this(source, token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
+ public UnaryNode(final long token, final Node rhs) {
+ this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
}
/**
* Constructor
- * @param source the source
+ *
* @param token token
* @param start start
* @param finish finish
* @param rhs expression
*/
- public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) {
- super(source, token, start, finish);
+ public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
+ super(token, start, finish);
this.rhs = rhs;
}
diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java
index fbc3eabe..c28f5456 100644
--- a/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/src/jdk/nashorn/internal/ir/VarNode.java
@@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* Node represents a var/let declaration.
*/
@Immutable
-public final class VarNode extends Node implements Assignment<IdentNode> {
+public final class VarNode extends Statement implements Assignment<IdentNode> {
/** Var name. */
private final IdentNode name;
@@ -54,14 +53,14 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param name name of variable
- * @param init init node or null if just a declaration
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param name name of variable
+ * @param init init node or null if just a declaration
*/
- public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
- this(source, token, finish, name, init, IS_STATEMENT);
+ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
+ this(lineNumber, token, finish, name, init, IS_STATEMENT);
}
private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
@@ -74,15 +73,15 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param name name of variable
- * @param init init node or null if just a declaration
- * @param flags flags
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param name name of variable
+ * @param init init node or null if just a declaration
+ * @param flags flags
*/
- public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
- super(source, token, finish);
+ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
+ super(lineNumber, token, finish);
this.name = init == null ? name : name.setIsInitializedHere();
this.init = init;
diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java
index 438be013..c52209fc 100644
--- a/src/jdk/nashorn/internal/ir/WhileNode.java
+++ b/src/jdk/nashorn/internal/ir/WhileNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a WHILE statement. This is the superclass of all
@@ -42,13 +41,13 @@ public final class WhileNode extends LoopNode {
/**
* Constructor
*
- * @param source the source
- * @param token token
- * @param finish finish
- * @param isDoWhile is this a do while loop?
+ * @param lineNumber line number
+ * @param token token
+ * @param finish finish
+ * @param isDoWhile is this a do while loop?
*/
- public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) {
- super(source, token, finish, null, null, false);
+ public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
+ super(lineNumber, token, finish, null, null, false);
this.isDoWhile = isDoWhile;
}
@@ -135,17 +134,9 @@ public final class WhileNode extends LoopNode {
@Override
public void toString(final StringBuilder sb) {
- if (isDoWhile()) {
- sb.append("do {");
- body.toString(sb);
- sb.append("} while (");
- test.toString(sb);
- sb.append(')');
- } else {
- sb.append("while (");
- test.toString(sb);
- sb.append(')');
- }
+ sb.append("while (");
+ test.toString(sb);
+ sb.append(')');
}
@Override
diff --git a/src/jdk/nashorn/internal/ir/WithNode.java b/src/jdk/nashorn/internal/ir/WithNode.java
index 5ebbfd55..e069ff5e 100644
--- a/src/jdk/nashorn/internal/ir/WithNode.java
+++ b/src/jdk/nashorn/internal/ir/WithNode.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for {@code with} statements.
@@ -43,20 +42,18 @@ public final class WithNode extends LexicalContextNode {
/**
* Constructor
*
- * @param source the source
+ * @param lineNumber line number
* @param token token
* @param finish finish
*/
- public WithNode(final Source source, final long token, final int finish) {
- super(source, token, finish);
-
+ public WithNode(final int lineNumber, final long token, final int finish) {
+ super(lineNumber, token, finish);
this.expression = null;
this.body = null;
}
private WithNode(final WithNode node, final Node expression, final Block body) {
super(node);
-
this.expression = expression;
this.body = body;
}
diff --git a/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java b/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java
new file mode 100644
index 00000000..c65f8ef7
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/debug/ClassHistogramElement.java
@@ -0,0 +1,113 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir.debug;
+
+import java.util.Comparator;
+
+/**
+ * Class histogram element for IR / Java object instrumentation
+ */
+public class ClassHistogramElement {
+ /**
+ * Instance comparator
+ */
+ public static final Comparator<ClassHistogramElement> COMPARE_INSTANCES = new Comparator<ClassHistogramElement>() {
+ @Override
+ public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+ return (int)Math.abs(o1.instances - o2.instances);
+ }
+ };
+
+ /**
+ * Bytes comparator
+ */
+ public static final Comparator<ClassHistogramElement> COMPARE_BYTES = new Comparator<ClassHistogramElement>() {
+ @Override
+ public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+ return (int)Math.abs(o1.bytes - o2.bytes);
+ }
+ };
+
+ /**
+ * Classname comparator
+ */
+ public static final Comparator<ClassHistogramElement> COMPARE_CLASSNAMES = new Comparator<ClassHistogramElement>() {
+ @Override
+ public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
+ return o1.clazz.getCanonicalName().compareTo(o2.clazz.getCanonicalName());
+ }
+ };
+
+ private final Class<?> clazz;
+ private long instances;
+ private long bytes;
+
+ /**
+ * Constructor
+ * @param clazz class for which to construct histogram
+ */
+ public ClassHistogramElement(final Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
+ * Add an instance
+ * @param sizeInBytes byte count
+ */
+ public void addInstance(final long sizeInBytes) {
+ instances++;
+ this.bytes += sizeInBytes;
+ }
+
+ /**
+ * Get size in bytes
+ * @return size in bytes
+ */
+ public long getBytes() {
+ return bytes;
+ }
+
+ /**
+ * Get class
+ * @return class
+ */
+ public Class<?> getClazz() {
+ return clazz;
+ }
+
+ /**
+ * Get number of instances
+ * @return number of instances
+ */
+ public long getInstances() {
+ return instances;
+ }
+
+ @Override
+ public String toString() {
+ return "ClassHistogramElement[class=" + clazz.getCanonicalName() + ", instances=" + instances + ", bytes=" + bytes + "]";
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
index 988b756c..177fcf95 100644
--- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
+++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir.debug;
import java.util.Arrays;
import java.util.List;
+
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -44,7 +45,6 @@ import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@@ -52,6 +52,7 @@ import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode;
@@ -406,17 +407,15 @@ public final class JSONWriter extends NodeVisitor {
}
// body consists of nested functions and statements
- final List<Node> stats = functionNode.getBody().getStatements();
+ final List<Statement> stats = functionNode.getBody().getStatements();
final int size = stats.size();
int idx = 0;
arrayStart("body");
for (final Node stat : stats) {
- if (! stat.isDebug()) {
- stat.accept(this);
- if (idx != (size - 1)) {
- comma();
- }
+ stat.accept(this);
+ if (idx != (size - 1)) {
+ comma();
}
idx++;
}
@@ -504,11 +503,6 @@ public final class JSONWriter extends NodeVisitor {
return leave();
}
- @Override
- public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- return false;
- }
-
@SuppressWarnings("rawtypes")
@Override
public boolean enterLiteralNode(final LiteralNode literalNode) {
@@ -931,15 +925,13 @@ public final class JSONWriter extends NodeVisitor {
int idx = 0;
arrayStart(name);
for (final Node node : nodes) {
- if (node == null || !node.isDebug()) {
- if (node != null) {
- node.accept(this);
- } else {
- nullValue();
- }
- if (idx != (size - 1)) {
- comma();
- }
+ if (node != null) {
+ node.accept(this);
+ } else {
+ nullValue();
+ }
+ if (idx != (size - 1)) {
+ comma();
}
idx++;
}
@@ -971,7 +963,7 @@ public final class JSONWriter extends NodeVisitor {
objectStart("loc");
// source name
- final Source src = node.getSource();
+ final Source src = getLexicalContext().getCurrentFunction().getSource();
property("source", src.getName());
comma();
diff --git a/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
new file mode 100644
index 00000000..2d4412e7
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
@@ -0,0 +1,457 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.nashorn.internal.ir.debug;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryPoolMXBean;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Contains utility methods for calculating the memory usage of objects. It
+ * only works on the HotSpot JVM, and infers the actual memory layout (32 bit
+ * vs. 64 bit word size, compressed object pointers vs. uncompressed) from
+ * best available indicators. It can reliably detect a 32 bit vs. 64 bit JVM.
+ * It can only make an educated guess at whether compressed OOPs are used,
+ * though; specifically, it knows what the JVM's default choice of OOP
+ * compression would be based on HotSpot version and maximum heap sizes, but if
+ * the choice is explicitly overridden with the <tt>-XX:{+|-}UseCompressedOops</tt> command line
+ * switch, it can not detect
+ * this fact and will report incorrect sizes, as it will presume the default JVM
+ * behavior.
+ *
+ * @author Attila Szegedi
+ */
+public class ObjectSizeCalculator {
+
+ /**
+ * Describes constant memory overheads for various constructs in a JVM implementation.
+ */
+ public interface MemoryLayoutSpecification {
+
+ /**
+ * Returns the fixed overhead of an array of any type or length in this JVM.
+ *
+ * @return the fixed overhead of an array.
+ */
+ int getArrayHeaderSize();
+
+ /**
+ * Returns the fixed overhead of for any {@link Object} subclass in this JVM.
+ *
+ * @return the fixed overhead of any object.
+ */
+ int getObjectHeaderSize();
+
+ /**
+ * Returns the quantum field size for a field owned by an object in this JVM.
+ *
+ * @return the quantum field size for an object.
+ */
+ int getObjectPadding();
+
+ /**
+ * Returns the fixed size of an object reference in this JVM.
+ *
+ * @return the size of all object references.
+ */
+ int getReferenceSize();
+
+ /**
+ * Returns the quantum field size for a field owned by one of an object's ancestor superclasses
+ * in this JVM.
+ *
+ * @return the quantum field size for a superclass field.
+ */
+ int getSuperclassFieldPadding();
+ }
+
+ private static class CurrentLayout {
+ private static final MemoryLayoutSpecification SPEC =
+ getEffectiveMemoryLayoutSpecification();
+ }
+
+ /**
+ * Given an object, returns the total allocated size, in bytes, of the object
+ * and all other objects reachable from it. Attempts to to detect the current JVM memory layout,
+ * but may fail with {@link UnsupportedOperationException};
+ *
+ * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
+ * anything special, it measures the size of all objects
+ * reachable through it (which will include its class loader, and by
+ * extension, all other Class objects loaded by
+ * the same loader, and all the parent class loaders). It doesn't provide the
+ * size of the static fields in the JVM class that the Class object
+ * represents.
+ * @return the total allocated size of the object and all other objects it
+ * retains.
+ * @throws UnsupportedOperationException if the current vm memory layout cannot be detected.
+ */
+ public static long getObjectSize(final Object obj) throws UnsupportedOperationException {
+ return obj == null ? 0 : new ObjectSizeCalculator(CurrentLayout.SPEC).calculateObjectSize(obj);
+ }
+
+ // Fixed object header size for arrays.
+ private final int arrayHeaderSize;
+ // Fixed object header size for non-array objects.
+ private final int objectHeaderSize;
+ // Padding for the object size - if the object size is not an exact multiple
+ // of this, it is padded to the next multiple.
+ private final int objectPadding;
+ // Size of reference (pointer) fields.
+ private final int referenceSize;
+ // Padding for the fields of superclass before fields of subclasses are
+ // added.
+ private final int superclassFieldPadding;
+
+ private final Map<Class<?>, ClassSizeInfo> classSizeInfos = new IdentityHashMap<>();
+
+
+ private final Map<Object, Object> alreadyVisited = new IdentityHashMap<>();
+ private final Map<Class<?>, ClassHistogramElement> histogram = new IdentityHashMap<>();
+
+ private final Deque<Object> pending = new ArrayDeque<>(16 * 1024);
+ private long size;
+
+ /**
+ * Creates an object size calculator that can calculate object sizes for a given
+ * {@code memoryLayoutSpecification}.
+ *
+ * @param memoryLayoutSpecification a description of the JVM memory layout.
+ */
+ public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
+ memoryLayoutSpecification.getClass();
+ arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
+ objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
+ objectPadding = memoryLayoutSpecification.getObjectPadding();
+ referenceSize = memoryLayoutSpecification.getReferenceSize();
+ superclassFieldPadding = memoryLayoutSpecification.getSuperclassFieldPadding();
+ }
+
+ /**
+ * Given an object, returns the total allocated size, in bytes, of the object
+ * and all other objects reachable from it.
+ *
+ * @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
+ * anything special, it measures the size of all objects
+ * reachable through it (which will include its class loader, and by
+ * extension, all other Class objects loaded by
+ * the same loader, and all the parent class loaders). It doesn't provide the
+ * size of the static fields in the JVM class that the Class object
+ * represents.
+ * @return the total allocated size of the object and all other objects it
+ * retains.
+ */
+ public synchronized long calculateObjectSize(final Object obj) {
+ // Breadth-first traversal instead of naive depth-first with recursive
+ // implementation, so we don't blow the stack traversing long linked lists.
+ histogram.clear();
+ try {
+ for (Object o = obj;;) {
+ visit(o);
+ if (pending.isEmpty()) {
+ return size;
+ }
+ o = pending.removeFirst();
+ }
+ } finally {
+ alreadyVisited.clear();
+ pending.clear();
+ size = 0;
+ }
+ }
+
+ /**
+ * Get the class histograpm
+ * @return class histogram element list
+ */
+ public List<ClassHistogramElement> getClassHistogram() {
+ return new ArrayList<>(histogram.values());
+ }
+
+ private ClassSizeInfo getClassSizeInfo(final Class<?> clazz) {
+ ClassSizeInfo csi = classSizeInfos.get(clazz);
+ if(csi == null) {
+ csi = new ClassSizeInfo(clazz);
+ classSizeInfos.put(clazz, csi);
+ }
+ return csi;
+ }
+
+ private void visit(final Object obj) {
+ if (alreadyVisited.containsKey(obj)) {
+ return;
+ }
+ final Class<?> clazz = obj.getClass();
+ if (clazz == ArrayElementsVisitor.class) {
+ ((ArrayElementsVisitor) obj).visit(this);
+ } else {
+ alreadyVisited.put(obj, obj);
+ if (clazz.isArray()) {
+ visitArray(obj);
+ } else {
+ getClassSizeInfo(clazz).visit(obj, this);
+ }
+ }
+ }
+
+ private void visitArray(final Object array) {
+ final Class<?> arrayClass = array.getClass();
+ final Class<?> componentType = arrayClass.getComponentType();
+ final int length = Array.getLength(array);
+ if (componentType.isPrimitive()) {
+ increaseByArraySize(arrayClass, length, getPrimitiveFieldSize(componentType));
+ } else {
+ increaseByArraySize(arrayClass, length, referenceSize);
+ // If we didn't use an ArrayElementsVisitor, we would be enqueueing every
+ // element of the array here instead. For large arrays, it would
+ // tremendously enlarge the queue. In essence, we're compressing it into
+ // a small command object instead. This is different than immediately
+ // visiting the elements, as their visiting is scheduled for the end of
+ // the current queue.
+ switch (length) {
+ case 0: {
+ break;
+ }
+ case 1: {
+ enqueue(Array.get(array, 0));
+ break;
+ }
+ default: {
+ enqueue(new ArrayElementsVisitor((Object[]) array));
+ }
+ }
+ }
+ }
+
+ private void increaseByArraySize(final Class<?> clazz, final int length, final long elementSize) {
+ increaseSize(clazz, roundTo(arrayHeaderSize + length * elementSize, objectPadding));
+ }
+
+ private static class ArrayElementsVisitor {
+ private final Object[] array;
+
+ ArrayElementsVisitor(final Object[] array) {
+ this.array = array;
+ }
+
+ public void visit(final ObjectSizeCalculator calc) {
+ for (final Object elem : array) {
+ if (elem != null) {
+ calc.visit(elem);
+ }
+ }
+ }
+ }
+
+ void enqueue(final Object obj) {
+ if (obj != null) {
+ pending.addLast(obj);
+ }
+ }
+
+ void increaseSize(final Class<?> clazz, final long objectSize) {
+ ClassHistogramElement he = histogram.get(clazz);
+ if(he == null) {
+ he = new ClassHistogramElement(clazz);
+ histogram.put(clazz, he);
+ }
+ he.addInstance(objectSize);
+ size += objectSize;
+ }
+
+ static long roundTo(final long x, final int multiple) {
+ return ((x + multiple - 1) / multiple) * multiple;
+ }
+
+ private class ClassSizeInfo {
+ // Padded fields + header size
+ private final long objectSize;
+ // Only the fields size - used to calculate the subclasses' memory
+ // footprint.
+ private final long fieldsSize;
+ private final Field[] referenceFields;
+
+ public ClassSizeInfo(final Class<?> clazz) {
+ long newFieldsSize = 0;
+ final List<Field> newReferenceFields = new LinkedList<>();
+ for (Field f : clazz.getDeclaredFields()) {
+ if (Modifier.isStatic(f.getModifiers())) {
+ continue;
+ }
+ final Class<?> type = f.getType();
+ if (type.isPrimitive()) {
+ newFieldsSize += getPrimitiveFieldSize(type);
+ } else {
+ f.setAccessible(true);
+ newReferenceFields.add(f);
+ newFieldsSize += referenceSize;
+ }
+ }
+ final Class<?> superClass = clazz.getSuperclass();
+ if (superClass != null) {
+ final ClassSizeInfo superClassInfo = getClassSizeInfo(superClass);
+ newFieldsSize += roundTo(superClassInfo.fieldsSize, superclassFieldPadding);
+ newReferenceFields.addAll(Arrays.asList(superClassInfo.referenceFields));
+ }
+ this.fieldsSize = newFieldsSize;
+ this.objectSize = roundTo(objectHeaderSize + newFieldsSize, objectPadding);
+ this.referenceFields = newReferenceFields.toArray(
+ new Field[newReferenceFields.size()]);
+ }
+
+ void visit(final Object obj, final ObjectSizeCalculator calc) {
+ calc.increaseSize(obj.getClass(), objectSize);
+ enqueueReferencedObjects(obj, calc);
+ }
+
+ public void enqueueReferencedObjects(final Object obj, final ObjectSizeCalculator calc) {
+ for (Field f : referenceFields) {
+ try {
+ calc.enqueue(f.get(obj));
+ } catch (IllegalAccessException e) {
+ final AssertionError ae = new AssertionError(
+ "Unexpected denial of access to " + f);
+ ae.initCause(e);
+ throw ae;
+ }
+ }
+ }
+ }
+
+ private static long getPrimitiveFieldSize(final Class<?> type) {
+ if (type == boolean.class || type == byte.class) {
+ return 1;
+ }
+ if (type == char.class || type == short.class) {
+ return 2;
+ }
+ if (type == int.class || type == float.class) {
+ return 4;
+ }
+ if (type == long.class || type == double.class) {
+ return 8;
+ }
+ throw new AssertionError("Encountered unexpected primitive type " +
+ type.getName());
+ }
+
+ /**
+ * Return the current memory usage
+ * @return current memory usage derived from system configuration
+ */
+ public static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification() {
+ final String vmName = System.getProperty("java.vm.name");
+ if (vmName == null || !vmName.startsWith("Java HotSpot(TM) ")) {
+ throw new UnsupportedOperationException(
+ "ObjectSizeCalculator only supported on HotSpot VM");
+ }
+
+ final String dataModel = System.getProperty("sun.arch.data.model");
+ if ("32".equals(dataModel)) {
+ // Running with 32-bit data model
+ return new MemoryLayoutSpecification() {
+ @Override public int getArrayHeaderSize() {
+ return 12;
+ }
+ @Override public int getObjectHeaderSize() {
+ return 8;
+ }
+ @Override public int getObjectPadding() {
+ return 8;
+ }
+ @Override public int getReferenceSize() {
+ return 4;
+ }
+ @Override public int getSuperclassFieldPadding() {
+ return 4;
+ }
+ };
+ } else if (!"64".equals(dataModel)) {
+ throw new UnsupportedOperationException("Unrecognized value '" +
+ dataModel + "' of sun.arch.data.model system property");
+ }
+
+ final String strVmVersion = System.getProperty("java.vm.version");
+ final int vmVersion = Integer.parseInt(strVmVersion.substring(0,
+ strVmVersion.indexOf('.')));
+ if (vmVersion >= 17) {
+ long maxMemory = 0;
+ for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
+ maxMemory += mp.getUsage().getMax();
+ }
+ if (maxMemory < 30L * 1024 * 1024 * 1024) {
+ // HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total
+ // for all memory pools (yes, including code cache).
+ return new MemoryLayoutSpecification() {
+ @Override public int getArrayHeaderSize() {
+ return 16;
+ }
+ @Override public int getObjectHeaderSize() {
+ return 12;
+ }
+ @Override public int getObjectPadding() {
+ return 8;
+ }
+ @Override public int getReferenceSize() {
+ return 4;
+ }
+ @Override public int getSuperclassFieldPadding() {
+ return 4;
+ }
+ };
+ }
+ }
+
+ // In other cases, it's a 64-bit uncompressed OOPs object model
+ return new MemoryLayoutSpecification() {
+ @Override public int getArrayHeaderSize() {
+ return 24;
+ }
+ @Override public int getObjectHeaderSize() {
+ return 16;
+ }
+ @Override public int getObjectPadding() {
+ return 8;
+ }
+ @Override public int getReferenceSize() {
+ return 8;
+ }
+ @Override public int getSuperclassFieldPadding() {
+ return 8;
+ }
+ };
+ }
+}
diff --git a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 8637b66d..3ac50067 100644
--- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -36,9 +36,9 @@ import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
@@ -55,7 +55,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
*/
public final class PrintVisitor extends NodeVisitor {
/** Tab width */
- private static final int TABWIDTH = 1;
+ private static final int TABWIDTH = 4;
/** Composing buffer. */
private final StringBuilder sb;
@@ -69,6 +69,8 @@ public final class PrintVisitor extends NodeVisitor {
/** Print line numbers */
private final boolean printLineNumbers;
+ private int lastLineNumber = -1;
+
/**
* Constructor.
*/
@@ -138,24 +140,27 @@ public final class PrintVisitor extends NodeVisitor {
@Override
public boolean enterBlock(final Block block) {
sb.append(' ');
+ //sb.append(Debug.id(block));
sb.append('{');
indent += TABWIDTH;
- final List<Node> statements = block.getStatements();
-
- boolean lastLineNumber = false;
+ final List<Statement> statements = block.getStatements();
for (final Node statement : statements) {
- if (printLineNumbers || !lastLineNumber) {
- sb.append(EOLN);
- indent();
+ if (printLineNumbers && (statement instanceof Statement)) {
+ final int lineNumber = ((Statement)statement).getLineNumber();
+ sb.append('\n');
+ if (lineNumber != lastLineNumber) {
+ indent();
+ sb.append("[|").append(lineNumber).append("|];").append('\n');
+ }
+ lastLineNumber = lineNumber;
}
+ indent();
statement.accept(this);
- lastLineNumber = statement instanceof LineNumberNode;
-
if (statement instanceof FunctionNode) {
continue;
}
@@ -168,12 +173,14 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(']');
}
- final char lastChar = sb.charAt(sb.length() - 1);
+ int lastIndex = sb.length() - 1;
+ char lastChar = sb.charAt(lastIndex);
+ while (Character.isWhitespace(lastChar) && lastIndex >= 0) {
+ lastChar = sb.charAt(--lastIndex);
+ }
if (lastChar != '}' && lastChar != ';') {
- if (printLineNumbers || !lastLineNumber) {
- sb.append(';');
- }
+ sb.append(';');
}
if (statement.hasGoto()) {
@@ -189,7 +196,8 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(EOLN);
indent();
- sb.append("}");
+ sb.append('}');
+ // sb.append(Debug.id(block));
return false;
}
@@ -221,7 +229,7 @@ public final class PrintVisitor extends NodeVisitor {
public boolean enterFunctionNode(final FunctionNode functionNode) {
functionNode.toString(sb);
enterBlock(functionNode.getBody());
- sb.append(EOLN);
+ //sb.append(EOLN);
return false;
}
@@ -252,15 +260,6 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
- public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- if (printLineNumbers) {
- lineNumberNode.toString(sb);
- }
-
- return false;
- }
-
- @Override
public boolean enterSplitNode(final SplitNode splitNode) {
splitNode.toString(sb);
sb.append(EOLN);
@@ -334,6 +333,7 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(" = ");
init.accept(this);
}
+
return false;
}
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 4f128412..2beba46c 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -149,7 +149,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
return enterASSIGN_SUB(binaryNode);
case BIND:
return enterBIND(binaryNode);
- case BIT_AND:
+ case BIT_AND:
return enterBIT_AND(binaryNode);
case BIT_OR:
return enterBIT_OR(binaryNode);
diff --git a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
index e3c0d34e..8c807df7 100644
--- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
+++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java
@@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@@ -454,26 +453,6 @@ public abstract class NodeVisitor {
}
/**
- * Callback for entering a LineNumberNode
- *
- * @param lineNumberNode the node
- * @return true if traversal should continue and node children be traversed, false otherwise
- */
- public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
- return enterDefault(lineNumberNode);
- }
-
- /**
- * Callback for leaving a LineNumberNode
- *
- * @param lineNumberNode the node
- * @return processed node, which will replace the original one, or the original node
- */
- public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
- return leaveDefault(lineNumberNode);
- }
-
- /**
* Callback for entering a LiteralNode
*
* @param literalNode the node
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index a659af4f..c9a71b57 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -297,7 +297,7 @@ public final class NativeArray extends ScriptObject {
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static Object length(final Object self) {
if (isArray(self)) {
- return ((NativeArray) self).getArray().length() & JSType.MAX_UINT;
+ return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT;
}
return 0;
@@ -311,7 +311,7 @@ public final class NativeArray extends ScriptObject {
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (isArray(self)) {
- ((NativeArray) self).setLength(validLength(length, true));
+ ((ScriptObject) self).setLength(validLength(length, true));
}
}
@@ -642,10 +642,9 @@ public final class NativeArray extends ScriptObject {
final boolean strict = sobj.isStrictContext();
if (bulkable(sobj)) {
- final NativeArray nativeArray = (NativeArray)sobj;
- if (nativeArray.getArray().length() + args.length <= JSType.MAX_UINT) {
- final ArrayData newData = nativeArray.getArray().push(nativeArray.isStrictContext(), args);
- nativeArray.setArray(newData);
+ if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
+ final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args);
+ sobj.setArray(newData);
return newData.length();
}
//fallthru
@@ -780,8 +779,7 @@ public final class NativeArray extends ScriptObject {
}
if (bulkable(sobj)) {
- final NativeArray narray = (NativeArray) sobj;
- return new NativeArray(narray.getArray().slice(k, finale));
+ return new NativeArray(sobj.getArray().slice(k, finale));
}
final NativeArray copy = new NativeArray(0);
@@ -1001,11 +999,10 @@ public final class NativeArray extends ScriptObject {
}
if (bulkable(sobj)) {
- final NativeArray nativeArray = (NativeArray) sobj;
- nativeArray.getArray().shiftRight(items.length);
+ sobj.getArray().shiftRight(items.length);
for (int j = 0; j < items.length; j++) {
- nativeArray.setArray(nativeArray.getArray().set(j, items[j], sobj.isStrictContext()));
+ sobj.setArray(sobj.getArray().set(j, items[j], sobj.isStrictContext()));
}
} else {
for (long k = len; k > 0; k--) {
diff --git a/src/jdk/nashorn/internal/objects/NativeDebug.java b/src/jdk/nashorn/internal/objects/NativeDebug.java
index aba76c8e..337f2e3d 100644
--- a/src/jdk/nashorn/internal/objects/NativeDebug.java
+++ b/src/jdk/nashorn/internal/objects/NativeDebug.java
@@ -87,66 +87,6 @@ public final class NativeDebug extends ScriptObject {
}
/**
- * Nashorn extension: get embed0 from {@link ScriptObject}
- *
- * @param self self reference
- * @param obj script object
- * @return the embed0 property value for the given ScriptObject
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object embed0(final Object self, final Object obj) {
- if (obj instanceof ScriptObject) {
- return ((ScriptObject)obj).embed0;
- }
- return UNDEFINED;
- }
-
- /**
- * Nashorn extension: get embed1 from {@link ScriptObject}
- *
- * @param self self reference
- * @param obj script object
- * @return the embed1 property value for the given ScriptObject
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object embed1(final Object self, final Object obj) {
- if (obj instanceof ScriptObject) {
- return ((ScriptObject)obj).embed1;
- }
- return UNDEFINED;
- }
-
- /**
- * Nashorn extension: get embed2 from {@link ScriptObject}
- *
- * @param self self reference
- * @param obj script object
- * @return the embed2 property value for the given ScriptObject
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object embed2(final Object self, final Object obj) {
- if (obj instanceof ScriptObject) {
- return ((ScriptObject)obj).embed2;
- }
- return UNDEFINED;
- }
-
- /**
- * Nashorn extension: get embed3 from {@link ScriptObject}
- *
- * @param self self reference
- * @param obj script object
- * @return the embed3 property value for the given ScriptObject
- */
- @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
- public static Object embed3(final Object self, final Object obj) {
- if (obj instanceof ScriptObject) {
- return ((ScriptObject)obj).embed3;
- }
- return UNDEFINED;
- }
-
- /**
* Nashorn extension: get spill vector from {@link ScriptObject}
*
* @param self self reference
diff --git a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index 8a3f42d2..153db769 100644
--- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -620,7 +620,7 @@ public final class NativeJSAdapter extends ScriptObject {
// to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
- adaptee.getMap().getProtoGetSwitchPoint(__call__), testJSAdaptor(adaptee, null, null, null));
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
default:
@@ -687,7 +687,7 @@ public final class NativeJSAdapter extends ScriptObject {
if (methodHandle != null) {
return new GuardedInvocation(
methodHandle,
- adaptee.getMap().getProtoGetSwitchPoint(hook),
+ adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
}
}
@@ -699,7 +699,7 @@ public final class NativeJSAdapter extends ScriptObject {
final MethodHandle methodHandle = hook.equals(__put__) ?
MH.asType(Lookup.EMPTY_SETTER, type) :
Lookup.emptyGetter(type.returnType());
- return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(hook), testJSAdaptor(adaptee, null, null, null));
+ return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook), testJSAdaptor(adaptee, null, null, null));
}
}
diff --git a/src/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk/nashorn/internal/objects/NativeRegExp.java
index 9a12911f..8b469bc1 100644
--- a/src/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -794,15 +794,15 @@ public final class NativeRegExp extends ScriptObject {
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 @@ public final class NativeRegExp extends ScriptObject {
}
}
- lastLength = match.length();
+ splitLastLength = match.length();
if (matches.size() >= limit) {
break;
@@ -818,10 +818,10 @@ public final class NativeRegExp extends ScriptObject {
}
// bump the index to avoid infinite loop
- if (lastIndex == lastLastIndex) {
- lastIndex++;
+ if (splitLastIndex == splitLastLastIndex) {
+ splitLastIndex++;
} else {
- lastLastIndex = lastIndex;
+ splitLastLastIndex = splitLastIndex;
}
}
@@ -829,12 +829,12 @@ public final class NativeRegExp extends ScriptObject {
// 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 @@ public final class NativeRegExp extends ScriptObject {
}
}
- private void setGlobal(final boolean global) {
- regexp.setGlobal(global);
- }
-
boolean getGlobal() {
return regexp.isGlobal();
}
diff --git a/src/jdk/nashorn/internal/parser/AbstractParser.java b/src/jdk/nashorn/internal/parser/AbstractParser.java
index 8f65e0f7..25b500ce 100644
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java
@@ -249,6 +249,7 @@ public abstract class AbstractParser {
*
* @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));
@@ -363,7 +364,7 @@ public abstract class AbstractParser {
next();
// Create IDENT node.
- return new IdentNode(source, identToken, finish, ident);
+ return new IdentNode(identToken, finish, ident);
}
// Get IDENT.
@@ -372,7 +373,7 @@ public abstract class AbstractParser {
return null;
}
// Create IDENT node.
- return new IdentNode(source, identToken, finish, ident);
+ return new IdentNode(identToken, finish, ident);
}
/**
@@ -407,7 +408,7 @@ public abstract class AbstractParser {
final String ident = (String)getValue(identToken);
next();
// Create IDENT node.
- return new IdentNode(source, identToken, finish, ident);
+ return new IdentNode(identToken, finish, ident);
} else {
expect(IDENT);
return null;
@@ -432,11 +433,11 @@ public abstract class AbstractParser {
LiteralNode<?> node = null;
if (value == null) {
- node = LiteralNode.newInstance(source, literalToken, finish);
+ node = LiteralNode.newInstance(literalToken, finish);
} else if (value instanceof Number) {
- node = LiteralNode.newInstance(source, literalToken, finish, (Number)value);
+ node = LiteralNode.newInstance(literalToken, finish, (Number)value);
} else if (value instanceof String) {
- node = LiteralNode.newInstance(source, literalToken, finish, (String)value);
+ node = LiteralNode.newInstance(literalToken, finish, (String)value);
} else if (value instanceof LexerToken) {
if (value instanceof RegexToken) {
final RegexToken regex = (RegexToken)value;
@@ -446,7 +447,7 @@ public abstract class AbstractParser {
throw error(e.getMessage());
}
}
- node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value);
+ node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value);
} else {
assert false : "unknown type for LiteralNode: " + value.getClass();
}
diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java
index e074cf01..d4985ea3 100644
--- a/src/jdk/nashorn/internal/parser/JSONParser.java
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java
@@ -193,13 +193,13 @@ public class JSONParser extends AbstractParser {
return getLiteral();
case FALSE:
next();
- return LiteralNode.newInstance(source, literalToken, finish, false);
+ return LiteralNode.newInstance(literalToken, finish, false);
case TRUE:
next();
- return LiteralNode.newInstance(source, literalToken, finish, true);
+ return LiteralNode.newInstance(literalToken, finish, true);
case NULL:
next();
- return LiteralNode.newInstance(source, literalToken, finish);
+ return LiteralNode.newInstance(literalToken, finish);
case LBRACKET:
return arrayLiteral();
case LBRACE:
@@ -218,7 +218,7 @@ public class JSONParser extends AbstractParser {
if (value instanceof Number) {
next();
- return new UnaryNode(source, literalToken, LiteralNode.newInstance(source, realToken, finish, (Number)value));
+ return new UnaryNode(literalToken, LiteralNode.newInstance(realToken, finish, (Number)value));
}
throw error(AbstractParser.message("expected", "number", type.getNameOrType()));
@@ -250,7 +250,7 @@ loop:
switch (type) {
case RBRACKET:
next();
- result = LiteralNode.newInstance(source, arrayToken, finish, elements);
+ result = LiteralNode.newInstance(arrayToken, finish, elements);
break loop;
case COMMARIGHT:
@@ -310,7 +310,7 @@ loop:
}
// Construct new object literal.
- return new ObjectNode(source, objectToken, finish, elements);
+ return new ObjectNode(objectToken, finish, elements);
}
/**
@@ -331,7 +331,7 @@ loop:
if (name != null) {
expect(COLON);
final Node value = jsonLiteral();
- return new PropertyNode(source, propertyToken, value.getFinish(), name, value, null, null);
+ return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null);
}
// Raise an error.
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index ab70859b..efb7a391 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -59,9 +59,11 @@ import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.AccessNode;
+import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext;
@@ -81,7 +83,6 @@ import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
@@ -90,6 +91,7 @@ import jdk.nashorn.internal.ir.PropertyKey;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode;
@@ -117,7 +119,7 @@ public class Parser extends AbstractParser {
/** Is scripting mode. */
private final boolean scripting;
- private List<Node> functionDeclarations;
+ private List<Statement> functionDeclarations;
private final BlockLexicalContext lc = new BlockLexicalContext();
@@ -275,8 +277,7 @@ loop:
* @return New block.
*/
private Block newBlock() {
- final Block block = new Block(source, token, Token.descPosition(token));
- return lc.push(block);
+ return lc.push(new Block(line, token, Token.descPosition(token)));
}
/**
@@ -305,11 +306,17 @@ loop:
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 =
new FunctionNode(
source,
+ line, //TODO?
token,
Token.descPosition(token),
startToken,
@@ -320,11 +327,11 @@ loop:
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 +339,19 @@ loop:
* 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.
@@ -469,7 +481,7 @@ loop:
}
// Build up node.
- return new BinaryNode(source, op, lhs, rhs);
+ return new BinaryNode(op, lhs, rhs);
}
/**
@@ -480,12 +492,12 @@ loop:
* @param isPostfix Prefix or postfix.
* @return Reduced expression.
*/
- private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
+ private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
if (isPostfix) {
- return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
+ return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
}
- return new UnaryNode(source, firstToken, expression);
+ return new UnaryNode(firstToken, expression);
}
/**
@@ -514,7 +526,7 @@ loop:
FunctionNode script = newFunctionNode(
functionToken,
- new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
+ new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
new ArrayList<IdentNode>(),
FunctionNode.Kind.SCRIPT);
@@ -529,6 +541,7 @@ loop:
script = restoreFunctionNode(script, token); //commit code
script = script.setBody(lc, script.getBody().setNeedsScope(lc));
+
return script;
}
@@ -670,8 +683,6 @@ loop:
* @param topLevel does this statement occur at the "top level" of a script or a function?
*/
private void statement(final boolean topLevel) {
- final LineNumberNode lineNumberNode = lineNumber();
-
if (type == FUNCTION) {
// As per spec (ECMA section 12), function declarations as arbitrary statement
// is not "portable". Implementation can issue a warning or disallow the same.
@@ -679,10 +690,6 @@ loop:
return;
}
- if (lineNumberNode != null) {
- appendStatement(lineNumberNode);
- }
-
switch (type) {
case LBRACE:
block();
@@ -763,7 +770,7 @@ loop:
private void block() {
final Block newBlock = getBlock(true);
// Force block execution.
- appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
+ appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
}
/**
@@ -800,7 +807,6 @@ loop:
* @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()) {
@@ -840,6 +846,7 @@ loop:
while (true) {
// Get starting token.
+ final int varLine = line;
final long varToken = token;
// Get name of var.
final IdentNode name = getIdent();
@@ -857,7 +864,7 @@ loop:
}
// Allocate var node.
- final VarNode var = new VarNode(source, varToken, finish, name, init);
+ final VarNode var = new VarNode(varLine, varToken, finish, name, init);
vars.add(var);
appendStatement(var);
@@ -889,7 +896,7 @@ loop:
*/
private void emptyStatement() {
if (env._empty_statements) {
- appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
+ appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
}
// SEMICOLON checked in caller.
@@ -906,6 +913,7 @@ loop:
*/
private void expressionStatement() {
// Lookahead checked in caller.
+ final int expressionLine = line;
final long expressionToken = token;
// Get expression and add as statement.
@@ -913,7 +921,7 @@ loop:
ExecuteNode executeNode = null;
if (expression != null) {
- executeNode = new ExecuteNode(source, expressionToken, finish, expression);
+ executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
appendStatement(executeNode);
} else {
expect(null);
@@ -938,6 +946,7 @@ loop:
*/
private void ifStatement() {
// Capture IF token.
+ final int ifLine = line;
final long ifToken = token;
// IF tested in caller.
next();
@@ -953,7 +962,7 @@ loop:
fail = getStatement();
}
- appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
+ appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
}
/**
@@ -970,8 +979,7 @@ loop:
*/
private void forStatement() {
// Create FOR node, capturing FOR token.
- ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
-
+ ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
// Set up new block for scope of vars. Captures first token.
Block outer = newBlock();
@@ -1074,7 +1082,7 @@ loop:
outer = restoreBlock(outer);
}
- appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1105,12 +1113,13 @@ loop:
*/
private void whileStatement() {
// Capture WHILE token.
+ final int whileLine = line;
final long whileToken = token;
// WHILE tested in caller.
next();
// Construct WHILE node.
- WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
+ WhileNode whileNode = new WhileNode(whileLine, whileToken, Token.descPosition(whileToken), false);
lc.push(whileNode);
try {
@@ -1136,11 +1145,12 @@ loop:
*/
private void doStatement() {
// Capture DO token.
+ final int doLine = line;
final long doToken = token;
// DO tested in the caller.
next();
- WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
+ WhileNode doWhileNode = new WhileNode(doLine, doToken, Token.descPosition(doToken), true);
lc.push(doWhileNode);
try {
@@ -1172,6 +1182,7 @@ loop:
*/
private void continueStatement() {
// Capture CONTINUE token.
+ final int continueLine = line;
final long continueToken = token;
// CONTINUE tested in caller.
nextOrEOL();
@@ -1206,7 +1217,7 @@ loop:
endOfLine();
// Construct and add CONTINUE node.
- appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
+ appendStatement(new ContinueNode(continueLine, continueToken, finish, label == null ? null : new IdentNode(label)));
}
/**
@@ -1218,6 +1229,7 @@ loop:
*/
private void breakStatement() {
// Capture BREAK token.
+ final int breakLine = line;
final long breakToken = token;
// BREAK tested in caller.
nextOrEOL();
@@ -1253,7 +1265,7 @@ loop:
endOfLine();
// Construct and add BREAK node.
- appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
+ appendStatement(new BreakNode(breakLine, breakToken, finish, label == null ? null : new IdentNode(label)));
}
/**
@@ -1271,6 +1283,7 @@ loop:
}
// Capture RETURN token.
+ final int returnLine = line;
final long returnToken = token;
// RETURN tested in caller.
nextOrEOL();
@@ -1292,7 +1305,7 @@ loop:
endOfLine();
// Construct and add RETURN node.
- appendStatement(new ReturnNode(source, returnToken, finish, expression));
+ appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
}
/**
@@ -1305,6 +1318,7 @@ loop:
*/
private void yieldStatement() {
// Capture YIELD token.
+ final int yieldLine = line;
final long yieldToken = token;
// YIELD tested in caller.
nextOrEOL();
@@ -1326,7 +1340,7 @@ loop:
endOfLine();
// Construct and add YIELD node.
- appendStatement(new ReturnNode(source, yieldToken, finish, expression));
+ appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
}
/**
@@ -1339,6 +1353,7 @@ loop:
*/
private void withStatement() {
// Capture WITH token.
+ final int withLine = line;
final long withToken = token;
// WITH tested in caller.
next();
@@ -1349,7 +1364,7 @@ loop:
}
// Get WITH expression.
- WithNode withNode = new WithNode(source, withToken, finish);
+ WithNode withNode = new WithNode(withLine, withToken, finish);
try {
lc.push(withNode);
@@ -1387,12 +1402,13 @@ loop:
* Parse SWITCH statement.
*/
private void switchStatement() {
+ final int switchLine = line;
final long switchToken = token;
// SWITCH tested in caller.
next();
// Create and add switch statement.
- SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+ SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
lc.push(switchNode);
try {
@@ -1434,7 +1450,7 @@ loop:
// Get CASE body.
final Block statements = getBlock(false);
- final CaseNode caseNode = new CaseNode(source, caseToken, finish, caseExpression, statements);
+ final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
statements.setFinish(finish);
if (caseExpression == null) {
@@ -1474,7 +1490,7 @@ loop:
throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
}
- LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
+ LabelNode labelNode = new LabelNode(line, labelToken, finish, ident, null);
try {
lc.push(labelNode);
labelNode = labelNode.setBody(lc, getStatement());
@@ -1496,6 +1512,7 @@ loop:
*/
private void throwStatement() {
// Capture THROW token.
+ final int throwLine = line;
final long throwToken = token;
// THROW tested in caller.
nextOrEOL();
@@ -1520,7 +1537,7 @@ loop:
endOfLine();
- appendStatement(new ThrowNode(source, throwToken, finish, expression));
+ appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
}
/**
@@ -1542,6 +1559,7 @@ loop:
*/
private void tryStatement() {
// Capture TRY token.
+ final int tryLine = line;
final long tryToken = token;
// TRY tested in caller.
next();
@@ -1556,6 +1574,7 @@ loop:
final List<Block> catchBlocks = new ArrayList<>();
while (type == CATCH) {
+ final int catchLine = line;
final long catchToken = token;
next();
expect(LPAREN);
@@ -1578,7 +1597,7 @@ loop:
try {
// Get CATCH body.
final Block catchBody = getBlock(true);
- final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
+ final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
appendStatement(catchNode);
} finally {
catchBlock = restoreBlock(catchBlock);
@@ -1604,7 +1623,7 @@ loop:
throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
}
- final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+ final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
// Add try.
assert lc.peek() == outer;
appendStatement(tryNode);
@@ -1616,7 +1635,7 @@ loop:
outer = restoreBlock(outer);
}
- appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1629,11 +1648,12 @@ loop:
*/
private void debuggerStatement() {
// Capture DEBUGGER token.
+ final int debuggerLine = line;
final long debuggerToken = token;
// DEBUGGER tested in caller.
next();
endOfLine();
- appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
+ appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
}
/**
@@ -1653,13 +1673,14 @@ loop:
@SuppressWarnings("fallthrough")
private Node primaryExpression() {
// Capture first token.
+ final int primaryLine = line;
final long primaryToken = token;
switch (type) {
case THIS:
final String name = type.getName();
next();
- return new IdentNode(source, primaryToken, finish, name);
+ return new IdentNode(primaryToken, finish, name);
case IDENT:
final IdentNode ident = getIdent();
if (ident == null) {
@@ -1680,16 +1701,16 @@ loop:
case XML:
return getLiteral();
case EXECSTRING:
- return execString(primaryToken);
+ return execString(primaryLine, primaryToken);
case FALSE:
next();
- return LiteralNode.newInstance(source, primaryToken, finish, false);
+ return LiteralNode.newInstance(primaryToken, finish, false);
case TRUE:
next();
- return LiteralNode.newInstance(source, primaryToken, finish, true);
+ return LiteralNode.newInstance(primaryToken, finish, true);
case NULL:
next();
- return LiteralNode.newInstance(source, primaryToken, finish);
+ return LiteralNode.newInstance(primaryToken, finish);
case LBRACKET:
return arrayLiteral();
case LBRACE:
@@ -1724,9 +1745,9 @@ loop:
* @param primaryToken Original string token.
* @return callNode to $EXEC.
*/
- Node execString(final long primaryToken) {
+ Node execString(final int primaryLine, final long primaryToken) {
// Synthesize an ident to call $EXEC.
- final IdentNode execIdent = new IdentNode(source, primaryToken, finish, ScriptingFunctions.EXEC_NAME);
+ final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
// Skip over EXECSTRING.
next();
// Set up argument list for call.
@@ -1738,7 +1759,7 @@ loop:
// Skip ending of edit string expression.
expect(RBRACE);
- return new CallNode(source, primaryToken, finish, execIdent, arguments);
+ return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments);
}
/**
@@ -1809,7 +1830,7 @@ loop:
}
}
- return LiteralNode.newInstance(source, arrayToken, finish, elements);
+ return LiteralNode.newInstance(arrayToken, finish, elements);
}
/**
@@ -1916,7 +1937,7 @@ loop:
map.put(key, newProperty = newProperty.setValue(value));
} else {
final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
- map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
+ map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
}
map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
@@ -1933,7 +1954,7 @@ loop:
}
}
- return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
+ return new ObjectNode(objectToken, finish, new ArrayList<Node>(map.values()));
}
/**
@@ -2003,16 +2024,16 @@ loop:
case "get":
final PropertyKey getIdent = propertyName();
final String getterName = getIdent.getPropertyName();
- final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
+ final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, "get " + getterName);
expect(LPAREN);
expect(RPAREN);
functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
- return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
+ return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null);
case "set":
final PropertyKey setIdent = propertyName();
final String setterName = setIdent.getPropertyName();
- final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName);
+ final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, "set " + setterName);
expect(LPAREN);
final IdentNode argIdent = getIdent();
verifyStrictIdent(argIdent, "setter argument");
@@ -2020,21 +2041,21 @@ loop:
List<IdentNode> parameters = new ArrayList<>();
parameters.add(argIdent);
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
- return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
+ return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode);
default:
break;
}
}
- propertyName = new IdentNode(source, propertyToken, finish, ident);
+ propertyName = new IdentNode(propertyToken, finish, ident);
} else {
propertyName = propertyName();
}
expect(COLON);
- return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
+ return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
}
/**
@@ -2054,6 +2075,7 @@ loop:
* @return Expression node.
*/
private Node leftHandSideExpression() {
+ int callLine = line;
long callToken = token;
Node lhs = memberExpression();
@@ -2066,12 +2088,13 @@ loop:
detectSpecialFunction((IdentNode)lhs);
}
- lhs = new CallNode(source, callToken, finish, lhs, arguments);
+ lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
}
loop:
while (true) {
// Capture token.
+ callLine = line;
callToken = token;
switch (type) {
@@ -2080,7 +2103,7 @@ loop:
final List<Node> arguments = argumentList();
// Create call node.
- lhs = new CallNode(source, callToken, finish, lhs, arguments);
+ lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
break;
@@ -2093,7 +2116,7 @@ loop:
expect(RBRACKET);
// Create indexing node.
- lhs = new IndexNode(source, callToken, finish, lhs, rhs);
+ lhs = new IndexNode(callToken, finish, lhs, rhs);
break;
@@ -2103,7 +2126,7 @@ loop:
final IdentNode property = getIdentifierName();
// Create property access node.
- lhs = new AccessNode(source, callToken, finish, lhs, property);
+ lhs = new AccessNode(callToken, finish, lhs, property);
break;
@@ -2131,6 +2154,7 @@ loop:
next();
// Get function base.
+ final int callLine = line;
final Node constructor = memberExpression();
if (constructor == null) {
return null;
@@ -2159,9 +2183,9 @@ loop:
arguments.add(objectLiteral());
}
- final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments);
+ final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
- return new UnaryNode(source, newToken, callNode);
+ return new UnaryNode(newToken, callNode);
}
/**
@@ -2213,7 +2237,7 @@ loop:
expect(RBRACKET);
// Create indexing node.
- lhs = new IndexNode(source, callToken, finish, lhs, index);
+ lhs = new IndexNode(callToken, finish, lhs, index);
break;
@@ -2227,7 +2251,7 @@ loop:
final IdentNode property = getIdentifierName();
// Create property access node.
- lhs = new AccessNode(source, callToken, finish, lhs, property);
+ lhs = new AccessNode(callToken, finish, lhs, property);
break;
@@ -2294,9 +2318,8 @@ loop:
* @return Expression node.
*/
private Node functionExpression(final boolean isStatement, final boolean topLevel) {
- final LineNumberNode lineNumber = lineNumber();
-
final long functionToken = token;
+ final int functionLine = line;
// FUNCTION is tested in caller.
next();
@@ -2316,7 +2339,7 @@ loop:
boolean isAnonymous = false;
if (name == null) {
final String tmpName = "_L" + source.getLine(Token.descPosition(token));
- name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName);
+ name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
isAnonymous = true;
}
@@ -2367,7 +2390,7 @@ loop:
// rename in non-strict mode
parameterName = functionNode.uniqueName(parameterName);
final long parameterToken = parameter.getToken();
- parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+ parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
}
parametersSet.add(parameterName);
@@ -2379,12 +2402,10 @@ loop:
}
if (isStatement) {
- final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+ final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
if (topLevel) {
- functionDeclarations.add(lineNumber);
functionDeclarations.add(varNode);
} else {
- appendStatement(lineNumber);
appendStatement(varNode);
}
}
@@ -2459,7 +2480,7 @@ loop:
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
// create a return statement - this creates code in itself and does not need to be
// wrapped into an ExecuteNode
- final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
+ final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), finish, expr);
appendStatement(returnNode);
lastToken = token;
functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
@@ -2468,7 +2489,7 @@ loop:
expect(LBRACE);
// Gather the function elements.
- final List<Node> prevFunctionDecls = functionDeclarations;
+ final List<Statement> prevFunctionDecls = functionDeclarations;
functionDeclarations = new ArrayList<>();
try {
sourceElements();
@@ -2492,7 +2513,7 @@ loop:
assert lc.peek() == lc.getFunctionBody(functionNode);
VarNode lastDecl = null;
for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
- Node decl = functionDeclarations.get(i);
+ Statement decl = functionDeclarations.get(i);
if (lastDecl == null && decl instanceof VarNode) {
decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
@@ -2501,16 +2522,16 @@ loop:
}
}
- private RuntimeNode referenceError(final Node lhs, final Node rhs) {
+ private static RuntimeNode referenceError(final Node lhs, final Node rhs) {
final ArrayList<Node> args = new ArrayList<>();
args.add(lhs);
if (rhs == null) {
- args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish()));
+ args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
} else {
args.add(rhs);
}
- args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
- return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
+ args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
+ return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
}
/*
@@ -2548,10 +2569,19 @@ loop:
* @return Expression node.
*/
private Node unaryExpression() {
+ final int unaryLine = line;
final long unaryToken = token;
switch (type) {
- case DELETE:
+ case DELETE: {
+ next();
+ final Node expr = unaryExpression();
+ if (expr instanceof BaseNode || expr instanceof IdentNode) {
+ return new UnaryNode(unaryToken, expr);
+ }
+ appendStatement(new ExecuteNode(unaryLine, unaryToken, finish, expr));
+ return LiteralNode.newInstance(unaryToken, finish, true);
+ }
case VOID:
case TYPEOF:
case ADD:
@@ -2560,7 +2590,7 @@ loop:
case NOT:
next();
final Node expr = unaryExpression();
- return new UnaryNode(source, unaryToken, expr);
+ return new UnaryNode(unaryToken, expr);
case INCPREFIX:
case DECPREFIX:
@@ -2749,7 +2779,7 @@ loop:
final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
// Build up node.
- lhs = new TernaryNode(source, op, lhs, rhs, third);
+ lhs = new TernaryNode(op, lhs, rhs, third);
} else {
// Skip operator.
next();
@@ -2805,16 +2835,6 @@ loop:
}
}
- /**
- * Add a line number node at current position
- */
- private LineNumberNode lineNumber() {
- if (env._debug_lines) {
- return new LineNumberNode(source, token, line);
- }
- return null;
- }
-
@Override
public String toString() {
return "[JavaScript Parsing]";
@@ -2835,11 +2855,11 @@ loop:
}
}
- private void prependStatement(final Node statement) {
+ private void prependStatement(final Statement statement) {
lc.prependStatement(statement);
}
- private void appendStatement(final Node statement) {
+ private void appendStatement(final Statement statement) {
lc.appendStatement(statement);
}
}
diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index b0ca46f7..38effdaf 100644
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -50,8 +50,6 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory;
/**
* An AccessorProperty is the most generic property type. An AccessorProperty is
* represented as fields in a ScriptObject class.
- *
- * @see SpillProperty
*/
public class AccessorProperty extends Property {
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
@@ -77,6 +75,7 @@ public class AccessorProperty extends Property {
private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
+ private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
/** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
private MethodHandle primitiveGetter;
@@ -285,7 +284,7 @@ public class AccessorProperty extends Property {
"get");
}
- return getters[i];
+ return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
}
private Property getWiderProperty(final Class<?> type) {
@@ -327,6 +326,7 @@ public class AccessorProperty extends Property {
final Class<?> forType = currentType == null ? type : currentType;
//if we are asking for an object setter, but are still a primitive type, we might try to box it
+ MethodHandle mh;
if (needsInvalidator(i, ci)) {
final Property newProperty = getWiderProperty(type);
@@ -335,12 +335,15 @@ public class AccessorProperty extends Property {
final MethodHandle explodeTypeSetter = MH.filterArguments(widerSetter, 0, MH.insertArguments(REPLACE_MAP, 1, newMap, getKey(), currentType, type));
if (currentType != null && currentType.isPrimitive() && type == Object.class) {
//might try a box check on this to avoid widening field to object storage
- return createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter);
+ mh = createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter);
+ } else {
+ mh = explodeTypeSetter;
}
- return explodeTypeSetter;
+ } else {
+ mh = generateSetter(forType, type);
}
- return generateSetter(forType, type);
+ return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh;
}
@Override
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
index 3cc9f09d..d36f216c 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -88,7 +88,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
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;
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
index ff660d3d..1ddc42b5 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java
@@ -69,5 +69,4 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return best(type).moreGenericThan(type);
}
-
}
diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java
index 40fe1ba1..338a8264 100644
--- a/src/jdk/nashorn/internal/runtime/Context.java
+++ b/src/jdk/nashorn/internal/runtime/Context.java
@@ -201,9 +201,6 @@ public final class Context {
/** Current error manager. */
private final ErrorManager errors;
- /** Empty map used for seed map for JO objects */
- final PropertyMap emptyMap = PropertyMap.newEmptyMap(this);
-
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
@@ -414,7 +411,7 @@ public final class Context {
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
@@ -513,7 +510,7 @@ public final class Context {
/**
* Lookup a Java class. This is used for JSR-223 stuff linking in from
- * {@link jdk.nashorn.internal.objects.NativeJava} and {@link jdk.nashorn.internal.runtime.NativeJavaPackage}
+ * {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
*
* @param fullName full name of class to load
*
@@ -762,10 +759,10 @@ public final class Context {
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);
diff --git a/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/src/jdk/nashorn/internal/runtime/JSONFunctions.java
index 729df58c..6106a314 100644
--- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java
@@ -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;
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index dfb8bf5d..585fc4b3 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -41,7 +41,6 @@ import jdk.nashorn.internal.codegen.types.Type;
*
* @see PropertyMap
* @see AccessorProperty
- * @see SpillProperty
* @see UserAccessorProperty
*/
public abstract class Property {
@@ -64,7 +63,7 @@ public abstract class Property {
private static final int MODIFY_MASK = 0b0000_0000_1111;
- /** Is this a spill property? See {@link SpillProperty} */
+ /** Is this a spill property? See {@link AccessorProperty} */
public static final int IS_SPILL = 0b0000_0001_0000;
/** Is this a function parameter? */
@@ -88,7 +87,7 @@ public abstract class Property {
/** Property flags. */
protected int flags;
- /** Property field number or spill slot */
+ /** Property field number or spill slot. */
private final int slot;
/**
@@ -248,7 +247,7 @@ public abstract class Property {
* Does this property use any slots in the spill array described in
* {@link Property#isSpill}? In that case how many. Currently a property
* only uses max one spill slot, but this may change in future representations
- * Only {@link SpillProperty} instances use spill slots
+ * Only {@link AccessorProperty} instances use spill slots
*
* @return number of spill slots a property is using
*/
@@ -345,6 +344,14 @@ public abstract class Property {
}
/**
+ * Get the field number or spill slot
+ * @return number/slot, -1 if none exists
+ */
+ public int getSlot() {
+ return slot;
+ }
+
+ /**
* Abstract method for retrieving the setter for the property. We do not know
* anything about the internal representation when we request the setter, we only
* know that the setter will take the property as a parameter of the given type.
@@ -388,14 +395,6 @@ public abstract class Property {
return null;
}
- /**
- * Get the field number or spill slot
- * @return number/slot, -1 if none exists
- */
- public int getSlot() {
- return slot;
- }
-
@Override
public int hashCode() {
final Class<?> type = getCurrentType();
diff --git a/src/jdk/nashorn/internal/runtime/PropertyHashMap.java b/src/jdk/nashorn/internal/runtime/PropertyHashMap.java
index 6e41fd56..bfa06920 100644
--- a/src/jdk/nashorn/internal/runtime/PropertyHashMap.java
+++ b/src/jdk/nashorn/internal/runtime/PropertyHashMap.java
@@ -110,7 +110,7 @@ public final class PropertyHashMap implements Map <String, Property> {
private static final int LIST_THRESHOLD = 8;
/** Initial map. */
- public static final PropertyHashMap EMPTY_MAP = new PropertyHashMap();
+ public static final PropertyHashMap EMPTY_HASHMAP = new PropertyHashMap();
/** Number of properties in the map. */
private final int size;
@@ -246,7 +246,7 @@ public final class PropertyHashMap implements Map <String, Property> {
}
} else if (findElement(list, key) != null) {
final int newSize = size - 1;
- return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_MAP;
+ return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_HASHMAP;
}
return this;
}
diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java
index b5154c85..077218d3 100644
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java
@@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime;
-import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_MAP;
+import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
@@ -49,29 +49,27 @@ import java.util.WeakHashMap;
* will return a new map.
*/
public final class PropertyMap implements Iterable<Object>, PropertyListener {
- /** Is this a prototype PropertyMap? */
- public static final int IS_PROTOTYPE = 0b0000_0001;
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
- public static final int NOT_EXTENSIBLE = 0b0000_0010;
+ public static final int NOT_EXTENSIBLE = 0b0000_0001;
/** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */
private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111;
/** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */
public static final int IS_LISTENER_ADDED = 0b0001_0000;
+ /** Empty map used for seed map for JO$ objects */
+ private static final PropertyMap EMPTY_MAP = new PropertyMap(EMPTY_HASHMAP);
+
/** Map status flags. */
private int flags;
- /** Class of object referenced.*/
- private final Class<?> structure;
-
- /** Context associated with this {@link PropertyMap}. */
- private final Context context;
-
/** Map of properties. */
private final PropertyHashMap properties;
- /** objects proto. */
- private ScriptObject proto;
+ /** Number of fields in use. */
+ private int fieldCount;
+
+ /** Number of fields available. */
+ private int fieldMaximum;
/** Length of spill in use. */
private int spillLength;
@@ -91,15 +89,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
/**
* Constructor.
*
- * @param structure Class the map's {@link AccessorProperty}s apply to.
- * @param context Context associated with this {@link PropertyMap}.
- * @param properties A {@link PropertyHashMap} with initial contents.
+ * @param properties A {@link PropertyHashMap} with initial contents.
+ * @param fieldCount Number of fields in use.
+ * @param fieldMaximum Number of fields available.
*/
- PropertyMap(final Class<?> structure, final Context context, final PropertyHashMap properties) {
- this.structure = structure;
- this.context = context;
- this.properties = properties;
- this.hashCode = computeHashCode();
+ private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) {
+ this.properties = properties;
+ this.hashCode = computeHashCode();
+ this.fieldCount = fieldCount;
+ this.fieldMaximum = fieldMaximum;
if (Context.DEBUG) {
count++;
@@ -107,19 +105,27 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
+ * Constructor.
+ *
+ * @param properties A {@link PropertyHashMap} with initial contents.
+ */
+ private PropertyMap(final PropertyHashMap properties) {
+ this(properties, 0, 0);
+ }
+
+ /**
* Cloning constructor.
*
* @param propertyMap Existing property map.
* @param properties A {@link PropertyHashMap} with a new set of properties.
*/
private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
- this.structure = propertyMap.structure;
- this.context = propertyMap.context;
- this.properties = properties;
- this.flags = propertyMap.getClonedFlags();
- this.proto = propertyMap.proto;
- this.spillLength = propertyMap.spillLength;
- this.hashCode = computeHashCode();
+ this.properties = properties;
+ this.flags = propertyMap.getClonedFlags();
+ this.spillLength = propertyMap.spillLength;
+ this.fieldCount = propertyMap.fieldCount;
+ this.fieldMaximum = propertyMap.fieldMaximum;
+ this.hashCode = computeHashCode();
if (Context.DEBUG) {
count++;
@@ -128,6 +134,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
+ * Cloning constructor.
+ *
+ * @param propertyMap Existing property map.
+ */
+ private PropertyMap(final PropertyMap propertyMap) {
+ this(propertyMap, propertyMap.properties);
+ }
+
+ /**
* Duplicates this PropertyMap instance. This is used by nasgen generated
* prototype and constructor classes. {@link PropertyMap} used for singletons
* like these (and global instance) are duplicated using this method and used.
@@ -138,7 +153,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return Duplicated {@link PropertyMap}.
*/
public PropertyMap duplicate() {
- return new PropertyMap(this.structure, this.context, this.properties);
+ return new PropertyMap(this.properties);
}
/**
@@ -146,20 +161,20 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
*
* @param structure Class the map's {@link AccessorProperty}s apply to.
* @param properties Collection of initial properties.
+ * @param fieldCount Number of fields in use.
+ * @param fieldMaximum Number of fields available.
*
* @return New {@link PropertyMap}.
*/
- public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties) {
- final Context context = Context.fromClass(structure);
-
+ public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties, final int fieldCount, final int fieldMaximum) {
// Reduce the number of empty maps in the context.
if (structure == jdk.nashorn.internal.scripts.JO.class) {
- return context.emptyMap;
+ return EMPTY_MAP;
}
- PropertyHashMap newProperties = EMPTY_MAP.immutableAdd(properties);
+ PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
- return new PropertyMap(structure, context, newProperties);
+ return new PropertyMap(newProperties, fieldCount, fieldMaximum);
}
/**
@@ -170,7 +185,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New {@link PropertyMap}.
*/
public static PropertyMap newMap(final Class<?> structure) {
- return newMap(structure, null);
+ return newMap(structure, null, 0, 0);
}
/**
@@ -180,7 +195,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New empty {@link PropertyMap}.
*/
public static PropertyMap newEmptyMap(final Context context) {
- return new PropertyMap(jdk.nashorn.internal.scripts.JO.class, context, EMPTY_MAP);
+ return new PropertyMap(EMPTY_HASHMAP);
}
/**
@@ -195,11 +210,12 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
/**
* Return a SwitchPoint used to track changes of a property in a prototype.
*
- * @param key {@link Property} key.
+ * @param proto Object prototype.
+ * @param key {@link Property} key.
*
* @return A shared {@link SwitchPoint} for the property.
*/
- public SwitchPoint getProtoGetSwitchPoint(final String key) {
+ public SwitchPoint getProtoGetSwitchPoint(final ScriptObject proto, final String key) {
if (proto == null) {
return null;
}
@@ -295,6 +311,11 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyHashMap newProperties = properties.immutableAdd(property);
newMap = new PropertyMap(this, newProperties);
addToHistory(property, newMap);
+
+ if(!property.isSpill()) {
+ newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1);
+ }
+
newMap.spillLength += property.getSpillCount();
}
@@ -355,7 +376,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted";
newMap.flags = getClonedFlags();
- newMap.proto = proto;
/*
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
@@ -411,7 +431,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New map with {@link #NOT_EXTENSIBLE} flag set.
*/
PropertyMap preventExtensions() {
- final PropertyMap newMap = new PropertyMap(this, this.properties);
+ final PropertyMap newMap = new PropertyMap(this);
newMap.flags |= NOT_EXTENSIBLE;
return newMap;
}
@@ -423,7 +443,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* {@link Property#NOT_CONFIGURABLE} set.
*/
PropertyMap seal() {
- PropertyHashMap newProperties = EMPTY_MAP;
+ PropertyHashMap newProperties = EMPTY_HASHMAP;
for (final Property oldProperty : properties.getProperties()) {
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
@@ -442,7 +462,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set.
*/
PropertyMap freeze() {
- PropertyHashMap newProperties = EMPTY_MAP;
+ PropertyHashMap newProperties = EMPTY_HASHMAP;
for (Property oldProperty : properties.getProperties()) {
int propertyFlags = Property.NOT_CONFIGURABLE;
@@ -578,11 +598,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return Computed hash code.
*/
private int computeHashCode() {
- int hash = structure.hashCode();
-
- if (proto != null) {
- hash ^= proto.hashCode();
- }
+ int hash = 0;
for (final Property property : getProperties()) {
hash = hash << 7 ^ hash >> 7;
@@ -605,9 +621,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyMap otherMap = (PropertyMap)other;
- if (structure != otherMap.structure ||
- proto != otherMap.proto ||
- properties.size() != otherMap.properties.size()) {
+ if (properties.size() != otherMap.properties.size()) {
return false;
}
@@ -659,31 +673,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
- * Return map's {@link Context}.
- *
- * @return The {@link Context} where the map originated.
- */
- Context getContext() {
- return context;
- }
-
- /**
- * Check if this map is a prototype
- *
- * @return {@code true} if is prototype
- */
- public boolean isPrototype() {
- return (flags & IS_PROTOTYPE) != 0;
- }
-
- /**
- * Flag this map as having a prototype.
- */
- private void setIsPrototype() {
- flags |= IS_PROTOTYPE;
- }
-
- /**
* Check whether a {@link PropertyListener} has been added to this map.
*
* @return {@code true} if {@link PropertyListener} exists
@@ -720,35 +709,41 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
boolean isFrozen() {
return !isExtensible() && allFrozen();
}
-
/**
- * Get length of spill area associated with this {@link PropertyMap}.
+ * Get the number of fields allocated for this {@link PropertyMap}.
*
- * @return Length of spill area.
+ * @return Number of fields allocated.
*/
- int getSpillLength() {
- return spillLength;
+ int getFieldCount() {
+ return fieldCount;
+ }
+ /**
+ * Get maximum number of fields available for this {@link PropertyMap}.
+ *
+ * @return Number of fields available.
+ */
+ int getFieldMaximum() {
+ return fieldMaximum;
}
/**
- * Return the prototype of objects associated with this {@link PropertyMap}.
+ * Get length of spill area associated with this {@link PropertyMap}.
*
- * @return Prototype object.
+ * @return Length of spill area.
*/
- ScriptObject getProto() {
- return proto;
+ int getSpillLength() {
+ return spillLength;
}
/**
- * Set the prototype of objects associated with this {@link PropertyMap}.
+ * Change the prototype of objects associated with this {@link PropertyMap}.
*
- * @param newProto Prototype object to use.
+ * @param oldProto Current prototype object.
+ * @param newProto New prototype object to replace oldProto.
*
* @return New {@link PropertyMap} with prototype changed.
*/
- PropertyMap setProto(final ScriptObject newProto) {
- final ScriptObject oldProto = this.proto;
-
+ PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) {
if (oldProto == newProto) {
return this;
}
@@ -761,18 +756,9 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
if (Context.DEBUG) {
incrementSetProtoNewMapCount();
}
- final PropertyMap newMap = new PropertyMap(this, this.properties);
- addToProtoHistory(newProto, newMap);
-
- newMap.proto = newProto;
-
- if (oldProto != null && newMap.isListenerAdded()) {
- oldProto.removePropertyListener(newMap);
- }
- if (newProto != null) {
- newProto.getMap().setIsPrototype();
- }
+ final PropertyMap newMap = new PropertyMap(this);
+ addToProtoHistory(newProto, newMap);
return newMap;
}
@@ -927,4 +913,3 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
setProtoNewMapCount++;
}
}
-
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index c2259896..03a25dab 100644
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -30,9 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
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 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
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,118 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
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();
+ if (snapshot == null) {
+ return mh;
}
- return mh;
+
+ 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)));
+ }
+
+ //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));
}
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
index 74fab0ce..0a556f9d 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@@ -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;
@@ -136,6 +140,9 @@ public final class ScriptEnvironment {
/** Print resulting bytecode for script */
public final boolean _print_code;
+ /** Print memory usage for IR after each phase */
+ public final boolean _print_mem_usage;
+
/** Print function will no print newline characters */
public final boolean _print_no_newline;
@@ -151,6 +158,9 @@ public final class ScriptEnvironment {
/** 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;
@@ -204,6 +214,7 @@ public final class ScriptEnvironment {
_print_ast = options.getBoolean("print.ast");
_print_lower_ast = options.getBoolean("print.lower.ast");
_print_code = options.getBoolean("print.code");
+ _print_mem_usage = options.getBoolean("print.mem.usage");
_print_no_newline = options.getBoolean("print.no.newline");
_print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse");
@@ -213,6 +224,17 @@ public final class ScriptEnvironment {
_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 +269,18 @@ public final class ScriptEnvironment {
}
/**
+ * 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
*/
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 93517201..61cce7b1 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -104,34 +104,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Per ScriptObject flag - is this an arguments object? */
public static final int IS_ARGUMENTS = 0b0000_0100;
+ /** Is this a prototype PropertyMap? */
+ public static final int IS_PROTOTYPE = 0b0000_1000;
+
/** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
public static final int SPILL_RATE = 8;
/** Map to property information and accessor functions. Ordered by insertion. */
private PropertyMap map;
+ /** objects proto. */
+ private ScriptObject proto;
+
+ /** Context of the object, lazily cached. */
+ private Context context;
+
/** Object flags. */
private int flags;
- /** Area for properties added to object after instantiation, see {@link SpillProperty} */
+ /** Area for properties added to object after instantiation, see {@link AccessorProperty} */
public Object[] spill;
- /** Local embed area position 0 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
- public Object embed0;
-
- /** Local embed area position 1 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
- public Object embed1;
-
- /** Local embed area position 2 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
- public Object embed2;
-
- /** Local embed area position 3 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
- public Object embed3;
-
/** Indexed array data. */
private ArrayData arrayData;
- static final MethodHandle SETEMBED = findOwnMH("setEmbed", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, int.class, Object.class, Object.class);
+ static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
static final MethodHandle SETSPILLWITHNEW = findOwnMH("setSpillWithNew", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
static final MethodHandle SETSPILLWITHGROW = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);
@@ -665,9 +662,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
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);
}
}
@@ -783,8 +780,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
// delete getter and setter function references so that we don't leak
if (property instanceof UserAccessorProperty) {
final UserAccessorProperty uc = (UserAccessorProperty) property;
- setEmbedOrSpill(uc.getGetterSlot(), null);
- setEmbedOrSpill(uc.getSetterSlot(), null);
+ setSpill(uc.getGetterSlot(), null);
+ setSpill(uc.getSetterSlot(), null);
}
return true;
}
@@ -809,7 +806,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int getterSlot = uc.getGetterSlot();
// clear the old getter and set the new getter
- setEmbedOrSpill(getterSlot, getter);
+ setSpill(getterSlot, getter);
// if getter function is null, flag the slot to be negative (less by 1)
if (getter == null) {
getterSlot = -getterSlot - 1;
@@ -817,7 +814,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int setterSlot = uc.getSetterSlot();
// clear the old setter and set the new setter
- setEmbedOrSpill(setterSlot, setter);
+ setSpill(setterSlot, setter);
// if setter function is null, flag the slot to be negative (less by 1)
if (setter == null) {
setterSlot = -setterSlot - 1;
@@ -973,9 +970,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @param bindName null or name to bind to second argument (property not found method.)
*
* @return value of property as a MethodHandle or null.
- *
*/
- @SuppressWarnings("static-method")
protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
return getCallMethodHandle(getObjectValue(find), type, bindName);
}
@@ -1056,8 +1051,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* Return the current context from the object's map.
* @return Current context.
*/
- final Context getContext() {
- return getMap().getContext();
+ protected final Context getContext() {
+ if (context == null) {
+ context = Context.fromClass(getClass());
+ }
+ return context;
}
/**
@@ -1097,44 +1095,30 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return __proto__ object.
*/
public final ScriptObject getProto() {
- return getMap().getProto();
- }
-
- /**
- * Check if this is a prototype
- * @return true if {@link PropertyMap#isPrototype()} is true for this ScriptObject
- */
- public final boolean isPrototype() {
- return getMap().isPrototype();
+ return proto;
}
/**
* Set the __proto__ of an object.
* @param newProto new __proto__ to set.
*/
- public final void setProto(final ScriptObject newProto) {
- PropertyMap oldMap = getMap();
- ScriptObject oldProto = getProto();
+ public synchronized final void setProto(final ScriptObject newProto) {
+ final ScriptObject oldProto = proto;
+ map = map.changeProto(oldProto, newProto);
- while (oldProto != newProto) {
- final PropertyMap newMap = oldMap.setProto(newProto);
-
- if (!compareAndSetMap(oldMap, newMap)) {
- oldMap = getMap();
- oldProto = getProto();
- } else {
- if (isPrototype()) {
+ if (newProto != null) {
+ newProto.setIsPrototype();
+ }
- if (oldProto != null) {
- oldProto.removePropertyListener(this);
- }
+ proto = newProto;
- if (newProto != null) {
- newProto.addPropertyListener(this);
- }
- }
+ if (isPrototype()) {
+ if (oldProto != null) {
+ oldProto.removePropertyListener(this);
+ }
- return;
+ if (newProto != null) {
+ newProto.addPropertyListener(this);
}
}
}
@@ -1327,6 +1311,25 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
/**
+ * Check if this object is a prototype
+ *
+ * @return {@code true} if is prototype
+ */
+ public boolean isPrototype() {
+ return (flags & IS_PROTOTYPE) != 0;
+ }
+
+ /**
+ * Flag this object as having a prototype.
+ */
+ public void setIsPrototype() {
+ if (proto != null && !isPrototype()) {
+ proto.addPropertyListener(this);
+ }
+ flags |= IS_PROTOTYPE;
+ }
+
+ /**
* Get the {@link ArrayData} for this ScriptObject if it is an array
* @return array data
*/
@@ -1719,11 +1722,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (!property.hasGetterFunction()) {
methodHandle = bindTo(methodHandle, prototype);
}
- return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(name), guard);
+ return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(proto, name), guard);
}
assert !NashornCallSiteDescriptor.isFastScope(desc);
- return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(name), guard);
+ return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
@@ -1822,27 +1825,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
final PropertyMap myMap = getMap();
- return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(myMap));
+ return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(myMap));
}
@SuppressWarnings("unused")
- private static void setEmbed(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final int i, final Object self, final Object value) throws Throwable {
+ private static void setField(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final Object self, final Object value) throws Throwable {
final ScriptObject obj = (ScriptObject)self;
- if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
- obj.useEmbed(i);
+ final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
+ if (!obj.isExtensible()) {
+ throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
+ } else if (obj.compareAndSetMap(oldMap, newMap)) {
setter.invokeExact(self, value);
+ } else {
+ obj.set(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND), value, isStrict);
}
}
@SuppressWarnings("unused")
private static void setSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) {
final ScriptObject obj = (ScriptObject)self;
- if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
+ if (obj.trySetSpill(desc, oldMap, newMap, value)) {
obj.spill[index] = value;
}
}
- private boolean trySetEmbedOrSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
+ private boolean trySetSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
if (!isExtensible() && isStrict) {
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(this));
@@ -1964,7 +1971,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
methodHandle = bindTo(methodHandle, UNDEFINED);
}
return new GuardedInvocation(methodHandle,
- find.isInherited()? getMap().getProtoGetSwitchPoint(NO_SUCH_PROPERTY_NAME) : null,
+ find.isInherited()? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null,
getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class), find.getOwner(), func));
}
}
@@ -1995,7 +2002,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
- return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap()));
+ return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
}
private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> {
@@ -2070,36 +2077,39 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return Added property.
*/
private Property addSpillProperty(final String key, final int propertyFlags) {
- int i = findEmbed();
- Property spillProperty;
-
- if (i >= EMBED_SIZE) {
- i = getMap().getSpillLength();
+ int fieldCount = getMap().getFieldCount();
+ int fieldMaximum = getMap().getFieldMaximum();
+ Property property;
+
+ if (fieldCount < fieldMaximum) {
+ property = new AccessorProperty(key, propertyFlags & ~Property.IS_SPILL, getClass(), fieldCount);
+ notifyPropertyAdded(this, property);
+ property = addOwnProperty(property);
+ } else {
+ int i = getMap().getSpillLength();
MethodHandle getter = MH.arrayElementGetter(Object[].class);
MethodHandle setter = MH.arrayElementSetter(Object[].class);
getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE);
setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE);
- spillProperty = new SpillProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
- notifyPropertyAdded(this, spillProperty);
- spillProperty = addOwnProperty(spillProperty);
- i = spillProperty.getSlot();
+ property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
+ notifyPropertyAdded(this, property);
+ property = addOwnProperty(property);
+ i = property.getSlot();
final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE;
- final Object[] newSpill = new Object[newLength];
- if (spill != null) {
- System.arraycopy(spill, 0, newSpill, 0, spill.length);
- }
+ if (spill == null || newLength > spill.length) {
+ final Object[] newSpill = new Object[newLength];
- spill = newSpill;
- } else {
- useEmbed(i);
- spillProperty = new SpillProperty(key, propertyFlags, i, GET_EMBED[i], SET_EMBED[i]);
- notifyPropertyAdded(this, spillProperty);
- spillProperty = addOwnProperty(spillProperty);
+ if (spill != null) {
+ System.arraycopy(spill, 0, newSpill, 0, spill.length);
+ }
+
+ spill = newSpill;
+ }
}
- return spillProperty;
+ return property;
}
@@ -3159,67 +3169,22 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
/*
- * Embed management
- */
-
- /** Number of embed slots */
- public static final int EMBED_SIZE = 4;
- /** Embed offset */
- public static final int EMBED_OFFSET = 32 - EMBED_SIZE;
-
- static final MethodHandle[] GET_EMBED;
- static final MethodHandle[] SET_EMBED;
-
- static {
- GET_EMBED = new MethodHandle[EMBED_SIZE];
- SET_EMBED = new MethodHandle[EMBED_SIZE];
-
- for (int i = 0; i < EMBED_SIZE; i++) {
- final String name = "embed" + i;
- GET_EMBED[i] = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.GET_OBJECT_TYPE);
- SET_EMBED[i] = MH.asType(MH.setter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.SET_OBJECT_TYPE);
- }
- }
-
- void useEmbed(final int i) {
- flags |= 1 << (EMBED_OFFSET + i);
- }
-
- int findEmbed() {
- final int bits = ~(flags >>> EMBED_OFFSET);
- final int least = bits ^ -bits;
- final int index = Integer.numberOfTrailingZeros(least) - 1;
-
- return index;
- }
-
- /*
* Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object.
*/
private UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
int oldSpillLength = getMap().getSpillLength();
- int getterSlot = findEmbed();
- if (getterSlot >= EMBED_SIZE) {
- getterSlot = oldSpillLength + EMBED_SIZE;
- ++oldSpillLength;
- } else {
- useEmbed(getterSlot);
- }
- setEmbedOrSpill(getterSlot, getter);
+ int getterSlot = oldSpillLength++;
+ setSpill(getterSlot, getter);
// if getter function is null, flag the slot to be negative (less by 1)
if (getter == null) {
getterSlot = -getterSlot - 1;
}
- int setterSlot = findEmbed();
- if (setterSlot >= EMBED_SIZE) {
- setterSlot = oldSpillLength + EMBED_SIZE;
- } else {
- useEmbed(setterSlot);
- }
- setEmbedOrSpill(setterSlot, setter);
+ int setterSlot = oldSpillLength++;
+
+ setSpill(setterSlot, setter);
// if setter function is null, flag the slot to be negative (less by 1)
if (setter == null) {
setterSlot = -setterSlot - 1;
@@ -3228,56 +3193,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot);
}
- private void setEmbedOrSpill(final int slot, final Object value) {
- switch (slot) {
- case 0:
- embed0 = value;
- break;
- case 1:
- embed1 = value;
- break;
- case 2:
- embed2 = value;
- break;
- case 3:
- embed3 = value;
- break;
- default:
- if (slot >= 0) {
- final int index = (slot - EMBED_SIZE);
- if (spill == null) {
- // create new spill.
- spill = new Object[Math.max(index + 1, SPILL_RATE)];
- } else if (index >= spill.length) {
- // grow spill as needed
- final Object[] newSpill = new Object[index + 1];
- System.arraycopy(spill, 0, newSpill, 0, spill.length);
- spill = newSpill;
- }
-
- spill[index] = value;
+ private void setSpill(final int slot, final Object value) {
+ if (slot >= 0) {
+ final int index = slot;
+ if (spill == null) {
+ // create new spill.
+ spill = new Object[Math.max(index + 1, SPILL_RATE)];
+ } else if (index >= spill.length) {
+ // grow spill as needed
+ final Object[] newSpill = new Object[index + 1];
+ System.arraycopy(spill, 0, newSpill, 0, spill.length);
+ spill = newSpill;
}
- break;
+
+ spill[index] = value;
}
}
- // user accessors are either stored in embed fields or spill array slots
- // get the accessor value using slot number. Note that slot is either embed
- // field number or (spill array index + embedSize).
- Object getEmbedOrSpill(final int slot) {
- switch (slot) {
- case 0:
- return embed0;
- case 1:
- return embed1;
- case 2:
- return embed2;
- case 3:
- return embed3;
- default:
- final int index = (slot - EMBED_SIZE);
- return (index < 0 || (index >= spill.length)) ? null : spill[index];
- }
+ // user accessors are either stored in spill array slots
+ // get the accessor value using slot number. Note that slot is spill array index.
+ Object getSpill(final int slot) {
+ final int index = slot;
+ return (index < 0 || (index >= spill.length)) ? null : spill[index];
}
// User defined getter and setter are always called by "dyn:call". Note that the user
@@ -3287,7 +3224,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@SuppressWarnings("unused")
private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getEmbedOrSpill(slot);
+ final Object func = container.getSpill(slot);
if (func instanceof ScriptFunction) {
try {
@@ -3305,7 +3242,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@SuppressWarnings("unused")
private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
- final Object func = container.getEmbedOrSpill(slot);
+ final Object func = container.getSpill(slot);
if (func instanceof ScriptFunction) {
try {
diff --git a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index 8012ce02..5ff321fc 100644
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -166,18 +166,20 @@ final class SetMethodCreator {
}
private SetMethod createNewPropertySetter() {
- final int nextEmbed = sobj.findEmbed();
- final SetMethod sm;
- if (nextEmbed >= ScriptObject.EMBED_SIZE) {
- sm = createNewSpillPropertySetter();
- } else {
- sm = createNewEmbedPropertySetter(nextEmbed);
- }
-
+ final SetMethod sm = map.getFieldCount() < map.getFieldMaximum() ? createNewFieldSetter() : createNewSpillPropertySetter();
sobj.notifyPropertyAdded(sobj, sm.property);
return sm;
}
+ private SetMethod createNewFieldSetter() {
+ final PropertyMap oldMap = getMap();
+ final Property property = new AccessorProperty(getName(), 0, sobj.getClass(), oldMap.getFieldCount());
+ final PropertyMap newMap = oldMap.addProperty(property);
+ MethodHandle setter = MH.insertArguments(ScriptObject.SETFIELD, 0, desc, oldMap, newMap, property.getSetter(Object.class, newMap));
+
+ return new SetMethod(MH.asType(setter, Lookup.SET_OBJECT_TYPE), property);
+ }
+
private SetMethod createNewSpillPropertySetter() {
final int nextSpill = getMap().getSpillLength();
@@ -189,7 +191,7 @@ final class SetMethodCreator {
final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE);
final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE);
- return new SpillProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
+ return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
}
private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) {
@@ -207,14 +209,6 @@ final class SetMethodCreator {
}
}
- private SetMethod createNewEmbedPropertySetter(final int nextEmbed) {
- sobj.useEmbed(nextEmbed);
- final Property property = new SpillProperty(getName(), 0, nextEmbed, ScriptObject.GET_EMBED[nextEmbed], ScriptObject.SET_EMBED[nextEmbed]);
- //TODO specfields
- final MethodHandle methodHandle = MH.insertArguments(ScriptObject.SETEMBED, 0, desc, getMap(), getNewMap(property), property.getSetter(Object.class, getMap()), nextEmbed);
- return new SetMethod(methodHandle, property);
- }
-
private PropertyMap getNewMap(Property property) {
return getMap().addProperty(property);
}
diff --git a/src/jdk/nashorn/internal/runtime/SpillProperty.java b/src/jdk/nashorn/internal/runtime/SpillProperty.java
deleted file mode 100644
index 716097d0..00000000
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java
+++ /dev/null
@@ -1,85 +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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-
-package jdk.nashorn.internal.runtime;
-
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import jdk.nashorn.internal.lookup.Lookup;
-
-/**
- * The SpillProperty is a subclass of AccessorProperties. Anything not in the initial property map
- * will end up in the embed fields of the ScriptObject or in the Spill, which currently is a growing
- * Object only array in ScriptObject
- *
- * @see AccessorProperty
- * @see ScriptObject
- */
-public final class SpillProperty extends AccessorProperty {
- private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
-
- /**
- * Constructor
- *
- * @param key property key
- * @param flags property flags
- * @param slot property slot/index
- * @param getter getter for property
- * @param setter setter for property, or null if not configurable and writable
- */
- public SpillProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
- super(key, flags, slot, getter, setter);
- }
-
- private SpillProperty(final SpillProperty property) {
- super(property);
- }
-
- @Override
- protected Property copy() {
- return new SpillProperty(this);
- }
-
- @Override
- public MethodHandle getGetter(final Class<?> type) {
- if (isSpill()) {
- return MH.filterArguments(super.getGetter(type), 0, SPILLGETTER);
- }
-
- return super.getGetter(type);
- }
-
- @Override
- public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- if (isSpill()) {
- return MH.filterArguments(super.getSetter(type, currentMap), 0, SPILLGETTER);
- }
-
- return super.getSetter(type, currentMap);
- }
-
-}
diff --git a/src/jdk/nashorn/internal/runtime/StructureLoader.java b/src/jdk/nashorn/internal/runtime/StructureLoader.java
index db55fff9..ff6973a9 100644
--- a/src/jdk/nashorn/internal/runtime/StructureLoader.java
+++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java
@@ -110,8 +110,7 @@ final class StructureLoader extends NashornLoader {
@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
- final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length();
- return generateClass(name, name.substring(start, name.length()));
+ return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
}
return super.findClass(name);
}
diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 83d3c8d7..75c285a6 100644
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -67,7 +67,6 @@ public final class UserAccessorProperty extends Property {
private UserAccessorProperty(final UserAccessorProperty property) {
super(property);
-
this.getterSlot = property.getterSlot;
this.setterSlot = property.setterSlot;
}
@@ -115,10 +114,10 @@ public final class UserAccessorProperty extends Property {
public int getSpillCount() {
// calculate how many spill array slots used by this propery.
int count = 0;
- if (getGetterSlot() >= ScriptObject.EMBED_SIZE) {
+ if (getGetterSlot() >= 0) {
count++;
}
- if (getSetterSlot() >= ScriptObject.EMBED_SIZE) {
+ if (getSetterSlot() >= 0) {
count++;
}
return count;
@@ -141,7 +140,7 @@ public final class UserAccessorProperty extends Property {
@Override
public ScriptFunction getGetterFunction(final ScriptObject obj) {
- final Object value = obj.getEmbedOrSpill(getterSlot);
+ final Object value = obj.getSpill(getterSlot);
return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
}
@@ -152,7 +151,7 @@ public final class UserAccessorProperty extends Property {
@Override
public ScriptFunction getSetterFunction(final ScriptObject obj) {
- final Object value = obj.getEmbedOrSpill(setterSlot);
+ final Object value = obj.getSpill(setterSlot);
return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java
index 1703b7ec..5061683a 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java
@@ -57,7 +57,6 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
* Is this a reverse order iteration?
* @return true if reverse
*/
- @SuppressWarnings("static-method")
public boolean isReverse() {
return false;
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java b/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
index 05b1a939..7457641e 100644
--- a/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
+++ b/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
@@ -278,7 +278,7 @@ public class LinkerCallSite extends ChainedCallSite {
@SuppressWarnings("resource")
@Override
public void run() {
- PrintWriter out = null;
+ PrintWriter out = null;
boolean fileOutput = false;
try {
diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
index e7cc78b0..083dfef3 100644
--- a/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java
@@ -44,11 +44,9 @@ import jdk.nashorn.internal.runtime.Undefined;
/**
* This is the main dynamic linker for Nashorn. It is used for linking all {@link ScriptObject} and its subclasses (this
- * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}. This linker is exported to other
- * language runtimes by being declared in {@code META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
- * file of Nashorn's distribution.
+ * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
*/
-final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
+public final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
/**
* Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
*/
diff --git a/src/jdk/nashorn/internal/runtime/options/Options.java b/src/jdk/nashorn/internal/runtime/options/Options.java
index 16f3bc0f..286feec9 100644
--- a/src/jdk/nashorn/internal/runtime/options/Options.java
+++ b/src/jdk/nashorn/internal/runtime/options/Options.java
@@ -243,7 +243,7 @@ public final class Options {
*/
public String getString(final String key) {
final Option<?> option = get(key);
- if(option != null) {
+ if (option != null) {
final String value = (String)option.getValue();
if(value != null) {
return value.intern();
diff --git a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
index ecbc8bc9..e3157ba5 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java
@@ -107,16 +107,16 @@ public class DefaultRegExp extends RegExp {
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 @@ public class DefaultRegExp extends RegExp {
@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();
}
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
index 719f6c39..1047221a 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java
@@ -121,16 +121,16 @@ public class JoniRegExp extends RegExp {
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 @@ public class JoniRegExp extends RegExp {
@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 @@ public class JoniRegExp extends RegExp {
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;
}
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
index e651c44e..956a99d7 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java
@@ -65,7 +65,7 @@ final class RegExpScanner extends Scanner {
/** Are we currently inside a negated character class? */
private boolean inNegativeClass = false;
- private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?";
+ private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
private static class Capture {
/**
@@ -934,7 +934,7 @@ final class RegExpScanner extends Scanner {
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 @@ final class RegExpScanner extends Scanner {
}
// 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;
diff --git a/src/jdk/nashorn/internal/runtime/resources/Options.properties b/src/jdk/nashorn/internal/runtime/resources/Options.properties
index 2b52e8b9..47173197 100644
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties
@@ -247,6 +247,12 @@ nashorn.option.print.code = { \
desc="Print bytecode." \
}
+nashorn.option.print.mem.usage = { \
+ name="--print-mem-usage", \
+ is_undocumented=true, \
+ desc="Print memory usage of IR after each compile stage." \
+}
+
nashorn.option.print.no.newline = { \
name="--print-no-newline", \
is_undocumented=true, \
@@ -288,12 +294,12 @@ nashorn.option.scripting = { \
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 +318,14 @@ nashorn.option.stderr = { \
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", \
diff --git a/src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js b/src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js
index 97b01a08..b78ebbc8 100644
--- a/src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js
+++ b/src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js
@@ -35,8 +35,6 @@ com.sun.javafx.application.LauncherImpl.launchApplication((Java.extend(javafx.ap
init: function() {
// Java FX packages and classes must be defined here because
// they may not be viable until launch time due to clinit ordering.
-
- load("fx:base.js");
},
// Overridden javafx.application.Application.start(Stage stage);
diff --git a/src/jdk/nashorn/internal/scripts/JO.java b/src/jdk/nashorn/internal/scripts/JO.java
index 44412364..d698a263 100644
--- a/src/jdk/nashorn/internal/scripts/JO.java
+++ b/src/jdk/nashorn/internal/scripts/JO.java
@@ -32,12 +32,11 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* Empty object class.
*/
public class JO extends ScriptObject {
-
/**
* Constructor
*/
public JO() {
- super();
+ super(PropertyMap.newMap(JO.class));
}
/**
diff --git a/src/jdk/nashorn/tools/Shell.java b/src/jdk/nashorn/tools/Shell.java
index 22d879f5..708fecc5 100644
--- a/src/jdk/nashorn/tools/Shell.java
+++ b/src/jdk/nashorn/tools/Shell.java
@@ -173,9 +173,9 @@ public class Shell {
if (env._fx) {
return runFXScripts(context, global, files);
- } else {
- return runScripts(context, global, files);
}
+
+ return runScripts(context, global, files);
}
/**
@@ -270,7 +270,7 @@ public class Shell {
}
//null - pass no code installer - this is compile only
- new Compiler(env, functionNode).compile();
+ new Compiler(env).compile(functionNode);
}
} finally {
env.getOut().flush();
@@ -343,7 +343,7 @@ public class Shell {
* @return error code
* @throws IOException when any script file read results in I/O error
*/
- private int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
+ private static int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
try {
diff --git a/test/script/basic/JDK-8013729.js b/test/script/basic/JDK-8013729.js
new file mode 100644
index 00000000..a500602a
--- /dev/null
+++ b/test/script/basic/JDK-8013729.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8013729: SwitchPoint invalidation not working over prototype chain
+ *
+ * @test
+ * @run
+ */
+
+var a = {x: 1};
+var b = Object.create(a, {y: {value: 2, configurable: true, writable: true}});
+var c = Object.create(b);
+var d = Object.create(c);
+
+function p() {
+ print(d.x);
+ print(d.y);
+}
+
+p();
+
+// Delete, then redefine properties
+delete a.x;
+delete b.y;
+a.x = 10;
+b.y = 20;
+
+p();
diff --git a/test/script/basic/JDK-8013729.js.EXPECTED b/test/script/basic/JDK-8013729.js.EXPECTED
new file mode 100644
index 00000000..c9fc4c61
--- /dev/null
+++ b/test/script/basic/JDK-8013729.js.EXPECTED
@@ -0,0 +1,4 @@
+1
+2
+10
+20
diff --git a/test/script/basic/JDK-8013873.js b/test/script/basic/JDK-8013873.js
new file mode 100644
index 00000000..dcae75cc
--- /dev/null
+++ b/test/script/basic/JDK-8013873.js
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8013873: Regexp regression for escaped dash in character class
+ *
+ * @test
+ * @run
+ */
+
+var re = /[a\-c]/;
+print(re.exec("a"));
+print(re.exec("-"));
+print(re.exec("c"));
+print(re.exec("b"));
+print(re.exec("\\"));
+
+re = /^\-$/;
+print(re.exec("-"));
+print(re.exec("\\-"));
diff --git a/test/script/basic/JDK-8013873.js.EXPECTED b/test/script/basic/JDK-8013873.js.EXPECTED
new file mode 100644
index 00000000..71319936
--- /dev/null
+++ b/test/script/basic/JDK-8013873.js.EXPECTED
@@ -0,0 +1,7 @@
+a
+-
+c
+null
+null
+-
+null
diff --git a/test/script/basic/JDK-8013874.js b/test/script/basic/JDK-8013874.js
new file mode 100644
index 00000000..4b02b92b
--- /dev/null
+++ b/test/script/basic/JDK-8013874.js
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8013874: Function argument's prototype seem cached and wrongly reused
+ *
+ * @test
+ * @run
+ */
+
+function deepEqual(actual, expected) {
+ print("deepEqual: " + (actual.prop === expected.prop) + ", prop: " + expected.prop);
+}
+
+var proto = {};
+var other = {
+ prop: 0
+};
+
+function NameBuilder(first, last) {
+ this.first = first;
+ this.last = last;
+ return this;
+}
+
+NameBuilder.prototype = proto;
+
+function NameBuilder2(first, last) {
+ this.first = first;
+ this.last = last;
+ return this;
+}
+
+NameBuilder2.prototype = proto;
+
+var nb1 = new NameBuilder('Ryan', 'Dahl');
+var nb2 = new NameBuilder2('Ryan', 'Dahl');
+
+print("In loader, nb1.prop === nb2.prop " + (nb1.prop === nb2.prop));
+deepEqual(nb1, nb2);
+
+NameBuilder2.prototype = other;
+nb2 = new NameBuilder2('Ryan', 'Dahl');
+
+print("In loader, nb1.prop === nb2.prop " + (nb1.prop === nb2.prop));
+deepEqual(nb1, nb2);
diff --git a/test/script/basic/JDK-8013874.js.EXPECTED b/test/script/basic/JDK-8013874.js.EXPECTED
new file mode 100644
index 00000000..af1d1d69
--- /dev/null
+++ b/test/script/basic/JDK-8013874.js.EXPECTED
@@ -0,0 +1,4 @@
+In loader, nb1.prop === nb2.prop true
+deepEqual: true, prop: undefined
+In loader, nb1.prop === nb2.prop false
+deepEqual: false, prop: 0
diff --git a/test/script/basic/JDK-8013878.js b/test/script/basic/JDK-8013878.js
new file mode 100644
index 00000000..81e39f91
--- /dev/null
+++ b/test/script/basic/JDK-8013878.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8013878: ClassCastException in Regex
+ *
+ * @test
+ * @run
+ */
+
+var re = /(a)(b)(c)/;
+var str = 'abc';
+
+print(re.exec(str).length);
+print(re.exec(str).concat(['d', 'e', 'f']));
+print(re.exec(str).join('-'));
+print(re.exec(str).push('d'));
+print(re.exec(str).pop());
+print(re.exec(str).reverse());
+print(re.exec(str).shift());
+print(re.exec(str).sort());
+print(re.exec(str).slice(1));
+print(re.exec(str).splice(1, 2, 'foo'));
+print(re.exec(str).unshift('x'));
+print(re.exec(str).indexOf('a'));
+print(re.exec(str).lastIndexOf('a'));
+print(re.exec(str).every(function(a) {return a.length;}));
+print(re.exec(str).some(function(a) {return a.length;}));
+print(re.exec(str).filter(function(a) {return a.length;}));
+print(re.exec(str).forEach(function(a) {print(a)}));
+print(re.exec(str).map(function(a) {return a.length;}));
+print(re.exec(str).reduce(function(a, b) {return a + b}));
+print(re.exec(str).reduceRight(function(a, b) {return a + b}));
diff --git a/test/script/basic/JDK-8013878.js.EXPECTED b/test/script/basic/JDK-8013878.js.EXPECTED
new file mode 100644
index 00000000..7dbcf439
--- /dev/null
+++ b/test/script/basic/JDK-8013878.js.EXPECTED
@@ -0,0 +1,24 @@
+4
+abc,a,b,c,d,e,f
+abc-a-b-c
+5
+c
+c,b,a,abc
+abc
+a,abc,b,c
+a,b,c
+a,b
+5
+1
+1
+true
+true
+abc,a,b,c
+abc
+a
+b
+c
+undefined
+3,1,1,1
+abcabc
+cbaabc
diff --git a/test/script/basic/no_line_numbers.js b/test/script/basic/no_line_numbers.js
new file mode 100644
index 00000000..bd18e4d5
--- /dev/null
+++ b/test/script/basic/no_line_numbers.js
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/**
+ * no_line_numbers.js - make sure that switching off line number generation
+ * doesn't break. Otherwise, this is just NASHORN-73, a unit test particularly
+ * prone to label bugs in CodeGenerator
+ *
+ * @test
+ * @run
+ * @option --debug-lines=false
+ */
+
+print("x = " + x);
+do {
+ break;
+ var x;
+} while (true);
+
+
+print("y = " + y);
+while (true) {
+ break;
+ var y;
+}
+
+print("z = " + z);
+for ( ; ; ) {
+ break;
+ var z;
+ print("THIS SHOULD NEVER BE PRINTED!");
+}
+
+while (true) {
+ break;
+ if (true) {
+ var s;
+ }
+}
+
+print("s = "+s);
+
+print("u = "+u);
+for ( ; ; ) {
+ break;
+ while (true) {
+ do {
+ var u;
+ } while (true);
+ }
+}
+
+function terminal() {
+ print("r = "+r);
+ print("t = "+t);
+ for (;;) {
+ var r;
+ return;
+ var t;
+ print("THIS SHOULD NEVER BE PRINTED!");
+ }
+ print("NEITHER SHOULD THIS");
+}
+
+terminal();
+
+function terminal2() {
+ print("q = "+q);
+ for (;;) {
+ return;
+ print("THIS SHOULD NEVER BE PRINTED!");
+ }
+ print("NEITHER SHOULD THIS");
+}
+
+try {
+ terminal2();
+} catch (e) {
+ print(e);
+}
+
+function scope2() {
+ var b = 10;
+ print("b = "+b);
+}
+
+scope2();
+
+try {
+ print("b is = "+b);
+} catch (e) {
+ print(e);
+}
+
+
+function disp_a() {
+ var a = 20;
+ print("Value of 'a' inside the function " + a);
+}
+
+var a = 10;
+
+disp_a();
+
+print("Value of 'a' outside the function " + a);
diff --git a/test/script/basic/no_line_numbers.js.EXPECTED b/test/script/basic/no_line_numbers.js.EXPECTED
new file mode 100644
index 00000000..4a513f91
--- /dev/null
+++ b/test/script/basic/no_line_numbers.js.EXPECTED
@@ -0,0 +1,12 @@
+x = undefined
+y = undefined
+z = undefined
+s = undefined
+u = undefined
+r = undefined
+t = undefined
+ReferenceError: "q" is not defined
+b = 10
+ReferenceError: "b" is not defined
+Value of 'a' inside the function 20
+Value of 'a' outside the function 10
diff --git a/test/script/basic/paramspec.js b/test/script/basic/paramspec.js
new file mode 100644
index 00000000..c0ea2a54
--- /dev/null
+++ b/test/script/basic/paramspec.js
@@ -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));
+
diff --git a/test/script/basic/paramspec.js.EXPECTED b/test/script/basic/paramspec.js.EXPECTED
new file mode 100644
index 00000000..bb101b64
--- /dev/null
+++ b/test/script/basic/paramspec.js.EXPECTED
@@ -0,0 +1,2 @@
+true
+true
diff --git a/test/script/basic/runsunspider.js b/test/script/basic/runsunspider.js
index 7f787975..149bd27b 100644
--- a/test/script/basic/runsunspider.js
+++ b/test/script/basic/runsunspider.js
@@ -86,7 +86,7 @@ function runsuite(tests) {
changed = true;
}
} catch (e) {
- print("error: " + e);
+ print("error: " + e.printStackTrace());
if (e.toString().indexOf(tests) == 1) {
throw e;
}
diff --git a/test/script/trusted/logcoverage.js b/test/script/currently-failing/logcoverage.js
index a2cd7a0f..18b16aa1 100644
--- a/test/script/trusted/logcoverage.js
+++ b/test/script/currently-failing/logcoverage.js
@@ -90,16 +90,17 @@ var methodsCalled = [
function check(str, strs) {
for each (s in strs) {
- if (s.indexOf(str) !== -1) {
+ if (str.indexOf(s) !== -1) {
continue;
}
- print(method + "not found");
+ 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]']);
diff --git a/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java b/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java
index 3fd5c218..1d0e6fad 100644
--- a/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java
+++ b/test/src/jdk/nashorn/internal/test/framework/AbstractScriptRunnable.java
@@ -117,7 +117,7 @@ public abstract class AbstractScriptRunnable {
// run this test - compile or compile-and-run depending on option passed
public void runTest() throws IOException {
log(toString());
-
+ Thread.currentThread().setName(testFile.getPath());
if (shouldRun) {
// Analysis of failing tests list -
// if test is in failing list it must fail
diff --git a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java
index cc0e1cd3..d4269fce 100644
--- a/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java
+++ b/test/src/jdk/nashorn/internal/test/framework/ParallelTestRunner.java
@@ -25,6 +25,7 @@
package jdk.nashorn.internal.test.framework;
+import static jdk.nashorn.internal.test.framework.TestConfig.TEST_FAILED_LIST_FILE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ENABLE_STRICT_MODE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDES_FILE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDE_LIST;
@@ -37,6 +38,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
@@ -324,7 +326,8 @@ public class ParallelTestRunner {
});
}
- public void run() {
+ @SuppressWarnings("resource")
+ public boolean run() throws IOException {
final int testCount = tests.size();
int passCount = 0;
int doneCount = 0;
@@ -371,23 +374,36 @@ public class ParallelTestRunner {
});
boolean hasFailed = false;
- for (final ScriptRunnable.Result result : results) {
- if (!result.passed()) {
- if (hasFailed == false) {
- hasFailed = true;
- System.out.println();
- System.out.println("FAILED TESTS");
- }
+ final String failedList = System.getProperty(TEST_FAILED_LIST_FILE);
+ final boolean hasFailedList = failedList != null;
+ final boolean hadPreviouslyFailingTests = hasFailedList && new File(failedList).length() > 0;
+ final FileWriter failedFileWriter = hasFailedList ? new FileWriter(failedList) : null;
+ try {
+ final PrintWriter failedListWriter = failedFileWriter == null ? null : new PrintWriter(failedFileWriter);
+ for (final ScriptRunnable.Result result : results) {
+ if (!result.passed()) {
+ if (hasFailed == false) {
+ hasFailed = true;
+ System.out.println();
+ System.out.println("FAILED TESTS");
+ }
- System.out.println(result.getTest());
- if (result.exception != null) {
- final String exceptionString = result.exception instanceof TestFailedError ? result.exception.getMessage() : result.exception.toString();
- System.out.print(exceptionString.endsWith("\n") ? exceptionString : exceptionString + "\n");
- System.out.print(result.out != null ? result.out : "");
+ System.out.println(result.getTest());
+ if(failedFileWriter != null) {
+ failedListWriter.println(result.getTest().testFile.getPath());
+ }
+ if (result.exception != null) {
+ final String exceptionString = result.exception instanceof TestFailedError ? result.exception.getMessage() : result.exception.toString();
+ System.out.print(exceptionString.endsWith("\n") ? exceptionString : exceptionString + "\n");
+ System.out.print(result.out != null ? result.out : "");
+ }
}
}
+ } finally {
+ if(failedFileWriter != null) {
+ failedFileWriter.close();
+ }
}
-
final double timeElapsed = (System.nanoTime() - startTime) / 1e9; // [s]
System.out.printf("Tests run: %d/%d tests, passed: %d (%.2f%%), failed: %d. Time elapsed: %.0fmin %.0fs.\n", doneCount, testCount, passCount, 100d * passCount / doneCount, doneCount - passCount, timeElapsed / 60, timeElapsed % 60);
System.out.flush();
@@ -397,12 +413,25 @@ public class ParallelTestRunner {
if (hasFailed) {
throw new AssertionError("TEST FAILED");
}
+
+ if(hasFailedList) {
+ new File(failedList).delete();
+ }
+
+ if(hadPreviouslyFailingTests) {
+ System.out.println();
+ System.out.println("Good job on getting all your previously failing tests pass!");
+ System.out.println("NOW re-running all tests to make sure you haven't caused any NEW test failures.");
+ System.out.println();
+ }
+
+ return hadPreviouslyFailingTests;
}
public static void main(final String[] args) throws Exception {
parseArgs(args);
- new ParallelTestRunner().run();
+ while(new ParallelTestRunner().run());
}
private static void parseArgs(final String[] args) {
diff --git a/test/src/jdk/nashorn/internal/test/framework/TestConfig.java b/test/src/jdk/nashorn/internal/test/framework/TestConfig.java
index cf798f67..05d59dc1 100644
--- a/test/src/jdk/nashorn/internal/test/framework/TestConfig.java
+++ b/test/src/jdk/nashorn/internal/test/framework/TestConfig.java
@@ -72,4 +72,7 @@ public interface TestConfig {
// shared context mode or not
static final String TEST_JS_SHARED_CONTEXT = "test.js.shared.context";
+
+ // file for storing last run's failed tests
+ static final String TEST_FAILED_LIST_FILE = "test.failed.list.file";
}
diff --git a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
index a326a599..776c4e7a 100644
--- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
+++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java
@@ -31,6 +31,7 @@ import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_EXPECT_COMP
import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_EXPECT_RUN_FAIL;
import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_IGNORE_STD_ERROR;
import static jdk.nashorn.internal.test.framework.TestConfig.OPTIONS_RUN;
+import static jdk.nashorn.internal.test.framework.TestConfig.TEST_FAILED_LIST_FILE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ENABLE_STRICT_MODE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDES_FILE;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_EXCLUDE_DIR;
@@ -41,7 +42,9 @@ import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_LIST;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_ROOTS;
import static jdk.nashorn.internal.test.framework.TestConfig.TEST_JS_UNCHECKED_DIR;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileReader;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
@@ -86,6 +89,22 @@ final class TestFinder {
static <T> void findAllTests(final List<T> tests, final Set<String> orphans, final TestFactory<T> testFactory) throws Exception {
final String framework = System.getProperty(TEST_JS_FRAMEWORK);
final String testList = System.getProperty(TEST_JS_LIST);
+ final String failedTestFileName = System.getProperty(TEST_FAILED_LIST_FILE);
+ if(failedTestFileName != null) {
+ File failedTestFile = new File(failedTestFileName);
+ if(failedTestFile.exists() && failedTestFile.length() > 0L) {
+ try(final BufferedReader r = new BufferedReader(new FileReader(failedTestFile))) {
+ for(;;) {
+ final String testFileName = r.readLine();
+ if(testFileName == null) {
+ break;
+ }
+ handleOneTest(framework, new File(testFileName).toPath(), tests, orphans, testFactory);
+ }
+ }
+ return;
+ }
+ }
if (testList == null || testList.length() == 0) {
// Run the tests under the test roots dir, selected by the
// TEST_JS_INCLUDES patterns