--- a/nashorn/make/build.xml Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/make/build.xml Tue Dec 23 13:57:28 2014 -0800
@@ -209,7 +209,7 @@
</target>
<target name="javadoc" depends="jar">
- <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="src/overview.html"
+ <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${src.dir}/overview.html"
extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
additionalparam="-quiet" failonerror="true">
<classpath>
--- a/nashorn/make/nbproject/ide-targets.xml Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/make/nbproject/ide-targets.xml Tue Dec 23 13:57:28 2014 -0800
@@ -32,9 +32,8 @@
</nbjpdastart>
<java classname="jdk.nashorn.tools.Shell" classpath="${run.test.classpath}" dir="samples" fork="true">
<jvmarg line="-Dnashorn.optimistic"/>
- <jvmarg line="${ext.class.path}"/>
+ <jvmarg line="${boot.class.path}"/>
<jvmarg line="${run.test.jvmargs}"/>
- <arg value="../samples/test.js"/>
<jvmarg value="-Xdebug"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
</java>
--- a/nashorn/make/nbproject/project.xml Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/make/nbproject/project.xml Tue Dec 23 13:57:28 2014 -0800
@@ -38,10 +38,6 @@
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../src</label>
- <location>../src</location>
- </source-folder>
- <source-folder>
<label>../test/src</label>
<location>../test/src</location>
</source-folder>
@@ -50,21 +46,25 @@
<location>../buildtools/nasgen/src</location>
</source-folder>
<source-folder>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
+ </source-folder>
+ <source-folder>
<label>../test/src</label>
<type>java</type>
<location>../test/src</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../src</label>
+ <label>../buildtools/nasgen/src</label>
<type>java</type>
- <location>../src</location>
+ <location>../buildtools/nasgen/src</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../buildtools/nasgen/src</label>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
<type>java</type>
- <location>../buildtools/nasgen/src</location>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
<encoding>UTF-8</encoding>
</source-folder>
</folders>
@@ -132,12 +132,12 @@
<location>../test/src</location>
</source-folder>
<source-folder style="packages">
- <label>../src</label>
- <location>../src</location>
+ <label>../buildtools/nasgen/src</label>
+ <location>../buildtools/nasgen/src</location>
</source-folder>
<source-folder style="packages">
- <label>../buildtools/nasgen/src</label>
- <location>../buildtools/nasgen/src</location>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
</source-folder>
<source-file>
<location>build.xml</location>
@@ -159,11 +159,7 @@
<compilation-unit>
<package-root>../test/src</package-root>
<unit-tests/>
- <classpath mode="compile">../test/lib/testng.jar:../build/classes:../src</classpath>
- <source-level>1.7</source-level>
- </compilation-unit>
- <compilation-unit>
- <package-root>../src</package-root>
+ <classpath mode="compile">../test/lib/testng.jar:../build/classes:../src/jdk.scripting.nashorn/share/classes</classpath>
<source-level>1.7</source-level>
</compilation-unit>
<compilation-unit>
@@ -171,6 +167,10 @@
<classpath mode="compile">../build/classes:../src</classpath>
<source-level>1.7</source-level>
</compilation-unit>
+ <compilation-unit>
+ <package-root>../src/jdk.scripting.nashorn/share/classes</package-root>
+ <source-level>1.7</source-level>
+ </compilation-unit>
</java-data>
</configuration>
</project>
--- a/nashorn/make/project.properties Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/make/project.properties Tue Dec 23 13:57:28 2014 -0800
@@ -24,7 +24,7 @@
application.title=nashorn
# location of JDK embedded ASM sources
-jdk.asm.src.dir=../jdk/src/share/classes/jdk/internal/org/objectweb/asm
+jdk.asm.src.dir=../jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm
# source and target levels
build.compiler=modern
--- a/nashorn/samples/browser_dom.js Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/samples/browser_dom.js Tue Dec 23 13:57:28 2014 -0800
@@ -1,4 +1,4 @@
-#// Usage: jjs -fx browser.js
+#// Usage: jjs -fx browser_dom.js
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
@@ -32,7 +32,7 @@
*/
if (!$OPTIONS._fx) {
- print("Usage: jjs -fx browser.js");
+ print("Usage: jjs -fx browser_dom.js");
exit(1);
}
@@ -40,7 +40,6 @@
var ChangeListener = Java.type("javafx.beans.value.ChangeListener");
var Scene = Java.type("javafx.scene.Scene");
var WebView = Java.type("javafx.scene.web.WebView");
-var EventListener = Java.type("org.w3c.dom.events.EventListener");
// JavaFX start method
function start(stage) {
@@ -74,10 +73,10 @@
var btn = document.createElement("button");
var n = 0;
// attach a button handler - nashorn function!
- btn.onclick = new EventListener(function() {
+ btn.onclick = function() {
n++; print("You clicked " + n + " time(s)");
print("you clicked OK " + wv.engine.executeScript("okCount"));
- });
+ };
// attach text to button
var t = document.createTextNode("Click Me!");
btn.appendChild(t);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/samples/time_color.fx Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,89 @@
+#// Usage: jjs -fx time_color.js [-- true/false]
+
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A simple javafx program that changes background color
+// of scene based on current time value (once per sec).
+// inspired by http://whatcolourisit.scn9a.org/
+
+if (!$OPTIONS._fx) {
+ print("Usage: jjs -fx time_color.js");
+ print(" jjs -fx time_color.js -- true");
+ exit(1);
+}
+
+// JavaFX classes used
+var Color = Java.type("javafx.scene.paint.Color");
+var Group = Java.type("javafx.scene.Group");
+var Label = Java.type("javafx.scene.control.Label");
+var Platform = Java.type("javafx.application.Platform");
+var Scene = Java.type("javafx.scene.Scene");
+var Timer = Java.type("java.util.Timer");
+
+// execute function periodically once per given time in millisec
+function setInterval(func, ms) {
+ // New timer, run as daemon so the application can quit
+ var timer = new Timer("setInterval", true);
+ timer.schedule(function() Platform.runLater(func), ms, ms);
+ return timer;
+}
+
+// do you want to flip hour/min/sec for RGB?
+var flip = arguments.length > 0? "true".equals(arguments[0]) : false;
+
+// JavaFX start method
+function start(stage) {
+ start.title = "Time Color";
+ var root = new Group();
+ var label = new Label("time");
+ label.textFill = Color.WHITE;
+ root.children.add(label);
+ stage.scene = new Scene(root, 700, 500);
+
+ setInterval(function() {
+ var d = new Date();
+ var hours = d.getHours();
+ var mins = d.getMinutes();
+ var secs = d.getSeconds();
+
+ if (hours < 10) hours = "0" + hours;
+ if (mins < 10) mins = "0" + mins;
+ if (secs < 10) secs = "0" + secs;
+
+ var hex = flip?
+ "#" + secs + mins + hours : "#" + hours + mins + secs;
+ label.text = "Color: " + hex;
+ stage.scene.fill = Color.web(hex);
+ }, 1000);
+
+ stage.show();
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Tue Dec 23 13:57:28 2014 -0800
@@ -40,21 +40,22 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
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.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
+import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.GetSplitState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
@@ -65,9 +66,11 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
@@ -82,6 +85,7 @@
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
+import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
@@ -131,8 +135,44 @@
OBJECT(Type.OBJECT);
private final Type type;
+ private final TypeHolderExpression typeExpression;
+
private LvarType(final Type type) {
this.type = type;
+ this.typeExpression = new TypeHolderExpression(type);
+ }
+ }
+
+ /**
+ * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
+ * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
+ * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
+ * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
+ * generation of higher number of temporary short lived nodes, though.
+ */
+ private static class TypeHolderExpression extends Expression {
+ private static final long serialVersionUID = 1L;
+
+ private final Type type;
+
+ TypeHolderExpression(final Type type) {
+ super(0L, 0, 0);
+ this.type = type;
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ throw new AssertionError();
+ }
+
+ @Override
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public void toString(final StringBuilder sb, final boolean printType) {
+ throw new AssertionError();
}
}
@@ -359,6 +399,8 @@
// allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
// value.
private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+ // Stack for evaluated expression types.
+ private final Deque<LvarType> typeStack = new ArrayDeque<>();
// Whether the current point in the AST is reachable code
private boolean reachable = true;
@@ -375,8 +417,6 @@
private final Map<IdentNode, LvarType> identifierLvarTypes = new IdentityHashMap<>();
private final Map<Symbol, SymbolConversions> symbolConversions = new IdentityHashMap<>();
- private SymbolToType symbolToType = new SymbolToType();
-
// Stack of open labels for starts of catch blocks, one for every currently traversed try block; for inserting
// control flow edges to them. Note that we currently don't insert actual control flow edges, but instead edges that
// help us with type calculations. This means that some operations that can result in an exception being thrown
@@ -400,62 +440,56 @@
private void doesNotContinueSequentially() {
reachable = false;
localVariableTypes = Collections.emptyMap();
+ assertTypeStackIsEmpty();
}
+ private boolean pushExpressionType(final Expression expr) {
+ typeStack.push(toLvarType(expr.getType()));
+ return false;
+ }
+
+ @Override
+ public boolean enterAccessNode(final AccessNode accessNode) {
+ visitExpression(accessNode.getBase());
+ return pushExpressionType(accessNode);
+ }
@Override
public boolean enterBinaryNode(final BinaryNode binaryNode) {
// NOTE: regardless of operator's lexical associativity, lhs is always evaluated first.
final Expression lhs = binaryNode.lhs();
- final boolean isAssignment = binaryNode.isAssignment();
- LvarType lhsTypeOnLoad = null;
- if(isAssignment) {
- if(lhs instanceof BaseNode) {
- ((BaseNode)lhs).getBase().accept(this);
- if(lhs instanceof IndexNode) {
- ((IndexNode)lhs).getIndex().accept(this);
- } else {
- assert lhs instanceof AccessNode;
- }
- } else {
- assert lhs instanceof IdentNode;
- if(binaryNode.isSelfModifying()) {
- final IdentNode ident = ((IdentNode)lhs);
- ident.accept(this);
- // Self-assignment can cause a change in the type of the variable. For purposes of evaluating
- // the type of the operation, we must use its type as it was when it was loaded. If we didn't
- // do this, some awkward expressions would end up being calculated incorrectly, e.g.
- // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN).
- // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the
- // result type would be either optimistic int or pessimistic long, which would be wrong.
- lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol());
- }
- }
+ final LvarType lhsType;
+ if (!(lhs instanceof IdentNode && binaryNode.tokenType() == TokenType.ASSIGN)) {
+ lhsType = visitExpression(lhs);
} else {
- lhs.accept(this);
+ // Can't visit IdentNode on LHS of a simple assignment, as visits imply use, and this is def.
+ // The type is irrelevant, as only RHS is used to determine the type anyway.
+ lhsType = LvarType.UNDEFINED;
}
final boolean isLogical = binaryNode.isLogical();
- assert !(isAssignment && isLogical); // there are no logical assignment operators in JS
final Label joinLabel = isLogical ? new Label("") : null;
if(isLogical) {
jumpToLabel((JoinPredecessor)lhs, joinLabel);
}
final Expression rhs = binaryNode.rhs();
- rhs.accept(this);
+ final LvarType rhsType = visitExpression(rhs);
if(isLogical) {
jumpToLabel((JoinPredecessor)rhs, joinLabel);
}
joinOnLabel(joinLabel);
- if(isAssignment && lhs instanceof IdentNode) {
+ final LvarType type = toLvarType(binaryNode.setOperands(lhsType.typeExpression, rhsType.typeExpression).getType());
+
+ if(binaryNode.isAssignment() && lhs instanceof IdentNode) {
if(binaryNode.isSelfModifying()) {
- onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad);
+ onSelfAssignment((IdentNode)lhs, type);
} else {
- onAssignment((IdentNode)lhs, rhs);
+ onAssignment((IdentNode)lhs, type);
}
}
+ typeStack.push(type);
return false;
}
@@ -475,6 +509,17 @@
}
@Override
+ public boolean enterCallNode(final CallNode callNode) {
+ visitExpression(callNode.getFunction());
+ visitExpressions(callNode.getArgs());
+ final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
+ if (evalArgs != null) {
+ visitExpressions(evalArgs.getArgs());
+ }
+ return pushExpressionType(callNode);
+ }
+
+ @Override
public boolean enterContinueNode(final ContinueNode continueNode) {
return enterJumpStatement(continueNode);
}
@@ -483,6 +528,7 @@
if(!reachable) {
return false;
}
+ assertTypeStackIsEmpty();
final BreakableNode target = jump.getTarget(lc);
jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
doesNotContinueSequentially();
@@ -495,6 +541,7 @@
}
private void enterDoWhileLoop(final WhileNode loopNode) {
+ assertTypeStackIsEmpty();
final JoinPredecessorExpression test = loopNode.getTest();
final Block body = loopNode.getBody();
final Label continueLabel = loopNode.getContinueLabel();
@@ -512,7 +559,7 @@
if(!reachable) {
break;
}
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
jumpToLabel(test, breakLabel);
if(isAlwaysFalse(test)) {
break;
@@ -535,6 +582,45 @@
}
@Override
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ if (reachable) {
+ visitExpressionOnEmptyStack(expressionStatement.getExpression());
+ }
+ return false;
+ }
+
+ private void assertTypeStackIsEmpty() {
+ assert typeStack.isEmpty();
+ }
+
+ @Override
+ protected Node leaveDefault(final Node node) {
+ assert !(node instanceof Expression); // All expressions were handled
+ assert !(node instanceof Statement) || typeStack.isEmpty(); // No statements leave with a non-empty stack
+ return node;
+ }
+
+ private LvarType visitExpressionOnEmptyStack(final Expression expr) {
+ assertTypeStackIsEmpty();
+ return visitExpression(expr);
+ }
+
+ private LvarType visitExpression(final Expression expr) {
+ final int stackSize = typeStack.size();
+ expr.accept(this);
+ assert typeStack.size() == stackSize + 1;
+ return typeStack.pop();
+ }
+
+ private void visitExpressions(final List<Expression> exprs) {
+ for(final Expression expr: exprs) {
+ if (expr != null) {
+ visitExpression(expr);
+ }
+ }
+ }
+
+ @Override
public boolean enterForNode(final ForNode forNode) {
if(!reachable) {
return false;
@@ -543,7 +629,7 @@
final Expression init = forNode.getInit();
if(forNode.isForIn()) {
final JoinPredecessorExpression iterable = forNode.getModify();
- iterable.accept(this);
+ visitExpression(iterable);
enterTestFirstLoop(forNode, null, init,
// If we're iterating over property names, and we can discern from the runtime environment
// of the compilation that the object being iterated over must use strings for property
@@ -552,16 +638,18 @@
!compiler.useOptimisticTypes() || (!forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())));
} else {
if(init != null) {
- init.accept(this);
+ visitExpressionOnEmptyStack(init);
}
enterTestFirstLoop(forNode, forNode.getModify(), null, false);
}
+ assertTypeStackIsEmpty();
return false;
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if(alreadyEnteredTopLevelFunction) {
+ typeStack.push(LvarType.OBJECT);
return false;
}
int pos = 0;
@@ -603,11 +691,20 @@
}
@Override
+ public boolean enterGetSplitState(final GetSplitState getSplitState) {
+ return pushExpressionType(getSplitState);
+ }
+
+ @Override
public boolean enterIdentNode(final IdentNode identNode) {
final Symbol symbol = identNode.getSymbol();
if(symbol.isBytecodeLocal()) {
symbolIsUsed(symbol);
- setIdentifierLvarType(identNode, getLocalVariableType(symbol));
+ final LvarType type = getLocalVariableType(symbol);
+ setIdentifierLvarType(identNode, type);
+ typeStack.push(type);
+ } else {
+ pushExpressionType(identNode);
}
return false;
}
@@ -622,11 +719,12 @@
final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail();
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
if(!isAlwaysFalse(test)) {
pass.accept(this);
+ assertTypeStackIsEmpty();
}
final Map<Symbol, LvarType> passLvarTypes = localVariableTypes;
final boolean reachableFromPass = reachable;
@@ -635,6 +733,7 @@
localVariableTypes = afterTestLvarTypes;
if(!isAlwaysTrue(test) && fail != null) {
fail.accept(this);
+ assertTypeStackIsEmpty();
final boolean reachableFromFail = reachable;
reachable |= reachableFromPass;
if(!reachable) {
@@ -667,15 +766,54 @@
}
@Override
- public boolean enterPropertyNode(final PropertyNode propertyNode) {
- // Avoid falsely adding property keys to the control flow graph
- if(propertyNode.getValue() != null) {
- propertyNode.getValue().accept(this);
+ public boolean enterIndexNode(final IndexNode indexNode) {
+ visitExpression(indexNode.getBase());
+ visitExpression(indexNode.getIndex());
+ return pushExpressionType(indexNode);
+ }
+
+ @Override
+ public boolean enterJoinPredecessorExpression(final JoinPredecessorExpression joinExpr) {
+ final Expression expr = joinExpr.getExpression();
+ if (expr != null) {
+ expr.accept(this);
+ } else {
+ typeStack.push(LvarType.UNDEFINED);
}
return false;
}
@Override
+ public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+ if (literalNode instanceof ArrayLiteralNode) {
+ final List<Expression> expressions = ((ArrayLiteralNode)literalNode).getElementExpressions();
+ if (expressions != null) {
+ visitExpressions(expressions);
+ }
+ }
+ pushExpressionType(literalNode);
+ return false;
+ }
+
+ @Override
+ public boolean enterObjectNode(final ObjectNode objectNode) {
+ for(final PropertyNode propertyNode: objectNode.getElements()) {
+ // Avoid falsely adding property keys to the control flow graph
+ final Expression value = propertyNode.getValue();
+ if (value != null) {
+ visitExpression(value);
+ }
+ }
+ return pushExpressionType(objectNode);
+ }
+
+ @Override
+ public boolean enterPropertyNode(final PropertyNode propertyNode) {
+ // Property nodes are only accessible through object literals, and we handled that case above
+ throw new AssertionError();
+ }
+
+ @Override
public boolean enterReturnNode(final ReturnNode returnNode) {
if(!reachable) {
return false;
@@ -684,9 +822,9 @@
final Expression returnExpr = returnNode.getExpression();
final Type returnExprType;
if(returnExpr != null) {
- returnExpr.accept(this);
- returnExprType = getType(returnExpr);
+ returnExprType = visitExpressionOnEmptyStack(returnExpr).type;
} else {
+ assertTypeStackIsEmpty();
returnExprType = Type.UNDEFINED;
}
returnType = Type.widestReturnType(returnType, returnExprType);
@@ -695,6 +833,12 @@
}
@Override
+ public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
+ visitExpressions(runtimeNode.getArgs());
+ return pushExpressionType(runtimeNode);
+ }
+
+ @Override
public boolean enterSplitReturn(final SplitReturn splitReturn) {
doesNotContinueSequentially();
return false;
@@ -706,8 +850,7 @@
return false;
}
- final Expression expr = switchNode.getExpression();
- expr.accept(this);
+ visitExpressionOnEmptyStack(switchNode.getExpression());
final List<CaseNode> cases = switchNode.getCases();
if(cases.isEmpty()) {
@@ -724,7 +867,7 @@
for(final CaseNode caseNode: cases) {
final Expression test = caseNode.getTest();
if(!isInteger && test != null) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
if(!tagUsed) {
symbolIsUsed(switchNode.getTag(), LvarType.OBJECT);
tagUsed = true;
@@ -769,29 +912,42 @@
final Expression trueExpr = ternaryNode.getTrueExpression();
final Expression falseExpr = ternaryNode.getFalseExpression();
- test.accept(this);
+ visitExpression(test);
final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes;
+ final LvarType trueType;
if(!isAlwaysFalse(test)) {
- trueExpr.accept(this);
+ trueType = visitExpression(trueExpr);
+ } else {
+ trueType = null;
}
final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes;
localVariableTypes = testExitLvarTypes;
+ final LvarType falseType;
if(!isAlwaysTrue(test)) {
- falseExpr.accept(this);
+ falseType = visitExpression(falseExpr);
+ } else {
+ falseType = null;
}
final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes;
localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes);
setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes);
setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes);
+
+ typeStack.push(trueType != null ? falseType != null ? widestLvarType(trueType, falseType) : trueType : assertNotNull(falseType));
return false;
}
+ private static <T> T assertNotNull(final T t) {
+ assert t != null;
+ return t;
+ }
+
private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
final Expression iteratorValues, final boolean iteratorValuesAreObject) {
final JoinPredecessorExpression test = loopNode.getTest();
if(isAlwaysFalse(test)) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
return;
}
@@ -804,7 +960,7 @@
jumpToLabel(loopNode, repeatLabel, beforeLoopTypes);
final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes;
if(test != null) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
}
if(!isAlwaysTrue(test)) {
jumpToLabel(test, breakLabel);
@@ -827,7 +983,7 @@
break;
}
if(modify != null) {
- modify.accept(this);
+ visitExpressionOnEmptyStack(modify);
jumpToLabel(modify, repeatLabel);
joinOnLabel(repeatLabel);
}
@@ -853,7 +1009,7 @@
return false;
}
- throwNode.getExpression().accept(this);
+ visitExpressionOnEmptyStack(throwNode.getExpression());
jumpToCatchBlock(throwNode);
doesNotContinueSequentially();
return false;
@@ -892,7 +1048,7 @@
onAssignment(exception, LvarType.OBJECT);
final Expression condition = catchNode.getExceptionCondition();
if(condition != null) {
- condition.accept(this);
+ visitExpression(condition);
}
final Map<Symbol, LvarType> afterConditionTypes = localVariableTypes;
final Block catchBody = catchNode.getBody();
@@ -927,14 +1083,11 @@
@Override
public boolean enterUnaryNode(final UnaryNode unaryNode) {
final Expression expr = unaryNode.getExpression();
- expr.accept(this);
-
- if(unaryNode.isSelfModifying()) {
- if(expr instanceof IdentNode) {
- final IdentNode ident = (IdentNode)expr;
- onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol()));
- }
+ final LvarType unaryType = toLvarType(unaryNode.setExpression(visitExpression(expr).typeExpression).getType());
+ if(unaryNode.isSelfModifying() && expr instanceof IdentNode) {
+ onSelfAssignment((IdentNode)expr, unaryType);
}
+ typeStack.push(unaryType);
return false;
}
@@ -945,8 +1098,7 @@
}
final Expression init = varNode.getInit();
if(init != null) {
- init.accept(this);
- onAssignment(varNode.getName(), init);
+ onAssignment(varNode.getName(), visitExpression(init));
}
return false;
}
@@ -964,6 +1116,15 @@
return false;
}
+ @Override
+ public boolean enterWithNode(final WithNode withNode) {
+ if (reachable) {
+ visitExpression(withNode.getExpression());
+ withNode.getBody().accept(this);
+ }
+ return false;
+ };
+
private Map<Symbol, LvarType> getBreakTargetTypes(final BreakableNode target) {
// Remove symbols defined in the the blocks that are being broken out of.
Map<Symbol, LvarType> types = localVariableTypes;
@@ -1002,18 +1163,6 @@
}
/**
- * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where
- * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to
- * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already
- * defined (that is, not null).
- * @param symbol the symbol representing the variable.
- * @return the current variable type, if it is a bytecode local, otherwise null.
- */
- private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) {
- return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null;
- }
-
- /**
* Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict
* of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where
* a just-defined symbol might still be null).
@@ -1154,6 +1303,7 @@
*/
private void leaveBreakable(final BreakableNode breakable) {
joinOnLabel(breakable.getBreakLabel());
+ assertTypeStackIsEmpty();
}
@Override
@@ -1329,10 +1479,6 @@
return conv == null || !conv.isLive();
}
- private void onAssignment(final IdentNode identNode, final Expression rhs) {
- onAssignment(identNode, toLvarType(getType(rhs)));
- }
-
private void onAssignment(final IdentNode identNode, final LvarType type) {
final Symbol symbol = identNode.getSymbol();
assert symbol != null : identNode.getName();
@@ -1400,13 +1546,12 @@
jumpToCatchBlock(identNode);
}
- private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) {
+ private void onSelfAssignment(final IdentNode identNode, final LvarType type) {
final Symbol symbol = identNode.getSymbol();
assert symbol != null : identNode.getName();
if(!symbol.isBytecodeLocal()) {
return;
}
- final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type));
// Self-assignment never produce either a boolean or undefined
assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN;
setType(symbol, type);
@@ -1466,7 +1611,6 @@
* @param symbol the symbol representing the variable
* @param type the type
*/
- @SuppressWarnings("unused")
private void setType(final Symbol symbol, final LvarType type) {
if(getLocalVariableTypeOrNull(symbol) == type) {
return;
@@ -1486,77 +1630,4 @@
private void symbolIsUsed(final Symbol symbol) {
symbolIsUsed(symbol, getLocalVariableType(symbol));
}
-
- /**
- * Gets the type of the expression, dependent on the current types of the local variables.
- *
- * @param expr the expression
- * @return the current type of the expression dependent on the current types of the local variables.
- */
- private Type getType(final Expression expr) {
- return expr.getType(getSymbolToType());
- }
-
- /**
- * Returns a function object from symbols to their types, used by the expressions to evaluate their type.
- * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes
- * sure to return the same function object while the local variable types don't change, and create a new function
- * object if the local variable types have been changed.
- * @return a function object representing a mapping from symbols to their types.
- */
- private Function<Symbol, Type> getSymbolToType() {
- if(symbolToType.isStale()) {
- symbolToType = new SymbolToType();
- }
- return symbolToType;
- }
-
- private class SymbolToType implements Function<Symbol, Type> {
- private final Object boundTypes = localVariableTypes;
- @Override
- public Type apply(final Symbol t) {
- return getLocalVariableType(t).type;
- }
-
- boolean isStale() {
- return boundTypes != localVariableTypes;
- }
- }
-
- /**
- * Gets the type of the expression, dependent on the current types of the local variables and a single overridden
- * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was
- * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for
- * the calculation.
- *
- * @param expr the expression
- * @param overriddenSymbol the overridden symbol
- * @param overriddenType the overridden type
- * @return the current type of the expression dependent on the current types of the local variables and the single
- * potentially overridden type.
- */
- private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) {
- return expr.getType(getSymbolToType(overriddenSymbol, overriddenType));
- }
-
- private Function<Symbol, Type> getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) {
- return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() :
- new SymbolToTypeOverride(overriddenSymbol, overriddenType);
- }
-
- private class SymbolToTypeOverride implements Function<Symbol, Type> {
- private final Function<Symbol, Type> originalSymbolToType = getSymbolToType();
- private final Symbol overriddenSymbol;
- private final Type overriddenType;
-
- SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) {
- this.overriddenSymbol = overriddenSymbol;
- this.overriddenType = overriddenType;
- }
-
- @Override
- public Type apply(final Symbol symbol) {
- return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol);
- }
- }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Tue Dec 23 13:57:28 2014 -0800
@@ -67,7 +67,7 @@
import jdk.nashorn.internal.runtime.options.Options;
/**
- * Static utility that encapsulates persistence of type information for functions compiled with optimistic
+ * <p>Static utility that encapsulates persistence of type information for functions compiled with optimistic
* typing. With this feature enabled, when a JavaScript function is recompiled because it gets deoptimized,
* the type information for deoptimization is stored in a cache file. If the same function is compiled in a
* subsequent JVM invocation, the type information is used for initial compilation, thus allowing the system
@@ -83,6 +83,7 @@
* {@code nashorn.typeInfo.cleanupDelaySeconds} system property. You can also specify the word
* {@code unlimited} as the value for {@code nashorn.typeInfo.maxFiles} in which case the type info cache is
* allowed to grow without limits.
+ * </p>
*/
public final class OptimisticTypesPersistence {
// Default is 0, for disabling the feature when not specified. A reasonable default when enabled is
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -27,7 +27,6 @@
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -98,7 +97,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return type == null ? getMostPessimisticType() : type;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -31,7 +31,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -57,9 +56,7 @@
private final int programPoint;
private final Type type;
-
private transient Type cachedType;
- private transient Object cachedTypeFunction;
@Ignore
private static final Set<TokenType> CAN_OVERFLOW =
@@ -143,24 +140,6 @@
}
}
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
- /**
- * Return the widest possible type for this operation. This is used for compile time
- * static type inference
- *
- * @return Type
- */
- @Override
- public Type getWidestOperationType() {
- return getWidestOperationType(UNKNOWN_LOCALS);
- }
-
/**
* Return the widest possible operand type for this operation.
*
@@ -181,14 +160,15 @@
}
}
- private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
+ @Override
+ public Type getWidestOperationType() {
switch (tokenType()) {
case ADD:
case ASSIGN_ADD: {
// Compare this logic to decideType(Type, Type); it's similar, but it handles the optimistic type
// calculation case while this handles the conservative case.
- final Type lhsType = lhs.getType(localVariableTypes);
- final Type rhsType = rhs.getType(localVariableTypes);
+ final Type lhsType = lhs.getType();
+ final Type rhsType = rhs.getType();
if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
// Will always fit in an int, as the value range is [0, 1, 2]. If we didn't treat them specially here,
// they'd end up being treated as generic INT operands and their sum would be conservatively considered
@@ -238,8 +218,8 @@
case SUB:
case ASSIGN_MUL:
case ASSIGN_SUB: {
- final Type lhsType = lhs.getType(localVariableTypes);
- final Type rhsType = rhs.getType(localVariableTypes);
+ final Type lhsType = lhs.getType();
+ final Type rhsType = rhs.getType();
if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
return Type.INT;
}
@@ -253,20 +233,20 @@
return Type.UNDEFINED;
}
case ASSIGN: {
- return rhs.getType(localVariableTypes);
+ return rhs.getType();
}
case INSTANCEOF: {
return Type.BOOLEAN;
}
case COMMALEFT: {
- return lhs.getType(localVariableTypes);
+ return lhs.getType();
}
case COMMARIGHT: {
- return rhs.getType(localVariableTypes);
+ return rhs.getType();
}
case AND:
case OR:{
- return Type.widestReturnType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
+ return Type.widestReturnType(lhs.getType(), rhs.getType());
}
default:
if (isComparison()) {
@@ -487,7 +467,7 @@
/**
* Set the right hand side expression for this node
- * @param rhs new left hand side expression
+ * @param rhs new right hand side expression
* @return a node equivalent to this one except for the requested change.
*/
public BinaryNode setRHS(final Expression rhs) {
@@ -497,6 +477,19 @@
return new BinaryNode(this, lhs, rhs, type, programPoint);
}
+ /**
+ * Set both the left and the right hand side expression for this node
+ * @param lhs new left hand side expression
+ * @param rhs new left hand side expression
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public BinaryNode setOperands(final Expression lhs, final Expression rhs) {
+ if (this.lhs == lhs && this.rhs == rhs) {
+ return this;
+ }
+ return new BinaryNode(this, lhs, rhs, type, programPoint);
+ }
+
@Override
public int getProgramPoint() {
return programPoint;
@@ -541,24 +534,22 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- if(localVariableTypes == cachedTypeFunction) {
- return cachedType;
+ public Type getType() {
+ if (cachedType == null) {
+ cachedType = getTypeUncached();
}
- cachedType = getTypeUncached(localVariableTypes);
- cachedTypeFunction = localVariableTypes;
return cachedType;
}
- private Type getTypeUncached(final Function<Symbol, Type> localVariableTypes) {
+ private Type getTypeUncached() {
if(type == OPTIMISTIC_UNDECIDED_TYPE) {
- return decideType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
+ return decideType(lhs.getType(), rhs.getType());
}
- final Type widest = getWidestOperationType(localVariableTypes);
+ final Type widest = getWidestOperationType();
if(type == null) {
return widest;
}
- return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes))));
+ return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
}
private static Type decideType(final Type lhsType, final Type rhsType) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -30,7 +30,6 @@
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -154,7 +153,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return optimisticType == null ? Type.OBJECT : optimisticType;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java Tue Dec 23 13:57:28 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
@@ -39,14 +38,7 @@
static final String OPT_IDENTIFIER = "%";
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
- Expression(final long token, final int start, final int finish) {
+ protected Expression(final long token, final int start, final int finish) {
super(token, start, finish);
}
@@ -63,18 +55,7 @@
*
* @return the type of the expression.
*/
- public final Type getType() {
- return getType(UNKNOWN_LOCALS);
- }
-
- /**
- * Returns the type of the expression under the specified symbol-to-type mapping. By default delegates to
- * {@link #getType()} but expressions whose type depends on their subexpressions' types and expressions whose type
- * depends on symbol type ({@link IdentNode}) will have a special implementation.
- * @param localVariableTypes a mapping from symbols to their types, used for type calculation.
- * @return the type of the expression under the specified symbol-to-type mapping.
- */
- public abstract Type getType(final Function<Symbol, Type> localVariableTypes);
+ public abstract Type getType();
/**
* Returns {@code true} if this expression depends exclusively on state that is constant
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -36,7 +36,6 @@
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
@@ -1101,7 +1100,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return FUNCTION_TYPE;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/GetSplitState.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/GetSplitState.java Tue Dec 23 13:57:28 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -47,7 +46,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.INT;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -30,7 +30,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -118,14 +117,13 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
if(type != null) {
return type;
} else if(symbol != null && symbol.isScope()) {
return Type.OBJECT;
}
- final Type symbolType = localVariableTypes.apply(symbol);
- return symbolType == null ? Type.UNDEFINED : symbolType;
+ return Type.UNDEFINED;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java Tue Dec 23 13:57:28 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -71,8 +70,8 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- return expression.getType(localVariableTypes);
+ public Type getType() {
+ return expression.getType();
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -29,7 +29,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
@@ -109,7 +108,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.typeFor(value.getClass());
}
@@ -164,16 +163,6 @@
}
/**
- * Get the array value of the node
- *
- * @return the array value
- */
- public Node[] getArray() {
- assert false : "not an array node";
- return null;
- }
-
- /**
* Fetch String value of node.
*
* @return String value of node.
@@ -325,7 +314,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.BOOLEAN;
}
@@ -389,7 +378,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return type;
}
@@ -519,7 +508,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
@@ -589,7 +578,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
@@ -840,9 +829,13 @@
this.units = units;
}
- @Override
- public Node[] getArray() {
- return value;
+ /**
+ * Returns a list of array element expressions. Note that empty array elements manifest themselves as
+ * null.
+ * @return a list of array element expressions.
+ */
+ public List<Expression> getElementExpressions() {
+ return Collections.unmodifiableList(Arrays.asList(value));
}
/**
@@ -879,7 +872,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.typeFor(NativeArray.class);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -27,7 +27,6 @@
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -69,7 +68,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -30,7 +30,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -460,7 +459,7 @@
* Return type for the ReferenceNode
*/
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return request.getReturnType();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -122,8 +121,8 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- return Type.widestReturnType(getTrueExpression().getType(localVariableTypes), getFalseExpression().getType(localVariableTypes));
+ public Type getType() {
+ return Type.widestReturnType(getTrueExpression().getType(), getFalseExpression().getType());
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java Tue Dec 23 13:57:28 2014 -0800
@@ -33,7 +33,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -123,23 +122,11 @@
return isAssignment();
}
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
-
@Override
public Type getWidestOperationType() {
- return getWidestOperationType(UNKNOWN_LOCALS);
- }
-
- private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
switch (tokenType()) {
case ADD:
- final Type operandType = getExpression().getType(localVariableTypes);
+ final Type operandType = getExpression().getType();
if(operandType == Type.BOOLEAN) {
return Type.INT;
} else if(operandType.isObject()) {
@@ -326,12 +313,12 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- final Type widest = getWidestOperationType(localVariableTypes);
+ public Type getType() {
+ final Type widest = getWidestOperationType();
if(type == null) {
return widest;
}
- return Type.narrowest(widest, Type.widest(type, expression.getType(localVariableTypes)));
+ return Type.narrowest(widest, Type.widest(type, expression.getType()));
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/JSONWriter.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/JSONWriter.java Tue Dec 23 13:57:28 2014 -0800
@@ -28,7 +28,6 @@
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -553,8 +552,7 @@
type("ArrayExpression");
comma();
- final Node[] value = literalNode.getArray();
- array("elements", Arrays.asList(value));
+ array("elements", ((LiteralNode.ArrayLiteralNode)literalNode).getElementExpressions());
} else {
type("Literal");
comma();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Tue Dec 23 13:57:28 2014 -0800
@@ -275,7 +275,7 @@
final PropertyDescriptor newLenDesc = desc;
// Step 3c and 3d - get new length and convert to long
- final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
+ final long newLen = NativeArray.validLength(newLenDesc.getValue());
// Step 3e
newLenDesc.setValue(newLen);
@@ -348,8 +348,8 @@
final PropertyDescriptor oldLenDesc = (PropertyDescriptor) super.getOwnPropertyDescriptor("length");
// Step 2
- // get old length and convert to long
- final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
+ // get old length and convert to long. Always a Long/Uint32 but we take the safe road.
+ final long oldLen = JSType.toUint32(oldLenDesc.getValue());
// Step 3
if ("length".equals(key)) {
@@ -471,7 +471,7 @@
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (isArray(self)) {
- ((ScriptObject)self).setLength(validLength(length, true));
+ ((ScriptObject)self).setLength(validLength(length));
}
}
@@ -495,18 +495,13 @@
length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype
}
- static long validLength(final Object length, final boolean reject) {
+ static long validLength(final Object length) {
+ // ES5 15.4.5.1, steps 3.c and 3.d require two ToNumber conversions here
final double doubleLength = JSType.toNumber(length);
- if (!Double.isNaN(doubleLength) && JSType.isRepresentableAsLong(doubleLength)) {
- final long len = (long) doubleLength;
- if (len >= 0 && len <= JSType.MAX_UINT) {
- return len;
- }
- }
- if (reject) {
+ if (doubleLength != JSType.toUint32(length)) {
throw rangeError("inappropriate.array.length", ScriptRuntime.safeToString(length));
}
- return -1;
+ return (long) doubleLength;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Tue Dec 23 13:57:28 2014 -0800
@@ -88,7 +88,7 @@
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (self instanceof ScriptObject) {
- ((ScriptObject)self).setLength(NativeArray.validLength(length, true));
+ ((ScriptObject)self).setLength(NativeArray.validLength(length));
}
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Tue Dec 23 13:57:28 2014 -0800
@@ -86,7 +86,7 @@
* @param source the script source
* @param mainClassName the main class name
* @param classBytes map of class names to class bytes
- * @param initializers compilation id -> FunctionInitializer map
+ * @param initializers compilation id -> FunctionInitializer map
* @param constants constants array
* @param compilationId compilation id
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Tue Dec 23 13:57:28 2014 -0800
@@ -180,10 +180,10 @@
/** Div exact wrapper for potentially integer division that turns into float point */
public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
- /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
+ /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
- /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
+ /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
/** Mod exact wrapper for potentially integer remainders that turns into float point */
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Tue Dec 23 13:57:28 2014 -0800
@@ -58,7 +58,7 @@
* @param compilationId compilation id
* @param mainClassName main class name
* @param classBytes map of class names to class bytes
- * @param initializers initializer map, id -> FunctionInitializer
+ * @param initializers initializer map, id -> FunctionInitializer
* @param constants constants array
*/
public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Tue Dec 23 13:57:28 2014 -0800
@@ -275,7 +275,7 @@
/**
* Align an array size up to the nearest array chunk size
* @param size size required
- * @return size given, always >= size
+ * @return size given, always >= size
*/
protected final static int alignUp(final int size) {
return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Tue Dec 23 13:57:28 2014 -0800
@@ -99,7 +99,7 @@
MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
if (isCall) {
// R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
- newMethodType = newMethodType.changeParameterType(1, boundThis.getClass());
+ newMethodType = newMethodType.changeParameterType(1, boundThis == null? Object.class : boundThis.getClass());
}
// R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
for(int i = boundArgs.length; i-- > 0;) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Tue Dec 23 13:57:28 2014 -0800
@@ -40,6 +40,7 @@
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
/**
@@ -118,20 +119,21 @@
private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception {
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
final int c = desc.getNameTokenCount();
+ GuardedInvocation inv;
+ try {
+ inv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
+ } catch (Throwable th) {
+ inv = null;
+ }
switch (operator) {
case "getProp":
case "getElem":
case "getMethod":
- if (c > 2) {
- return findGetMethod(desc);
- }
- // For indexed get, we want GuardedInvocation from beans linker and pass it.
- // BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access.
- return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
+ return c > 2? findGetMethod(desc, inv) : findGetIndexMethod(inv);
case "setProp":
case "setElem":
- return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
+ return c > 2? findSetMethod(desc, inv) : findSetIndexMethod();
case "call":
return findCallMethod(desc);
default:
@@ -139,7 +141,10 @@
}
}
- private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) {
+ private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final GuardedInvocation inv) {
+ if (inv != null) {
+ return inv;
+ }
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final MethodHandle getter = MH.insertArguments(JSOBJECT_GETMEMBER, 1, name);
return new GuardedInvocation(getter, IS_JSOBJECT_GUARD);
@@ -150,7 +155,10 @@
return inv.replaceMethods(getter, inv.getGuard());
}
- private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc) {
+ private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final GuardedInvocation inv) {
+ if (inv != null) {
+ return inv;
+ }
final MethodHandle getter = MH.insertArguments(JSOBJECT_SETMEMBER, 1, desc.getNameToken(2));
return new GuardedInvocation(getter, IS_JSOBJECT_GUARD);
}
@@ -178,12 +186,12 @@
if (index > -1) {
return JSOBJECT_GETSLOT.invokeExact(jsobj, index);
}
- } else if (key instanceof String) {
- final String name = (String)key;
+ } else if (key instanceof String || key instanceof ConsString) {
+ final String name = key.toString();
if (name.indexOf('(') != -1) {
- return fallback.invokeExact(jsobj, key);
+ return fallback.invokeExact(jsobj, (Object) name);
}
- return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
+ return JSOBJECT_GETMEMBER.invokeExact(jsobj, name);
}
return null;
}
@@ -194,8 +202,8 @@
JSOBJECT_SETSLOT.invokeExact(jsobj, (int)key, value);
} else if (key instanceof Number) {
JSOBJECT_SETSLOT.invokeExact(jsobj, getIndex((Number)key), value);
- } else if (key instanceof String) {
- JSOBJECT_SETMEMBER.invokeExact(jsobj, (String)key, value);
+ } else if (key instanceof String || key instanceof ConsString) {
+ JSOBJECT_SETMEMBER.invokeExact(jsobj, key.toString(), value);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Tue Dec 23 13:57:28 2014 -0800
@@ -42,6 +42,7 @@
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
/**
@@ -185,11 +186,11 @@
if (index > -1) {
return ((JSObject)jsobj).getSlot(index);
}
- } else if (key instanceof String) {
- final String name = (String)key;
+ } else if (key instanceof String || key instanceof ConsString) {
+ final String name = key.toString();
// get with method name and signature. delegate it to beans linker!
if (name.indexOf('(') != -1) {
- return fallback.invokeExact(jsobj, key);
+ return fallback.invokeExact(jsobj, (Object) name);
}
return ((JSObject)jsobj).getMember(name);
}
@@ -202,8 +203,8 @@
((JSObject)jsobj).setSlot((Integer)key, value);
} else if (key instanceof Number) {
((JSObject)jsobj).setSlot(getIndex((Number)key), value);
- } else if (key instanceof String) {
- ((JSObject)jsobj).setMember((String)key, value);
+ } else if (key instanceof String || key instanceof ConsString) {
+ ((JSObject)jsobj).setMember(key.toString(), value);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Dec 23 13:57:28 2014 -0800
@@ -26,17 +26,23 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.GlobalConstants;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
/**
@@ -46,6 +52,11 @@
*/
public final class PrimitiveLookup {
+ /** Method handle to link setters on primitive base. See ES5 8.7.2. */
+ private static final MethodHandle PRIMITIVE_SETTER = findOwnMH("primitiveSetter",
+ MH.type(void.class, ScriptObject.class, Object.class, Object.class, boolean.class, Object.class));
+
+
private PrimitiveLookup() {
}
@@ -87,40 +98,58 @@
final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+ final String name;
+ final FindProperty find;
- //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
- //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
- //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
if (desc.getNameTokenCount() > 2) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- final FindProperty find = wrappedReceiver.findProperty(name, true);
+ name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ find = wrappedReceiver.findProperty(name, true);
+ } else {
+ name = null;
+ find = null;
+ }
- if (find == null) {
- // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
- return null;
- }
+ final String firstOp = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
- final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
- if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
- return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
- }
+ switch (firstOp) {
+ case "getProp":
+ case "getElem":
+ case "getMethod":
+ //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
+ //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
+ //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
+ if (name != null) {
+ if (find == null) {
+ // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
+ return null;
+ }
- if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
- // If property is found in the prototype object bind the method handle directly to
- // the proto filter instead of going through wrapper instantiation below.
- final ScriptObject proto = wrappedReceiver.getProto();
- final GuardedInvocation link = proto.lookup(desc, request);
+ final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
+ if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
+ return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
+ }
- if (link != null) {
- final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+ if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+ // If property is found in the prototype object bind the method handle directly to
+ // the proto filter instead of going through wrapper instantiation below.
+ final ScriptObject proto = wrappedReceiver.getProto();
+ final GuardedInvocation link = proto.lookup(desc, request);
- final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
- final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
- final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
-
- return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+ if (link != null) {
+ final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+ final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
+ final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
+ final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+ return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+ }
}
}
+ break;
+ case "setProp":
+ case "setElem":
+ return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc));
+ default:
+ break;
}
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
@@ -138,4 +167,41 @@
return null;
}
+
+ private static GuardedInvocation getPrimitiveSetter(final String name, final MethodHandle guard,
+ final MethodHandle wrapFilter, final boolean isStrict) {
+ MethodHandle filter = MH.asType(wrapFilter, wrapFilter.type().changeReturnType(ScriptObject.class));
+ final MethodHandle target;
+
+ if (name == null) {
+ filter = MH.dropArguments(filter, 1, Object.class, Object.class);
+ target = MH.insertArguments(PRIMITIVE_SETTER, 3, isStrict);
+ } else {
+ filter = MH.dropArguments(filter, 1, Object.class);
+ target = MH.insertArguments(PRIMITIVE_SETTER, 2, name, isStrict);
+ }
+
+ return new GuardedInvocation(MH.foldArguments(target, filter), guard);
+ }
+
+
+ @SuppressWarnings("unused")
+ private static void primitiveSetter(final ScriptObject wrappedSelf, final Object self, final Object key,
+ final boolean strict, final Object value) {
+ // See ES5.1 8.7.2 PutValue (V, W)
+ final String name = JSType.toString(key);
+ final FindProperty find = wrappedSelf.findProperty(name, true);
+ if (find == null || !(find.getProperty() instanceof UserAccessorProperty) || !find.getProperty().isWritable()) {
+ if (strict) {
+ throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
+ }
+ return;
+ }
+ // property found and is a UserAccessorProperty
+ find.setValue(value, strict);
+ }
+
+ private static MethodHandle findOwnMH(final String name, final MethodType type) {
+ return MH.findStatic(MethodHandles.lookup(), PrimitiveLookup.class, name, type);
+ }
}
--- a/nashorn/test/script/basic/JDK-8055762.js Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/test/script/basic/JDK-8055762.js Tue Dec 23 13:57:28 2014 -0800
@@ -74,9 +74,12 @@
}
};
+ var a = "a";
print(obj["foo"]);
+ print(obj[a + "bc"]);
print(obj[2]);
obj.bar = 23;
+ obj[a + "bc"] = 23;
obj[3] = 23;
obj.func("hello");
}
--- a/nashorn/test/script/basic/JDK-8055762.js.EXPECTED Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/test/script/basic/JDK-8055762.js.EXPECTED Tue Dec 23 13:57:28 2014 -0800
@@ -1,5 +1,7 @@
FOO
+ABC
0
bar set to 23
+abc set to 23
[3] set to 23
func called with hello
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066215.js Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 2014, 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-8066215: Fuzzing bug: length valueOf bug
+ *
+ * @test
+ * @run
+ */
+
+function defineLength(arr, length) {
+ Object.defineProperty(arr, "length", {
+ value: {
+ valueOf: function() {
+ print("value retrieved: " + length);
+ return length;
+ }
+ }
+ });
+ print("done: " + arr.length + ", " + typeof arr.length);
+}
+
+var a = [];
+defineLength(a, 3);
+defineLength(a, 6);
+defineLength(a, 3);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066215.js.EXPECTED Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,9 @@
+value retrieved: 3
+value retrieved: 3
+done: 3, number
+value retrieved: 6
+value retrieved: 6
+done: 6, number
+value retrieved: 3
+value retrieved: 3
+done: 3, number
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066226.js Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014, 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-8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory
+ *
+ * @test
+ * @run
+ */
+
+Object.defineProperty(Object.prototype, "accessor", {
+ set: function(value) {
+ print("Setting accessor on " + this + " to " + value);
+ }
+});
+
+Object.defineProperty(Object.prototype, "getterOnly", {
+ get: function() {
+ return 1;
+ }
+});
+
+function set(o) {
+ print("set(" + o + ")");
+ o.foo = 1;
+ o.constructor = 1;
+ o.accessor = 1;
+ o.getterOnly = 1;
+ print();
+}
+
+function setStrict(o) {
+ "use strict";
+ print("setStrict(" + o + ")")
+ try {
+ o.foo = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.constructor = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.accessor = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.getterOnly = 1;
+ } catch (e) {
+ print(e);
+ }
+ print();
+}
+
+function setAttr(o, id) {
+ print("setAttr(" + o + ", " + id + ")")
+ o[id] = 1;
+ print();
+}
+
+function setAttrStrict(o, id) {
+ "use strict";
+ print("setAttrStrict(" + o + ", " + id + ")")
+ try {
+ o[id] = 1;
+ } catch (e) {
+ print(e);
+ }
+ print();
+}
+
+set(1);
+set("str");
+set(true);
+set({});
+set([]);
+
+setStrict(1);
+setStrict("str");
+setStrict(true);
+setStrict({});
+setStrict([]);
+
+setAttr(1, "foo");
+setAttr(1, "constructor");
+setAttr(1, "accessor");
+setAttr(1, "getterOnly");
+setAttr("str", "foo");
+setAttr("str", "constructor");
+setAttr("str", "accessor");
+setAttr("str", "getterOnly");
+setAttr(true, "foo");
+setAttr(true, "constructor");
+setAttr(true, "accessor");
+setAttr(true, "getterOnly");
+
+setAttrStrict(1, "foo");
+setAttrStrict(1, "constructor");
+setAttrStrict(1, "accessor");
+setAttrStrict(1, "getterOnly");
+setAttrStrict("str", "foo");
+setAttrStrict("str", "constructor");
+setAttrStrict("str", "accessor");
+setAttrStrict("str", "getterOnly");
+setAttrStrict(true, "foo");
+setAttrStrict(true, "constructor");
+setAttrStrict(true, "accessor");
+setAttrStrict(true, "getterOnly");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066226.js.EXPECTED Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,104 @@
+set(1)
+Setting accessor on 1 to 1
+
+set(str)
+Setting accessor on str to 1
+
+set(true)
+Setting accessor on true to 1
+
+set([object Object])
+Setting accessor on [object Object] to 1
+
+set()
+Setting accessor on to 1
+
+setStrict(1)
+TypeError: "foo" is not a writable property of 1
+TypeError: "constructor" is not a writable property of 1
+Setting accessor on 1 to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict(str)
+TypeError: "foo" is not a writable property of str
+TypeError: "constructor" is not a writable property of str
+Setting accessor on str to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict(true)
+TypeError: "foo" is not a writable property of true
+TypeError: "constructor" is not a writable property of true
+Setting accessor on true to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict([object Object])
+Setting accessor on [object Object] to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict()
+Setting accessor on to 1
+TypeError: Cannot set property "getterOnly" of [object Array] that has only a getter
+
+setAttr(1, foo)
+
+setAttr(1, constructor)
+
+setAttr(1, accessor)
+Setting accessor on 1 to 1
+
+setAttr(1, getterOnly)
+
+setAttr(str, foo)
+
+setAttr(str, constructor)
+
+setAttr(str, accessor)
+Setting accessor on str to 1
+
+setAttr(str, getterOnly)
+
+setAttr(true, foo)
+
+setAttr(true, constructor)
+
+setAttr(true, accessor)
+Setting accessor on true to 1
+
+setAttr(true, getterOnly)
+
+setAttrStrict(1, foo)
+TypeError: "foo" is not a writable property of 1
+
+setAttrStrict(1, constructor)
+TypeError: "constructor" is not a writable property of 1
+
+setAttrStrict(1, accessor)
+Setting accessor on 1 to 1
+
+setAttrStrict(1, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setAttrStrict(str, foo)
+TypeError: "foo" is not a writable property of str
+
+setAttrStrict(str, constructor)
+TypeError: "constructor" is not a writable property of str
+
+setAttrStrict(str, accessor)
+Setting accessor on str to 1
+
+setAttrStrict(str, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setAttrStrict(true, foo)
+TypeError: "foo" is not a writable property of true
+
+setAttrStrict(true, constructor)
+TypeError: "constructor" is not a writable property of true
+
+setAttrStrict(true, accessor)
+Setting accessor on true to 1
+
+setAttrStrict(true, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8067774.js Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014 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-8067774: Use a stack of types when calculating local variable types
+ *
+ * @test
+ * @run
+ */
+
+print((function (p) {
+ var a, b;
+
+ a = p ? ((b = 1), b) : 0;
+
+ return a;
+})(true));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8067774.js.EXPECTED Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,1 @@
+1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8067854.js Tue Dec 23 13:57:28 2014 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, 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-8067854: bound java static method throws NPE when 'null' is used for this argument
+ *
+ * @test
+ * @run
+ */
+
+getProp = java.lang.System.getProperty;
+
+// bind this and an argument. "null" for this as getProperty is a
+// static method of java.lang.System
+getHome = Function.prototype.bind.call(getProp, null, "java.home");
+
+if (getHome() != getProp("java.home")) {
+ fail("getHome() failed to get java.home");
+}
--- a/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Thu Dec 18 19:57:57 2014 -0800
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Tue Dec 23 13:57:28 2014 -0800
@@ -109,6 +109,35 @@
}
}
+ // @bug 8062030: Nashorn bug retrieving array property after key string concatenation
+ @Test
+ // ConsString attribute access on a JSObject
+ public void consStringTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ final MapWrapperObject obj = new MapWrapperObject();
+ e.put("obj", obj);
+ e.put("f", "f");
+ e.eval("obj[f + 'oo'] = 'bar';");
+
+ assertEquals(obj.getMap().get("foo"), "bar");
+ assertEquals(e.eval("obj[f + 'oo']"), "bar");
+ assertEquals(e.eval("obj['foo']"), "bar");
+ assertEquals(e.eval("f + 'oo' in obj"), Boolean.TRUE);
+ assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
+ e.eval("delete obj[f + 'oo']");
+ assertFalse(obj.getMap().containsKey("foo"));
+ assertEquals(e.eval("obj[f + 'oo']"), null);
+ assertEquals(e.eval("obj['foo']"), null);
+ assertEquals(e.eval("f + 'oo' in obj"), Boolean.FALSE);
+ assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
public static class BufferObject extends AbstractJSObject {
private final IntBuffer buf;