Merge
This commit is contained in:
commit
62ca9dfc18
@ -219,8 +219,10 @@
|
||||
target="${javac.target}"
|
||||
debug="${javac.debug}"
|
||||
encoding="${javac.encoding}"
|
||||
includeantruntime="false">
|
||||
<compilerarg line="-extdirs """/>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
115
nashorn/src/jdk/nashorn/internal/ir/BlockStatement.java
Normal file
115
nashorn/src/jdk/nashorn/internal/ir/BlockStatement.java
Normal file
@ -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();
|
||||
}
|
||||
|
91
nashorn/src/jdk/nashorn/internal/ir/BreakableStatement.java
Normal file
91
nashorn/src/jdk/nashorn/internal/ir/BreakableStatement.java
Normal file
@ -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;
|
||||
}
|
||||
|
99
nashorn/src/jdk/nashorn/internal/ir/Expression.java
Normal file
99
nashorn/src/jdk/nashorn/internal/ir/Expression.java
Normal file
@ -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) {
|
||||
|
53
nashorn/test/script/basic/JDK-8012191.js
Normal file
53
nashorn/test/script/basic/JDK-8012191.js
Normal file
@ -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
|
6
nashorn/test/script/basic/JDK-8012191.js.EXPECTED
Normal file
6
nashorn/test/script/basic/JDK-8012191.js.EXPECTED
Normal file
@ -0,0 +1,6 @@
|
||||
obj.__noSuchProperty__ invoked for nonExistent
|
||||
JSAdapter.__put__
|
||||
x
|
||||
343
|
||||
JSAdapter.__get__
|
||||
y
|
62
nashorn/test/script/basic/JDK-8014785.js
Normal file
62
nashorn/test/script/basic/JDK-8014785.js
Normal file
@ -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
|
8
nashorn/test/script/basic/JDK-8014785.js.EXPECTED
Normal file
8
nashorn/test/script/basic/JDK-8014785.js.EXPECTED
Normal file
@ -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
|
42
nashorn/test/script/basic/JDK-8016681.js
Normal file
42
nashorn/test/script/basic/JDK-8016681.js
Normal file
@ -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"));
|
15
nashorn/test/script/basic/JDK-8016681.js.EXPECTED
Normal file
15
nashorn/test/script/basic/JDK-8016681.js.EXPECTED
Normal file
@ -0,0 +1,15 @@
|
||||
a
|
||||
|
||||
|
||||
a
|
||||
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
xy
|
||||
xy
|
||||
undefined
|
||||
undefined
|
||||
null
|
29
nashorn/test/script/basic/JDK-8019822.js
Normal file
29
nashorn/test/script/basic/JDK-8019822.js
Normal file
@ -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 }); }
|
66
nashorn/test/script/basic/JDK-8019963.js
Normal file
66
nashorn/test/script/basic/JDK-8019963.js
Normal file
@ -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})*$/;
|
29
nashorn/test/script/basic/JDK-8019963.js.EXPECTED
Normal file
29
nashorn/test/script/basic/JDK-8019963.js.EXPECTED
Normal file
@ -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
|
32
nashorn/test/script/basic/JDK-8020124.js
Normal file
32
nashorn/test/script/basic/JDK-8020124.js
Normal file
@ -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; }")
|
71
nashorn/test/script/basic/JDK-8020223.js
Normal file
71
nashorn/test/script/basic/JDK-8020223.js
Normal file
@ -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);
|
||||
}
|
||||
}
|
38
nashorn/test/script/basic/JDK-8020325.js
Normal file
38
nashorn/test/script/basic/JDK-8020325.js
Normal file
@ -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));
|
4
nashorn/test/script/basic/JDK-8020325.js.EXPECTED
Normal file
4
nashorn/test/script/basic/JDK-8020325.js.EXPECTED
Normal file
@ -0,0 +1,4 @@
|
||||
[JavaClass java.util.ArrayList]
|
||||
[JavaClass java.util.HashMap]
|
||||
[JavaClass java.lang.Object]
|
||||
[JavaClass [Ljava.lang.Object;]
|
36
nashorn/test/script/basic/JDK-8020380.js
Normal file
36
nashorn/test/script/basic/JDK-8020380.js
Normal file
@ -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
Loading…
Reference in New Issue
Block a user