This commit is contained in:
Athijegannathan Sundararajan 2013-07-12 20:12:29 +05:30
commit 62ca9dfc18
109 changed files with 2541 additions and 1092 deletions
nashorn
make
src/jdk/nashorn
api/scripting
internal
test/script/basic

@ -219,8 +219,10 @@
target="${javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false">
<compilerarg line="-extdirs &quot;&quot;"/>
includeantruntime="false" fork="true">
<compilerarg value="-J-Djava.ext.dirs="/>
<compilerarg value="-Xlint:unchecked"/>
<compilerarg value="-Xlint:deprecation"/>
</javac>
<!-- tests that check nashorn internals and internal API -->

@ -33,6 +33,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.AccessController;
@ -184,6 +185,19 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
private <T> T getInterfaceInner(final Object self, final Class<T> clazz) {
if (clazz == null || !clazz.isInterface()) {
throw new IllegalArgumentException("interface Class expected");
}
// perform security access check as early as possible
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (! Modifier.isPublic(clazz.getModifiers())) {
throw new SecurityException("attempt to implement non-public interfce: " + clazz);
}
Context.checkPackageAccess(clazz.getName());
}
final ScriptObject realSelf;
final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
if(self == null) {
@ -193,6 +207,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} else {
realSelf = (ScriptObject)self;
}
try {
final ScriptObject oldGlobal = getNashornGlobal();
try {

@ -61,6 +61,7 @@ import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@ -72,7 +73,6 @@ import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
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;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@ -94,7 +94,6 @@ import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
* This is the attribution pass of the code generator. Attr takes Lowered IR,
@ -166,19 +165,19 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE);
initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL);
initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT);
if (functionNode.isVarArg()) {
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY);
initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL);
if (functionNode.needsArguments()) {
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
addLocalDef(ARGUMENTS.symbolName());
}
}
initParameters(functionNode, body);
initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.OBJECT);
}
@ -513,7 +512,6 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
assert nameSymbol != null;
selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol);
newStatements.add(selfInit);
newStatements.addAll(body.getStatements());
@ -740,15 +738,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return end(ensureSymbol(Type.OBJECT, objectNode));
}
@Override
public Node leavePropertyNode(final PropertyNode propertyNode) {
// assign a pseudo symbol to property name, see NASHORN-710
return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
}
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
final Expression expr = returnNode.getExpression();
final Type returnType;
if (expr != null) {
@ -785,7 +777,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
final LiteralNode<?> lit = (LiteralNode<?>)test;
if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
if (JSType.isRepresentableAsInt(lit.getNumber())) {
newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
newCaseNode = caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
}
}
} else {
@ -848,19 +840,18 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveVarNode(final VarNode varNode) {
VarNode newVarNode = varNode;
final Expression init = varNode.getInit();
final IdentNode ident = varNode.getName();
final String name = ident.getName();
final Node init = newVarNode.getInit();
final IdentNode ident = newVarNode.getName();
final String name = ident.getName();
final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
final Symbol symbol = findSymbol(lc.getCurrentBlock(), name);
assert ident.getSymbol() == symbol;
if (init == null) {
// var x; with no init will be treated like a use of x by
// leaveIdentNode unless we remove the name from the localdef list.
removeLocalDef(name);
return end(newVarNode.setSymbol(lc, symbol));
return end(varNode);
}
addLocalDef(name);
@ -869,8 +860,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
newVarNode = newVarNode.setName(newIdent);
newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol);
final VarNode newVarNode = varNode.setName(newIdent);
final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56
if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
@ -880,7 +870,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
newType(symbol, Type.OBJECT);
}
assert newVarNode.hasType() : newVarNode + " has no type";
assert newVarNode.getName().hasType() : newVarNode + " has no type";
return end(newVarNode);
}
@ -908,11 +898,11 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
public Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
final Node rhs = unaryNode.rhs();
final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
final Expression rhs = unaryNode.rhs();
final Expression strictFlagNode = (Expression)LiteralNode.newInstance(unaryNode, strictMode).accept(this);
Request request = Request.DELETE;
final List<Node> args = new ArrayList<>();
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode) {
// If this is a declared variable or a function parameter, delete always fails (except for globals).
@ -923,7 +913,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
if (failDelete && rhs.getSymbol().isThis()) {
return LiteralNode.newInstance(unaryNode, true).accept(this);
}
final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this);
final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
if (!failDelete) {
args.add(compilerConstant(SCOPE));
@ -935,16 +925,17 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
request = Request.FAIL_DELETE;
}
} else if (rhs instanceof AccessNode) {
final Node base = ((AccessNode)rhs).getBase();
final IdentNode property = ((AccessNode)rhs).getProperty();
final Expression base = ((AccessNode)rhs).getBase();
final IdentNode property = ((AccessNode)rhs).getProperty();
args.add(base);
args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
args.add((Expression)LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
args.add(strictFlagNode);
} else if (rhs instanceof IndexNode) {
final Node base = ((IndexNode)rhs).getBase();
final Node index = ((IndexNode)rhs).getIndex();
final IndexNode indexNode = (IndexNode)rhs;
final Expression base = indexNode.getBase();
final Expression index = indexNode.getIndex();
args.add(base);
args.add(index);
@ -999,15 +990,15 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTYPEOF(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
final Expression rhs = unaryNode.rhs();
List<Node> args = new ArrayList<>();
List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
args.add(compilerConstant(SCOPE));
args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
} else {
args.add(rhs);
args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
}
RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
@ -1041,8 +1032,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
*/
@Override
public Node leaveADD(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
ensureTypeNotUnknown(lhs);
ensureTypeNotUnknown(rhs);
@ -1097,8 +1088,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private Node leaveAssignmentNode(final BinaryNode binaryNode) {
BinaryNode newBinaryNode = binaryNode;
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type type;
if (rhs.getType().isNumeric()) {
@ -1134,8 +1125,8 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type widest = Type.widest(lhs.getType(), rhs.getType());
//Type.NUMBER if we can't prove that the add doesn't overflow. todo
@ -1414,19 +1405,26 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node lhs = ternaryNode.rhs();
final Node rhs = ternaryNode.third();
final Expression trueExpr = ternaryNode.getTrueExpression();
final Expression falseExpr = ternaryNode.getFalseExpression();
ensureTypeNotUnknown(lhs);
ensureTypeNotUnknown(rhs);
ensureTypeNotUnknown(trueExpr);
ensureTypeNotUnknown(falseExpr);
final Type type = Type.widest(lhs.getType(), rhs.getType());
final Type type = Type.widest(trueExpr.getType(), falseExpr.getType());
return end(ensureSymbol(type, ternaryNode));
}
private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
final Class<?> type = cc.type();
// Must not call this method for constants with no explicit types; use the one with (..., Type) signature instead.
assert type != null;
initCompileConstant(cc, block, flags, Type.typeFor(type));
}
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.setTypeOverride(type);
symbol.setNeedsSlot(true);
}
@ -1531,7 +1529,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
}
}
private static void ensureTypeNotUnknown(final Node node) {
private static void ensureTypeNotUnknown(final Expression node) {
final Symbol symbol = node.getSymbol();
@ -1588,13 +1586,13 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
*
* @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
*/
private Node ensureAssignmentSlots(final Node assignmentDest) {
private Expression ensureAssignmentSlots(final Expression assignmentDest) {
final LexicalContext attrLexicalContext = lc;
return assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
return (Expression)assignmentDest.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public Node leaveIndexNode(final IndexNode indexNode) {
assert indexNode.getSymbol().isTemp();
final Node index = indexNode.getIndex();
final Expression 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
Symbol indexSymbol = index.getSymbol();
@ -1636,7 +1634,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
changed.clear();
final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
private Node widen(final Node node, final Type to) {
private Expression widen(final Expression node, final Type to) {
if (node instanceof LiteralNode) {
return node;
}
@ -1648,7 +1646,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
}
newType(symbol, to);
final Node newNode = node.setSymbol(lc, symbol);
final Expression newNode = node.setSymbol(lc, symbol);
changed.add(newNode);
return newNode;
}
@ -1703,7 +1701,7 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) {
//e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType()) is the coerce type
final Node lhs = binaryNode.lhs();
final Expression 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
@ -1711,9 +1709,9 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
}
private Node ensureSymbol(final Type type, final Node node) {
private Expression ensureSymbol(final Type type, final Expression expr) {
LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
return temporarySymbols.ensureSymbol(lc, type, node);
return temporarySymbols.ensureSymbol(lc, type, expr);
}
private Symbol newInternal(final String name, final Type type) {
@ -1835,11 +1833,11 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
return true;
}
private Node end(final Node node) {
private <T extends Node> T end(final T node) {
return end(node, true);
}
private Node end(final Node node, final boolean printNode) {
private <T extends Node> T end(final T node, final boolean printNode) {
if(node instanceof Statement) {
// If we're done with a statement, all temporaries can be reused.
temporarySymbols.reuse();
@ -1854,10 +1852,13 @@ final class Attr extends NodeOperatorVisitor<LexicalContext> {
append(" in '").
append(lc.getCurrentFunction().getName());
if (node.getSymbol() == null) {
sb.append(" <NO SYMBOL>");
} else {
sb.append(" <symbol=").append(node.getSymbol()).append('>');
if(node instanceof Expression) {
final Symbol symbol = ((Expression)node).getSymbol();
if (symbol == null) {
sb.append(" <NO SYMBOL>");
} else {
sb.append(" <symbol=").append(symbol).append('>');
}
}
LOG.unindent();

@ -34,7 +34,7 @@ import static jdk.nashorn.internal.codegen.Condition.NE;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
@ -52,16 +52,16 @@ final class BranchOptimizer {
this.method = method;
}
void execute(final Node node, final Label label, final boolean state) {
void execute(final Expression node, final Label label, final boolean state) {
branchOptimizer(node, label, state);
}
private void load(final Node node) {
private void load(final Expression node) {
codegen.load(node);
}
private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
final Node rhs = unaryNode.rhs();
final Expression rhs = unaryNode.rhs();
switch (unaryNode.tokenType()) {
case NOT:
@ -88,8 +88,8 @@ final class BranchOptimizer {
}
private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
switch (binaryNode.tokenType()) {
case AND:
@ -173,7 +173,7 @@ final class BranchOptimizer {
}
}
private void branchOptimizer(final Node node, final Label label, final boolean state) {
private void branchOptimizer(final Expression node, final Label label, final boolean state) {
if (!(node instanceof TernaryNode)) {
if (node instanceof BinaryNode) {

@ -55,10 +55,12 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@ -69,6 +71,7 @@ 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.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
@ -76,7 +79,8 @@ import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
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;
@ -182,6 +186,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
/** From what size should we use spill instead of fields for JavaScript objects? */
private static final int OBJECT_SPILL_THRESHOLD = 300;
private final Set<String> emittedMethods = new HashSet<>();
/**
* Constructor.
*
@ -350,11 +356,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* @return the method emitter used
*/
MethodEmitter load(final Node node) {
MethodEmitter load(final Expression node) {
return load(node, false);
}
private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) {
private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) {
final Symbol symbol = node.getSymbol();
// If we lack symbols, we just generate what we see.
@ -488,6 +494,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterBlock(final Block block) {
if(lc.isFunctionBody() && emittedMethods.contains(lc.getCurrentFunction().getName())) {
return false;
}
method.label(block.getEntryLabel());
initLocals(block);
@ -539,11 +548,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
private int loadArgs(final List<Node> args) {
private int loadArgs(final List<Expression> args) {
return loadArgs(args, null, false, args.size());
}
private int loadArgs(final List<Node> args, final String signature, final boolean isVarArg, final int argCount) {
private int loadArgs(final List<Expression> args, final String signature, final boolean isVarArg, final int argCount) {
// arg have already been converted to objects here.
if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) {
loadArgsArray(args);
@ -553,7 +562,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// pad with undefined if size is too short. argCount is the real number of args
int n = 0;
final Type[] params = signature == null ? null : Type.getMethodArguments(signature);
for (final Node arg : args) {
for (final Expression arg : args) {
assert arg != null;
load(arg);
if (n >= argCount) {
@ -574,13 +583,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterCallNode(final CallNode callNode) {
lineNumber(callNode);
lineNumber(callNode.getLineNumber());
final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction();
final Block currentBlock = lc.getCurrentBlock();
final List<Expression> args = callNode.getArgs();
final Expression function = callNode.getFunction();
final Block currentBlock = lc.getCurrentBlock();
final CodeGeneratorLexicalContext codegenLexicalContext = lc;
final Type callNodeType = callNode.getType();
final Type callNodeType = callNode.getType();
function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@ -771,11 +780,19 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
@Override
public boolean enterExecuteNode(final ExecuteNode executeNode) {
lineNumber(executeNode);
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
lineNumber(expressionStatement);
final Node expression = executeNode.getExpression();
expression.accept(this);
expressionStatement.getExpression().accept(this);
return false;
}
@Override
public boolean enterBlockStatement(final BlockStatement blockStatement) {
lineNumber(blockStatement);
blockStatement.getBlock().accept(this);
return false;
}
@ -794,10 +811,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void enterFor(final ForNode forNode) {
final Node init = forNode.getInit();
final Node test = forNode.getTest();
final Block body = forNode.getBody();
final Node modify = forNode.getModify();
final Expression init = forNode.getInit();
final Expression test = forNode.getTest();
final Block body = forNode.getBody();
final Expression modify = forNode.getModify();
if (init != null) {
init.accept(this);
@ -827,19 +844,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private void enterForIn(final ForNode forNode) {
final Block body = forNode.getBody();
final Node modify = forNode.getModify();
final Expression modify = forNode.getModify();
final Symbol iter = forNode.getIterator();
final Label loopLabel = new Label("loop");
Node init = forNode.getInit();
// We have to evaluate the optional initializer expression
// of the iterator variable of the for-in statement.
if (init instanceof VarNode) {
init.accept(this);
init = ((VarNode)init).getName();
}
final Expression init = forNode.getInit();
assert init instanceof IdentNode;
load(modify);
assert modify.getType().isObject();
@ -848,7 +859,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method._goto(forNode.getContinueLabel());
method.label(loopLabel);
new Store<Node>(init) {
new Store<Expression>(init) {
@Override
protected void storeNonDiscard() {
return;
@ -1003,17 +1014,28 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
LOG.info("=== BEGIN ", functionNode.getName());
final String fnName = functionNode.getName();
// NOTE: we only emit the method for a function with the given name once. We can have multiple functions with
// the same name as a result of inlining finally blocks. However, in the future -- with type specialization,
// notably -- we might need to check for both name *and* signature. Of course, even that might not be
// sufficient; the function might have a code dependency on the type of the variables in its enclosing scopes,
// and the type of such a variable can be different in catch and finally blocks. So, in the future we will have
// to decide to either generate a unique method for each inlined copy of the function, maybe figure out its
// exact type closure and deduplicate based on that, or just decide that functions in finally blocks aren't
// worth it, and generate one method with most generic type closure.
if(!emittedMethods.contains(fnName)) {
LOG.info("=== BEGIN ", fnName);
assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
unit = lc.pushCompileUnit(functionNode.getCompileUnit());
assert lc.hasCompileUnits();
assert functionNode.getCompileUnit() != null : "no compile unit for " + fnName + " " + Debug.id(functionNode);
unit = lc.pushCompileUnit(functionNode.getCompileUnit());
assert lc.hasCompileUnits();
method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
// new method - reset last line number
lastLineNumber = -1;
// Mark end for variable tables.
method.begin();
method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
// new method - reset last line number
lastLineNumber = -1;
// Mark end for variable tables.
method.begin();
}
return true;
}
@ -1021,13 +1043,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
try {
method.end(); // wrap up this method
unit = lc.popCompileUnit(functionNode.getCompileUnit());
method = lc.popMethodEmitter(method);
LOG.info("=== END ", functionNode.getName());
if(emittedMethods.add(functionNode.getName())) {
method.end(); // wrap up this method
unit = lc.popCompileUnit(functionNode.getCompileUnit());
method = lc.popMethodEmitter(method);
LOG.info("=== END ", functionNode.getName());
}
final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
newFunctionObject(newFunctionNode, functionNode);
return newFunctionNode;
} catch (final Throwable t) {
@ -1047,7 +1070,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterIfNode(final IfNode ifNode) {
lineNumber(ifNode);
final Node test = ifNode.getTest();
final Expression test = ifNode.getTest();
final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail();
@ -1087,7 +1110,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void lineNumber(final Statement statement) {
final int lineNumber = statement.getLineNumber();
lineNumber(statement.getLineNumber());
}
private void lineNumber(int lineNumber) {
if (lineNumber != lastLineNumber) {
method.lineNumber(lineNumber);
}
@ -1106,7 +1132,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
final Node[] nodes = arrayLiteralNode.getValue();
final Expression[] nodes = arrayLiteralNode.getValue();
final Object presets = arrayLiteralNode.getPresets();
final int[] postsets = arrayLiteralNode.getPostsets();
final Class<?> type = arrayType.getTypeClass();
@ -1166,11 +1192,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method;
}
private void storeElement(final Node[] nodes, final Type elementType, final int index) {
private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
method.dup();
method.load(index);
final Node element = nodes[index];
final Expression element = nodes[index];
if (element == null) {
method.loadEmpty(elementType);
@ -1182,7 +1208,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.arraystore();
}
private MethodEmitter loadArgsArray(final List<Node> args) {
private MethodEmitter loadArgsArray(final List<Expression> args) {
final Object[] array = new Object[args.size()];
loadConstant(array);
@ -1313,7 +1339,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
@Override
public boolean enterLiteralNode(final LiteralNode literalNode) {
public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
load(literalNode).store(literalNode.getSymbol());
return false;
@ -1323,16 +1349,16 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterObjectNode(final ObjectNode objectNode) {
final List<PropertyNode> elements = objectNode.getElements();
final List<String> keys = new ArrayList<>();
final List<Symbol> symbols = new ArrayList<>();
final List<Node> values = new ArrayList<>();
final List<String> keys = new ArrayList<>();
final List<Symbol> symbols = new ArrayList<>();
final List<Expression> values = new ArrayList<>();
boolean hasGettersSetters = false;
for (PropertyNode propertyNode: elements) {
final Node value = propertyNode.getValue();
final Expression value = propertyNode.getValue();
final String key = propertyNode.getKeyName();
final Symbol symbol = value == null ? null : propertyNode.getSymbol();
final Symbol symbol = value == null ? null : propertyNode.getKey().getSymbol();
if (value == null) {
hasGettersSetters = true;
@ -1346,9 +1372,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (elements.size() > OBJECT_SPILL_THRESHOLD) {
new SpillObjectCreator(this, keys, symbols, values).makeObject(method);
} else {
new FieldObjectCreator<Node>(this, keys, symbols, values) {
new FieldObjectCreator<Expression>(this, keys, symbols, values) {
@Override
protected void loadValue(final Node node) {
protected void loadValue(final Expression node) {
load(node);
}
@ -1419,7 +1445,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Type returnType = lc.getCurrentFunction().getReturnType();
final Node expression = returnNode.getExpression();
final Expression expression = returnNode.getExpression();
if (expression != null) {
load(expression);
} else {
@ -1435,7 +1461,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return node instanceof LiteralNode<?> && ((LiteralNode<?>) node).isNull();
}
private boolean nullCheck(final RuntimeNode runtimeNode, final List<Node> args, final String signature) {
private boolean nullCheck(final RuntimeNode runtimeNode, final List<Expression> args, final String signature) {
final Request request = runtimeNode.getRequest();
if (!Request.isEQ(request) && !Request.isNE(request)) {
@ -1444,11 +1470,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
assert args.size() == 2 : "EQ or NE or TYPEOF need two args";
Node lhs = args.get(0);
Node rhs = args.get(1);
Expression lhs = args.get(0);
Expression rhs = args.get(1);
if (isNullLiteral(lhs)) {
final Node tmp = lhs;
final Expression tmp = lhs;
lhs = rhs;
rhs = tmp;
}
@ -1502,7 +1528,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List<Node> args) {
private boolean specializationCheck(final RuntimeNode.Request request, final Expression node, final List<Expression> args) {
if (!request.canSpecialize()) {
return false;
}
@ -1555,10 +1581,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* TODO - remove this - Access Specializer will always know after Attr/Lower
*/
final List<Expression> args = runtimeNode.getArgs();
if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) {
final Node lhs = runtimeNode.getArgs().get(0);
assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args";
final Node rhs = runtimeNode.getArgs().get(1);
final Expression lhs = args.get(0);
assert args.size() > 1 : runtimeNode + " must have two args";
final Expression rhs = args.get(1);
final Type type = runtimeNode.getType();
final Symbol symbol = runtimeNode.getSymbol();
@ -1595,9 +1622,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
}
// Get the request arguments.
final List<Node> args = runtimeNode.getArgs();
if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
return false;
}
@ -1606,7 +1630,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
for (final Node arg : runtimeNode.getArgs()) {
for (final Expression arg : args) {
load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower
}
@ -1617,7 +1641,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
false,
false,
runtimeNode.getType(),
runtimeNode.getArgs().size()).toString());
args.size()).toString());
method.convert(runtimeNode.getType());
method.store(runtimeNode.getSymbol());
@ -1626,8 +1650,6 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterSplitNode(final SplitNode splitNode) {
lineNumber(splitNode);
final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
final FunctionNode fn = lc.getCurrentFunction();
@ -1772,7 +1794,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterSwitchNode(final SwitchNode switchNode) {
lineNumber(switchNode);
final Node expression = switchNode.getExpression();
final Expression expression = switchNode.getExpression();
final Symbol tag = switchNode.getTag();
final boolean allInteger = tag.getSymbolType().isInteger();
final List<CaseNode> cases = switchNode.getCases();
@ -1869,11 +1891,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.store(tag);
method.conditionalJump(Condition.NE, true, defaultLabel);
} else {
assert tag.getSymbolType().isObject();
method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object
method.store(tag);
}
for (final CaseNode caseNode : cases) {
final Node test = caseNode.getTest();
final Expression test = caseNode.getTest();
if (test != null) {
method.load(tag);
@ -1913,10 +1937,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final Source source = lc.getCurrentFunction().getSource();
final Node expression = throwNode.getExpression();
final int position = throwNode.position();
final int line = source.getLine(position);
final int column = source.getColumn(position);
final Expression expression = throwNode.getExpression();
final int position = throwNode.position();
final int line = source.getLine(position);
final int column = source.getColumn(position);
load(expression);
assert expression.getType().isObject();
@ -1965,10 +1989,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lc.push(catchBlock);
enterBlock(catchBlock);
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
final IdentNode exception = catchNode.getException();
final Node exceptionCondition = catchNode.getExceptionCondition();
final Block catchBody = catchNode.getBody();
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
final IdentNode exception = catchNode.getException();
final Expression exceptionCondition = catchNode.getExceptionCondition();
final Block catchBody = catchNode.getBody();
new Store<IdentNode>(exception) {
@Override
@ -2036,7 +2060,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
final Expression init = varNode.getInit();
if (init == null) {
return false;
@ -2044,8 +2068,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lineNumber(varNode);
final Symbol varSymbol = varNode.getSymbol();
assert varSymbol != null : "variable node " + varNode + " requires a symbol";
final Symbol varSymbol = varNode.getName().getSymbol();
assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol";
assert method != null;
@ -2065,9 +2089,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method.dynamicSet(type, identNode.getName(), flags);
}
} else {
assert varNode.getType() == varNode.getName().getType() : "varNode type=" + varNode.getType() + " nametype=" + varNode.getName().getType() + " inittype=" + init.getType();
method.convert(varNode.getType()); // aw: convert moved here
method.convert(varNode.getName().getType()); // aw: convert moved here
method.store(varSymbol);
}
@ -2078,11 +2100,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterWhileNode(final WhileNode whileNode) {
lineNumber(whileNode);
final Node test = whileNode.getTest();
final Block body = whileNode.getBody();
final Label breakLabel = whileNode.getBreakLabel();
final Label continueLabel = whileNode.getContinueLabel();
final Label loopLabel = new Label("loop");
final Expression test = whileNode.getTest();
final Block body = whileNode.getBody();
final Label breakLabel = whileNode.getBreakLabel();
final Label continueLabel = whileNode.getContinueLabel();
final Label loopLabel = new Label("loop");
if (!whileNode.isDoWhile()) {
method._goto(continueLabel);
@ -2109,8 +2131,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterWithNode(final WithNode withNode) {
final Node expression = withNode.getExpression();
final Node body = withNode.getBody();
final Expression expression = withNode.getExpression();
final Node body = withNode.getBody();
// It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's
// pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the
@ -2185,7 +2207,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// do this better with convert calls to method. TODO
@Override
public boolean enterCONVERT(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
final Expression rhs = unaryNode.rhs();
final Type to = unaryNode.getType();
if (to.isObject() && rhs instanceof LiteralNode) {
@ -2222,11 +2244,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterDECINC(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
final Type type = unaryNode.getType();
final TokenType tokenType = unaryNode.tokenType();
final boolean isPostfix = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
final boolean isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
final Expression rhs = unaryNode.rhs();
final Type type = unaryNode.getType();
final TokenType tokenType = unaryNode.tokenType();
final boolean isPostfix = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
final boolean isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
assert !type.isObject();
@ -2270,7 +2292,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterDISCARD(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
final Expression rhs = unaryNode.rhs();
lc.pushDiscard(rhs);
load(rhs);
@ -2287,7 +2309,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterNEW(final UnaryNode unaryNode) {
final CallNode callNode = (CallNode)unaryNode.rhs();
final List<Node> args = callNode.getArgs();
final List<Expression> args = callNode.getArgs();
// Load function reference.
load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error
@ -2300,7 +2322,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterNOT(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs();
final Expression rhs = unaryNode.rhs();
load(rhs);
@ -2334,19 +2356,18 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) {
private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) {
assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
load(lhs);
load(rhs);
method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
method.store(symbol);
return null;
}
@Override
public boolean enterADD(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type type = binaryNode.getType();
if (type.isNumeric()) {
@ -2362,8 +2383,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private boolean enterAND_OR(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Label skip = new Label("skip");
@ -2390,8 +2411,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterASSIGN(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type lhsType = lhs.getType();
final Type rhsType = rhs.getType();
@ -2659,8 +2680,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private boolean enterComma(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
load(lhs);
load(rhs);
@ -2691,7 +2712,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return false;
}
private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) {
private boolean enterCmp(final Expression lhs, final Expression rhs, final Condition cond, final Type type, final Symbol symbol) {
final Type lhsType = lhs.getType();
final Type rhsType = rhs.getType();
@ -2844,21 +2865,21 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override
public boolean enterTernaryNode(final TernaryNode ternaryNode) {
final Node lhs = ternaryNode.lhs();
final Node rhs = ternaryNode.rhs();
final Node third = ternaryNode.third();
final Expression test = ternaryNode.getTest();
final Expression trueExpr = ternaryNode.getTrueExpression();
final Expression falseExpr = ternaryNode.getFalseExpression();
final Symbol symbol = ternaryNode.getSymbol();
final Label falseLabel = new Label("ternary_false");
final Label exitLabel = new Label("ternary_exit");
Type widest = Type.widest(rhs.getType(), third.getType());
if (rhs.getType().isArray() || third.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
Type widest = Type.widest(trueExpr.getType(), falseExpr.getType());
if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
widest = Type.OBJECT;
}
load(lhs);
assert lhs.getType().isBoolean() : "lhs in ternary must be boolean";
load(test);
assert test.getType().isBoolean() : "lhs in ternary must be boolean";
// we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17
// will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the
@ -2866,11 +2887,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
// do this property. Then we never need any conversions in CodeGenerator
method.ifeq(falseLabel);
load(rhs);
load(trueExpr);
method.convert(widest);
method._goto(exitLabel);
method.label(falseLabel);
load(third);
load(falseExpr);
method.convert(widest);
method.label(exitLabel);
method.store(symbol);
@ -2923,8 +2944,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*
* @param <T>
*/
private abstract class SelfModifyingStore<T extends Node> extends Store<T> {
protected SelfModifyingStore(final T assignNode, final Node target) {
private abstract class SelfModifyingStore<T extends Expression> extends Store<T> {
protected SelfModifyingStore(final T assignNode, final Expression target) {
super(assignNode, target);
}
@ -2937,13 +2958,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
/**
* Helper class to generate stores
*/
private abstract class Store<T extends Node> {
private abstract class Store<T extends Expression> {
/** An assignment node, e.g. x += y */
protected final T assignNode;
/** The target node to store to, e.g. x */
private final Node target;
private final Expression target;
/** How deep on the stack do the arguments go if this generates an indy call */
private int depth;
@ -2957,7 +2978,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param assignNode the node representing the whole assignment
* @param target the target node of the assignment (destination)
*/
protected Store(final T assignNode, final Node target) {
protected Store(final T assignNode, final Expression target) {
this.assignNode = assignNode;
this.target = target;
}
@ -3000,8 +3021,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private void enterBaseNode() {
assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode";
final BaseNode baseNode = (BaseNode)target;
final Node base = baseNode.getBase();
final BaseNode baseNode = (BaseNode)target;
final Expression base = baseNode.getBase();
load(base);
method.convert(Type.OBJECT);
@ -3022,7 +3043,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
public boolean enterIndexNode(final IndexNode node) {
enterBaseNode();
final Node index = node.getIndex();
final Expression index = node.getIndex();
// could be boolean here as well
load(index);
if (!index.getType().isNumeric()) {

@ -21,6 +21,7 @@ import java.util.Set;
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
@ -256,17 +257,20 @@ enum CompilationPhase {
@Override
public Node leaveDefault(final Node node) {
final Symbol symbol = node.getSymbol();
if (symbol != null) {
final Range range = symbol.getRange();
final Type symbolType = symbol.getSymbolType();
if (!symbolType.isNumeric()) {
return node;
}
final Type rangeType = range.getType();
if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
if(node instanceof Expression) {
final Expression expr = (Expression)node;
final Symbol symbol = expr.getSymbol();
if (symbol != null) {
final Range range = symbol.getRange();
final Type symbolType = symbol.getSymbolType();
if (!symbolType.isNumeric()) {
return expr;
}
final Type rangeType = range.getType();
if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
return expr.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
}
}
}
return node;

@ -528,8 +528,8 @@ public final class Compiler {
return this.env;
}
private static String safeSourceName(final Source source) {
String baseName = new File(source.getName()).getName();
private String safeSourceName(final Source src) {
String baseName = new File(src.getName()).getName();
final int index = baseName.lastIndexOf(".js");
if (index != -1) {
@ -537,6 +537,9 @@ public final class Compiler {
}
baseName = baseName.replace('.', '_').replace('-', '_');
if (! env._loader_per_compile) {
baseName = baseName + installer.getUniqueScriptId();
}
final String mangled = NameCodec.encode(baseName);
return mangled != null ? mangled : baseName;

@ -100,10 +100,10 @@ public enum CompilerConstants {
CALLEE(":callee", ScriptFunction.class),
/** the varargs variable when necessary */
VARARGS(":varargs"),
VARARGS(":varargs", Object[].class),
/** the arguments vector when necessary and the slot */
ARGUMENTS("arguments", Object.class, 2),
ARGUMENTS("arguments", ScriptObject.class, 2),
/** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX(":i", Iterator.class),

@ -39,7 +39,8 @@ import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ExecuteNode;
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;
@ -146,9 +147,9 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* strings etc as well.
*/
@Override
public Node leaveADD(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
public Expression leaveADD(final BinaryNode binaryNode) {
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
final Type type = binaryNode.getType();
@ -240,7 +241,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return leaveASSIGN(binaryNode);
}
private boolean symbolIsInteger(Node node) {
private boolean symbolIsInteger(final Expression node) {
final Symbol symbol = node.getSymbol();
assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
return true;
@ -372,7 +373,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveCatchNode(final CatchNode catchNode) {
final Node exceptionCondition = catchNode.getExceptionCondition();
final Expression exceptionCondition = catchNode.getExceptionCondition();
if (exceptionCondition != null) {
return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
}
@ -380,16 +381,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
public Node leaveExecuteNode(final ExecuteNode executeNode) {
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
temporarySymbols.reuse();
return executeNode.setExpression(discard(executeNode.getExpression()));
return expressionStatement.setExpression(discard(expressionStatement.getExpression()));
}
@Override
public Node leaveForNode(final ForNode forNode) {
final Node init = forNode.getInit();
final Node test = forNode.getTest();
final Node modify = forNode.getModify();
final Expression init = forNode.getInit();
final Expression test = forNode.getTest();
final Expression modify = forNode.getModify();
if (forNode.isForIn()) {
return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
@ -439,13 +440,13 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
public boolean enterLiteralNode(final LiteralNode literalNode) {
if (literalNode instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] array = arrayLiteralNode.getValue();
final Expression[] array = arrayLiteralNode.getValue();
final Type elementType = arrayLiteralNode.getElementType();
for (int i = 0; i < array.length; i++) {
final Node element = array[i];
if (element != null) {
array[i] = convert(element.accept(this), elementType);
array[i] = convert((Expression)element.accept(this), elementType);
}
}
}
@ -455,7 +456,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
final Expression expr = returnNode.getExpression();
if (expr != null) {
return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
}
@ -464,8 +465,8 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
final List<Node> args = runtimeNode.getArgs();
for (final Node arg : args) {
final List<Expression> args = runtimeNode.getArgs();
for (final Expression arg : args) {
assert !arg.getType().isUnknown();
}
return runtimeNode;
@ -479,12 +480,12 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return switchNode;
}
final Node expression = switchNode.getExpression();
final Expression expression = switchNode.getExpression();
final List<CaseNode> cases = switchNode.getCases();
final List<CaseNode> newCases = new ArrayList<>();
for (final CaseNode caseNode : cases) {
final Node test = caseNode.getTest();
final Expression test = caseNode.getTest();
newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
}
@ -495,7 +496,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN));
}
@Override
@ -505,16 +506,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
final Expression init = varNode.getInit();
if (init != null) {
final SpecializedNode specialized = specialize(varNode);
final VarNode specVarNode = (VarNode)specialized.node;
Type destType = specialized.type;
if (destType == null) {
destType = specVarNode.getType();
destType = specVarNode.getName().getType();
}
assert specVarNode.hasType() : specVarNode + " doesn't have a type";
final Node convertedInit = convert(init, destType);
assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type";
final Expression convertedInit = convert(init, destType);
temporarySymbols.reuse();
return specVarNode.setInit(convertedInit);
}
@ -524,7 +525,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
@Override
public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
final Expression test = whileNode.getTest();
if (test != null) {
return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
}
@ -599,8 +600,8 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
*/
@SuppressWarnings("fallthrough")
private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
Type widest = Type.widest(lhs.getType(), rhs.getType());
@ -696,10 +697,10 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
}
<T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
<T extends Expression> SpecializedNode specialize(final Assignment<T> assignment) {
final Node node = ((Node)assignment);
final T lhs = assignment.getAssignmentDest();
final Node rhs = assignment.getAssignmentSource();
final Expression rhs = assignment.getAssignmentSource();
if (!canHaveCallSiteType(lhs)) {
return new SpecializedNode(node, null);
@ -718,8 +719,16 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
}
final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
final Node typePropagatedNode = propagateType(newNode, to);
final Node typePropagatedNode;
if(newNode instanceof Expression) {
typePropagatedNode = propagateType((Expression)newNode, to);
} else if(newNode instanceof VarNode) {
// VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead.
final VarNode varNode = (VarNode)newNode;
typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to));
} else {
throw new AssertionError();
}
return new SpecializedNode(typePropagatedNode, to);
}
@ -759,7 +768,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param to new type
*/
@SuppressWarnings("unchecked")
<T extends Node> T setTypeOverride(final T node, final Type to) {
<T extends Expression> 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);
@ -788,7 +797,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param to destination type
* @return conversion node
*/
private Node convert(final Node node, final Type to) {
private Expression convert(final Expression 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! " + lc.getCurrentFunction();
@ -804,7 +813,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return node;
}
Node resultNode = node;
Expression resultNode = node;
if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval();
@ -828,9 +837,9 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
return temporarySymbols.ensureSymbol(lc, to, resultNode);
}
private static Node discard(final Node node) {
private static Expression discard(final Expression node) {
if (node.getSymbol() != null) {
final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
final UnaryNode 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;
@ -853,7 +862,7 @@ final class FinalizeTypes extends NodeOperatorVisitor<LexicalContext> {
* @param node
* @param to
*/
private Node propagateType(final Node node, final Type to) {
private Expression propagateType(final Expression node, final Type to) {
Symbol symbol = node.getSymbol();
if (symbol.isTemp() && symbol.getSymbolType() != to) {
symbol = symbol.setTypeOverrideShared(to, temporarySymbols);

@ -28,8 +28,8 @@ package jdk.nashorn.internal.codegen;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
@ -91,7 +91,7 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
if (shortCut != null) {
return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
return new BlockStatement(ifNode.getLineNumber(), shortCut);
}
return new EmptyNode(ifNode);
}
@ -100,9 +100,9 @@ final class FoldConstants extends NodeVisitor<LexicalContext> {
@Override
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node test = ternaryNode.lhs();
final Node test = ternaryNode.getTest();
if (test instanceof LiteralNode) {
return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
return ((LiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
}
return ternaryNode;
}

@ -31,8 +31,8 @@ import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@ -63,7 +63,7 @@ public final class FunctionSignature {
* @param retType what is the return type
* @param args argument list of AST Nodes
*/
public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List<? extends Node> args) {
public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List<? extends Expression> args) {
this(hasSelf, hasCallee, retType, FunctionSignature.typeArray(args));
}
@ -167,7 +167,7 @@ public final class FunctionSignature {
*
* @return the array of types
*/
private static Type[] typeArray(final List<? extends Node> args) {
private static Type[] typeArray(final List<? extends Expression> args) {
if (args == null) {
return null;
}
@ -175,7 +175,7 @@ public final class FunctionSignature {
final Type[] typeArray = new Type[args.size()];
int pos = 0;
for (final Node arg : args) {
for (final Expression arg : args) {
typeArray[pos++] = arg.getType();
}

@ -37,12 +37,14 @@ import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
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;
@ -138,7 +140,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
public boolean enterBlock(final Block block) {
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);
new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
}
return true;
}
@ -154,7 +156,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
final boolean isProgram = currentFunction.isProgram();
final Statement last = lc.getLastStatement();
final ReturnNode returnNode = new ReturnNode(
last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO?
currentFunction.getToken(),
currentFunction.getFinish(),
isProgram ?
@ -195,29 +197,32 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
}
@Override
public Node leaveExecuteNode(final ExecuteNode executeNode) {
final Node expr = executeNode.getExpression();
ExecuteNode node = executeNode;
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
final Expression expr = expressionStatement.getExpression();
ExpressionStatement node = expressionStatement;
final FunctionNode currentFunction = lc.getCurrentFunction();
if (currentFunction.isProgram()) {
if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
node = executeNode.setExpression(
new BinaryNode(
Token.recast(
executeNode.getToken(),
TokenType.ASSIGN),
compilerConstant(RETURN),
expr));
}
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
node = expressionStatement.setExpression(
new BinaryNode(
Token.recast(
expressionStatement.getToken(),
TokenType.ASSIGN),
compilerConstant(RETURN),
expr));
}
}
return addStatement(node);
}
@Override
public Node leaveBlockStatement(BlockStatement blockStatement) {
return addStatement(blockStatement);
}
@Override
public Node leaveForNode(final ForNode forNode) {
ForNode newForNode = forNode;
@ -302,11 +307,11 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all"));
final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
final Block catchBody = new Block(token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
setIsTerminal(lc, true); //ends with throw, so terminal
final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW);
final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
final Block catchAllBlock = new Block(token, finish, catchAllNode);
//catchallblock -> catchallnode (catchnode) -> exception -> throw
@ -355,14 +360,14 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (!isTerminal(newStatements)) {
newStatements.add(throwNode);
}
return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
return BlockStatement.createReplacement(throwNode, newStatements);
}
return throwNode;
}
@Override
public Node leaveBreakNode(final BreakNode breakNode) {
return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel()));
return copy(breakNode, (Node)Lower.this.lc.getBreakable(breakNode.getLabel()));
}
@Override
@ -372,15 +377,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
@Override
public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
final Expression expr = returnNode.getExpression();
final List<Statement> newStatements = new ArrayList<>();
final Node resultNode;
final Expression 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(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
} else {
resultNode = null;
}
@ -390,7 +395,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
}
return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements));
return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements);
}
private Node copy(final Statement endpoint, final Node targetNode) {
@ -399,7 +404,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (!isTerminal(newStatements)) {
newStatements.add(endpoint);
}
return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
return BlockStatement.createReplacement(endpoint, finish, newStatements);
}
return endpoint;
}
@ -461,7 +466,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
if (tryNode.getCatchBlocks().isEmpty()) {
newTryNode = tryNode.setFinallyBody(null);
} else {
Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
}
@ -478,7 +483,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) {
new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
}
return varNode;
}
@ -511,7 +516,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
* @param function function called by a CallNode
* @return transformed node to marker function or identity if not ident/access/indexnode
*/
private static Node markerFunction(final Node function) {
private static Expression markerFunction(final Expression function) {
if (function instanceof IdentNode) {
return ((IdentNode)function).setIsFunction();
} else if (function instanceof BaseNode) {
@ -553,15 +558,15 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
private CallNode checkEval(final CallNode callNode) {
if (callNode.getFunction() instanceof IdentNode) {
final List<Node> args = callNode.getArgs();
final IdentNode callee = (IdentNode)callNode.getFunction();
final List<Expression> args = callNode.getArgs();
final IdentNode callee = (IdentNode)callNode.getFunction();
// 'eval' call with at least one argument
if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
final FunctionNode currentFunction = lc.getCurrentFunction();
return callNode.setEvalArgs(
new CallNode.EvalArgs(
ensureUniqueNamesIn(args.get(0)).accept(this),
(Expression)ensureUniqueNamesIn(args.get(0)).accept(this),
compilerConstant(THIS),
evalLocation(callee),
currentFunction.isStrict()));
@ -630,7 +635,7 @@ final class Lower extends NodeOperatorVisitor<BlockLexicalContext> {
* @param expression expression to check for internal symbol
* @return true if internal, false otherwise
*/
private static boolean isInternalExpression(final Node expression) {
private static boolean isInternalExpression(final Expression expression) {
final Symbol symbol = expression.getSymbol();
return symbol != null && symbol.isInternal();
}

@ -435,13 +435,13 @@ public final class ObjectClassGenerator {
* @return Open method emitter.
*/
private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) {
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, ScriptObject.class);
init.begin();
init.load(Type.OBJECT, JAVA_THIS.slot());
init.load(Type.OBJECT, INIT_MAP.slot());
init.load(Type.OBJECT, INIT_SCOPE.slot());
init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, ScriptObject.class));
return init;
}

@ -28,11 +28,11 @@ package jdk.nashorn.internal.codegen;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Assignment;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
@ -87,7 +87,7 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
}
//destination visited
private Symbol setRange(final Node dest, final Range range) {
private Symbol setRange(final Expression dest, final Range range) {
if (range.isUnknown()) {
return null;
}
@ -352,7 +352,6 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
range = range.isUnknown() ? Range.createGenericRange() : range;
setRange(node.getName(), range);
setRange(node, range);
}
return node;
@ -438,12 +437,12 @@ final class RangeAnalyzer extends NodeOperatorVisitor<LexicalContext> {
* @return
*/
private static Symbol findLoopCounter(final LoopNode node) {
final Node test = node.getTest();
final Expression test = node.getTest();
if (test != null && test.isComparison()) {
final BinaryNode binaryNode = (BinaryNode)test;
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
final Expression lhs = binaryNode.lhs();
final Expression rhs = binaryNode.rhs();
//detect ident cmp int_literal
if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode<?>)rhs).getType().isInteger()) {

@ -25,26 +25,25 @@
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.scripts.JO;
import java.util.List;
import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
/**
* An object creator that uses spill properties.
*/
public class SpillObjectCreator extends ObjectCreator {
private final List<Node> values;
private final List<Expression> values;
/**
* Constructor
@ -54,7 +53,7 @@ public class SpillObjectCreator extends ObjectCreator {
* @param symbols symbols for fields in object
* @param values list of values corresponding to keys
*/
protected SpillObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<Node> values) {
protected SpillObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final List<Expression> values) {
super(codegen, keys, symbols, false, false);
this.values = values;
makeMap();
@ -107,7 +106,7 @@ public class SpillObjectCreator extends ObjectCreator {
for (int i = 0; i < length; i++) {
final String key = keys.get(i);
final Property property = propertyMap.findProperty(key);
final Node value = values.get(i);
final Expression value = values.get(i);
if (property == null && value != null) {
method.dup();

@ -31,7 +31,6 @@ 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;
@ -221,14 +220,13 @@ final class Splitter extends NodeVisitor<LexicalContext> {
* @return New split node.
*/
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(lineNumber, token, finish, statements);
final Block newBlock = new Block(token, finish, statements);
return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
}
@Override

@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@ -36,7 +35,7 @@ import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@ -158,8 +157,8 @@ final class WeighNodes extends NodeOperatorVisitor<LexicalContext> {
}
@Override
public Node leaveExecuteNode(final ExecuteNode executeNode) {
return executeNode;
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
return expressionStatement;
}
@Override

@ -47,9 +47,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
import java.lang.invoke.MethodHandle;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@ -548,19 +547,19 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
* @return the Type representing this class
*/
public static Type typeFor(final Class<?> clazz) {
Type type = cache.get(clazz);
if (type == null) {
assert !clazz.isPrimitive() || clazz == void.class;
if (clazz.isArray()) {
type = new ArrayType(clazz);
} else {
type = new ObjectType(clazz);
}
cache.put(clazz, type);
final Type type = cache.get(clazz);
if(type != null) {
return type;
}
return type;
assert !clazz.isPrimitive() || clazz == void.class;
final Type newType;
if (clazz.isArray()) {
newType = new ArrayType(clazz);
} else {
newType = new ObjectType(clazz);
}
final Type existingType = cache.putIfAbsent(clazz, newType);
return existingType == null ? newType : existingType;
}
@Override
@ -663,35 +662,38 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
}
/** Mappings between java classes and their Type singletons */
private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>();
/**
* This is the boolean singleton, used for all boolean types
*/
public static final Type BOOLEAN = new BooleanType();
public static final Type BOOLEAN = putInCache(new BooleanType());
/**
* This is an integer type, i.e INT, INT32.
*/
public static final Type INT = new IntType();
public static final Type INT = putInCache(new IntType());
/**
* This is the number singleton, used for all number types
*/
public static final Type NUMBER = new NumberType();
public static final Type NUMBER = putInCache(new NumberType());
/**
* This is the long singleton, used for all long types
*/
public static final Type LONG = new LongType();
public static final Type LONG = putInCache(new LongType());
/**
* A string singleton
*/
public static final Type STRING = new ObjectType(String.class);
public static final Type STRING = putInCache(new ObjectType(String.class));
/**
* This is the object singleton, used for all object types
*/
public static final Type OBJECT = new ObjectType();
public static final Type OBJECT = putInCache(new ObjectType());
/**
* This is the singleton for integer arrays
@ -775,13 +777,13 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
};
/** Singleton for method handle arrays used for properties etc. */
public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(MethodHandle[].class);
public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
/** This is the singleton for string arrays */
public static final ArrayType STRING_ARRAY = new ArrayType(String[].class);
public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
/** This is the singleton for object arrays */
public static final ArrayType OBJECT_ARRAY = new ArrayType(Object[].class);
public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
/** This type, always an object type, just a toString override */
public static final Type THIS = new ObjectType() {
@ -855,18 +857,8 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
}
};
/** Mappings between java classes and their Type singletons */
private static final Map<Class<?>, Type> cache = Collections.synchronizedMap(new HashMap<Class<?>, Type>());
//TODO may need to be cleared, as all types are retained throughout code generation
static {
cache.put(BOOLEAN.getTypeClass(), BOOLEAN);
cache.put(INT.getTypeClass(), INT);
cache.put(LONG.getTypeClass(), LONG);
cache.put(NUMBER.getTypeClass(), NUMBER);
cache.put(STRING.getTypeClass(), STRING);
cache.put(OBJECT.getTypeClass(), OBJECT);
cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY);
private static <T extends Type> T putInCache(T type) {
cache.put(type.getTypeClass(), type);
return type;
}
}

@ -45,12 +45,12 @@ public final class AccessNode extends BaseNode {
* @param base base node
* @param property property
*/
public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) {
super(token, finish, base, false, false);
this.property = property.setIsPropertyName();
}
private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
super(accessNode, base, isFunction, hasCallSiteType);
this.property = property;
}
@ -63,7 +63,7 @@ public final class AccessNode extends BaseNode {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterAccessNode(this)) {
return visitor.leaveAccessNode(
setBase(base.accept(visitor)).
setBase((Expression)base.accept(visitor)).
setProperty((IdentNode)property.accept(visitor)));
}
return this;
@ -103,7 +103,7 @@ public final class AccessNode extends BaseNode {
return property;
}
private AccessNode setBase(final Node base) {
private AccessNode setBase(final Expression base) {
if (this.base == base) {
return this;
}

@ -31,7 +31,7 @@ package jdk.nashorn.internal.ir;
*
* @param <D> the destination type
*/
public interface Assignment<D extends Node> {
public interface Assignment<D extends Expression> {
/**
* Get assignment destination
@ -45,7 +45,7 @@ public interface Assignment<D extends Node> {
*
* @return get the assignment source node
*/
public Node getAssignmentSource();
public Expression getAssignmentSource();
/**
* Set assignment destination node.

@ -26,6 +26,7 @@
package jdk.nashorn.internal.ir;
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;
@ -37,10 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
* @see IndexNode
*/
@Immutable
public abstract class BaseNode extends Node implements FunctionCall, TypeOverride<BaseNode> {
public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride<BaseNode> {
/** Base Node. */
protected final Node base;
protected final Expression base;
private final boolean isFunction;
@ -55,7 +56,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type
*/
public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
super(token, base.getStart(), finish);
this.base = base;
this.isFunction = isFunction;
@ -69,7 +70,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type
*/
protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
super(baseNode);
this.base = base;
this.isFunction = isFunction;
@ -80,7 +81,7 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
* Get the base node for this access
* @return the base node
*/
public Node getBase() {
public Expression getBase() {
return base;
}

@ -34,11 +34,11 @@ import jdk.nashorn.internal.parser.TokenType;
* BinaryNode nodes represent two operand operations.
*/
@Immutable
public final class BinaryNode extends Node implements Assignment<Node> {
public final class BinaryNode extends Expression implements Assignment<Expression> {
/** Left hand side argument. */
private final Node lhs;
private final Expression lhs;
private final Node rhs;
private final Expression rhs;
/**
* Constructor
@ -47,13 +47,13 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param lhs left hand side
* @param rhs right hand side
*/
public BinaryNode(final long token, final Node lhs, final Node rhs) {
public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
super(token, lhs.getStart(), rhs.getFinish());
this.lhs = lhs;
this.rhs = rhs;
}
private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) {
private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs) {
super(binaryNode);
this.lhs = lhs;
this.rhs = rhs;
@ -141,17 +141,17 @@ public final class BinaryNode extends Node implements Assignment<Node> {
}
@Override
public Node getAssignmentDest() {
public Expression getAssignmentDest() {
return isAssignment() ? lhs() : null;
}
@Override
public Node setAssignmentDest(Node n) {
public BinaryNode setAssignmentDest(Expression n) {
return setLHS(n);
}
@Override
public Node getAssignmentSource() {
public Expression getAssignmentSource() {
return rhs();
}
@ -162,7 +162,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBinaryNode(this)) {
return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor)));
return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
}
return this;
@ -218,7 +218,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* Get the left hand side expression for this node
* @return the left hand side expression
*/
public Node lhs() {
public Expression lhs() {
return lhs;
}
@ -226,7 +226,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* Get the right hand side expression for this node
* @return the left hand side expression
*/
public Node rhs() {
public Expression rhs() {
return rhs;
}
@ -235,7 +235,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param lhs new left hand side expression
* @return a node equivalent to this one except for the requested change.
*/
public BinaryNode setLHS(final Node lhs) {
public BinaryNode setLHS(final Expression lhs) {
if (this.lhs == lhs) {
return this;
}
@ -247,7 +247,7 @@ public final class BinaryNode extends Node implements Assignment<Node> {
* @param rhs new left hand side expression
* @return a node equivalent to this one except for the requested change.
*/
public BinaryNode setRHS(final Node rhs) {
public BinaryNode setRHS(final Expression rhs) {
if (this.rhs == rhs) {
return this;
}

@ -38,11 +38,10 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
* IR representation for a list of statements and functions. All provides the
* basis for script body.
* IR representation for a list of statements.
*/
@Immutable
public class Block extends BreakableNode implements Flags<Block> {
public class Block extends Node implements BreakableNode, Flags<Block> {
/** List of statements */
protected final List<Statement> statements;
@ -52,6 +51,9 @@ public class Block extends BreakableNode implements Flags<Block> {
/** Entry label. */
protected final Label entryLabel;
/** Break label. */
private final Label breakLabel;
/** Does the block/function need a new scope? */
protected final int flags;
@ -76,17 +78,17 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
super(lineNumber, token, finish, new Label("block_break"));
public Block(final long token, final int finish, final Statement... statements) {
super(token, finish);
this.statements = Arrays.asList(statements);
this.symbols = new LinkedHashMap<>();
this.entryLabel = new Label("block_entry");
this.breakLabel = new Label("block_break");
this.flags = 0;
}
@ -98,8 +100,8 @@ public class Block extends BreakableNode implements Flags<Block> {
* @param finish finish
* @param statements statements
*/
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()]));
public Block(final long token, final int finish, final List<Statement> statements) {
this(token, finish, statements.toArray(new Statement[statements.size()]));
}
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols) {
@ -108,6 +110,7 @@ public class Block extends BreakableNode implements Flags<Block> {
this.flags = flags;
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.breakLabel = new Label(block.breakLabel);
this.finish = finish;
}
@ -223,6 +226,11 @@ public class Block extends BreakableNode implements Flags<Block> {
return entryLabel;
}
@Override
public Label getBreakLabel() {
return breakLabel;
}
/**
* Get the list of statements in this block
*
@ -322,7 +330,17 @@ public class Block extends BreakableNode implements Flags<Block> {
}
@Override
protected boolean isBreakableWithoutLabel() {
public boolean isBreakableWithoutLabel() {
return false;
}
@Override
public List<Label> getLabels() {
return Collections.singletonList(breakLabel);
}
@Override
public Node accept(NodeVisitor<? extends LexicalContext> visitor) {
return Acceptor.accept(this, visitor);
}
}

@ -0,0 +1,115 @@
/*
* 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 java.util.List;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
* Represents a block used as a statement.
*/
public class BlockStatement extends Statement {
/** Block to execute. */
private final Block block;
/**
* Constructor
*
* @param lineNumber line number
* @param block the block to execute
*/
public BlockStatement(final int lineNumber, final Block block) {
super(lineNumber, block.getToken(), block.getFinish());
this.block = block;
}
private BlockStatement(final BlockStatement blockStatement, final Block block) {
super(blockStatement);
this.block = block;
}
/**
* Use this method to create a block statement meant to replace a single statement.
* @param stmt the statement to replace
* @param newStmts the statements for the new block statement
* @return a block statement with the new statements. It will have the line number, token, and finish of the
* original statement.
*/
public static Statement createReplacement(final Statement stmt, final List<Statement> newStmts) {
return createReplacement(stmt, stmt.getFinish(), newStmts);
}
/**
* Use this method to create a block statement meant to replace a single statement.
* @param stmt the statement to replace
* @param finish the new finish for the block
* @param newStmts the statements for the new block statement
* @return a block statement with the new statements. It will have the line number, and token of the
* original statement.
*/
public static Statement createReplacement(final Statement stmt, int finish, final List<Statement> newStmts) {
return new BlockStatement(stmt.getLineNumber(), new Block(stmt.getToken(), finish, newStmts));
}
@Override
public boolean isTerminal() {
return block.isTerminal();
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterBlockStatement(this)) {
return visitor.leaveBlockStatement(setBlock((Block)block.accept(visitor)));
}
return this;
}
@Override
public void toString(final StringBuilder sb) {
block.toString(sb);
}
/**
* Return the block to be executed
* @return the block
*/
public Block getBlock() {
return block;
}
/**
* Reset the block to be executed
* @param block the block
* @return new or same execute node
*/
public BlockStatement setBlock(final Block block) {
if (this.block == block) {
return this;
}
return new BlockStatement(this, block);
}
}

@ -25,46 +25,14 @@
package jdk.nashorn.internal.ir;
import java.util.Arrays;
import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
/**
* This class represents a node from which control flow can execute
* a {@code break} statement
*/
@Immutable
public abstract class BreakableNode extends LexicalContextNode {
/** break label. */
protected final Label breakLabel;
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param breakLabel break label
*/
protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
super(lineNumber, token, finish);
this.breakLabel = breakLabel;
}
/**
* Copy constructor
*
* @param breakableNode source node
*/
protected BreakableNode(final BreakableNode breakableNode) {
super(breakableNode);
this.breakLabel = new Label(breakableNode.getBreakLabel());
}
@Override
public interface BreakableNode extends LexicalContextNode {
public abstract Node ensureUniqueLabels(final LexicalContext lc);
/**
@ -72,17 +40,13 @@ public abstract class BreakableNode extends LexicalContextNode {
* e.g. everything but Blocks, basically
* @return true if breakable without label
*/
protected boolean isBreakableWithoutLabel() {
return true;
}
public boolean isBreakableWithoutLabel();
/**
* Return the break label, i.e. the location to go to on break.
* @return the break label
*/
public Label getBreakLabel() {
return breakLabel;
}
public Label getBreakLabel();
/**
* Return the labels associated with this node. Breakable nodes that
@ -90,8 +54,5 @@ public abstract class BreakableNode extends LexicalContextNode {
* afterwards the node in code
* @return list of labels representing locations around this node
*/
public List<Label> getLabels() {
return Arrays.asList(breakLabel);
}
public List<Label> getLabels();
}

@ -0,0 +1,91 @@
/*
* 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 java.util.Collections;
import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
@Immutable
abstract class BreakableStatement extends LexicalContextStatement implements BreakableNode {
/** break label. */
protected final Label breakLabel;
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
* @param breakLabel break label
*/
protected BreakableStatement(final int lineNumber, final long token, final int finish, final Label breakLabel) {
super(lineNumber, token, finish);
this.breakLabel = breakLabel;
}
/**
* Copy constructor
*
* @param breakableNode source node
*/
protected BreakableStatement(final BreakableStatement breakableNode) {
super(breakableNode);
this.breakLabel = new Label(breakableNode.getBreakLabel());
}
/**
* Check whether this can be broken out from without using a label,
* e.g. everything but Blocks, basically
* @return true if breakable without label
*/
@Override
public boolean isBreakableWithoutLabel() {
return true;
}
/**
* Return the break label, i.e. the location to go to on break.
* @return the break label
*/
@Override
public Label getBreakLabel() {
return breakLabel;
}
/**
* Return the labels associated with this node. Breakable nodes that
* aren't LoopNodes only have a break label - the location immediately
* afterwards the node in code
* @return list of labels representing locations around this node
*/
@Override
public List<Label> getLabels() {
return Collections.singletonList(breakLabel);
}
}

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import java.util.Collections;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@ -37,27 +36,29 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for a function call.
*/
@Immutable
public final class CallNode extends LexicalContextNode implements TypeOverride<CallNode> {
public final class CallNode extends LexicalContextExpression implements TypeOverride<CallNode> {
private final Type type;
/** Function identifier or function body. */
private final Node function;
private final Expression function;
/** Call arguments. */
private final List<Node> args;
private final List<Expression> args;
/** Is this a "new" operation */
public static final int IS_NEW = 0x1;
private final int flags;
private final int lineNumber;
/**
* Arguments to be passed to builtin {@code eval} function
*/
public static class EvalArgs {
/** evaluated code */
private final Node code;
private final Expression code;
/** 'this' passed to evaluated code */
private final IdentNode evalThis;
@ -76,7 +77,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param location location for the eval call
* @param strictMode is this a call from a strict context?
*/
public EvalArgs(final Node code, final IdentNode evalThis, final String location, final boolean strictMode) {
public EvalArgs(final Expression code, final IdentNode evalThis, final String location, final boolean strictMode) {
this.code = code;
this.evalThis = evalThis;
this.location = location;
@ -87,11 +88,11 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Return the code that is to be eval:ed by this eval function
* @return code as an AST node
*/
public Node getCode() {
public Expression getCode() {
return code;
}
private EvalArgs setCode(final Node code) {
private EvalArgs setCode(final Expression code) {
if (this.code == code) {
return this;
}
@ -143,18 +144,20 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param function the function to call
* @param args args to the call
*/
public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
super(lineNumber, token, finish);
public CallNode(final int lineNumber, final long token, final int finish, final Expression function, final List<Expression> args) {
super(token, finish);
this.function = function;
this.args = args;
this.flags = 0;
this.type = null;
this.evalArgs = null;
this.function = function;
this.args = args;
this.flags = 0;
this.type = null;
this.evalArgs = null;
this.lineNumber = lineNumber;
}
private CallNode(final CallNode callNode, final Node function, final List<Node> args, final int flags, final Type type, final EvalArgs evalArgs) {
private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final Type type, final EvalArgs evalArgs) {
super(callNode);
this.lineNumber = callNode.lineNumber;
this.function = function;
this.args = args;
this.flags = flags;
@ -162,6 +165,14 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
this.evalArgs = evalArgs;
}
/**
* Returns the line number.
* @return the line number.
*/
public int getLineNumber() {
return lineNumber;
}
@Override
public Type getType() {
if (hasCallSiteType()) {
@ -198,13 +209,13 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCallNode(this)) {
final CallNode newCallNode = (CallNode)visitor.leaveCallNode(
setFunction(function.accept(visitor)).
setArgs(Node.accept(visitor, Node.class, args)).
setFunction((Expression)function.accept(visitor)).
setArgs(Node.accept(visitor, Expression.class, args)).
setFlags(flags).
setType(null, lc, type).
setEvalArgs(evalArgs == null ?
null :
evalArgs.setCode(evalArgs.getCode().accept(visitor)).
evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)).
setThis((IdentNode)evalArgs.getThis().accept(visitor))));
// Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice,
// setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now.
@ -248,7 +259,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Get the arguments for the call
* @return a list of arguments
*/
public List<Node> getArgs() {
public List<Expression> getArgs() {
return Collections.unmodifiableList(args);
}
@ -256,7 +267,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Reset the arguments for the call
* @param args new arguments list
*/
private CallNode setArgs(final List<Node> args) {
private CallNode setArgs(final List<Expression> args) {
if (this.args == args) {
return this;
}
@ -297,7 +308,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* Return the function expression that this call invokes
* @return the function
*/
public Node getFunction() {
public Expression getFunction() {
return function;
}
@ -306,7 +317,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
* @param function the function
* @return same node or new one on state change
*/
public CallNode setFunction(final Node function) {
public CallNode setFunction(final Expression function) {
if (this.function == function) {
return this;
}

@ -36,7 +36,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class CaseNode extends Node {
/** Test expression. */
private final Node test;
private final Expression test;
/** Statements. */
private final Block body;
@ -52,7 +52,7 @@ public final class CaseNode extends Node {
* @param test case test node, can be any node in JavaScript
* @param body case body
*/
public CaseNode(final long token, final int finish, final Node test, final Block body) {
public CaseNode(final long token, final int finish, final Expression test, final Block body) {
super(token, finish);
this.test = test;
@ -60,7 +60,7 @@ public final class CaseNode extends Node {
this.entry = new Label("entry");
}
CaseNode(final CaseNode caseNode, final Node test, final Block body) {
CaseNode(final CaseNode caseNode, final Expression test, final Block body) {
super(caseNode);
this.test = test;
@ -80,7 +80,7 @@ public final class CaseNode extends Node {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCaseNode(this)) {
final Node newTest = test == null ? null : test.accept(visitor);
final Expression newTest = test == null ? null : (Expression)test.accept(visitor);
final Block newBody = body == null ? null : (Block)body.accept(visitor);
return visitor.leaveCaseNode(setTest(newTest).setBody(newBody));
@ -120,7 +120,7 @@ public final class CaseNode extends Node {
* Get the test expression for this case node
* @return the test
*/
public Node getTest() {
public Expression getTest() {
return test;
}
@ -129,7 +129,7 @@ public final class CaseNode extends Node {
* @param test new test expression
* @return new or same CaseNode
*/
public CaseNode setTest(final Node test) {
public CaseNode setTest(final Expression test) {
if (this.test == test) {
return this;
}

@ -37,7 +37,7 @@ public final class CatchNode extends Statement {
private final IdentNode exception;
/** Exception condition. */
private final Node exceptionCondition;
private final Expression exceptionCondition;
/** Catch body. */
private final Block body;
@ -58,7 +58,7 @@ public final class CatchNode extends Statement {
* @param body catch body
* @param flags flags
*/
public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Expression exceptionCondition, final Block body, final int flags) {
super(lineNumber, token, finish);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
@ -66,7 +66,7 @@ public final class CatchNode extends Statement {
this.flags = flags;
}
private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body, final int flags) {
private CatchNode(final CatchNode catchNode, final IdentNode exception, final Expression exceptionCondition, final Block body, final int flags) {
super(catchNode);
this.exception = exception;
this.exceptionCondition = exceptionCondition;
@ -83,7 +83,7 @@ public final class CatchNode extends Statement {
if (visitor.enterCatchNode(this)) {
return visitor.leaveCatchNode(
setException((IdentNode)exception.accept(visitor)).
setExceptionCondition(exceptionCondition == null ? null : exceptionCondition.accept(visitor)).
setExceptionCondition(exceptionCondition == null ? null : (Expression)exceptionCondition.accept(visitor)).
setBody((Block)body.accept(visitor)));
}
@ -119,7 +119,7 @@ public final class CatchNode extends Statement {
* Get the exception condition for this catch block
* @return the exception condition
*/
public Node getExceptionCondition() {
public Expression getExceptionCondition() {
return exceptionCondition;
}
@ -128,7 +128,7 @@ public final class CatchNode extends Statement {
* @param exceptionCondition the new exception condition
* @return new or same CatchNode
*/
public CatchNode setExceptionCondition(final Node exceptionCondition) {
public CatchNode setExceptionCondition(final Expression exceptionCondition) {
if (this.exceptionCondition == exceptionCondition) {
return this;
}

@ -0,0 +1,99 @@
/*
* 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.codegen.types.Type;
/**
* Common superclass for all expression nodes. Expression nodes can have
* an associated symbol as well as a type.
*
*/
public abstract class Expression extends Node {
private Symbol symbol;
Expression(long token, int start, int finish) {
super(token, start, finish);
}
Expression(long token, int finish) {
super(token, finish);
}
Expression(Expression expr) {
super(expr);
this.symbol = expr.symbol;
}
/**
* Return the Symbol the compiler has assigned to this Node. The symbol
* is the place where it's expression value is stored after evaluation
*
* @return the symbol
*/
public Symbol getSymbol() {
return symbol;
}
/**
* Assign a symbol to this node. See {@link Expression#getSymbol()} for explanation
* of what a symbol is
*
* @param lc lexical context
* @param symbol the symbol
* @return new node
*/
public Expression setSymbol(final LexicalContext lc, final Symbol symbol) {
if (this.symbol == symbol) {
return this;
}
final Expression newExpr = (Expression)clone();
newExpr.symbol = symbol;
return newExpr;
}
/**
* Check if the expression has a type. The default behavior is to go into the symbol
* and check the symbol type, but there may be overrides, for example in
* getters that require a different type than the internal representation
*
* @return true if a type exists
*/
public boolean hasType() {
return getSymbol() != null;
}
/**
* Returns the type of the expression. Typically this is the symbol type. No types
* are stored in the expression itself, unless it implements TypeOverride.
*
* @return the type of the node.
*/
public Type getType() {
assert hasType() : this + " has no type";
return symbol.getSymbolType();
}
}

@ -34,9 +34,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* statements being added to the IR
*/
@Immutable
public final class ExecuteNode extends Statement {
public final class ExpressionStatement extends Statement {
/** Expression to execute. */
private final Node expression;
private final Expression expression;
/**
* Constructor
@ -46,13 +46,13 @@ public final class ExecuteNode extends Statement {
* @param finish finish
* @param expression the expression to execute
*/
public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
public ExpressionStatement(final int lineNumber, final long token, final int finish, final Expression expression) {
super(lineNumber, token, finish);
this.expression = expression;
}
private ExecuteNode(final ExecuteNode executeNode, final Node expression) {
super(executeNode);
private ExpressionStatement(final ExpressionStatement expressionStatement, final Expression expression) {
super(expressionStatement);
this.expression = expression;
}
@ -63,8 +63,8 @@ public final class ExecuteNode extends Statement {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterExecuteNode(this)) {
return visitor.leaveExecuteNode(setExpression(expression.accept(visitor)));
if (visitor.enterExpressionStatement(this)) {
return visitor.leaveExpressionStatement(setExpression((Expression)expression.accept(visitor)));
}
return this;
@ -79,7 +79,7 @@ public final class ExecuteNode extends Statement {
* Return the expression to be executed
* @return the expression
*/
public Node getExpression() {
public Expression getExpression() {
return expression;
}
@ -88,10 +88,10 @@ public final class ExecuteNode extends Statement {
* @param expression the expression
* @return new or same execute node
*/
public ExecuteNode setExpression(final Node expression) {
public ExpressionStatement setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}
return new ExecuteNode(this, expression);
return new ExpressionStatement(this, expression);
}
}

@ -34,10 +34,10 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class ForNode extends LoopNode {
/** Initialize expression. */
private final Node init;
private final Expression init;
/** Test expression. */
private final Node modify;
private final Expression modify;
/** Iterator symbol. */
private Symbol iterator;
@ -65,14 +65,14 @@ public final class ForNode extends LoopNode {
* @param modify modify
* @param flags flags
*/
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) {
public ForNode(final int lineNumber, final long token, final int finish, final Expression init, final Expression test, final Block body, final Expression modify, final int flags) {
super(lineNumber, token, finish, test, body, false);
this.init = init;
this.modify = modify;
this.flags = flags;
}
private ForNode(final ForNode forNode, final Node init, final Node test, final Block body, final Node modify, final int flags, final boolean controlFlowEscapes) {
private ForNode(final ForNode forNode, final Expression init, final Expression test, final Block body, final Expression modify, final int flags, final boolean controlFlowEscapes) {
super(forNode, test, body, controlFlowEscapes);
this.init = init;
this.modify = modify;
@ -86,12 +86,12 @@ public final class ForNode extends LoopNode {
}
@Override
protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterForNode(this)) {
return visitor.leaveForNode(
setInit(lc, init == null ? null : init.accept(visitor)).
setTest(lc, test == null ? null : test.accept(visitor)).
setModify(lc, modify == null ? null : modify.accept(visitor)).
setInit(lc, init == null ? null : (Expression)init.accept(visitor)).
setTest(lc, test == null ? null : (Expression)test.accept(visitor)).
setModify(lc, modify == null ? null : (Expression)modify.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
@ -140,7 +140,7 @@ public final class ForNode extends LoopNode {
* Get the initialization expression for this for loop
* @return the initialization expression
*/
public Node getInit() {
public Expression getInit() {
return init;
}
@ -150,7 +150,7 @@ public final class ForNode extends LoopNode {
* @param init new initialization expression
* @return new for node if changed or existing if not
*/
public ForNode setInit(final LexicalContext lc, final Node init) {
public ForNode setInit(final LexicalContext lc, final Expression init) {
if (this.init == init) {
return this;
}
@ -212,7 +212,7 @@ public final class ForNode extends LoopNode {
* Get the modification expression for this ForNode
* @return the modification expression
*/
public Node getModify() {
public Expression getModify() {
return modify;
}
@ -222,7 +222,7 @@ public final class ForNode extends LoopNode {
* @param modify new modification expression
* @return new for node if changed or existing if not
*/
public ForNode setModify(final LexicalContext lc, final Node modify) {
public ForNode setModify(final LexicalContext lc, final Expression modify) {
if (this.modify == modify) {
return this;
}
@ -230,12 +230,12 @@ public final class ForNode extends LoopNode {
}
@Override
public Node getTest() {
public Expression getTest() {
return test;
}
@Override
public ForNode setTest(final LexicalContext lc, final Node test) {
public ForNode setTest(final LexicalContext lc, final Expression test) {
if (this.test == test) {
return this;
}

@ -47,7 +47,7 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
* IR representation for function (or script.)
*/
@Immutable
public final class FunctionNode extends LexicalContextNode implements Flags<FunctionNode> {
public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode> {
/** Type used for all FunctionNodes */
public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
@ -138,6 +138,8 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** Function flags. */
private final int flags;
private final int lineNumber;
/** Is anonymous function flag. */
public static final int IS_ANONYMOUS = 1 << 0;
@ -234,9 +236,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
final int flags) {
super(lineNumber, token, finish);
super(token, finish);
this.source = source;
this.lineNumber = lineNumber;
this.ident = ident;
this.name = name;
this.kind = kind;
@ -266,7 +269,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final FunctionNode snapshot,
final Compiler.Hints hints) {
super(functionNode);
this.lineNumber = functionNode.lineNumber;
this.flags = flags;
this.name = name;
this.returnType = returnType;
@ -304,6 +307,14 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
return source;
}
/**
* Returns the line number.
* @return the line number.
*/
public int getLineNumber() {
return lineNumber;
}
/**
* Get the version of this function node's code as it looked upon construction
* i.e typically parsed and nothing else

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__;
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
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;
@ -38,7 +39,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for an identifier.
*/
@Immutable
public final class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
public final class IdentNode extends Expression implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
private static final int PROPERTY_NAME = 1 << 0;
private static final int INITIALIZED_HERE = 1 << 1;
private static final int FUNCTION = 1 << 2;

@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class IfNode extends Statement {
/** Test expression. */
private final Node test;
private final Expression test;
/** Pass statements. */
private final Block pass;
@ -52,14 +52,14 @@ public final class IfNode extends Statement {
* @param pass block to execute when test passes
* @param fail block to execute when test fails or null
*/
public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
public IfNode(final int lineNumber, final long token, final int finish, final Expression test, final Block pass, final Block fail) {
super(lineNumber, token, finish);
this.test = test;
this.pass = pass;
this.fail = fail;
}
private IfNode(final IfNode ifNode, final Node test, final Block pass, final Block fail) {
private IfNode(final IfNode ifNode, final Expression test, final Block pass, final Block fail) {
super(ifNode);
this.test = test;
this.pass = pass;
@ -75,7 +75,7 @@ public final class IfNode extends Statement {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIfNode(this)) {
return visitor.leaveIfNode(
setTest(test.accept(visitor)).
setTest((Expression)test.accept(visitor)).
setPass((Block)pass.accept(visitor)).
setFail(fail == null ? null : (Block)fail.accept(visitor)));
}
@ -124,7 +124,7 @@ public final class IfNode extends Statement {
* Get the test expression for this IfNode
* @return the test expression
*/
public Node getTest() {
public Expression getTest() {
return test;
}
@ -133,7 +133,7 @@ public final class IfNode extends Statement {
* @param test a new test expression
* @return new or same IfNode
*/
public IfNode setTest(final Node test) {
public IfNode setTest(final Expression test) {
if (this.test == test) {
return this;
}

@ -35,7 +35,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class IndexNode extends BaseNode {
/** Property index. */
private final Node index;
private final Expression index;
/**
* Constructors
@ -45,12 +45,12 @@ public final class IndexNode extends BaseNode {
* @param base base node for access
* @param index index for access
*/
public IndexNode(final long token, final int finish, final Node base, final Node index) {
public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
super(token, finish, base, false, false);
this.index = index;
}
private IndexNode(final IndexNode indexNode, final Node base, final Node index, final boolean isFunction, final boolean hasCallSiteType) {
private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final boolean hasCallSiteType) {
super(indexNode, base, isFunction, hasCallSiteType);
this.index = index;
}
@ -59,8 +59,8 @@ public final class IndexNode extends BaseNode {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterIndexNode(this)) {
return visitor.leaveIndexNode(
setBase(base.accept(visitor)).
setIndex(index.accept(visitor)));
setBase((Expression)base.accept(visitor)).
setIndex((Expression)index.accept(visitor)));
}
return this;
}
@ -95,11 +95,11 @@ public final class IndexNode extends BaseNode {
* Get the index expression for this IndexNode
* @return the index
*/
public Node getIndex() {
public Expression getIndex() {
return index;
}
private IndexNode setBase(final Node base) {
private IndexNode setBase(final Expression base) {
if (this.base == base) {
return this;
}
@ -111,7 +111,7 @@ public final class IndexNode extends BaseNode {
* @param index new index expression
* @return a node equivalent to this one except for the requested change.
*/
public IndexNode setIndex(Node index) {
public IndexNode setIndex(Expression index) {
if(this.index == index) {
return this;
}

@ -32,7 +32,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for a labeled statement.
*/
@Immutable
public final class LabelNode extends LexicalContextNode {
public final class LabelNode extends LexicalContextStatement {
/** Label ident. */
private final IdentNode label;

@ -576,19 +576,20 @@ public class LexicalContext {
final StringBuffer sb = new StringBuffer();
sb.append("[ ");
for (int i = 0; i < sp; i++) {
final Node node = stack[i];
final Object node = stack[i];
sb.append(node.getClass().getSimpleName());
sb.append('@');
sb.append(Debug.id(node));
sb.append(':');
if (node instanceof FunctionNode) {
final Source source = ((FunctionNode)node).getSource();
final FunctionNode fn = (FunctionNode)node;
final Source source = fn.getSource();
String src = source.toString();
if (src.indexOf(File.pathSeparator) != -1) {
src = src.substring(src.lastIndexOf(File.pathSeparator));
}
src += ' ';
src += source.getLine(node.getStart());
src += source.getLine(fn.getStart());
sb.append(src);
}
sb.append(' ');
@ -631,7 +632,7 @@ public class LexicalContext {
private T findNext() {
for (int i = index; i >= 0; i--) {
final Node node = stack[i];
final Object node = stack[i];
if (node == until) {
return null;
}

@ -0,0 +1,59 @@
/*
* 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.ir.visitor.NodeVisitor;
abstract class LexicalContextExpression extends Expression implements LexicalContextNode {
LexicalContextExpression(LexicalContextExpression expr) {
super(expr);
}
LexicalContextExpression(long token, int start, int finish) {
super(token, start, finish);
}
LexicalContextExpression(long token, int finish) {
super(token, finish);
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
return Acceptor.accept(this, visitor);
}
/**
* 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 Expression setSymbol(final LexicalContext lc, final Symbol symbol) {
return Node.replaceInLexicalContext(lc, this, (LexicalContextExpression)super.setSymbol(null, symbol));
}
}

@ -26,31 +26,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
/**
* Superclass for nodes that can be part of the lexical context
* Interface for nodes that can be part of the lexical context.
* @see LexicalContext
*/
public abstract class LexicalContextNode extends Statement {
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
*/
protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
super(lineNumber, token, finish);
}
/**
* Copy constructor
*
* @param node source node
*/
protected LexicalContextNode(final LexicalContextNode node) {
super(node);
}
public interface LexicalContextNode {
/**
* Accept function for the node given a lexical context. It must be prepared
* to replace itself if present in the lexical context
@ -60,25 +41,15 @@ public abstract class LexicalContextNode extends Statement {
*
* @return new node or same node depending on state change
*/
protected abstract Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor);
Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor);
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
final LexicalContext lc = visitor.getLexicalContext();
lc.push(this);
final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
return lc.pop(newNode);
// Would be a default method on Java 8
static class Acceptor {
static Node accept(LexicalContextNode node, final NodeVisitor<? extends LexicalContext> visitor) {
final LexicalContext lc = visitor.getLexicalContext();
lc.push(node);
final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor);
return (Node)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));
}
}

@ -0,0 +1,55 @@
/*
* 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.ir.visitor.NodeVisitor;
abstract class LexicalContextStatement extends Statement implements LexicalContextNode {
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param finish finish
*/
protected LexicalContextStatement(final int lineNumber, final long token, final int finish) {
super(lineNumber, token, finish);
}
/**
* Copy constructor
*
* @param node source node
*/
protected LexicalContextStatement(final LexicalContextStatement node) {
super(node);
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
return Acceptor.accept(this, visitor);
}
}

@ -45,7 +45,7 @@ import jdk.nashorn.internal.runtime.Undefined;
* @param <T> the literal type
*/
@Immutable
public abstract class LiteralNode<T> extends Node implements PropertyKey {
public abstract class LiteralNode<T> extends Expression implements PropertyKey {
/** Literal value */
protected final T value;
@ -551,7 +551,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/**
* Array literal node class.
*/
public static final class ArrayLiteralNode extends LiteralNode<Node[]> {
public static final class ArrayLiteralNode extends LiteralNode<Expression[]> {
/** Array element type. */
private Type elementType;
@ -619,7 +619,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @param finish finish
* @param value array literal value, a Node array
*/
protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
protected ArrayLiteralNode(final long token, final int finish, final Expression[] value) {
super(Token.recast(token, TokenType.ARRAY), finish, value);
this.elementType = Type.UNKNOWN;
}
@ -628,7 +628,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* Copy constructor
* @param node source array literal node
*/
private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value) {
super(node, value);
this.elementType = node.elementType;
this.presets = node.presets;
@ -737,7 +737,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
}
private void analyzeElements() {
for (final Node node : value) {
for (final Expression node : value) {
if (node == null) {
elementType = elementType.widest(Type.OBJECT); //no way to represent undefined as number
break;
@ -826,15 +826,15 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterLiteralNode(this)) {
final List<Node> oldValue = Arrays.asList(value);
final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
final List<Expression> oldValue = Arrays.asList(value);
final List<Expression> newValue = Node.accept(visitor, Expression.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()]));
private ArrayLiteralNode setValue(final List<Expression> value) {
return new ArrayLiteralNode(this, value.toArray(new Expression[value.size()]));
}
@Override
@ -866,8 +866,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*
* @return the new literal node
*/
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()]));
public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final List<Expression> value) {
return new ArrayLiteralNode(token, finish, value.toArray(new Expression[value.size()]));
}
@ -879,8 +879,8 @@ 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.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
public static LiteralNode<?> newInstance(final Node parent, final List<Expression> value) {
return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Expression[value.size()]));
}
/**
@ -892,7 +892,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*
* @return the new literal node
*/
public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final Expression[] value) {
return new ArrayLiteralNode(token, finish, value);
}
}

@ -27,18 +27,17 @@ package jdk.nashorn.internal.ir;
import java.util.Arrays;
import java.util.List;
import jdk.nashorn.internal.codegen.Label;
/**
* A loop node, for example a while node, do while node or for node
*/
public abstract class LoopNode extends BreakableNode {
public abstract class LoopNode extends BreakableStatement {
/** loop continue label. */
protected final Label continueLabel;
/** Loop test node, null if infinite */
protected final Node test;
protected final Expression test;
/** Loop body */
protected final Block body;
@ -56,7 +55,7 @@ public abstract class LoopNode extends BreakableNode {
* @param body loop body
* @param controlFlowEscapes controlFlowEscapes
*/
protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
protected LoopNode(final int lineNumber, final long token, final int finish, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = test;
@ -72,7 +71,7 @@ public abstract class LoopNode extends BreakableNode {
* @param body new body
* @param controlFlowEscapes controlFlowEscapes
*/
protected LoopNode(final LoopNode loopNode, final Node test, final Block body, final boolean controlFlowEscapes) {
protected LoopNode(final LoopNode loopNode, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(loopNode);
this.continueLabel = new Label(loopNode.continueLabel);
this.test = test;
@ -151,7 +150,7 @@ public abstract class LoopNode extends BreakableNode {
* Get the test for this for node
* @return the test
*/
public abstract Node getTest();
public abstract Expression getTest();
/**
* Set the test for this for node
@ -160,7 +159,7 @@ public abstract class LoopNode extends BreakableNode {
* @param test new test
* @return same or new node depending on if test was changed
*/
public abstract LoopNode setTest(final LexicalContext lc, final Node test);
public abstract LoopNode setTest(final LexicalContext lc, final Expression test);
/**
* Set the control flow escapes flag for this node.

@ -27,7 +27,6 @@ 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;
@ -37,9 +36,6 @@ import jdk.nashorn.internal.parser.TokenType;
* Nodes are used to compose Abstract Syntax Trees.
*/
public abstract class Node implements Cloneable {
/** Node symbol. */
private Symbol symbol;
/** Start of source range. */
protected final int start;
@ -81,33 +77,10 @@ public abstract class Node implements Cloneable {
*/
protected Node(final Node node) {
this.token = node.token;
this.symbol = node.symbol;
this.start = node.start;
this.finish = node.finish;
}
/**
* Check if the node has a type. The default behavior is to go into the symbol
* and check the symbol type, but there may be overrides, for example in
* getters that require a different type than the internal representation
*
* @return true if a type exists
*/
public boolean hasType() {
return getSymbol() != null;
}
/**
* Returns the type of the node. Typically this is the symbol type. No types
* are stored in the node itself, unless it implements TypeOverride
*
* @return the type of the node.
*/
public Type getType() {
assert hasType() : this + " has no type";
return symbol.getSymbolType();
}
/**
* Is this an atom node - for example a literal or an identity
*
@ -235,16 +208,6 @@ public abstract class Node implements Cloneable {
return start;
}
/**
* Return the Symbol the compiler has assigned to this Node. The symbol
* is the place where it's expression value is stored after evaluation
*
* @return the symbol
*/
public Symbol getSymbol() {
return symbol;
}
@Override
protected Object clone() {
try {
@ -254,24 +217,6 @@ public abstract class Node implements Cloneable {
}
}
/**
* 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);

@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation of an object literal.
*/
@Immutable
public final class ObjectNode extends Node {
public final class ObjectNode extends Expression {
/** Literal elements. */
private final List<PropertyNode> elements;

@ -38,7 +38,7 @@ public final class PropertyNode extends Node {
private final PropertyKey key;
/** Property value. */
private final Node value;
private final Expression value;
/** Property getter. */
private final FunctionNode getter;
@ -56,7 +56,7 @@ public final class PropertyNode extends Node {
* @param getter getter function body
* @param setter setter function body
*/
public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
super(token, finish);
this.key = key;
this.value = value;
@ -64,7 +64,7 @@ public final class PropertyNode extends Node {
this.setter = setter;
}
private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
super(propertyNode);
this.key = key;
this.value = value;
@ -85,7 +85,7 @@ public final class PropertyNode extends Node {
if (visitor.enterPropertyNode(this)) {
return visitor.leavePropertyNode(
setKey((PropertyKey)((Node)key).accept(visitor)).
setValue(value == null ? null : value.accept(visitor)).
setValue(value == null ? null : (Expression)value.accept(visitor)).
setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
}
@ -140,8 +140,8 @@ public final class PropertyNode extends Node {
* Return the key for this property node
* @return the key
*/
public Node getKey() {
return (Node)key;
public Expression getKey() {
return (Expression)key;
}
private PropertyNode setKey(final PropertyKey key) {
@ -175,7 +175,7 @@ public final class PropertyNode extends Node {
* Get the value of this property
* @return property value
*/
public Node getValue() {
public Expression getValue() {
return value;
}
@ -184,7 +184,7 @@ public final class PropertyNode extends Node {
* @param value new value
* @return same node or new node if state changed
*/
public PropertyNode setValue(final Node value) {
public PropertyNode setValue(final Expression value) {
if (this.value == value) {
return this;
}

@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir;
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;
@ -36,7 +37,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public class ReturnNode extends Statement {
/** Optional expression. */
private final Node expression;
private final Expression expression;
/**
* Constructor
@ -46,12 +47,12 @@ public class ReturnNode extends Statement {
* @param finish finish
* @param expression expression to return
*/
public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
public ReturnNode(final int lineNumber, final long token, final int finish, final Expression expression) {
super(lineNumber, token, finish);
this.expression = expression;
}
private ReturnNode(final ReturnNode returnNode, final Node expression) {
private ReturnNode(final ReturnNode returnNode, final Expression expression) {
super(returnNode);
this.expression = expression;
}
@ -89,7 +90,7 @@ public class ReturnNode extends Statement {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterReturnNode(this)) {
if (expression != null) {
return visitor.leaveReturnNode(setExpression(expression.accept(visitor)));
return visitor.leaveReturnNode(setExpression((Expression)expression.accept(visitor)));
}
return visitor.leaveReturnNode(this);
}
@ -111,7 +112,7 @@ public class ReturnNode extends Statement {
* Get the expression this node returns
* @return return expression, or null if void return
*/
public Node getExpression() {
public Expression getExpression() {
return expression;
}
@ -120,7 +121,7 @@ public class ReturnNode extends Statement {
* @param expression new expression, or null if void return
* @return new or same return node
*/
public ReturnNode setExpression(final Node expression) {
public ReturnNode setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}

@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@ -39,7 +38,7 @@ import jdk.nashorn.internal.parser.TokenType;
* IR representation for a runtime call.
*/
@Immutable
public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode> {
/**
* Request enum used for meta-information about the runtime request
@ -267,7 +266,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
private final Request request;
/** Call arguments. */
private final List<Node> args;
private final List<Expression> args;
/** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
private final Type callSiteType;
@ -283,7 +282,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
public RuntimeNode(final long token, final int finish, final Request request, final List<Expression> args) {
super(token, finish);
this.request = request;
@ -292,7 +291,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
this.isFinal = false;
}
private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Node> args) {
private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Expression> args) {
super(runtimeNode);
this.request = request;
@ -309,7 +308,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
public RuntimeNode(final long token, final int finish, final Request request, final Expression... args) {
this(token, finish, request, Arrays.asList(args));
}
@ -320,7 +319,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
public RuntimeNode(final Node parent, final Request request, final Node... args) {
public RuntimeNode(final Expression parent, final Request request, final Expression... args) {
this(parent, request, Arrays.asList(args));
}
@ -331,7 +330,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @param request the request
* @param args arguments to request
*/
public RuntimeNode(final Node parent, final Request request, final List<Node> args) {
public RuntimeNode(final Expression parent, final Request request, final List<Expression> args) {
super(parent);
this.request = request;
@ -408,9 +407,9 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterRuntimeNode(this)) {
final List<Node> newArgs = new ArrayList<>();
final List<Expression> newArgs = new ArrayList<>();
for (final Node arg : args) {
newArgs.add(arg.accept(visitor));
newArgs.add((Expression)arg.accept(visitor));
}
return visitor.leaveRuntimeNode(setArgs(newArgs));
}
@ -443,11 +442,11 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* Get the arguments for this runtime node
* @return argument list
*/
public List<Node> getArgs() {
public List<Expression> getArgs() {
return Collections.unmodifiableList(args);
}
private RuntimeNode setArgs(final List<Node> args) {
private RuntimeNode setArgs(final List<Expression> args) {
if (this.args == args) {
return this;
}
@ -470,7 +469,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
* @return true if all arguments now are primitive
*/
public boolean isPrimitive() {
for (final Node arg : args) {
for (final Expression arg : args) {
if (arg.getType().isObject()) {
return false;
}

@ -33,7 +33,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* Node indicating code is split across classes.
*/
@Immutable
public class SplitNode extends LexicalContextNode {
public class SplitNode extends LexicalContextStatement {
/** Split node method name. */
private final String name;
@ -46,13 +46,12 @@ 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 int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
super(lineNumber, body.getToken(), body.getFinish());
public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
super(-1, body.getToken(), body.getFinish());
this.name = name;
this.body = body;
this.compileUnit = compileUnit;

@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@ -37,9 +36,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation of a SWITCH statement.
*/
@Immutable
public final class SwitchNode extends BreakableNode {
public final class SwitchNode extends BreakableStatement {
/** Switch expression. */
private final Node expression;
private final Expression expression;
/** Switch cases. */
private final List<CaseNode> cases;
@ -60,14 +59,14 @@ public final class SwitchNode extends BreakableNode {
* @param cases cases
* @param defaultCase the default case node - null if none, otherwise has to be present in cases list
*/
public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
public SwitchNode(final int lineNumber, final long token, final int finish, final Expression 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);
}
private SwitchNode(final SwitchNode switchNode, final Node expression, final List<CaseNode> cases, final int defaultCase) {
private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases, final int defaultCase) {
super(switchNode);
this.expression = expression;
this.cases = cases;
@ -103,7 +102,7 @@ public final class SwitchNode extends BreakableNode {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterSwitchNode(this)) {
return visitor.leaveSwitchNode(
setExpression(lc, expression.accept(visitor)).
setExpression(lc, (Expression)expression.accept(visitor)).
setCases(lc, Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex));
}
@ -167,7 +166,7 @@ public final class SwitchNode extends BreakableNode {
* Return the expression to switch on
* @return switch expression
*/
public Node getExpression() {
public Expression getExpression() {
return expression;
}
@ -177,7 +176,7 @@ public final class SwitchNode extends BreakableNode {
* @param expression switch expression
* @return new switch node or same if no state was changed
*/
public SwitchNode setExpression(final LexicalContext lc, final Node expression) {
public SwitchNode setExpression(final LexicalContext lc, final Expression expression) {
if (this.expression == expression) {
return this;
}

@ -49,7 +49,7 @@ public class TemporarySymbols {
* @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) {
public Expression ensureSymbol(final LexicalContext lc, final Type type, final Expression node) {
final Symbol symbol = node.getSymbol();
if (symbol != null) {
return node;

@ -32,43 +32,43 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* TernaryNode nodes represent three operand operations (?:).
*/
@Immutable
public final class TernaryNode extends Node {
private final Node lhs;
public final class TernaryNode extends Expression {
private final Expression test;
private final Node rhs;
private final Expression trueExpr;
/** Third argument. */
private final Node third;
private final Expression falseExpr;
/**
* Constructor
*
* @param token token
* @param lhs left hand side node
* @param rhs right hand side node
* @param third third node
* @param token token
* @param test test expression
* @param trueExpr expression evaluated when test evaluates to true
* @param falseExpr expression evaluated when test evaluates to true
*/
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;
public TernaryNode(final long token, final Expression test, final Expression trueExpr, final Expression falseExpr) {
super(token, falseExpr.getFinish());
this.test = test;
this.trueExpr = trueExpr;
this.falseExpr = falseExpr;
}
private TernaryNode(final TernaryNode ternaryNode, final Node lhs, final Node rhs, final Node third) {
private TernaryNode(final TernaryNode ternaryNode, final Expression test, final Expression trueExpr, final Expression falseExpr) {
super(ternaryNode);
this.lhs = lhs;
this.rhs = rhs;
this.third = third;
this.test = test;
this.trueExpr = trueExpr;
this.falseExpr = falseExpr;
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTernaryNode(this)) {
final Node newLhs = lhs().accept(visitor);
final Node newRhs = rhs().accept(visitor);
final Node newThird = third.accept(visitor);
return visitor.leaveTernaryNode(setThird(newThird).setLHS(newLhs).setRHS(newRhs));
final Expression newTest = (Expression)getTest().accept(visitor);
final Expression newTrueExpr = (Expression)getTrueExpression().accept(visitor);
final Expression newFalseExpr = (Expression)falseExpr.accept(visitor);
return visitor.leaveTernaryNode(setTest(newTest).setTrueExpression(newTrueExpr).setFalseExpression1(newFalseExpr));
}
return this;
@ -76,96 +76,96 @@ public final class TernaryNode extends Node {
@Override
public void toString(final StringBuilder sb) {
final boolean lhsParen = tokenType().needsParens(lhs().tokenType(), true);
final boolean rhsParen = tokenType().needsParens(rhs().tokenType(), false);
final boolean thirdParen = tokenType().needsParens(third().tokenType(), false);
final boolean testParen = tokenType().needsParens(getTest().tokenType(), true);
final boolean trueParen = tokenType().needsParens(getTrueExpression().tokenType(), false);
final boolean falseParen = tokenType().needsParens(getFalseExpression().tokenType(), false);
if (lhsParen) {
if (testParen) {
sb.append('(');
}
lhs().toString(sb);
if (lhsParen) {
getTest().toString(sb);
if (testParen) {
sb.append(')');
}
sb.append(" ? ");
if (rhsParen) {
if (trueParen) {
sb.append('(');
}
rhs().toString(sb);
if (rhsParen) {
getTrueExpression().toString(sb);
if (trueParen) {
sb.append(')');
}
sb.append(" : ");
if (thirdParen) {
if (falseParen) {
sb.append('(');
}
third().toString(sb);
if (thirdParen) {
getFalseExpression().toString(sb);
if (falseParen) {
sb.append(')');
}
}
/**
* Get the lhs node for this ternary expression, i.e. "x" in x ? y : z
* @return a node
* Get the test expression for this ternary expression, i.e. "x" in x ? y : z
* @return the test expression
*/
public Node lhs() {
return lhs;
public Expression getTest() {
return test;
}
/**
* Get the rhs node for this ternary expression, i.e. "y" in x ? y : z
* @return a node
* Get the true expression for this ternary expression, i.e. "y" in x ? y : z
* @return the true expression
*/
public Node rhs() {
return rhs;
public Expression getTrueExpression() {
return trueExpr;
}
/**
* Get the "third" node for this ternary expression, i.e. "z" in x ? y : z
* @return a node
* Get the false expression for this ternary expression, i.e. "z" in x ? y : z
* @return the false expression
*/
public Node third() {
return third;
public Expression getFalseExpression() {
return falseExpr;
}
/**
* Set the left hand side expression for this node
* @param lhs new left hand side expression
* Set the test expression for this node
* @param test new test expression
* @return a node equivalent to this one except for the requested change.
*/
public TernaryNode setLHS(final Node lhs) {
if (this.lhs == lhs) {
public TernaryNode setTest(final Expression test) {
if (this.test == test) {
return this;
}
return new TernaryNode(this, lhs, rhs, third);
return new TernaryNode(this, test, trueExpr, falseExpr);
}
/**
* Set the right hand side expression for this node
* @param rhs new left hand side expression
* Set the true expression for this node
* @param trueExpr new true expression
* @return a node equivalent to this one except for the requested change.
*/
public TernaryNode setRHS(final Node rhs) {
if (this.rhs == rhs) {
public TernaryNode setTrueExpression(final Expression trueExpr) {
if (this.trueExpr == trueExpr) {
return this;
}
return new TernaryNode(this, lhs, rhs, third);
return new TernaryNode(this, test, trueExpr, falseExpr);
}
/**
* Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
* @param third a node
* Set the false expression for this node
* @param falseExpr new false expression
* @return a node equivalent to this one except for the requested change.
*/
public TernaryNode setThird(final Node third) {
if (this.third == third) {
public TernaryNode setFalseExpression1(final Expression falseExpr) {
if (this.falseExpr == falseExpr) {
return this;
}
return new TernaryNode(this, lhs, rhs, third);
return new TernaryNode(this, test, trueExpr, falseExpr);
}
}

@ -34,7 +34,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@Immutable
public final class ThrowNode extends Statement {
/** Exception expression. */
private final Node expression;
private final Expression expression;
private final int flags;
@ -50,13 +50,13 @@ public final class ThrowNode extends Statement {
* @param expression expression to throw
* @param flags flags
*/
public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression, final int flags) {
public ThrowNode(final int lineNumber, final long token, final int finish, final Expression expression, final int flags) {
super(lineNumber, token, finish);
this.expression = expression;
this.flags = flags;
}
private ThrowNode(final ThrowNode node, final Node expression, final int flags) {
private ThrowNode(final ThrowNode node, final Expression expression, final int flags) {
super(node);
this.expression = expression;
this.flags = flags;
@ -74,7 +74,7 @@ public final class ThrowNode extends Statement {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterThrowNode(this)) {
return visitor.leaveThrowNode(setExpression(expression.accept(visitor)));
return visitor.leaveThrowNode(setExpression((Expression)expression.accept(visitor)));
}
return this;
@ -93,7 +93,7 @@ public final class ThrowNode extends Statement {
* Get the expression that is being thrown by this node
* @return expression
*/
public Node getExpression() {
public Expression getExpression() {
return expression;
}
@ -102,7 +102,7 @@ public final class ThrowNode extends Statement {
* @param expression new expression
* @return new or same thrownode
*/
public ThrowNode setExpression(final Node expression) {
public ThrowNode setExpression(final Expression expression) {
if (this.expression == expression) {
return this;
}

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.parser.TokenType.BIT_NOT;
import static jdk.nashorn.internal.parser.TokenType.CONVERT;
import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@ -39,9 +40,9 @@ import jdk.nashorn.internal.parser.TokenType;
* UnaryNode nodes represent single operand operations.
*/
@Immutable
public final class UnaryNode extends Node implements Assignment<Node> {
public final class UnaryNode extends Expression implements Assignment<Expression> {
/** Right hand side argument. */
private final Node rhs;
private final Expression rhs;
/**
* Constructor
@ -49,7 +50,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param token token
* @param rhs expression
*/
public UnaryNode(final long token, final Node rhs) {
public UnaryNode(final long token, final Expression rhs) {
this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
}
@ -61,13 +62,13 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param finish finish
* @param rhs expression
*/
public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
public UnaryNode(final long token, final int start, final int finish, final Expression rhs) {
super(token, start, finish);
this.rhs = rhs;
}
private UnaryNode(final UnaryNode unaryNode, final Node rhs) {
private UnaryNode(final UnaryNode unaryNode, final Expression rhs) {
super(unaryNode);
this.rhs = rhs;
}
@ -101,17 +102,17 @@ public final class UnaryNode extends Node implements Assignment<Node> {
}
@Override
public Node getAssignmentDest() {
public Expression getAssignmentDest() {
return isAssignment() ? rhs() : null;
}
@Override
public Node setAssignmentDest(Node n) {
public UnaryNode setAssignmentDest(Expression n) {
return setRHS(n);
}
@Override
public Node getAssignmentSource() {
public Expression getAssignmentSource() {
return getAssignmentDest();
}
@ -122,7 +123,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterUnaryNode(this)) {
return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
return visitor.leaveUnaryNode(setRHS((Expression)rhs.accept(visitor)));
}
return this;
@ -130,6 +131,22 @@ public final class UnaryNode extends Node implements Assignment<Node> {
@Override
public void toString(final StringBuilder sb) {
toString(sb, new Runnable() {
@Override
public void run() {
sb.append(rhs().toString());
}
});
}
/**
* Creates the string representation of this unary node, delegating the creation of the string representation of its
* operand to a specified runnable.
* @param sb the string builder to use
* @param rhsStringBuilder the runnable that appends the string representation of the operand to the string builder
* when invoked.
*/
public void toString(final StringBuilder sb, final Runnable rhsStringBuilder) {
final TokenType type = tokenType();
final String name = type.getName();
final boolean isPostfix = type == DECPOSTFIX || type == INCPOSTFIX;
@ -161,7 +178,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
if (rhsParen) {
sb.append('(');
}
rhs().toString(sb);
rhsStringBuilder.run();
if (rhsParen) {
sb.append(')');
}
@ -189,7 +206,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
*
* @return right hand side or expression node
*/
public Node rhs() {
public Expression rhs() {
return rhs;
}
@ -202,7 +219,7 @@ public final class UnaryNode extends Node implements Assignment<Node> {
* @param rhs right hand side or expression node
* @return a node equivalent to this one except for the requested change.
*/
public UnaryNode setRHS(final Node rhs) {
public UnaryNode setRHS(final Expression rhs) {
if (this.rhs == rhs) {
return this;
}

@ -37,7 +37,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
private final IdentNode name;
/** Initialization expression. */
private final Node init;
private final Expression init;
/** Is this a var statement (as opposed to a "var" in a for loop statement) */
private final int flags;
@ -59,11 +59,11 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param name name of variable
* @param init init node or null if just a declaration
*/
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) {
this(lineNumber, token, finish, name, init, IS_STATEMENT);
}
private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) {
super(varNode);
this.name = init == null ? name : name.setIsInitializedHere();
this.init = init;
@ -80,7 +80,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param init init node or null if just a declaration
* @param flags flags
*/
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init, final int flags) {
super(lineNumber, token, finish);
this.name = init == null ? name : name.setIsInitializedHere();
@ -99,12 +99,12 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
}
@Override
public Node setAssignmentDest(IdentNode n) {
public VarNode setAssignmentDest(IdentNode n) {
return setName(n);
}
@Override
public Node getAssignmentSource() {
public Expression getAssignmentSource() {
return isAssignment() ? getInit() : null;
}
@ -123,9 +123,9 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterVarNode(this)) {
final IdentNode newName = (IdentNode)name.accept(visitor);
final Node newInit = init == null ? null : init.accept(visitor);
final VarNode newThis;
final IdentNode newName = (IdentNode)name.accept(visitor);
final Expression newInit = init == null ? null : (Expression)init.accept(visitor);
final VarNode newThis;
if (name != newName || init != newInit) {
newThis = new VarNode(this, newName, newInit, flags);
} else {
@ -151,7 +151,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* If this is an assignment of the form {@code var x = init;}, get the init part.
* @return the expression to initialize the variable to, null if just a declaration
*/
public Node getInit() {
public Expression getInit() {
return init;
}
@ -160,7 +160,7 @@ public final class VarNode extends Statement implements Assignment<IdentNode> {
* @param init new initialization expression
* @return a node equivalent to this one except for the requested change.
*/
public VarNode setInit(final Node init) {
public VarNode setInit(final Expression init) {
if (this.init == init) {
return this;
}

@ -59,7 +59,7 @@ public final class WhileNode extends LoopNode {
* @param body body
* @param controlFlowEscapes control flow escapes?
*/
protected WhileNode(final WhileNode whileNode, final Node test, final Block body, final boolean controlFlowEscapes) {
protected WhileNode(final WhileNode whileNode, final Expression test, final Block body, final boolean controlFlowEscapes) {
super(whileNode, test, body, controlFlowEscapes);
this.isDoWhile = whileNode.isDoWhile;
}
@ -75,28 +75,28 @@ public final class WhileNode extends LoopNode {
}
@Override
protected Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWhileNode(this)) {
if (isDoWhile()) {
return visitor.leaveWhileNode(
setTest(lc, test.accept(visitor)).
setTest(lc, (Expression)test.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
return visitor.leaveWhileNode(
setBody(lc, (Block)body.accept(visitor)).
setTest(lc, test.accept(visitor)));
setTest(lc, (Expression)test.accept(visitor)));
}
return this;
}
@Override
public Node getTest() {
public Expression getTest() {
return test;
}
@Override
public WhileNode setTest(final LexicalContext lc, final Node test) {
public WhileNode setTest(final LexicalContext lc, final Expression test) {
if (this.test == test) {
return this;
}

@ -32,9 +32,9 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
* IR representation for {@code with} statements.
*/
@Immutable
public final class WithNode extends LexicalContextNode {
public final class WithNode extends LexicalContextStatement {
/** This expression. */
private final Node expression;
private final Expression expression;
/** Statements. */
private final Block body;
@ -52,7 +52,7 @@ public final class WithNode extends LexicalContextNode {
this.body = null;
}
private WithNode(final WithNode node, final Node expression, final Block body) {
private WithNode(final WithNode node, final Expression expression, final Block body) {
super(node);
this.expression = expression;
this.body = body;
@ -67,7 +67,7 @@ public final class WithNode extends LexicalContextNode {
public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterWithNode(this)) {
return visitor.leaveWithNode(
setExpression(lc, expression.accept(visitor)).
setExpression(lc, (Expression)expression.accept(visitor)).
setBody(lc, (Block)body.accept(visitor)));
}
return this;
@ -110,7 +110,7 @@ public final class WithNode extends LexicalContextNode {
* Get the expression of this WithNode
* @return the expression
*/
public Node getExpression() {
public Expression getExpression() {
return expression;
}
@ -120,7 +120,7 @@ public final class WithNode extends LexicalContextNode {
* @param expression new expression
* @return new or same withnode
*/
public WithNode setExpression(final LexicalContext lc, final Node expression) {
public WithNode setExpression(final LexicalContext lc, final Expression expression) {
if (this.expression == expression) {
return this;
}

@ -33,10 +33,11 @@ import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Reference;
@ -111,8 +112,15 @@ public final class ASTWriter {
type = "ref: " + type;
}
type += "@" + Debug.id(node);
if (node.getSymbol() != null) {
type += "#" + node.getSymbol();
final Symbol symbol;
if(node instanceof Expression) {
symbol = ((Expression)node).getSymbol();
} else {
symbol = null;
}
if (symbol != null) {
type += "#" + symbol;
}
if (node instanceof Block && ((Block)node).needsScope()) {
@ -135,8 +143,8 @@ public final class ASTWriter {
status += " Goto ";
}
if (node.getSymbol() != null) {
status += node.getSymbol();
if (symbol != null) {
status += symbol;
}
status = status.trim();
@ -144,8 +152,8 @@ public final class ASTWriter {
status = " [" + status + "]";
}
if (node.getSymbol() != null) {
String tname = node.getType().toString();
if (symbol != null) {
String tname = ((Expression)node).getType().toString();
if (tname.indexOf('.') != -1) {
tname = tname.substring(tname.lastIndexOf('.') + 1, tname.length());
}

@ -27,18 +27,18 @@ 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;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
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.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@ -298,14 +298,27 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
}
@Override
public boolean enterExecuteNode(final ExecuteNode executeNode) {
enterDefault(executeNode);
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
enterDefault(expressionStatement);
type("ExpressionStatement");
comma();
property("expression");
executeNode.getExpression().accept(this);
expressionStatement.getExpression().accept(this);
return leave();
}
@Override
public boolean enterBlockStatement(BlockStatement blockStatement) {
enterDefault(blockStatement);
type("BlockStatement");
comma();
property("block");
blockStatement.getBlock().accept(this);
return leave();
}
@ -680,15 +693,15 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
comma();
property("test");
ternaryNode.lhs().accept(this);
ternaryNode.getTest().accept(this);
comma();
property("consequent");
ternaryNode.rhs().accept(this);
ternaryNode.getTrueExpression().accept(this);
comma();
property("alternate");
ternaryNode.third().accept(this);
ternaryNode.getFalseExpression().accept(this);
return leave();
}

@ -26,12 +26,11 @@
package jdk.nashorn.internal.ir.debug;
import java.util.List;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IfNode;
@ -41,8 +40,8 @@ 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;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
@ -167,14 +166,6 @@ public final class PrintVisitor extends NodeVisitor<LexicalContext> {
continue;
}
final Symbol symbol = statement.getSymbol();
if (symbol != null) {
sb.append(" [");
sb.append(symbol.toString());
sb.append(']');
}
int lastIndex = sb.length() - 1;
char lastChar = sb.charAt(lastIndex);
while (Character.isWhitespace(lastChar) && lastIndex >= 0) {
@ -215,8 +206,19 @@ public final class PrintVisitor extends NodeVisitor<LexicalContext> {
}
@Override
public boolean enterExecuteNode(final ExecuteNode executeNode) {
executeNode.getExpression().accept(this);
public boolean enterUnaryNode(final UnaryNode unaryNode) {
unaryNode.toString(sb, new Runnable() {
@Override
public void run() {
unaryNode.rhs().accept(PrintVisitor.this);
}
});
return false;
}
@Override
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
expressionStatement.getExpression().accept(this);
return false;
}

@ -1263,6 +1263,4 @@ public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T
public Node leaveSUB(final BinaryNode binaryNode) {
return leaveDefault(binaryNode);
}
}

@ -28,13 +28,14 @@ package jdk.nashorn.internal.ir.visitor;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
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.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
@ -308,23 +309,43 @@ public abstract class NodeVisitor<T extends LexicalContext> {
}
/**
* Callback for entering an ExecuteNode
* Callback for entering an ExpressionStatement
*
* @param executeNode the node
* @param expressionStatement the node
* @return true if traversal should continue and node children be traversed, false otherwise
*/
public boolean enterExecuteNode(final ExecuteNode executeNode) {
return enterDefault(executeNode);
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
return enterDefault(expressionStatement);
}
/**
* Callback for leaving an ExecuteNode
* Callback for leaving an ExpressionStatement
*
* @param executeNode the node
* @param expressionStatement the node
* @return processed node, which will replace the original one, or the original node
*/
public Node leaveExecuteNode(final ExecuteNode executeNode) {
return leaveDefault(executeNode);
public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
return leaveDefault(expressionStatement);
}
/**
* Callback for entering a BlockStatement
*
* @param blockStatement the node
* @return true if traversal should continue and node children be traversed, false otherwise
*/
public boolean enterBlockStatement(final BlockStatement blockStatement) {
return enterDefault(blockStatement);
}
/**
* Callback for leaving a BlockStatement
*
* @param blockStatement the node
* @return processed node, which will replace the original one, or the original node
*/
public Node leaveBlockStatement(final BlockStatement blockStatement) {
return leaveDefault(blockStatement);
}
/**

@ -32,8 +32,6 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**

@ -179,6 +179,9 @@ public final class NativeDebug extends ScriptObject {
/**
* Returns the property listener count for a script object
*
* @param self self reference
* @param obj script object whose listener count is returned
* @return listener count
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)

@ -622,12 +622,15 @@ public final class NativeJSAdapter extends ScriptObject {
case "getMethod":
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
final ScriptFunctionImpl func = (ScriptFunctionImpl)getObjectValue(find);
// TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
// 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(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
final Object value = getObjectValue(find);
if (value instanceof ScriptFunction) {
final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
// TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
// 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(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
}
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
default:
@ -687,16 +690,19 @@ public final class NativeJSAdapter extends ScriptObject {
final MethodType type = desc.getMethodType();
if (findData != null) {
final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
final ScriptFunction func = (ScriptFunction)getObjectValue(findData);
final Object value = getObjectValue(findData);
if (value instanceof ScriptFunction) {
final ScriptFunction func = (ScriptFunction)value;
final MethodHandle methodHandle = getCallMethodHandle(findData, type,
final MethodHandle methodHandle = getCallMethodHandle(findData, type,
useName ? name : null);
if (methodHandle != null) {
return new GuardedInvocation(
methodHandle,
adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
}
if (methodHandle != null) {
return new GuardedInvocation(
methodHandle,
adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
}
}
}
switch (hook) {

@ -48,7 +48,6 @@ import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
/**

@ -27,18 +27,24 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.AccessorProperty;
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;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
/**
@ -471,4 +477,114 @@ public final class NativeObject {
return false;
}
/**
* Nashorn extension: Object.bindProperties
*
* Binds the source object's properties to the target object. Binding
* properties allows two-way read/write for the properties of the source object.
*
* Example:
* <pre>
* var obj = { x: 34, y: 100 };
* var foo = {}
*
* // bind properties of "obj" to "foo" object
* Object.bindProperties(foo, obj);
*
* // now, we can access/write on 'foo' properties
* print(foo.x); // prints obj.x which is 34
*
* // update obj.x via foo.x
* foo.x = "hello";
* print(obj.x); // prints "hello" now
*
* obj.x = 42; // foo.x also becomes 42
* print(foo.x); // prints 42
* </pre>
* <p>
* The source object bound can be a ScriptObject or a ScriptOjectMirror.
* null or undefined source object results in TypeError being thrown.
* </p>
* Example:
* <pre>
* var obj = loadWithNewGlobal({
* name: "test",
* script: "obj = { x: 33, y: 'hello' }"
* });
*
* // bind 'obj's properties to global scope 'this'
* Object.bindProperties(this, obj);
* print(x); // prints 33
* print(y); // prints "hello"
* x = Math.PI; // changes obj.x to Math.PI
* print(obj.x); // prints Math.PI
* </pre>
*
* Limitations of property binding:
* <ul>
* <li> Only enumerable, immediate (not proto inherited) properties of the source object are bound.
* <li> If the target object already contains a property called "foo", the source's "foo" is skipped (not bound).
* <li> Properties added to the source object after binding to the target are not bound.
* <li> Property configuration changes on the source object (or on the target) is not propagated.
* <li> Delete of property on the target (or the source) is not propagated -
* only the property value is set to 'undefined' if the property happens to be a data property.
* </ul>
* <p>
* It is recommended that the bound properties be treated as non-configurable
* properties to avoid surprises.
* </p>
*
* @param self self reference
* @param target the target object to which the source object's properties are bound
* @param source the source object whose properties are bound to the target
* @return the target object after property binding
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object bindProperties(final Object self, final Object target, final Object source) {
// target object has to be a ScriptObject
Global.checkObject(target);
// check null or undefined source object
Global.checkObjectCoercible(source);
final ScriptObject targetObj = (ScriptObject)target;
if (source instanceof ScriptObject) {
final ScriptObject sourceObj = (ScriptObject)source;
final Property[] properties = sourceObj.getMap().getProperties();
// filter non-enumerable properties
final ArrayList<Property> propList = new ArrayList<>();
for (Property prop : properties) {
if (prop.isEnumerable()) {
propList.add(prop);
}
}
if (! propList.isEmpty()) {
targetObj.addBoundProperties(sourceObj, propList.toArray(new Property[propList.size()]));
}
} else if (source instanceof ScriptObjectMirror) {
// get enumerable, immediate properties of mirror
final ScriptObjectMirror mirror = (ScriptObjectMirror)source;
final String[] keys = mirror.getOwnKeys(false);
if (keys.length == 0) {
// nothing to bind
return target;
}
// make accessor properties using dynamic invoker getters and setters
final AccessorProperty[] props = new AccessorProperty[keys.length];
for (int idx = 0; idx < keys.length; idx++) {
final String name = keys[idx];
final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, ScriptObjectMirror.class);
final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, Object.class, ScriptObjectMirror.class, Object.class);
props[idx] = (AccessorProperty.create(name, 0, getter, setter));
}
targetObj.addBoundProperties(source, props);
}
return target;
}
}

@ -212,10 +212,10 @@ public class ScriptFunctionImpl extends ScriptFunction {
// Instance of this class is used as global anonymous function which
// serves as Function.prototype object.
private static class AnonymousFunction extends ScriptFunctionImpl {
private static final PropertyMap map$ = PropertyMap.newMap().setIsShared();
private static final PropertyMap anonmap$ = PropertyMap.newMap().setIsShared();
static PropertyMap getInitialMap() {
return map$;
return anonmap$;
}
AnonymousFunction(final Global global) {

@ -35,6 +35,7 @@ import static jdk.nashorn.internal.parser.TokenType.STRING;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@ -274,7 +275,7 @@ public class JSONParser extends AbstractParser {
* Parse a JSON literal from the token stream
* @return the JSON literal as a Node
*/
private Node jsonLiteral() {
private Expression jsonLiteral() {
final long literalToken = token;
switch (type) {
@ -326,7 +327,7 @@ public class JSONParser extends AbstractParser {
* Parse an array literal from the token stream
* @return the array literal as a Node
*/
private Node arrayLiteral() {
private LiteralNode<Expression[]> arrayLiteral() {
// Unlike JavaScript array literals, elison is not permitted in JSON.
// Capture LBRACKET token.
@ -334,9 +335,9 @@ public class JSONParser extends AbstractParser {
// LBRACKET tested in caller.
next();
Node result = null;
LiteralNode<Expression[]> result = null;
// Prepare to accummulating elements.
final List<Node> elements = new ArrayList<>();
final List<Expression> elements = new ArrayList<>();
loop:
while (true) {
@ -368,7 +369,7 @@ loop:
* Parse an object literal from the token stream
* @return the object literal as a Node
*/
private Node objectLiteral() {
private ObjectNode objectLiteral() {
// Capture LBRACE token.
final long objectToken = token;
// LBRACE tested in caller.
@ -423,7 +424,7 @@ loop:
if (name != null) {
expect(COLON);
final Node value = jsonLiteral();
final Expression value = jsonLiteral();
return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null);
}

@ -545,15 +545,28 @@ public class Lexer extends Scanner {
return token.startsWith('/') || ((scripting || XML_LITERALS) && token.startsWith('<'));
}
/**
* interface to receive line information for multi-line literals.
*/
protected interface LineInfoReceiver {
/**
* Receives line information
* @param line last line number
* @param linePosition position of last line
*/
public void lineInfo(int line, int linePosition);
}
/**
* Check whether the given token represents the beginning of a literal. If so scan
* the literal and return <tt>true</tt>, otherwise return false.
*
* @param token the token.
* @param startTokenType the token type.
* @parasm lir LineInfoReceiver that receives line info for multi-line string literals.
* @return True if a literal beginning with startToken was found and scanned.
*/
protected boolean scanLiteral(final long token, final TokenType startTokenType) {
protected boolean scanLiteral(final long token, final TokenType startTokenType, final LineInfoReceiver lir) {
// Check if it can be a literal.
if (!canStartLiteral(startTokenType)) {
return false;
@ -569,7 +582,7 @@ public class Lexer extends Scanner {
return scanRegEx();
} else if (ch0 == '<') {
if (ch1 == '<') {
return scanHereString();
return scanHereString(lir);
} else if (Character.isJavaIdentifierStart(ch1)) {
return scanXMLLiteral();
}
@ -1417,7 +1430,7 @@ public class Lexer extends Scanner {
*
* @return TRUE if is a here string.
*/
private boolean scanHereString() {
private boolean scanHereString(final LineInfoReceiver lir) {
assert ch0 == '<' && ch1 == '<';
if (scripting) {
// Record beginning of here string.
@ -1446,7 +1459,13 @@ public class Lexer extends Scanner {
// Record rest of line.
final State restState = saveState();
// keep line number updated
int lastLine = line;
int lastLinePosition = linePosition;
skipLine(false);
lastLine++;
lastLinePosition = position;
restState.setLimit(position);
// Record beginning of string.
@ -1463,9 +1482,14 @@ public class Lexer extends Scanner {
}
skipLine(false);
lastLine++;
lastLinePosition = position;
stringEnd = position;
}
// notify last line information
lir.lineInfo(lastLine, lastLinePosition);
// Record end of string.
stringState.setLimit(stringEnd);

@ -54,6 +54,7 @@ import static jdk.nashorn.internal.parser.TokenType.TERNARY;
import static jdk.nashorn.internal.parser.TokenType.WHILE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@ -66,6 +67,7 @@ import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext;
import jdk.nashorn.internal.ir.BlockStatement;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
import jdk.nashorn.internal.ir.CallNode;
@ -73,7 +75,8 @@ import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
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;
@ -127,6 +130,9 @@ public class Parser extends AbstractParser {
private static final DebugLogger LOG = new DebugLogger("parser");
/** to receive line information from Lexer when scanning multine literals. */
protected final Lexer.LineInfoReceiver lineInfoReceiver;
/**
* Constructor
*
@ -151,6 +157,19 @@ public class Parser extends AbstractParser {
this.env = env;
this.namespace = new Namespace(env.getNamespace());
this.scripting = env._scripting;
if (this.scripting) {
this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
@Override
public void lineInfo(final int line, final int linePosition) {
// update the parser maintained line information
Parser.this.line = line;
Parser.this.linePosition = linePosition;
}
};
} else {
// non-scripting mode script can't have multi-line literals
this.lineInfoReceiver = null;
}
}
/**
@ -350,7 +369,7 @@ loop:
* @return New block.
*/
private Block newBlock() {
return lc.push(new Block(line, token, Token.descPosition(token)));
return lc.push(new Block(token, Token.descPosition(token)));
}
/**
@ -516,7 +535,7 @@ loop:
* @param rhs Right hand side expression.
* @return Verified expression.
*/
private Node verifyAssignment(final long op, final Node lhs, final Node rhs) {
private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) {
final TokenType opType = Token.descType(op);
switch (opType) {
@ -562,7 +581,7 @@ loop:
* @param isPostfix Prefix or postfix.
* @return Reduced expression.
*/
private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) {
if (isPostfix) {
return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
}
@ -622,8 +641,8 @@ loop:
* @return Directive value if the given statement is a directive
*/
private String getDirective(final Node stmt) {
if (stmt instanceof ExecuteNode) {
final Node expr = ((ExecuteNode)stmt).getExpression();
if (stmt instanceof ExpressionStatement) {
final Node expr = ((ExpressionStatement)stmt).getExpression();
if (expr instanceof LiteralNode) {
final LiteralNode<?> lit = (LiteralNode<?>)expr;
final long litToken = lit.getToken();
@ -836,9 +855,7 @@ loop:
* Parse a statement block.
*/
private void block() {
final Block newBlock = getBlock(true);
// Force block execution.
appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
appendStatement(new BlockStatement(line, getBlock(true)));
}
/**
@ -921,7 +938,7 @@ loop:
verifyStrictIdent(name, "variable name");
// Assume no init.
Node init = null;
Expression init = null;
// Look for initializer assignment.
if (type == ASSIGN) {
@ -985,20 +1002,20 @@ loop:
final long expressionToken = token;
// Get expression and add as statement.
final Node expression = expression();
final Expression expression = expression();
ExecuteNode executeNode = null;
ExpressionStatement expressionStatement = null;
if (expression != null) {
executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
appendStatement(executeNode);
expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression);
appendStatement(expressionStatement);
} else {
expect(null);
}
endOfLine();
if (executeNode != null) {
executeNode.setFinish(finish);
if (expressionStatement != null) {
expressionStatement.setFinish(finish);
lc.getCurrentBlock().setFinish(finish);
}
}
@ -1020,7 +1037,7 @@ loop:
next();
expect(LPAREN);
final Node test = expression();
final Expression test = expression();
expect(RPAREN);
final Block pass = getStatement();
@ -1049,8 +1066,6 @@ loop:
// Create FOR node, capturing FOR token.
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();
lc.push(forNode);
try {
@ -1076,7 +1091,7 @@ loop:
case SEMICOLON:
break;
default:
final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
forNode = forNode.setInit(lc, expression);
break;
}
@ -1148,15 +1163,11 @@ loop:
final Block body = getStatement();
forNode = forNode.setBody(lc, body);
forNode.setFinish(body.getFinish());
outer.setFinish(body.getFinish());
appendStatement(forNode);
} finally {
lc.pop(forNode);
outer = restoreBlock(outer);
}
appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
}
/**
@ -1364,7 +1375,7 @@ loop:
// RETURN tested in caller.
nextOrEOL();
Node expression = null;
Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@ -1400,7 +1411,7 @@ loop:
// YIELD tested in caller.
nextOrEOL();
Node expression = null;
Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@ -1502,7 +1513,7 @@ loop:
while (type != RBRACE) {
// Prepare for next case.
Node caseExpression = null;
Expression caseExpression = null;
final long caseToken = token;
switch (type) {
@ -1595,7 +1606,7 @@ loop:
// THROW tested in caller.
nextOrEOL();
Node expression = null;
Expression expression = null;
// SEMICOLON or expression.
switch (type) {
@ -1643,6 +1654,7 @@ loop:
next();
// Container block needed to act as target for labeled break statements
final int startLine = line;
Block outer = newBlock();
// Create try.
@ -1662,11 +1674,13 @@ loop:
verifyStrictIdent(exception, "catch argument");
// Check for conditional catch.
Node ifExpression = null;
final Expression ifExpression;
if (type == IF) {
next();
// Get the exception condition.
ifExpression = expression();
} else {
ifExpression = null;
}
expect(RPAREN);
@ -1713,7 +1727,7 @@ loop:
outer = restoreBlock(outer);
}
appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
appendStatement(new BlockStatement(startLine, outer));
}
/**
@ -1731,7 +1745,7 @@ loop:
// DEBUGGER tested in caller.
next();
endOfLine();
appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
}
/**
@ -1749,7 +1763,7 @@ loop:
* @return Expression node.
*/
@SuppressWarnings("fallthrough")
private Node primaryExpression() {
private Expression primaryExpression() {
// Capture first token.
final int primaryLine = line;
final long primaryToken = token;
@ -1796,7 +1810,7 @@ loop:
case LPAREN:
next();
final Node expression = expression();
final Expression expression = expression();
expect(RPAREN);
@ -1804,7 +1818,7 @@ loop:
default:
// In this context some operator tokens mark the start of a literal.
if (lexer.scanLiteral(primaryToken, type)) {
if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) {
next();
return getLiteral();
}
@ -1823,17 +1837,16 @@ loop:
* @param primaryToken Original string token.
* @return callNode to $EXEC.
*/
Node execString(final int primaryLine, final long primaryToken) {
CallNode execString(final int primaryLine, final long primaryToken) {
// Synthesize an ident to call $EXEC.
final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
// Skip over EXECSTRING.
next();
// Set up argument list for call.
final List<Node> arguments = new ArrayList<>();
// Skip beginning of edit string expression.
expect(LBRACE);
// Add the following expression to arguments.
arguments.add(expression());
final List<Expression> arguments = Collections.singletonList(expression());
// Skip ending of edit string expression.
expect(RBRACE);
@ -1860,14 +1873,14 @@ loop:
* Parse array literal.
* @return Expression node.
*/
private Node arrayLiteral() {
private LiteralNode<Expression[]> arrayLiteral() {
// Capture LBRACKET token.
final long arrayToken = token;
// LBRACKET tested in caller.
next();
// Prepare to accummulating elements.
final List<Node> elements = new ArrayList<>();
final List<Expression> elements = new ArrayList<>();
// Track elisions.
boolean elision = true;
loop:
@ -1895,7 +1908,7 @@ loop:
throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
}
// Add expression element.
final Node expression = assignmentExpression(false);
final Expression expression = assignmentExpression(false);
if (expression != null) {
elements.add(expression);
@ -1925,7 +1938,7 @@ loop:
* Parse an object literal.
* @return Expression node.
*/
private Node objectLiteral() {
private ObjectNode objectLiteral() {
// Capture LBRACE token.
final long objectToken = token;
// LBRACE tested in caller.
@ -1972,11 +1985,11 @@ loop:
// ECMA section 11.1.5 Object Initialiser
// point # 4 on property assignment production
final Node value = property.getValue();
final Expression value = property.getValue();
final FunctionNode getter = property.getGetter();
final FunctionNode setter = property.getSetter();
final Node prevValue = existingProperty.getValue();
final Expression prevValue = existingProperty.getValue();
final FunctionNode prevGetter = existingProperty.getGetter();
final FunctionNode prevSetter = existingProperty.getSetter();
@ -2052,7 +2065,7 @@ loop:
private PropertyKey propertyName() {
switch (type) {
case IDENT:
return getIdent();
return getIdent().setIsPropertyName();
case OCTAL:
if (isStrictMode) {
throw error(AbstractParser.message("strict.no.octal"), token);
@ -2129,7 +2142,7 @@ loop:
}
}
propertyName = new IdentNode(propertyToken, finish, ident);
propertyName = new IdentNode(propertyToken, finish, ident).setIsPropertyName();
} else {
propertyName = propertyName();
}
@ -2155,14 +2168,14 @@ loop:
* Parse left hand side expression.
* @return Expression node.
*/
private Node leftHandSideExpression() {
private Expression leftHandSideExpression() {
int callLine = line;
long callToken = token;
Node lhs = memberExpression();
Expression lhs = memberExpression();
if (type == LPAREN) {
final List<Node> arguments = argumentList();
final List<Expression> arguments = optimizeList(argumentList());
// Catch special functions.
if (lhs instanceof IdentNode) {
@ -2181,7 +2194,7 @@ loop:
switch (type) {
case LPAREN:
// Get NEW or FUNCTION arguments.
final List<Node> arguments = argumentList();
final List<Expression> arguments = optimizeList(argumentList());
// Create call node.
lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
@ -2192,7 +2205,7 @@ loop:
next();
// Get array index.
final Node rhs = expression();
final Expression rhs = expression();
expect(RBRACKET);
@ -2229,19 +2242,19 @@ loop:
* Parse new expression.
* @return Expression node.
*/
private Node newExpression() {
private Expression newExpression() {
final long newToken = token;
// NEW is tested in caller.
next();
// Get function base.
final int callLine = line;
final Node constructor = memberExpression();
final Expression constructor = memberExpression();
if (constructor == null) {
return null;
}
// Get arguments.
List<Node> arguments;
ArrayList<Expression> arguments;
// Allow for missing arguments.
if (type == LPAREN) {
@ -2259,12 +2272,11 @@ loop:
//
// The object literal following the "new Constructor()" expresssion
// is passed as an additional (last) argument to the constructor.
if (!env._no_syntax_extensions && type == LBRACE) {
arguments.add(objectLiteral());
}
final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments));
return new UnaryNode(newToken, callNode);
}
@ -2282,9 +2294,9 @@ loop:
* Parse member expression.
* @return Expression node.
*/
private Node memberExpression() {
private Expression memberExpression() {
// Prepare to build operation.
Node lhs;
Expression lhs;
switch (type) {
case NEW:
@ -2313,7 +2325,7 @@ loop:
next();
// Get array index.
final Node index = expression();
final Expression index = expression();
expect(RBRACKET);
@ -2358,9 +2370,9 @@ loop:
* Parse function call arguments.
* @return Argument list.
*/
private List<Node> argumentList() {
private ArrayList<Expression> argumentList() {
// Prepare to accumulate list of arguments.
final List<Node> nodeList = new ArrayList<>();
final ArrayList<Expression> nodeList = new ArrayList<>();
// LPAREN tested in caller.
next();
@ -2380,9 +2392,23 @@ loop:
}
expect(RPAREN);
return nodeList;
}
}
private static <T> List<T> optimizeList(ArrayList<T> list) {
switch(list.size()) {
case 0: {
return Collections.emptyList();
}
case 1: {
return Collections.singletonList(list.get(0));
}
default: {
list.trimToSize();
return list;
}
}
}
/**
* FunctionDeclaration :
@ -2398,7 +2424,7 @@ loop:
*
* @return Expression node.
*/
private Node functionExpression(final boolean isStatement, final boolean topLevel) {
private Expression functionExpression(final boolean isStatement, final boolean topLevel) {
final long functionToken = token;
final int functionLine = line;
// FUNCTION is tested in caller.
@ -2574,10 +2600,8 @@ loop:
*/
// just expression as function body
final Node expr = assignmentExpression(true);
final Expression expr = assignmentExpression(true);
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(functionNode.getLineNumber(), expr.getToken(), finish, expr);
appendStatement(returnNode);
lastToken = token;
@ -2620,11 +2644,11 @@ loop:
}
}
private RuntimeNode referenceError(final Node lhs, final Node rhs, final boolean earlyError) {
private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) {
if (earlyError) {
throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
}
final ArrayList<Node> args = new ArrayList<>();
final ArrayList<Expression> args = new ArrayList<>();
args.add(lhs);
if (rhs == null) {
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
@ -2669,18 +2693,18 @@ loop:
* Parse unary expression.
* @return Expression node.
*/
private Node unaryExpression() {
private Expression unaryExpression() {
final int unaryLine = line;
final long unaryToken = token;
switch (type) {
case DELETE: {
next();
final Node expr = unaryExpression();
final Expression expr = unaryExpression();
if (expr instanceof BaseNode || expr instanceof IdentNode) {
return new UnaryNode(unaryToken, expr);
}
appendStatement(new ExecuteNode(unaryLine, unaryToken, finish, expr));
appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr));
return LiteralNode.newInstance(unaryToken, finish, true);
}
case VOID:
@ -2690,7 +2714,7 @@ loop:
case BIT_NOT:
case NOT:
next();
final Node expr = unaryExpression();
final Expression expr = unaryExpression();
return new UnaryNode(unaryToken, expr);
case INCPREFIX:
@ -2698,7 +2722,7 @@ loop:
final TokenType opType = type;
next();
final Node lhs = leftHandSideExpression();
final Expression lhs = leftHandSideExpression();
// ++, -- without operand..
if (lhs == null) {
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
@ -2723,14 +2747,14 @@ loop:
break;
}
Node expression = leftHandSideExpression();
Expression expression = leftHandSideExpression();
if (last != EOL) {
switch (type) {
case INCPREFIX:
case DECPREFIX:
final TokenType opType = type;
final Node lhs = expression;
final Expression lhs = expression;
// ++, -- without operand..
if (lhs == null) {
throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
@ -2855,16 +2879,16 @@ loop:
* Parse expression.
* @return Expression node.
*/
private Node expression() {
private Expression expression() {
// TODO - Destructuring array.
// Include commas in expression parsing.
return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
}
private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) {
private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) {
// Get the precedence of the next operator.
int precedence = type.getPrecedence();
Node lhs = exprLhs;
Expression lhs = exprLhs;
// While greater precedence.
while (type.isOperator(noIn) && precedence >= minPrecedence) {
@ -2877,12 +2901,12 @@ loop:
// Pass expression. Middle expression of a conditional expression can be a "in"
// expression - even in the contexts where "in" is not permitted.
final Node rhs = expression(unaryExpression(), ASSIGN.getPrecedence(), false);
final Expression rhs = expression(unaryExpression(), ASSIGN.getPrecedence(), false);
expect(COLON);
// Fail expression.
final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
final Expression third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
// Build up node.
lhs = new TernaryNode(op, lhs, rhs, third);
@ -2891,7 +2915,7 @@ loop:
next();
// Get the next primary expression.
Node rhs = unaryExpression();
Expression rhs = unaryExpression();
// Get precedence of next operator.
int nextPrecedence = type.getPrecedence();
@ -2913,7 +2937,7 @@ loop:
return lhs;
}
private Node assignmentExpression(final boolean noIn) {
private Expression assignmentExpression(final boolean noIn) {
// TODO - Handle decompose.
// Exclude commas in expression parsing.
return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);

@ -147,9 +147,9 @@ public class AccessorProperty extends Property {
* and are thus rebound with that as receiver
*
* @param property accessor property to rebind
* @param delegate delegate script object to rebind receiver to
* @param delegate delegate object to rebind receiver to
*/
public AccessorProperty(final AccessorProperty property, final ScriptObject delegate) {
public AccessorProperty(final AccessorProperty property, final Object delegate) {
super(property);
this.primitiveGetter = bindTo(property.primitiveGetter, delegate);
@ -248,11 +248,10 @@ public class AccessorProperty extends Property {
primitiveSetter = null;
if (isParameter() && hasArguments()) {
final MethodHandle arguments = MH.getter(lookup, structure, "arguments", Object.class);
final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
final MethodHandle arguments = MH.getter(lookup, structure, "arguments", ScriptObject.class);
objectGetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.GET_OBJECT_TYPE);
objectSetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot), Lookup.SET_OBJECT_TYPE);
objectGetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, arguments), 1, slot), Lookup.GET_OBJECT_TYPE);
objectSetter = MH.asType(MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, arguments), 1, slot), Lookup.SET_OBJECT_TYPE);
} else {
final GettersSetters gs = GETTERS_SETTERS.get(structure);
objectGetter = gs.getters[slot];

@ -62,4 +62,10 @@ public interface CodeInstaller<T> {
* @param code bytecode to verify
*/
public void verify(final byte[] code);
/**
* Get next unique script id
* @return unique script id
*/
public long getUniqueScriptId();
}

@ -36,15 +36,13 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.atomic.AtomicLong;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Map;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
@ -96,6 +94,11 @@ public final class Context {
public void verify(final byte[] code) {
context.verify(code);
}
@Override
public long getUniqueScriptId() {
return context.getUniqueScriptId();
}
}
/** Is Context global debug mode enabled ? */
@ -197,6 +200,9 @@ public final class Context {
/** Current error manager. */
private final ErrorManager errors;
/** Unique id for script. Used only when --loader-per-compile=false */
private final AtomicLong uniqueScriptId;
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
@ -253,7 +259,13 @@ public final class Context {
this.env = new ScriptEnvironment(options, out, err);
this._strict = env._strict;
this.appLoader = appLoader;
this.scriptLoader = env._loader_per_compile? null : createNewLoader();
if (env._loader_per_compile) {
this.scriptLoader = null;
this.uniqueScriptId = null;
} else {
this.scriptLoader = createNewLoader();
this.uniqueScriptId = new AtomicLong();
}
this.errors = errors;
// if user passed -classpath option, make a class loader with that and set it as
@ -542,6 +554,21 @@ public final class Context {
return Class.forName(fullName, true, sharedLoader);
}
/**
* Checks that the given package can be accessed from current call stack.
*
* @param fullName fully qualified package name
*/
public static void checkPackageAccess(final String fullName) {
final int index = fullName.lastIndexOf('.');
if (index != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPackageAccess(fullName.substring(0, index));
}
}
}
/**
* Lookup a Java class. This is used for JSR-223 stuff linking in from
* {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
@ -554,19 +581,7 @@ public final class Context {
*/
public Class<?> findClass(final String fullName) throws ClassNotFoundException {
// check package access as soon as possible!
final int index = fullName.lastIndexOf('.');
if (index != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
sm.checkPackageAccess(fullName.substring(0, index));
return null;
}
}, createNoPermissionsContext());
}
}
checkPackageAccess(fullName);
// try the script -classpath loader, if that is set
if (classPathLoader != null) {
@ -707,10 +722,6 @@ public final class Context {
return (context != null) ? context : Context.getContextTrusted();
}
private static AccessControlContext createNoPermissionsContext() {
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
}
private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
ScriptFunction script = null;
@ -818,4 +829,8 @@ public final class Context {
private ScriptObject newGlobalTrusted() {
return new Global(this);
}
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
}

@ -41,7 +41,7 @@ package jdk.nashorn.internal.runtime;
public class FunctionScope extends ScriptObject implements Scope {
/** Area to store scope arguments. (public for access from scripts.) */
public final Object arguments;
public final ScriptObject arguments;
/** Flag to indicate that a split method issued a return statement */
private int splitState = -1;
@ -53,7 +53,7 @@ public class FunctionScope extends ScriptObject implements Scope {
* @param callerScope caller scope
* @param arguments arguments
*/
public FunctionScope(final PropertyMap map, final ScriptObject callerScope, final Object arguments) {
public FunctionScope(final PropertyMap map, final ScriptObject callerScope, final ScriptObject arguments) {
super(callerScope, map);
this.arguments = arguments;
setIsScope();

@ -260,7 +260,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
*
* @return New {@link PropertyMap} with {@link Property} added.
*/
PropertyMap addPropertyBind(final AccessorProperty property, final ScriptObject bindTo) {
PropertyMap addPropertyBind(final AccessorProperty property, final Object bindTo) {
return addProperty(new AccessorProperty(property, bindTo));
}

@ -71,6 +71,8 @@ public abstract class ScriptFunction extends ScriptObject {
private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
private static final MethodHandle ADD_ZEROTH_ELEMENT = findOwnMH("addZerothElement", Object[].class, Object[].class, Object.class);
/** The parent scope. */
private final ScriptObject scope;
@ -546,7 +548,21 @@ public abstract class ScriptFunction extends ScriptObject {
}
private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
return bindName == null ? methodHandle : MH.insertArguments(methodHandle, 1, bindName);
if (bindName == null) {
return methodHandle;
} else {
// if it is vararg method, we need to extend argument array with
// a new zeroth element that is set to bindName value.
final MethodType methodType = methodHandle.type();
final int parameterCount = methodType.parameterCount();
final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
if (isVarArg) {
return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName));
} else {
return MH.insertArguments(methodHandle, 1, bindName);
}
}
}
/**
@ -586,6 +602,16 @@ public abstract class ScriptFunction extends ScriptObject {
return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
}
@SuppressWarnings("unused")
private static Object[] addZerothElement(final Object[] args, final Object value) {
// extends input array with by adding new zeroth element
final Object[] src = (args == null)? ScriptRuntime.EMPTY_ARRAY : args;
final Object[] result = new Object[src.length + 1];
System.arraycopy(src, 0, result, 1, src.length);
result[0] = value;
return result;
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
final Class<?> own = ScriptFunction.class;
final MethodType mt = MH.type(rtype, types);

@ -203,9 +203,19 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @param source The source object to copy from.
*/
public void addBoundProperties(final ScriptObject source) {
addBoundProperties(source, source.getMap().getProperties());
}
/**
* Copy all properties from the array with their receiver bound to the source.
*
* @param source The source object to copy from.
* @param properties The array of properties to copy.
*/
public void addBoundProperties(final ScriptObject source, final Property[] properties) {
PropertyMap newMap = this.getMap();
for (final Property property : source.getMap().getProperties()) {
for (final Property property : properties) {
final String key = property.getKey();
if (newMap.findProperty(key) == null) {
@ -221,6 +231,26 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
this.setMap(newMap);
}
/**
* Copy all properties from the array with their receiver bound to the source.
*
* @param source The source object to copy from.
* @param properties The collection of accessor properties to copy.
*/
public void addBoundProperties(final Object source, final AccessorProperty[] properties) {
PropertyMap newMap = this.getMap();
for (final AccessorProperty property : properties) {
final String key = property.getKey();
if (newMap.findProperty(key) == null) {
newMap = newMap.addPropertyBind(property, source);
}
}
this.setMap(newMap);
}
/**
* Bind the method handle to the specified receiver, while preserving its original type (it will just ignore the
* first argument in lieu of the bound argument).
@ -1948,7 +1978,12 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return noSuchProperty(desc, request);
}
final ScriptFunction func = (ScriptFunction)getObjectValue(find);
final Object value = getObjectValue(find);
if (! (value instanceof ScriptFunction)) {
return createEmptyGetter(desc, name);
}
final ScriptFunction func = (ScriptFunction)value;
final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
// TODO: It'd be awesome if we could bind "name" without binding "this".
return new GuardedInvocation(MH.dropArguments(MH.constant(ScriptFunction.class,
@ -1968,8 +2003,13 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
if (find != null) {
final ScriptFunction func = (ScriptFunction)getObjectValue(find);
MethodHandle methodHandle = getCallMethodHandle(func, desc.getMethodType(), name);
final Object value = getObjectValue(find);
ScriptFunction func = null;
MethodHandle methodHandle = null;
if (value instanceof ScriptFunction) {
func = (ScriptFunction)value;
methodHandle = getCallMethodHandle(func, desc.getMethodType(), name);
}
if (methodHandle != null) {
if (scopeAccess && func.isStrict()) {

@ -83,7 +83,7 @@ public class InvokeByName {
*/
public InvokeByName(final String name, final Class<?> targetClass, final Class<?> rtype, final Class<?>... ptypes) {
this.name = name;
getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getItem:" + name, Object.class, targetClass);
getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, Object.class, targetClass);
final Class<?>[] finalPtypes;
final int plength = ptypes.length;

@ -43,6 +43,7 @@ import java.util.Map;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.LinkRequestImpl;
import jdk.nashorn.internal.objects.NativeJava;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@ -99,6 +100,13 @@ public final class JavaAdapterFactory {
*/
public static StaticClass getAdapterClassFor(final Class<?>[] types, ScriptObject classOverrides) {
assert types != null && types.length > 0;
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
for (Class<?> type : types) {
// check for restricted package access
Context.checkPackageAccess(type.getName());
}
}
return getAdapterInfo(types).getAdapterClassFor(classOverrides);
}

@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.linker;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import jdk.internal.dynalink.CallSiteDescriptor;
@ -111,7 +110,7 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operator, operand, methodType, flags);
// Many of these call site descriptors are identical (e.g. every getter for a property color will be
// "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them.
final Map<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
final ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
final NashornCallSiteDescriptor canonical = classCanonicals.putIfAbsent(csd, csd);
return canonical != null ? canonical : csd;
}

@ -25,10 +25,14 @@
package jdk.nashorn.internal.runtime.linker;
import java.lang.reflect.Modifier;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.runtime.Context;
/**
* Check java reflection permission for java reflective and java.lang.invoke access from scripts
@ -52,6 +56,25 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
throws Exception {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
final Object self = requestWithoutContext.getReceiver();
// allow 'static' access on Class objects representing public classes of non-restricted packages
if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
// check for 'get' on 'static' property
switch (operator) {
case "getProp":
case "getMethod": {
if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
Context.checkPackageAccess(((Class)self).getName());
// let bean linker do the actual linking part
return null;
}
}
break;
} // fall through for all other stuff
}
sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
}
// let the next linker deal with actual linking

@ -57,7 +57,10 @@ final class RegExpScanner extends Scanner {
private final LinkedList<Integer> forwardReferences = new LinkedList<>();
/** Current level of zero-width negative lookahead assertions. */
private int negativeLookaheadLevel;
private int negLookaheadLevel;
/** Sequential id of current top-level zero-width negative lookahead assertion. */
private int negLookaheadGroup;
/** Are we currently inside a character class? */
private boolean inCharClass = false;
@ -68,17 +71,18 @@ final class RegExpScanner extends Scanner {
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
private static class Capture {
/**
* Zero-width negative lookaheads enclosing the capture.
*/
private final int negativeLookaheadLevel;
/** Zero-width negative lookaheads enclosing the capture. */
private final int negLookaheadLevel;
/** Sequential id of top-level negative lookaheads containing the capture. */
private final int negLookaheadGroup;
Capture(final int negativeLookaheadLevel) {
this.negativeLookaheadLevel = negativeLookaheadLevel;
Capture(final int negLookaheadGroup, final int negLookaheadLevel) {
this.negLookaheadGroup = negLookaheadGroup;
this.negLookaheadLevel = negLookaheadLevel;
}
public int getNegativeLookaheadLevel() {
return negativeLookaheadLevel;
boolean isContained(final int group, final int level) {
return group == this.negLookaheadGroup && level >= this.negLookaheadLevel;
}
}
@ -152,7 +156,7 @@ final class RegExpScanner extends Scanner {
BitVector vec = null;
for (int i = 0; i < caps.size(); i++) {
final Capture cap = caps.get(i);
if (cap.getNegativeLookaheadLevel() > 0) {
if (cap.negLookaheadLevel > 0) {
if (vec == null) {
vec = new BitVector(caps.size() + 1);
}
@ -311,11 +315,14 @@ final class RegExpScanner extends Scanner {
commit(3);
if (isNegativeLookahead) {
negativeLookaheadLevel++;
if (negLookaheadLevel == 0) {
negLookaheadGroup++;
}
negLookaheadLevel++;
}
disjunction();
if (isNegativeLookahead) {
negativeLookaheadLevel--;
negLookaheadLevel--;
}
if (ch0 == ')') {
@ -432,20 +439,17 @@ final class RegExpScanner extends Scanner {
}
if (ch0 == '(') {
boolean capturingParens = true;
commit(1);
if (ch0 == '?' && ch1 == ':') {
capturingParens = false;
commit(2);
} else {
caps.add(new Capture(negLookaheadGroup, negLookaheadLevel));
}
disjunction();
if (ch0 == ')') {
commit(1);
if (capturingParens) {
caps.add(new Capture(negativeLookaheadLevel));
}
return true;
}
}
@ -675,24 +679,22 @@ final class RegExpScanner extends Scanner {
sb.setLength(sb.length() - 1);
octalOrLiteral(Integer.toString(decimalValue), sb);
} else if (decimalValue <= caps.size() && caps.get(decimalValue - 1).getNegativeLookaheadLevel() > 0) {
// Captures that live inside a negative lookahead are dead after the
// lookahead and will be undefined if referenced from outside.
if (caps.get(decimalValue - 1).getNegativeLookaheadLevel() > negativeLookaheadLevel) {
} else if (decimalValue <= caps.size()) {
// Captures inside a negative lookahead are undefined when referenced from the outside.
if (!caps.get(decimalValue - 1).isContained(negLookaheadGroup, negLookaheadLevel)) {
// Reference to capture in negative lookahead, omit from output buffer.
sb.setLength(sb.length() - 1);
} else {
// Append backreference to output buffer.
sb.append(decimalValue);
}
} else if (decimalValue > caps.size()) {
// Forward reference to a capture group. Forward references are always undefined so we can omit
// it from the output buffer. However, if the target capture does not exist, we need to rewrite
// the reference as hex escape or literal string, so register the reference for later processing.
} else {
// Forward references to a capture group are always undefined so we can omit it from the output buffer.
// However, if the target capture does not exist, we need to rewrite the reference as hex escape
// or literal string, so register the reference for later processing.
sb.setLength(sb.length() - 1);
forwardReferences.add(decimalValue);
forwardReferences.add(sb.length());
} else {
// Append as backreference
sb.append(decimalValue);
}
}

@ -183,7 +183,7 @@ public final class CodeRangeBuffer {
// add_code_range, be aware of it returning null!
public static CodeRangeBuffer addCodeRange(CodeRangeBuffer pbuf, ScanEnvironment env, int from, int to) {
if (from >to) {
if (from > to) {
if (env.syntax.allowEmptyRangeInCC()) {
return pbuf;
} else {

@ -125,32 +125,8 @@ class Parser extends Lexer {
break;
case RAW_BYTE:
if (token.base != 0) { /* tok->base != 0 : octal or hexadec. */
byte[] buf = new byte[4];
int psave = p;
int base = token.base;
buf[0] = (byte)token.getC();
int i;
for (i=1; i<4; i++) {
fetchTokenInCC();
if (token.type != TokenType.RAW_BYTE || token.base != base) {
fetched = true;
break;
}
buf[i] = (byte)token.getC();
}
if (i == 1) {
arg.v = buf[0] & 0xff;
arg.inType = CCVALTYPE.SB; // goto raw_single
} else {
arg.v = EncodingHelper.mbcToCode(buf, 0, buf.length);
arg.inType = CCVALTYPE.CODE_POINT;
}
} else {
arg.v = token.getC();
arg.inType = CCVALTYPE.SB; // raw_single:
}
arg.v = token.getC();
arg.inType = CCVALTYPE.SB; // raw_single:
arg.vIsRaw = true;
parseCharClassValEntry2(cc, arg); // goto val_entry2
break;
@ -615,31 +591,10 @@ class Parser extends Lexer {
StringNode node = new StringNode((char)token.getC());
node.setRaw();
int len = 1;
while (true) {
if (len >= 1) {
if (len == 1) {
fetchToken();
node.clearRaw();
// !goto string_end;!
return parseExpRepeat(node, group);
}
}
fetchToken();
if (token.type != TokenType.RAW_BYTE) {
/* Don't use this, it is wrong for little endian encodings. */
// USE_PAD_TO_SHORT_BYTE_CHAR ...
newValueException(ERR_TOO_SHORT_MULTI_BYTE_STRING);
}
// important: we don't use 0xff mask here neither in the compiler
// (in the template string) so we won't have to mask target
// strings when comparing against them in the matcher
node.cat((char)token.getC());
len++;
} // while
fetchToken();
node.clearRaw();
// !goto string_end;!
return parseExpRepeat(node, group);
}
private Node parseExpRepeat(Node target, boolean group) {

@ -48,7 +48,7 @@ Object.defineProperty(this, "importPackage", {
var _packages = [];
var global = this;
var oldNoSuchProperty = global.__noSuchProperty__;
global.__noSuchProperty__ = function(name) {
var __noSuchProperty__ = function(name) {
'use strict';
for (var i in _packages) {
try {
@ -69,6 +69,11 @@ Object.defineProperty(this, "importPackage", {
}
}
Object.defineProperty(global, "__noSuchProperty__", {
writable: true, configurable: true, enumerable: false,
value: __noSuchProperty__
});
var prefix = "[JavaPackage ";
return function() {
for (var i in arguments) {

@ -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-8012191: noSuchProperty can't cope with vararg functions
*
* @test
* @run
*/
// ClassCastException: Cannot cast java.lang.String to [Ljava.lang.Object;
__noSuchProperty__ = function() {
print("obj.__noSuchProperty__ invoked for " + arguments[0]);
}
nonExistent;
// related issue was seen in JSAdapter __get__, __set__ too
var obj = new JSAdapter() {
__put__: function() {
print("JSAdapter.__put__");
print(arguments[0]);
print(arguments[1]);
},
__get__: function() {
print("JSAdapter.__get__");
print(arguments[0]);
}
};
obj.x = 343;
obj.y

@ -0,0 +1,6 @@
obj.__noSuchProperty__ invoked for nonExistent
JSAdapter.__put__
x
343
JSAdapter.__get__
y

@ -0,0 +1,62 @@
/*
* 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-8014785: Ability to extend global instance by binding properties of another object
*
* @test
* @run
*/
var obj = { x: 34, y: 100 };
var foo = {}
// bind properties of "obj" to "foo" obj
Object.bindProperties(foo, obj);
// now we can access/write on foo properties
print("foo.x = " + foo.x); // prints obj.x which is 34
// update obj.x via foo.x
foo.x = "hello";
print("obj.x = " + obj.x); // prints "hello" now
obj.x = 42; // foo.x also becomes 42
print("obj.x = " + obj.x); // prints 42
print("foo.x = " + foo.x); // prints 42
// now bind a mirror object to an object
var obj = loadWithNewGlobal({
name: "test",
script: "obj = { x: 33, y: 'hello' }"
});
Object.bindProperties(this, obj);
print("x = " + x); // prints 33
print("y = " + y); // prints "hello"
x = Math.PI; // changes obj.x to Math.PI
print("obj.x = " +obj.x); // prints Math.PI
obj.y = 32;
print("y = " + y); // should print 32

@ -0,0 +1,8 @@
foo.x = 34
obj.x = hello
obj.x = 42
foo.x = 42
x = 33
y = hello
obj.x = 3.141592653589793
y = 32

@ -0,0 +1,42 @@
/*
* 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-8016681: regex capture behaves differently than on V8
*
* @test
* @run
*/
// regexp similar to the one used in marked.js
/^((?:[^\n]+\n?(?!( *[-*_]){3,} *(?:\n+|$)| *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)|([^\n]+)\n *(=|-){3,} *\n*))+)\n*/
.exec("a\n\nb")
.forEach(function(e) { print(e); });
// simplified regexp
/(x(?!(a))(?!(b))y)/
.exec("xy")
.forEach(function(e) { print(e); });
// should not match as cross-negative-lookeahead backreference \2 should be undefined
print(/(x(?!(a))(?!(b)\2))/.exec("xbc"));

@ -0,0 +1,15 @@
a
a
undefined
undefined
undefined
undefined
undefined
xy
xy
undefined
undefined
null

@ -0,0 +1,29 @@
/*
* 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-8019822: Duplicate name/signature for a function in finally block
*
* @test
*/
try { function (x) /x/ } finally { (function(id) { return id }); }

@ -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-8019963: empty char range in regex
*
* @test
* @run
*/
var re1 = /[\x00-\x08\x0B\x0C\x0E-\x9F\uD800-\uDFFF\uFFFE\uFFFF]/;
print(re1.test("\x00"));
print(re1.test("\x04"));
print(re1.test("\x08"));
print(re1.test("\x0a"));
print(re1.test("\x0B"));
print(re1.test("\x0C"));
print(re1.test("\x0E"));
print(re1.test("\x10"));
print(re1.test("\x1A"));
print(re1.test("\x2F"));
print(re1.test("\x8E"));
print(re1.test("\x8F"));
print(re1.test("\x9F"));
print(re1.test("\xA0"));
print(re1.test("\xAF"));
print(re1.test("\uD800"));
print(re1.test("\xDA00"));
print(re1.test("\xDCFF"));
print(re1.test("\xDFFF"));
print(re1.test("\xFFFE"));
print(re1.test("\xFFFF"));
var re2 = /[\x1F\x7F-\x84\x86]/;
print(re2.test("\x1F"));
print(re2.test("\x2F"));
print(re2.test("\x3F"));
print(re2.test("\x7F"));
print(re2.test("\x80"));
print(re2.test("\x84"));
print(re2.test("\x85"));
print(re2.test("\x86"));
var re3 = /^([\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/;

@ -0,0 +1,29 @@
true
true
true
false
true
true
true
true
true
true
true
true
true
false
false
true
true
true
true
true
true
true
false
false
true
true
true
false
true

@ -0,0 +1,32 @@
/*
* 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-8020124: explicit conversion needed for switch tag
*
* @test
* @run
*/
x = {};
Function("switch((a? x = 1 : 3)) { default: return; }")

@ -0,0 +1,71 @@
/*
* 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-8020223: ClassCastException: String can not be casted to ScriptFunction
*
* @test
* @run
*/
__noSuchMethod__ = "";
try {
foo();
fail("Must have thrown exception");
} catch (e) {
if (! (e instanceof TypeError)) {
fail("TypeError expected, got " + e);
}
}
__noSuchProperty__ = 23;
try {
foo;
fail("Must have thrown exception");
} catch (e) {
if (! (e instanceof ReferenceError)) {
fail("ReferenceError expected, got " + e);
}
}
var obj = new JSAdapter() {
__get__: 332,
__call__: "hello"
}
try {
obj.foo; // should just be undefined
} catch (e) {
fail("unexpected error : " + e);
}
try {
obj.foo();
fail("Must have thrown exception");
} catch(e) {
if (! (e instanceof TypeError)) {
fail("TypeError expected, got " + e);
}
}

@ -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.
*/
/**
* JDK-8020325: static property does not work on accessible, public classes
*
* @test
* @run
*/
function printStatic(obj) {
print(obj.getClass().static);
}
printStatic(new java.util.ArrayList());
printStatic(new java.util.HashMap());
printStatic(new java.lang.Object());
printStatic(new (Java.type("java.lang.Object[]"))(0));

@ -0,0 +1,4 @@
[JavaClass java.util.ArrayList]
[JavaClass java.util.HashMap]
[JavaClass java.lang.Object]
[JavaClass [Ljava.lang.Object;]

@ -0,0 +1,36 @@
/*
* 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-8020380: __noSuchProperty__ defined in mozilla_compat.js script should be non-enumerable
*
* @test
* @run
*/
load("nashorn:mozilla_compat.js");
var desc = Object.getOwnPropertyDescriptor(this, "__noSuchProperty__");
if (typeof desc.enumerable != 'boolean' || desc.enumerable != false) {
fail("__noSuchProperty__ is enumerable");
}

Some files were not shown because too many files have changed in this diff Show More