Merge
This commit is contained in:
commit
670660bae0
@ -8,6 +8,7 @@ private.xml
|
||||
private.properties
|
||||
webrev/*
|
||||
webrev.zip
|
||||
.classpath
|
||||
*.class
|
||||
*.clazz
|
||||
*.log
|
||||
|
@ -26,4 +26,4 @@
|
||||
|
||||
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
|
||||
|
||||
$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
|
||||
$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
|
||||
|
@ -194,6 +194,8 @@ test262-test-sys-prop.test.js.enable.strict.mode=true
|
||||
test262-test-sys-prop.test.js.exclude.dir=\
|
||||
${test262.suite.dir}/intl402/
|
||||
|
||||
test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
|
||||
|
||||
# test262 test frameworks
|
||||
test262-test-sys-prop.test.js.framework=\
|
||||
-timezone=PST \
|
||||
@ -214,7 +216,7 @@ run.test.xms=2G
|
||||
|
||||
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
|
||||
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
|
||||
run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
|
||||
run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
|
||||
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
|
||||
run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
|
||||
|
||||
|
@ -78,7 +78,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
this(factory, DEFAULT_OPTIONS, appLoader);
|
||||
}
|
||||
|
||||
@SuppressWarnings("LeakingThisInConstructor")
|
||||
NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
|
||||
this.factory = factory;
|
||||
final Options options = new Options("nashorn");
|
||||
@ -102,7 +101,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
|
||||
});
|
||||
|
||||
// create new global object
|
||||
this.global = createNashornGlobal();
|
||||
this.global = createNashornGlobal();
|
||||
// set the default engine scope for the default context
|
||||
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
|
||||
|
||||
|
@ -31,7 +31,6 @@ import java.util.List;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import jdk.nashorn.internal.runtime.Version;
|
||||
import sun.reflect.Reflection;
|
||||
|
||||
/**
|
||||
* JSR-223 compliant script engine factory for Nashorn. The engine answers for:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode;
|
||||
@ -88,7 +89,6 @@ import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.LexicalContextNode;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
|
||||
@ -100,6 +100,7 @@ import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode.Request;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.TernaryNode;
|
||||
@ -191,6 +192,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
/** Current compile unit */
|
||||
private CompileUnit unit;
|
||||
|
||||
private int lastLineNumber = -1;
|
||||
|
||||
/** When should we stop caching regexp expressions in fields to limit bytecode size? */
|
||||
private static final int MAX_REGEX_FIELDS = 2 * 1024;
|
||||
|
||||
@ -261,14 +264,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
return method.load(symbol);
|
||||
}
|
||||
|
||||
final String name = symbol.getName();
|
||||
final String name = symbol.getName();
|
||||
final Source source = getLexicalContext().getCurrentFunction().getSource();
|
||||
|
||||
if (CompilerConstants.__FILE__.name().equals(name)) {
|
||||
return method.load(identNode.getSource().getName());
|
||||
return method.load(source.getName());
|
||||
} else if (CompilerConstants.__DIR__.name().equals(name)) {
|
||||
return method.load(identNode.getSource().getBase());
|
||||
return method.load(source.getBase());
|
||||
} else if (CompilerConstants.__LINE__.name().equals(name)) {
|
||||
return method.load(identNode.getSource().getLine(identNode.position())).convert(Type.OBJECT);
|
||||
return method.load(source.getLine(identNode.position())).convert(Type.OBJECT);
|
||||
} else {
|
||||
assert identNode.getSymbol().isScope() : identNode + " is not in scope!";
|
||||
|
||||
@ -568,8 +572,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
* @param block block containing symbols.
|
||||
*/
|
||||
private void symbolInfo(final Block block) {
|
||||
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
|
||||
final Symbol symbol = iter.next();
|
||||
for (final Symbol symbol : block.getSymbols()) {
|
||||
if (symbol.hasSlot()) {
|
||||
method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
|
||||
}
|
||||
@ -619,6 +622,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterBreakNode(final BreakNode breakNode) {
|
||||
lineNumber(breakNode);
|
||||
|
||||
final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
|
||||
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
|
||||
closeWith();
|
||||
@ -663,6 +668,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterCallNode(final CallNode callNode) {
|
||||
lineNumber(callNode);
|
||||
|
||||
final List<Node> args = callNode.getArgs();
|
||||
final Node function = callNode.getFunction();
|
||||
final Block currentBlock = getLexicalContext().getCurrentBlock();
|
||||
@ -836,6 +843,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterContinueNode(final ContinueNode continueNode) {
|
||||
lineNumber(continueNode);
|
||||
|
||||
final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
|
||||
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
|
||||
closeWith();
|
||||
@ -847,11 +856,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterEmptyNode(final EmptyNode emptyNode) {
|
||||
lineNumber(emptyNode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterExecuteNode(final ExecuteNode executeNode) {
|
||||
lineNumber(executeNode);
|
||||
|
||||
final Node expression = executeNode.getExpression();
|
||||
expression.accept(this);
|
||||
|
||||
@ -860,6 +873,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterForNode(final ForNode forNode) {
|
||||
lineNumber(forNode);
|
||||
|
||||
final Node test = forNode.getTest();
|
||||
final Block body = forNode.getBody();
|
||||
final Node modify = forNode.getModify();
|
||||
@ -937,11 +952,10 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
private static int assignSlots(final Block block, final int firstSlot) {
|
||||
int nextSlot = firstSlot;
|
||||
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
|
||||
final Symbol next = iter.next();
|
||||
if (next.hasSlot()) {
|
||||
next.setSlot(nextSlot);
|
||||
nextSlot += next.slotCount();
|
||||
for (final Symbol symbol : block.getSymbols()) {
|
||||
if (symbol.hasSlot()) {
|
||||
symbol.setSlot(nextSlot);
|
||||
nextSlot += symbol.slotCount();
|
||||
}
|
||||
}
|
||||
return nextSlot;
|
||||
@ -1002,10 +1016,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
final boolean hasArguments = function.needsArguments();
|
||||
|
||||
final Iterator<Symbol> symbols = block.symbolIterator();
|
||||
|
||||
while (symbols.hasNext()) {
|
||||
final Symbol symbol = symbols.next();
|
||||
for (final Symbol symbol : block.getSymbols()) {
|
||||
|
||||
if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
|
||||
continue;
|
||||
@ -1076,12 +1087,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
final Iterator<Symbol> iter = block.symbolIterator();
|
||||
final List<Symbol> symbols = new ArrayList<>();
|
||||
while (iter.hasNext()) {
|
||||
symbols.add(iter.next());
|
||||
}
|
||||
initSymbols(symbols);
|
||||
initSymbols(block.getSymbols());
|
||||
}
|
||||
|
||||
// Debugging: print symbols? @see --print-symbols flag
|
||||
@ -1157,6 +1163,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterIfNode(final IfNode ifNode) {
|
||||
lineNumber(ifNode);
|
||||
|
||||
final Node test = ifNode.getTest();
|
||||
final Block pass = ifNode.getPass();
|
||||
final Block fail = ifNode.getFail();
|
||||
@ -1196,12 +1204,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
final Label label = new Label((String)null);
|
||||
method.label(label);
|
||||
method.lineNumber(lineNumberNode.getLineNumber(), label);
|
||||
return false;
|
||||
private void lineNumber(final Statement statement) {
|
||||
final int lineNumber = statement.getLineNumber();
|
||||
if (lineNumber != lastLineNumber) {
|
||||
method.lineNumber(statement.getLineNumber());
|
||||
}
|
||||
lastLineNumber = lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1533,6 +1541,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterReturnNode(final ReturnNode returnNode) {
|
||||
lineNumber(returnNode);
|
||||
|
||||
method.registerReturn();
|
||||
|
||||
final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
|
||||
@ -1742,6 +1752,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterSplitNode(final SplitNode splitNode) {
|
||||
lineNumber(splitNode);
|
||||
|
||||
final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
|
||||
|
||||
final FunctionNode fn = getLexicalContext().getCurrentFunction();
|
||||
@ -1885,6 +1897,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterSwitchNode(final SwitchNode switchNode) {
|
||||
lineNumber(switchNode);
|
||||
|
||||
final Node expression = switchNode.getExpression();
|
||||
final Symbol tag = switchNode.getTag();
|
||||
final boolean allInteger = tag.getSymbolType().isInteger();
|
||||
@ -1967,7 +1981,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
method.tableswitch(lo, hi, defaultLabel, table);
|
||||
} else {
|
||||
final int[] ints = new int[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
ints[i] = values[i];
|
||||
}
|
||||
@ -2013,10 +2026,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterThrowNode(final ThrowNode throwNode) {
|
||||
lineNumber(throwNode);
|
||||
|
||||
method._new(ECMAException.class).dup();
|
||||
|
||||
final Source source = getLexicalContext().getCurrentFunction().getSource();
|
||||
|
||||
final Node expression = throwNode.getExpression();
|
||||
final Source source = throwNode.getSource();
|
||||
final int position = throwNode.position();
|
||||
final int line = source.getLine(position);
|
||||
final int column = source.getColumn(position);
|
||||
@ -2036,6 +2052,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterTryNode(final TryNode tryNode) {
|
||||
lineNumber(tryNode);
|
||||
|
||||
final Block body = tryNode.getBody();
|
||||
final List<Block> catchBlocks = tryNode.getCatchBlocks();
|
||||
final Symbol symbol = tryNode.getException();
|
||||
@ -2132,12 +2150,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterVarNode(final VarNode varNode) {
|
||||
|
||||
final Node init = varNode.getInit();
|
||||
|
||||
if (init == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lineNumber(varNode);
|
||||
|
||||
final Symbol varSymbol = varNode.getSymbol();
|
||||
assert varSymbol != null : "variable node " + varNode + " requires a symbol";
|
||||
|
||||
@ -2170,6 +2191,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public boolean enterWhileNode(final WhileNode whileNode) {
|
||||
lineNumber(whileNode);
|
||||
|
||||
final Node test = whileNode.getTest();
|
||||
final Block body = whileNode.getBody();
|
||||
final Label breakLabel = whileNode.getBreakLabel();
|
||||
@ -2192,7 +2215,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
}
|
||||
|
||||
private void closeWith() {
|
||||
if(method.hasScope()) {
|
||||
if (method.hasScope()) {
|
||||
method.loadCompilerConstant(SCOPE);
|
||||
method.invoke(ScriptRuntime.CLOSE_WITH);
|
||||
method.storeCompilerConstant(SCOPE);
|
||||
@ -2235,7 +2258,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
// Always process body
|
||||
body.accept(this);
|
||||
|
||||
if(hasScope) {
|
||||
if (hasScope) {
|
||||
// Ensure we always close the WithObject
|
||||
final Label endLabel = new Label("with_end");
|
||||
final Label catchLabel = new Label("with_catch");
|
||||
@ -2364,7 +2387,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
public boolean enterDISCARD(final UnaryNode unaryNode) {
|
||||
final Node rhs = unaryNode.rhs();
|
||||
|
||||
// System.err.println("**** Enter discard " + unaryNode);
|
||||
discard.push(rhs);
|
||||
load(rhs);
|
||||
|
||||
@ -2373,7 +2395,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
method.pop();
|
||||
discard.pop();
|
||||
}
|
||||
// System.err.println("**** Leave discard " + unaryNode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3019,12 +3041,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
* @param block the block we are in
|
||||
* @param ident identifier for block or function where applicable
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
private void printSymbols(final Block block, final String ident) {
|
||||
if (!compiler.getEnv()._print_symbols) {
|
||||
return;
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
final PrintWriter out = compiler.getEnv().getErr();
|
||||
out.println("[BLOCK in '" + ident + "']");
|
||||
if (!block.printSymbols(out)) {
|
||||
@ -3200,9 +3222,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
return;
|
||||
}
|
||||
|
||||
//System.err.println("Store with out discard that shouldn't just return " + assignNode);
|
||||
//new Throwable().printStackTrace();
|
||||
|
||||
final Symbol symbol = assignNode.getSymbol();
|
||||
if (symbol.hasSlot()) {
|
||||
method.dup().store(symbol);
|
||||
@ -3298,7 +3317,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
// Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded
|
||||
// visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their
|
||||
// static method's parameter list.
|
||||
if(lc.getOutermostFunction() == functionNode ||
|
||||
if (lc.getOutermostFunction() == functionNode ||
|
||||
(!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) {
|
||||
return;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.TemporarySymbols;
|
||||
import jdk.nashorn.internal.ir.debug.ASTWriter;
|
||||
import jdk.nashorn.internal.ir.debug.PrintVisitor;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
|
||||
@ -42,7 +43,7 @@ enum CompilationPhase {
|
||||
*/
|
||||
LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
|
||||
@Override
|
||||
FunctionNode transform(final Compiler compiler, final FunctionNode fn0) {
|
||||
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
|
||||
|
||||
/*
|
||||
* For lazy compilation, we might be given a node previously marked
|
||||
@ -58,8 +59,7 @@ enum CompilationPhase {
|
||||
* function from a trampoline
|
||||
*/
|
||||
|
||||
final FunctionNode outermostFunctionNode = compiler.getFunctionNode();
|
||||
assert outermostFunctionNode == fn0;
|
||||
final FunctionNode outermostFunctionNode = fn;
|
||||
|
||||
final Set<FunctionNode> neverLazy = new HashSet<>();
|
||||
final Set<FunctionNode> lazy = new HashSet<>();
|
||||
@ -172,20 +172,31 @@ enum CompilationPhase {
|
||||
ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
|
||||
@Override
|
||||
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
|
||||
return (FunctionNode)initReturnTypes(fn).accept(new Attr());
|
||||
final TemporarySymbols ts = compiler.getTemporarySymbols();
|
||||
final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
|
||||
if(compiler.getEnv()._print_mem_usage) {
|
||||
Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
|
||||
}
|
||||
return newFunctionNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pessimistically set all lazy functions' return types to Object
|
||||
* and the function symbols to object
|
||||
* @param functionNode node where to start iterating
|
||||
*/
|
||||
private FunctionNode initReturnTypes(final FunctionNode functionNode) {
|
||||
private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) {
|
||||
return (FunctionNode)functionNode.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public Node leaveFunctionNode(final FunctionNode node) {
|
||||
return node.isLazy() ?
|
||||
node.setReturnType(getLexicalContext(), Type.OBJECT) :
|
||||
node.setReturnType(getLexicalContext(), Type.UNKNOWN);
|
||||
final LexicalContext lc = getLexicalContext();
|
||||
if (node.isLazy()) {
|
||||
FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT);
|
||||
return ts.ensureSymbol(lc, Type.OBJECT, newNode);
|
||||
}
|
||||
//node may have a reference here that needs to be nulled if it was referred to by
|
||||
//its outer context, if it is lazy and not attributed
|
||||
return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -207,6 +218,7 @@ enum CompilationPhase {
|
||||
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
|
||||
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
|
||||
|
||||
// assert fn.isProgram() ;
|
||||
final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
|
||||
|
||||
assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
|
||||
@ -216,15 +228,6 @@ enum CompilationPhase {
|
||||
compiler.setStrictMode(true);
|
||||
}
|
||||
|
||||
/*
|
||||
newFunctionNode.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public boolean enterFunctionNode(final FunctionNode functionNode) {
|
||||
assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit";
|
||||
return true;
|
||||
}
|
||||
});*/
|
||||
|
||||
return newFunctionNode;
|
||||
}
|
||||
|
||||
@ -252,7 +255,7 @@ enum CompilationPhase {
|
||||
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
|
||||
final ScriptEnvironment env = compiler.getEnv();
|
||||
|
||||
final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes());
|
||||
final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes(compiler.getTemporarySymbols()));
|
||||
|
||||
if (env._print_lower_ast) {
|
||||
env.getErr().println(new ASTWriter(newFunctionNode));
|
||||
|
@ -36,26 +36,32 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
|
||||
|
||||
import jdk.nashorn.internal.ir.TemporarySymbols;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import jdk.internal.dynalink.support.NameCodec;
|
||||
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||
import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
|
||||
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
|
||||
import jdk.nashorn.internal.runtime.CodeInstaller;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.ScriptEnvironment;
|
||||
@ -77,6 +83,8 @@ public final class Compiler {
|
||||
/** Name of the objects package */
|
||||
public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
|
||||
|
||||
private Source source;
|
||||
|
||||
private final Map<String, byte[]> bytecode;
|
||||
|
||||
private final Set<CompileUnit> compileUnits;
|
||||
@ -87,14 +95,14 @@ public final class Compiler {
|
||||
|
||||
private final ScriptEnvironment env;
|
||||
|
||||
private final String scriptName;
|
||||
private String scriptName;
|
||||
|
||||
private boolean strict;
|
||||
|
||||
private FunctionNode functionNode;
|
||||
|
||||
private CodeInstaller<ScriptEnvironment> installer;
|
||||
|
||||
private final TemporarySymbols temporarySymbols = new TemporarySymbols();
|
||||
|
||||
/** logger for compiler, trampolines, splits and related code generation events
|
||||
* that affect classes */
|
||||
public static final DebugLogger LOG = new DebugLogger("compiler");
|
||||
@ -167,6 +175,41 @@ public final class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Environment information known to the compile, e.g. params
|
||||
*/
|
||||
public static class Hints {
|
||||
private final Type[] paramTypes;
|
||||
|
||||
/** singleton empty hints */
|
||||
public static final Hints EMPTY = new Hints();
|
||||
|
||||
private Hints() {
|
||||
this.paramTypes = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param paramTypes known parameter types for this callsite
|
||||
*/
|
||||
public Hints(final Type[] paramTypes) {
|
||||
this.paramTypes = paramTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parameter type for this parameter position, or
|
||||
* null if now known
|
||||
* @param pos position
|
||||
* @return parameter type for this callsite if known
|
||||
*/
|
||||
public Type getParameterType(final int pos) {
|
||||
if (paramTypes != null && pos < paramTypes.length) {
|
||||
return paramTypes[pos];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard (non-lazy) compilation, that basically will take an entire script
|
||||
* and JIT it at once. This can lead to long startup time and fewer type
|
||||
@ -207,21 +250,22 @@ public final class Compiler {
|
||||
* @param strict should this compilation use strict mode semantics
|
||||
*/
|
||||
//TODO support an array of FunctionNodes for batch lazy compilation
|
||||
Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) {
|
||||
Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) {
|
||||
this.env = env;
|
||||
this.functionNode = functionNode;
|
||||
this.sequence = sequence;
|
||||
this.installer = installer;
|
||||
this.strict = strict || functionNode.isStrict();
|
||||
this.constantData = new ConstantData();
|
||||
this.compileUnits = new HashSet<>();
|
||||
this.bytecode = new HashMap<>();
|
||||
}
|
||||
|
||||
private void initCompiler(final FunctionNode functionNode) {
|
||||
this.strict = strict || functionNode.isStrict();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
|
||||
append('$').
|
||||
append(safeSourceName(functionNode.getSource()));
|
||||
|
||||
this.source = functionNode.getSource();
|
||||
this.scriptName = sb.toString();
|
||||
}
|
||||
|
||||
@ -229,52 +273,79 @@ public final class Compiler {
|
||||
* Constructor
|
||||
*
|
||||
* @param installer code installer
|
||||
* @param functionNode function node (in any available {@link CompilationState}) to compile
|
||||
* @param strict should this compilation use strict mode semantics
|
||||
*/
|
||||
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) {
|
||||
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict);
|
||||
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
|
||||
this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - compilation will use the same strict semantics as in script environment
|
||||
*
|
||||
* @param installer code installer
|
||||
* @param functionNode function node (in any available {@link CompilationState}) to compile
|
||||
*/
|
||||
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) {
|
||||
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
|
||||
public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
|
||||
this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - compilation needs no installer, but uses a script environment
|
||||
* Used in "compile only" scenarios
|
||||
* @param env a script environment
|
||||
* @param functionNode functionNode to compile
|
||||
*/
|
||||
public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) {
|
||||
this(env, null, functionNode, sequence(env._lazy_compilation), env._strict);
|
||||
public Compiler(final ScriptEnvironment env) {
|
||||
this(env, null, sequence(env._lazy_compilation), env._strict);
|
||||
}
|
||||
|
||||
private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
|
||||
LOG.info(phaseName + " finished. Doing IR size calculation...");
|
||||
|
||||
final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
|
||||
osc.calculateObjectSize(functionNode);
|
||||
|
||||
final List<ClassHistogramElement> list = osc.getClassHistogram();
|
||||
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final long totalSize = osc.calculateObjectSize(functionNode);
|
||||
sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
|
||||
LOG.info(sb);
|
||||
|
||||
Collections.sort(list, new Comparator<ClassHistogramElement>() {
|
||||
@Override
|
||||
public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
|
||||
final long diff = o1.getBytes() - o2.getBytes();
|
||||
if (diff < 0) {
|
||||
return 1;
|
||||
} else if (diff > 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (final ClassHistogramElement e : list) {
|
||||
final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
|
||||
LOG.info(line);
|
||||
if (e.getBytes() < totalSize / 200) {
|
||||
LOG.info(" ...");
|
||||
break; // never mind, so little memory anyway
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the compilation this Compiler was created with
|
||||
* @params param types if known, for specialization
|
||||
* @param functionNode function node to compile from its current state
|
||||
* @throws CompilationException if something goes wrong
|
||||
* @return function node that results from code transforms
|
||||
*/
|
||||
public FunctionNode compile() throws CompilationException {
|
||||
return compile(null);
|
||||
}
|
||||
public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
|
||||
FunctionNode newFunctionNode = functionNode;
|
||||
|
||||
initCompiler(newFunctionNode); //TODO move this state into functionnode?
|
||||
|
||||
/**
|
||||
* Execute the compilation this Compiler was created with
|
||||
* @param paramTypes param types if known, for specialization
|
||||
* @throws CompilationException if something goes wrong
|
||||
* @return function node that results from code transforms
|
||||
*/
|
||||
public FunctionNode compile(final Class<?> paramTypes) throws CompilationException {
|
||||
for (final String reservedName : RESERVED_NAMES) {
|
||||
functionNode.uniqueName(reservedName);
|
||||
newFunctionNode.uniqueName(reservedName);
|
||||
}
|
||||
|
||||
final boolean fine = !LOG.levelAbove(Level.FINE);
|
||||
@ -283,7 +354,11 @@ public final class Compiler {
|
||||
long time = 0L;
|
||||
|
||||
for (final CompilationPhase phase : sequence) {
|
||||
this.functionNode = phase.apply(this, functionNode);
|
||||
newFunctionNode = phase.apply(this, newFunctionNode);
|
||||
|
||||
if (env._print_mem_usage) {
|
||||
printMemoryUsage(phase.toString(), newFunctionNode);
|
||||
}
|
||||
|
||||
final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
|
||||
time += duration;
|
||||
@ -293,7 +368,7 @@ public final class Compiler {
|
||||
|
||||
sb.append(phase.toString()).
|
||||
append(" done for function '").
|
||||
append(functionNode.getName()).
|
||||
append(newFunctionNode.getName()).
|
||||
append('\'');
|
||||
|
||||
if (duration > 0L) {
|
||||
@ -309,7 +384,7 @@ public final class Compiler {
|
||||
if (info) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("Compile job for '").
|
||||
append(functionNode.getName()).
|
||||
append(newFunctionNode.getName()).
|
||||
append("' finished");
|
||||
|
||||
if (time > 0L) {
|
||||
@ -321,7 +396,7 @@ public final class Compiler {
|
||||
LOG.info(sb);
|
||||
}
|
||||
|
||||
return functionNode;
|
||||
return newFunctionNode;
|
||||
}
|
||||
|
||||
private Class<?> install(final String className, final byte[] code) {
|
||||
@ -330,7 +405,6 @@ public final class Compiler {
|
||||
final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
|
||||
|
||||
try {
|
||||
final Source source = getSource();
|
||||
final Object[] constants = getConstantData().toArray();
|
||||
// Need doPrivileged because these fields are private
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
@ -355,9 +429,10 @@ public final class Compiler {
|
||||
|
||||
/**
|
||||
* Install compiled classes into a given loader
|
||||
* @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state
|
||||
* @return root script class - if there are several compile units they will also be installed
|
||||
*/
|
||||
public Class<?> install() {
|
||||
public Class<?> install(final FunctionNode functionNode) {
|
||||
final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
|
||||
|
||||
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
|
||||
@ -430,10 +505,6 @@ public final class Compiler {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
FunctionNode getFunctionNode() {
|
||||
return functionNode;
|
||||
}
|
||||
|
||||
ConstantData getConstantData() {
|
||||
return constantData;
|
||||
}
|
||||
@ -442,8 +513,8 @@ public final class Compiler {
|
||||
return installer;
|
||||
}
|
||||
|
||||
Source getSource() {
|
||||
return functionNode.getSource();
|
||||
TemporarySymbols getTemporarySymbols() {
|
||||
return temporarySymbols;
|
||||
}
|
||||
|
||||
void addClass(final String name, final byte[] code) {
|
||||
@ -496,7 +567,7 @@ public final class Compiler {
|
||||
}
|
||||
|
||||
private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
|
||||
final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict);
|
||||
final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict);
|
||||
final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
|
||||
|
||||
classEmitter.begin();
|
||||
@ -550,6 +621,4 @@ public final class Compiler {
|
||||
USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic");
|
||||
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -105,25 +105,25 @@ public enum CompilerConstants {
|
||||
ARGUMENTS("arguments", Object.class, 2),
|
||||
|
||||
/** prefix for iterators for for (x in ...) */
|
||||
ITERATOR_PREFIX(":iter"),
|
||||
ITERATOR_PREFIX(":i"),
|
||||
|
||||
/** prefix for tag variable used for switch evaluation */
|
||||
SWITCH_TAG_PREFIX(":tag"),
|
||||
SWITCH_TAG_PREFIX(":s"),
|
||||
|
||||
/** prefix for all exceptions */
|
||||
EXCEPTION_PREFIX(":exception"),
|
||||
EXCEPTION_PREFIX(":e"),
|
||||
|
||||
/** prefix for quick slots generated in Store */
|
||||
QUICK_PREFIX(":quick"),
|
||||
QUICK_PREFIX(":q"),
|
||||
|
||||
/** prefix for temporary variables */
|
||||
TEMP_PREFIX(":temp"),
|
||||
TEMP_PREFIX(":t"),
|
||||
|
||||
/** prefix for literals */
|
||||
LITERAL_PREFIX(":lit"),
|
||||
LITERAL_PREFIX(":l"),
|
||||
|
||||
/** prefix for regexps */
|
||||
REGEX_PREFIX(":regex"),
|
||||
REGEX_PREFIX(":r"),
|
||||
|
||||
/** "this" used in non-static Java methods; always in slot 0 */
|
||||
JAVA_THIS(null, 0),
|
||||
|
@ -30,7 +30,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
@ -56,6 +55,7 @@ import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode.Request;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.TemporarySymbols;
|
||||
import jdk.nashorn.internal.ir.TernaryNode;
|
||||
import jdk.nashorn.internal.ir.ThrowNode;
|
||||
import jdk.nashorn.internal.ir.TypeOverride;
|
||||
@ -88,7 +88,10 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
|
||||
private static final DebugLogger LOG = new DebugLogger("finalize");
|
||||
|
||||
FinalizeTypes() {
|
||||
private final TemporarySymbols temporarySymbols;
|
||||
|
||||
FinalizeTypes(final TemporarySymbols temporarySymbols) {
|
||||
this.temporarySymbols = temporarySymbols;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -228,21 +231,27 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
return leaveASSIGN(binaryNode);
|
||||
}
|
||||
|
||||
private boolean symbolIsInteger(Node node) {
|
||||
final Symbol symbol = node.getSymbol();
|
||||
assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveBIT_AND(BinaryNode binaryNode) {
|
||||
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
|
||||
public Node leaveBIT_AND(final BinaryNode binaryNode) {
|
||||
assert symbolIsInteger(binaryNode);
|
||||
return leaveBinary(binaryNode, Type.INT, Type.INT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveBIT_OR(BinaryNode binaryNode) {
|
||||
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
|
||||
public Node leaveBIT_OR(final BinaryNode binaryNode) {
|
||||
assert symbolIsInteger(binaryNode);
|
||||
return leaveBinary(binaryNode, Type.INT, Type.INT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveBIT_XOR(BinaryNode binaryNode) {
|
||||
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol();
|
||||
public Node leaveBIT_XOR(final BinaryNode binaryNode) {
|
||||
assert symbolIsInteger(binaryNode);
|
||||
return leaveBinary(binaryNode, Type.INT, Type.INT);
|
||||
}
|
||||
|
||||
@ -252,8 +261,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
|
||||
// AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
|
||||
// in that case, update the node type as well
|
||||
propagateType(newBinaryNode, newBinaryNode.lhs().getType());
|
||||
return newBinaryNode;
|
||||
return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -262,8 +270,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
|
||||
// AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
|
||||
// in that case, update the node type as well
|
||||
propagateType(newBinaryNode, newBinaryNode.rhs().getType());
|
||||
return newBinaryNode;
|
||||
return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -354,13 +361,6 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public Node leaveBlock(final Block block) {
|
||||
final LexicalContext lc = getLexicalContext();
|
||||
return block;//.setFlag(lc, lc.getFlags(block));
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public Node leaveCatchNode(final CatchNode catchNode) {
|
||||
final Node exceptionCondition = catchNode.getExceptionCondition();
|
||||
@ -372,6 +372,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public Node leaveExecuteNode(final ExecuteNode executeNode) {
|
||||
temporarySymbols.reuse();
|
||||
return executeNode.setExpression(discard(executeNode.getExpression()));
|
||||
}
|
||||
|
||||
@ -497,8 +498,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
|
||||
@Override
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
final Node rhs = varNode.getInit();
|
||||
if (rhs != null) {
|
||||
final Node init = varNode.getInit();
|
||||
if (init != null) {
|
||||
final SpecializedNode specialized = specialize(varNode);
|
||||
final VarNode specVarNode = (VarNode)specialized.node;
|
||||
Type destType = specialized.type;
|
||||
@ -506,8 +507,11 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
destType = specVarNode.getType();
|
||||
}
|
||||
assert specVarNode.hasType() : specVarNode + " doesn't have a type";
|
||||
return specVarNode.setInit(convert(rhs, destType));
|
||||
final Node convertedInit = convert(init, destType);
|
||||
temporarySymbols.reuse();
|
||||
return specVarNode.setInit(convertedInit);
|
||||
}
|
||||
temporarySymbols.reuse();
|
||||
return varNode;
|
||||
}
|
||||
|
||||
@ -551,8 +555,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
final boolean allVarsInScope = functionNode.allVarsInScope();
|
||||
final boolean isVarArg = functionNode.isVarArg();
|
||||
|
||||
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
|
||||
final Symbol symbol = iter.next();
|
||||
for (final Symbol symbol : block.getSymbols()) {
|
||||
if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
|
||||
continue;
|
||||
}
|
||||
@ -687,7 +690,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
|
||||
<T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
|
||||
final Node node = ((Node)assignment);
|
||||
final T lhs = assignment.getAssignmentDest();
|
||||
final Node rhs = assignment.getAssignmentSource();
|
||||
@ -709,9 +712,9 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
}
|
||||
|
||||
final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
|
||||
propagateType(newNode, to);
|
||||
final Node typePropagatedNode = propagateType(newNode, to);
|
||||
|
||||
return new SpecializedNode(newNode, to);
|
||||
return new SpecializedNode(typePropagatedNode, to);
|
||||
}
|
||||
|
||||
|
||||
@ -750,7 +753,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
* @param to new type
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Node> T setTypeOverride(final T node, final Type to) {
|
||||
<T extends Node> T setTypeOverride(final T node, final Type to) {
|
||||
final Type from = node.getType();
|
||||
if (!node.getType().equals(to)) {
|
||||
LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
|
||||
@ -759,7 +762,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
}
|
||||
}
|
||||
LOG.info("Type override for lhs in '", node, "' => ", to);
|
||||
return ((TypeOverride<T>)node).setType(to);
|
||||
return ((TypeOverride<T>)node).setType(temporarySymbols, getLexicalContext(), to);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -782,7 +785,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
private Node convert(final Node node, final Type to) {
|
||||
assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
|
||||
assert node != null : "node is null";
|
||||
assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction() + " " + node.getSource();
|
||||
assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction();
|
||||
assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
|
||||
|
||||
final Type from = node.getType();
|
||||
@ -807,24 +810,22 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
assert node instanceof TypeOverride;
|
||||
return setTypeOverride(node, to);
|
||||
}
|
||||
resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
|
||||
resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node);
|
||||
}
|
||||
|
||||
LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
|
||||
|
||||
assert !node.isTerminal();
|
||||
|
||||
final LexicalContext lc = getLexicalContext();
|
||||
//This is the only place in this file that can create new temporaries
|
||||
//FinalizeTypes may not introduce ANY node that is not a conversion.
|
||||
lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode);
|
||||
|
||||
assert !node.isTerminal();
|
||||
|
||||
return resultNode;
|
||||
return temporarySymbols.ensureSymbol(lc, to, resultNode);
|
||||
}
|
||||
|
||||
private static Node discard(final Node node) {
|
||||
if (node.getSymbol() != null) {
|
||||
final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node);
|
||||
final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
|
||||
//discard never has a symbol in the discard node - then it would be a nop
|
||||
assert !node.isTerminal();
|
||||
return discard;
|
||||
@ -847,12 +848,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
* @param node
|
||||
* @param to
|
||||
*/
|
||||
private static void propagateType(final Node node, final Type to) {
|
||||
final Symbol symbol = node.getSymbol();
|
||||
if (symbol.isTemp()) {
|
||||
symbol.setTypeOverride(to);
|
||||
private Node propagateType(final Node node, final Type to) {
|
||||
Symbol symbol = node.getSymbol();
|
||||
if (symbol.isTemp() && symbol.getSymbolType() != to) {
|
||||
symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
|
||||
LOG.info("Type override for temporary in '", node, "' => ", to);
|
||||
}
|
||||
return node.setSymbol(getLexicalContext(), symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -877,7 +879,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
* Whenever an explicit conversion is needed and the convertee is a literal, we can
|
||||
* just change the literal
|
||||
*/
|
||||
static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
|
||||
class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
|
||||
private final Type type;
|
||||
|
||||
LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
|
||||
@ -892,20 +894,20 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
LiteralNode<?> literalNode = null;
|
||||
|
||||
if (type.isString()) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value));
|
||||
literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
|
||||
} else if (type.isBoolean()) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toBoolean(value));
|
||||
literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value));
|
||||
} else if (type.isInteger()) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
|
||||
literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value));
|
||||
} else if (type.isLong()) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
|
||||
literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value));
|
||||
} else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toNumber(value));
|
||||
literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value));
|
||||
}
|
||||
|
||||
if (literalNode != null) {
|
||||
//inherit literal symbol for attr.
|
||||
literalNode.setSymbol(parent.getSymbol());
|
||||
literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol());
|
||||
}
|
||||
|
||||
return literalNode;
|
||||
|
@ -41,7 +41,6 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Simple constant folding pass, executed before IR is starting to be lowered.
|
||||
@ -89,7 +88,7 @@ final class FoldConstants extends NodeVisitor {
|
||||
if (test instanceof LiteralNode) {
|
||||
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
|
||||
if (shortCut != null) {
|
||||
return new ExecuteNode(shortCut);
|
||||
return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
|
||||
}
|
||||
return new EmptyNode(ifNode);
|
||||
}
|
||||
@ -112,13 +111,11 @@ final class FoldConstants extends NodeVisitor {
|
||||
*/
|
||||
abstract static class ConstantEvaluator<T extends Node> {
|
||||
protected T parent;
|
||||
protected final Source source;
|
||||
protected final long token;
|
||||
protected final int finish;
|
||||
|
||||
protected ConstantEvaluator(final T parent) {
|
||||
this.parent = parent;
|
||||
this.source = parent.getSource();
|
||||
this.token = parent.getToken();
|
||||
this.finish = parent.getFinish();
|
||||
}
|
||||
@ -152,23 +149,23 @@ final class FoldConstants extends NodeVisitor {
|
||||
switch (parent.tokenType()) {
|
||||
case ADD:
|
||||
if (rhsInteger) {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32());
|
||||
literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
|
||||
} else {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber());
|
||||
literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
|
||||
}
|
||||
break;
|
||||
case SUB:
|
||||
if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getInt32());
|
||||
literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
|
||||
} else {
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber());
|
||||
literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean());
|
||||
literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
|
||||
break;
|
||||
case BIT_NOT:
|
||||
literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32());
|
||||
literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
@ -234,7 +231,7 @@ final class FoldConstants extends NodeVisitor {
|
||||
break;
|
||||
}
|
||||
assert res instanceof CharSequence : res + " was not a CharSequence, it was a " + res.getClass();
|
||||
return LiteralNode.newInstance(source, token, finish, res.toString());
|
||||
return LiteralNode.newInstance(token, finish, res.toString());
|
||||
}
|
||||
return null;
|
||||
case MUL:
|
||||
@ -247,33 +244,33 @@ final class FoldConstants extends NodeVisitor {
|
||||
value = lhs.getNumber() - rhs.getNumber();
|
||||
break;
|
||||
case SHR:
|
||||
return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
|
||||
return LiteralNode.newInstance(token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
|
||||
case SAR:
|
||||
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
|
||||
return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
|
||||
case SHL:
|
||||
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32());
|
||||
return LiteralNode.newInstance(token, finish, lhs.getInt32() << rhs.getInt32());
|
||||
case BIT_XOR:
|
||||
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() ^ rhs.getInt32());
|
||||
return LiteralNode.newInstance(token, finish, lhs.getInt32() ^ rhs.getInt32());
|
||||
case BIT_AND:
|
||||
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() & rhs.getInt32());
|
||||
return LiteralNode.newInstance(token, finish, lhs.getInt32() & rhs.getInt32());
|
||||
case BIT_OR:
|
||||
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32());
|
||||
return LiteralNode.newInstance(token, finish, lhs.getInt32() | rhs.getInt32());
|
||||
case GE:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.GE(lhs.getObject(), rhs.getObject()));
|
||||
case LE:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.LE(lhs.getObject(), rhs.getObject()));
|
||||
case GT:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.GT(lhs.getObject(), rhs.getObject()));
|
||||
case LT:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.LT(lhs.getObject(), rhs.getObject()));
|
||||
case NE:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.NE(lhs.getObject(), rhs.getObject()));
|
||||
case NE_STRICT:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.NE_STRICT(lhs.getObject(), rhs.getObject()));
|
||||
case EQ:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ(lhs.getObject(), rhs.getObject()));
|
||||
case EQ_STRICT:
|
||||
return LiteralNode.newInstance(source, token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
|
||||
return LiteralNode.newInstance(token, finish, ScriptRuntime.EQ_STRICT(lhs.getObject(), rhs.getObject()));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -282,12 +279,12 @@ final class FoldConstants extends NodeVisitor {
|
||||
isLong &= value != 0.0 && JSType.isRepresentableAsLong(value);
|
||||
|
||||
if (isInteger) {
|
||||
return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value));
|
||||
return LiteralNode.newInstance(token, finish, JSType.toInt32(value));
|
||||
} else if (isLong) {
|
||||
return LiteralNode.newInstance(source, token, finish, JSType.toLong(value));
|
||||
return LiteralNode.newInstance(token, finish, JSType.toLong(value));
|
||||
}
|
||||
|
||||
return LiteralNode.newInstance(source, token, finish, value);
|
||||
return LiteralNode.newInstance(token, finish, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,8 @@
|
||||
*/
|
||||
package jdk.nashorn.internal.codegen;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
|
||||
/**
|
||||
* Abstraction for labels, separating a label from the underlying
|
||||
@ -35,12 +34,87 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
*
|
||||
* see -Dnashorn.codegen.debug, --log=codegen
|
||||
*/
|
||||
public class Label extends jdk.internal.org.objectweb.asm.Label {
|
||||
public final class Label {
|
||||
//byte code generation evaluation type stack for consistency check
|
||||
//and correct opcode selection. one per label as a label may be a
|
||||
//join point
|
||||
static final class Stack {
|
||||
Type[] data = new Type[8];
|
||||
int sp = 0;
|
||||
|
||||
Stack() {
|
||||
}
|
||||
|
||||
private Stack(final Type[] type, final int sp) {
|
||||
this();
|
||||
this.data = new Type[type.length];
|
||||
this.sp = sp;
|
||||
for (int i = 0; i < sp; i++) {
|
||||
data[i] = type[i];
|
||||
}
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return sp == 0;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return sp;
|
||||
}
|
||||
|
||||
boolean isEquivalentTo(final Stack other) {
|
||||
if (sp != other.sp) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < sp; i++) {
|
||||
if (!data[i].isEquivalentTo(other.data[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
sp = 0;
|
||||
}
|
||||
|
||||
void push(final Type type) {
|
||||
if (data.length == sp) {
|
||||
final Type[] newData = new Type[sp * 2];
|
||||
for (int i = 0; i < sp; i++) {
|
||||
newData[i] = data[i];
|
||||
}
|
||||
data = newData;
|
||||
}
|
||||
data[sp++] = type;
|
||||
}
|
||||
|
||||
Type peek() {
|
||||
return peek(0);
|
||||
}
|
||||
|
||||
Type peek(final int n) {
|
||||
int pos = sp - 1 - n;
|
||||
return pos < 0 ? null : data[pos];
|
||||
}
|
||||
|
||||
Type pop() {
|
||||
return data[--sp];
|
||||
}
|
||||
|
||||
Stack copy() {
|
||||
return new Stack(data, sp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Name of this label */
|
||||
private final String name;
|
||||
|
||||
/** Type stack at this label */
|
||||
private ArrayDeque<Type> stack;
|
||||
private Label.Stack stack;
|
||||
|
||||
/** ASM representation of this label */
|
||||
private jdk.internal.org.objectweb.asm.Label label;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -62,22 +136,24 @@ public class Label extends jdk.internal.org.objectweb.asm.Label {
|
||||
this.name = label.name;
|
||||
}
|
||||
|
||||
ArrayDeque<Type> getStack() {
|
||||
|
||||
jdk.internal.org.objectweb.asm.Label getLabel() {
|
||||
if (this.label == null) {
|
||||
this.label = new jdk.internal.org.objectweb.asm.Label();
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
Label.Stack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
void setStack(final ArrayDeque<Type> stack) {
|
||||
void setStack(final Label.Stack stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
String s = super.toString();
|
||||
s = s.substring(1, s.length());
|
||||
sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s)));
|
||||
|
||||
return sb.toString();
|
||||
return name + '_' + Debug.id(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.ir.BaseNode;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
@ -49,16 +50,15 @@ import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.LoopNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.ThrowNode;
|
||||
import jdk.nashorn.internal.ir.TryNode;
|
||||
import jdk.nashorn.internal.ir.UnaryNode;
|
||||
import jdk.nashorn.internal.ir.VarNode;
|
||||
import jdk.nashorn.internal.ir.WhileNode;
|
||||
import jdk.nashorn.internal.ir.WithNode;
|
||||
@ -93,21 +93,25 @@ final class Lower extends NodeOperatorVisitor {
|
||||
super(new BlockLexicalContext() {
|
||||
|
||||
@Override
|
||||
public List<Node> popStatements() {
|
||||
List<Node> newStatements = new ArrayList<>();
|
||||
public List<Statement> popStatements() {
|
||||
final List<Statement> newStatements = new ArrayList<>();
|
||||
boolean terminated = false;
|
||||
|
||||
final List<Node> statements = super.popStatements();
|
||||
for (final Node statement : statements) {
|
||||
final List<Statement> statements = super.popStatements();
|
||||
for (final Statement statement : statements) {
|
||||
if (!terminated) {
|
||||
newStatements.add(statement);
|
||||
if (statement.isTerminal()) {
|
||||
if (statement.isTerminal() || statement instanceof BreakNode || statement instanceof ContinueNode) { //TODO hasGoto? But some Loops are hasGoto too - why?
|
||||
terminated = true;
|
||||
}
|
||||
} else {
|
||||
if (statement instanceof VarNode) {
|
||||
newStatements.add(((VarNode)statement).setInit(null));
|
||||
}
|
||||
statement.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public boolean enterVarNode(final VarNode varNode) {
|
||||
newStatements.add(varNode.setInit(null));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return newStatements;
|
||||
@ -118,8 +122,9 @@ final class Lower extends NodeOperatorVisitor {
|
||||
@Override
|
||||
public boolean enterBlock(final Block block) {
|
||||
final LexicalContext lc = getLexicalContext();
|
||||
if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) {
|
||||
new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
|
||||
final FunctionNode function = lc.getCurrentFunction();
|
||||
if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
|
||||
new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -131,20 +136,20 @@ final class Lower extends NodeOperatorVisitor {
|
||||
|
||||
final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
|
||||
|
||||
Node last = lc.getLastStatement();
|
||||
Statement last = lc.getLastStatement();
|
||||
|
||||
if (lc.isFunctionBody()) {
|
||||
final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
|
||||
final boolean isProgram = currentFunction.isProgram();
|
||||
final ReturnNode returnNode = new ReturnNode(
|
||||
currentFunction.getSource(),
|
||||
last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
|
||||
currentFunction.getToken(),
|
||||
currentFunction.getFinish(),
|
||||
isProgram ?
|
||||
compilerConstant(RETURN) :
|
||||
LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
|
||||
|
||||
last = returnNode.accept(this);
|
||||
last = (Statement)returnNode.accept(this);
|
||||
}
|
||||
|
||||
if (last != null && last.isTerminal()) {
|
||||
@ -193,7 +198,6 @@ final class Lower extends NodeOperatorVisitor {
|
||||
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
|
||||
node = executeNode.setExpression(
|
||||
new BinaryNode(
|
||||
executeNode.getSource(),
|
||||
Token.recast(
|
||||
executeNode.getToken(),
|
||||
TokenType.ASSIGN),
|
||||
@ -239,12 +243,6 @@ final class Lower extends NodeOperatorVisitor {
|
||||
return addStatement(labelNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
addStatement(lineNumberNode); // don't put it in lastStatement cache
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveReturnNode(final ReturnNode returnNode) {
|
||||
addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
|
||||
@ -272,10 +270,10 @@ final class Lower extends NodeOperatorVisitor {
|
||||
});
|
||||
}
|
||||
|
||||
private static List<Node> copyFinally(final Block finallyBody) {
|
||||
final List<Node> newStatements = new ArrayList<>();
|
||||
for (final Node statement : finallyBody.getStatements()) {
|
||||
newStatements.add(ensureUniqueLabelsIn(statement));
|
||||
private static List<Statement> copyFinally(final Block finallyBody) {
|
||||
final List<Statement> newStatements = new ArrayList<>();
|
||||
for (final Statement statement : finallyBody.getStatements()) {
|
||||
newStatements.add((Statement)ensureUniqueLabelsIn(statement));
|
||||
if (statement.hasTerminalFlags()) {
|
||||
return newStatements;
|
||||
}
|
||||
@ -284,17 +282,17 @@ final class Lower extends NodeOperatorVisitor {
|
||||
}
|
||||
|
||||
private Block catchAllBlock(final TryNode tryNode) {
|
||||
final Source source = tryNode.getSource();
|
||||
final long token = tryNode.getToken();
|
||||
final int finish = tryNode.getFinish();
|
||||
final int lineNumber = tryNode.getLineNumber();
|
||||
final long token = tryNode.getToken();
|
||||
final int finish = tryNode.getFinish();
|
||||
|
||||
final IdentNode exception = new IdentNode(source, token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
|
||||
final IdentNode exception = new IdentNode(token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
|
||||
|
||||
final Block catchBody = new Block(source, token, finish, new ThrowNode(source, token, finish, new IdentNode(exception))).
|
||||
final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception))).
|
||||
setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
|
||||
|
||||
final CatchNode catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
|
||||
final Block catchAllBlock = new Block(source, token, finish, catchAllNode);
|
||||
final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody);
|
||||
final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
|
||||
|
||||
//catchallblock -> catchallnode (catchnode) -> exception -> throw
|
||||
|
||||
@ -303,10 +301,10 @@ final class Lower extends NodeOperatorVisitor {
|
||||
|
||||
private IdentNode compilerConstant(final CompilerConstants cc) {
|
||||
final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
|
||||
return new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
|
||||
return new IdentNode(functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
|
||||
}
|
||||
|
||||
private static boolean isTerminal(final List<Node> statements) {
|
||||
private static boolean isTerminal(final List<Statement> statements) {
|
||||
return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags();
|
||||
}
|
||||
|
||||
@ -318,8 +316,7 @@ final class Lower extends NodeOperatorVisitor {
|
||||
* @return new try node after splicing finally code (same if nop)
|
||||
*/
|
||||
private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
|
||||
final Source source = tryNode.getSource();
|
||||
final int finish = tryNode.getFinish();
|
||||
final int finish = tryNode.getFinish();
|
||||
|
||||
assert tryNode.getFinallyBody() == null;
|
||||
|
||||
@ -341,11 +338,11 @@ final class Lower extends NodeOperatorVisitor {
|
||||
@Override
|
||||
public Node leaveThrowNode(final ThrowNode throwNode) {
|
||||
if (rethrows.contains(throwNode)) {
|
||||
final List<Node> newStatements = copyFinally(finallyBody);
|
||||
final List<Statement> newStatements = copyFinally(finallyBody);
|
||||
if (!isTerminal(newStatements)) {
|
||||
newStatements.add(throwNode);
|
||||
}
|
||||
return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements);
|
||||
return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
|
||||
}
|
||||
return throwNode;
|
||||
}
|
||||
@ -363,14 +360,14 @@ final class Lower extends NodeOperatorVisitor {
|
||||
@Override
|
||||
public Node leaveReturnNode(final ReturnNode returnNode) {
|
||||
final Node expr = returnNode.getExpression();
|
||||
final List<Node> newStatements = new ArrayList<>();
|
||||
final List<Statement> newStatements = new ArrayList<>();
|
||||
|
||||
final Node resultNode;
|
||||
if (expr != null) {
|
||||
//we need to evaluate the result of the return in case it is complex while
|
||||
//still in the try block, store it in a result value and return it afterwards
|
||||
resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
|
||||
newStatements.add(new ExecuteNode(new BinaryNode(source, Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
|
||||
newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
|
||||
} else {
|
||||
resultNode = null;
|
||||
}
|
||||
@ -380,16 +377,16 @@ final class Lower extends NodeOperatorVisitor {
|
||||
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
|
||||
}
|
||||
|
||||
return new ExecuteNode(new Block(source, returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
|
||||
return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
|
||||
}
|
||||
|
||||
private Node copy(final Node endpoint, final Node targetNode) {
|
||||
private Node copy(final Statement endpoint, final Node targetNode) {
|
||||
if (!insideTry.contains(targetNode)) {
|
||||
final List<Node> newStatements = copyFinally(finallyBody);
|
||||
final List<Statement> newStatements = copyFinally(finallyBody);
|
||||
if (!isTerminal(newStatements)) {
|
||||
newStatements.add(endpoint);
|
||||
}
|
||||
return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements));
|
||||
return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
@ -397,7 +394,7 @@ final class Lower extends NodeOperatorVisitor {
|
||||
|
||||
addStatement(newTryNode);
|
||||
for (final Node statement : finallyBody.getStatements()) {
|
||||
addStatement(statement);
|
||||
addStatement((Statement)statement);
|
||||
}
|
||||
|
||||
return newTryNode;
|
||||
@ -451,7 +448,7 @@ final class Lower extends NodeOperatorVisitor {
|
||||
if (tryNode.getCatchBlocks().isEmpty()) {
|
||||
newTryNode = tryNode.setFinallyBody(null);
|
||||
} else {
|
||||
Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Node>(Arrays.asList(tryNode.setFinallyBody(null))));
|
||||
Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Statement>(Arrays.asList(tryNode.setFinallyBody(null))));
|
||||
newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
|
||||
}
|
||||
|
||||
@ -468,19 +465,19 @@ final class Lower extends NodeOperatorVisitor {
|
||||
public Node leaveVarNode(final VarNode varNode) {
|
||||
addStatement(varNode);
|
||||
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
|
||||
new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
|
||||
new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
|
||||
}
|
||||
return varNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveWhileNode(final WhileNode whileNode) {
|
||||
final Node test = whileNode.getTest();
|
||||
final Node test = whileNode.getTest();
|
||||
final Block body = whileNode.getBody();
|
||||
|
||||
if (conservativeAlwaysTrue(test)) {
|
||||
//turn it into a for node without a test.
|
||||
final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
|
||||
final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
|
||||
getLexicalContext().replace(whileNode, forNode);
|
||||
return forNode;
|
||||
}
|
||||
@ -493,16 +490,6 @@ final class Lower extends NodeOperatorVisitor {
|
||||
return addStatement(withNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveDELETE(final UnaryNode unaryNode) {
|
||||
final Node rhs = unaryNode.rhs();
|
||||
if (rhs instanceof IdentNode || rhs instanceof BaseNode) {
|
||||
return unaryNode;
|
||||
}
|
||||
addStatement(new ExecuteNode(rhs));
|
||||
return LiteralNode.newInstance(unaryNode, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a function node that is a callee in a CallNode, replace it with
|
||||
* the appropriate marker function. This is used by {@link CodeGenerator}
|
||||
@ -525,11 +512,12 @@ final class Lower extends NodeOperatorVisitor {
|
||||
* @param node a node
|
||||
* @return eval location
|
||||
*/
|
||||
private static String evalLocation(final IdentNode node) {
|
||||
private String evalLocation(final IdentNode node) {
|
||||
final Source source = getLexicalContext().getCurrentFunction().getSource();
|
||||
return new StringBuilder().
|
||||
append(node.getSource().getName()).
|
||||
append(source.getName()).
|
||||
append('#').
|
||||
append(node.getSource().getLine(node.position())).
|
||||
append(source.getLine(node.position())).
|
||||
append("<eval>").
|
||||
toString();
|
||||
}
|
||||
@ -618,7 +606,7 @@ final class Lower extends NodeOperatorVisitor {
|
||||
}
|
||||
|
||||
|
||||
private Node addStatement(final Node statement) {
|
||||
private Node addStatement(final Statement statement) {
|
||||
((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
|
||||
return statement;
|
||||
}
|
||||
|
@ -65,10 +65,12 @@ public class MapCreator {
|
||||
* Constructs a property map based on a set of fields.
|
||||
*
|
||||
* @param hasArguments does the created object have an "arguments" property
|
||||
* @param fieldCount Number of fields in use.
|
||||
* @param fieldMaximum Number of fields available.
|
||||
*
|
||||
* @return New map populated with accessor properties.
|
||||
*/
|
||||
PropertyMap makeMap(final boolean hasArguments) {
|
||||
PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
|
||||
final List<Property> properties = new ArrayList<>();
|
||||
|
||||
assert keys != null;
|
||||
@ -82,7 +84,7 @@ public class MapCreator {
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyMap.newMap(structure, properties);
|
||||
return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -67,10 +67,9 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.dynalink.support.NameCodec;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
@ -114,7 +113,7 @@ public class MethodEmitter implements Emitter {
|
||||
private final MethodVisitor method;
|
||||
|
||||
/** Current type stack for current evaluation */
|
||||
private ArrayDeque<Type> stack;
|
||||
private Label.Stack stack;
|
||||
|
||||
/** Parent classEmitter representing the class of this method */
|
||||
private final ClassEmitter classEmitter;
|
||||
@ -189,7 +188,7 @@ public class MethodEmitter implements Emitter {
|
||||
@Override
|
||||
public void begin() {
|
||||
classEmitter.beginMethod(this);
|
||||
stack = new ArrayDeque<>();
|
||||
newStack();
|
||||
method.visitCode();
|
||||
}
|
||||
|
||||
@ -205,6 +204,10 @@ public class MethodEmitter implements Emitter {
|
||||
classEmitter.endMethod(this);
|
||||
}
|
||||
|
||||
private void newStack() {
|
||||
stack = new Label.Stack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
|
||||
@ -288,11 +291,7 @@ public class MethodEmitter implements Emitter {
|
||||
* @return the type at position "pos" on the stack
|
||||
*/
|
||||
final Type peekType(final int pos) {
|
||||
final Iterator<Type> iter = stack.iterator();
|
||||
for (int i = 0; i < pos; i++) {
|
||||
iter.next();
|
||||
}
|
||||
return iter.next();
|
||||
return stack.peek(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -484,7 +483,7 @@ public class MethodEmitter implements Emitter {
|
||||
name = THIS_DEBUGGER.symbolName();
|
||||
}
|
||||
|
||||
method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
|
||||
method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -508,17 +507,6 @@ public class MethodEmitter implements Emitter {
|
||||
return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a variable with a given range
|
||||
*
|
||||
* @param name name of the variable
|
||||
* @param start start
|
||||
* @param end end
|
||||
*/
|
||||
void markerVariable(final String name, final Label start, final Label end) {
|
||||
method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops two integer types from the stack, performs a bitwise and and pushes
|
||||
* the result
|
||||
@ -626,7 +614,7 @@ public class MethodEmitter implements Emitter {
|
||||
* @param typeDescriptor type descriptor for exception
|
||||
*/
|
||||
void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
|
||||
method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor);
|
||||
method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -638,7 +626,7 @@ public class MethodEmitter implements Emitter {
|
||||
* @param clazz exception class
|
||||
*/
|
||||
void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
|
||||
method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz));
|
||||
method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -871,7 +859,7 @@ public class MethodEmitter implements Emitter {
|
||||
}
|
||||
|
||||
private boolean isThisSlot(final int slot) {
|
||||
if(functionNode == null) {
|
||||
if (functionNode == null) {
|
||||
return slot == CompilerConstants.JAVA_THIS.slot();
|
||||
}
|
||||
final int thisSlot = compilerConstant(THIS).getSlot();
|
||||
@ -915,7 +903,6 @@ public class MethodEmitter implements Emitter {
|
||||
dup();
|
||||
return this;
|
||||
}
|
||||
debug("load compiler constant ", symbol);
|
||||
return load(symbol);
|
||||
}
|
||||
|
||||
@ -1228,6 +1215,14 @@ public class MethodEmitter implements Emitter {
|
||||
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
|
||||
}
|
||||
|
||||
static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
|
||||
final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
|
||||
for (int i = 0; i < table.length; i++) {
|
||||
internalLabels[i] = table[i].getLabel();
|
||||
}
|
||||
return internalLabels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a lookup switch, popping the switch value from the stack
|
||||
*
|
||||
@ -1235,10 +1230,10 @@ public class MethodEmitter implements Emitter {
|
||||
* @param values case values for the table
|
||||
* @param table default label
|
||||
*/
|
||||
void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) {
|
||||
void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
|
||||
debug("lookupswitch", peekType());
|
||||
popType(Type.INT);
|
||||
method.visitLookupSwitchInsn(defaultLabel, values, table);
|
||||
method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1248,10 +1243,10 @@ public class MethodEmitter implements Emitter {
|
||||
* @param defaultLabel default label
|
||||
* @param table label table
|
||||
*/
|
||||
void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) {
|
||||
void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
|
||||
debug("tableswitch", peekType());
|
||||
popType(Type.INT);
|
||||
method.visitTableSwitchInsn(lo, hi, defaultLabel, table);
|
||||
method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1358,7 +1353,7 @@ public class MethodEmitter implements Emitter {
|
||||
popType();
|
||||
}
|
||||
mergeStackTo(label);
|
||||
method.visitJumpInsn(opcode, label);
|
||||
method.visitJumpInsn(opcode, label.getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1487,9 +1482,9 @@ public class MethodEmitter implements Emitter {
|
||||
* @param label destination label
|
||||
*/
|
||||
void _goto(final Label label) {
|
||||
debug("goto", label);
|
||||
//debug("goto", label);
|
||||
jump(GOTO, label, 0);
|
||||
stack = null;
|
||||
stack = null; //whoever reaches the point after us provides the stack, because we don't
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1500,38 +1495,31 @@ public class MethodEmitter implements Emitter {
|
||||
*
|
||||
* @return true if stacks are equivalent, false otherwise
|
||||
*/
|
||||
private boolean stacksEquivalent(final ArrayDeque<Type> s0, final ArrayDeque<Type> s1) {
|
||||
if (s0.size() != s1.size()) {
|
||||
debug("different stack sizes", s0, s1);
|
||||
return false;
|
||||
}
|
||||
|
||||
final Type[] s0a = s0.toArray(new Type[s0.size()]);
|
||||
final Type[] s1a = s1.toArray(new Type[s1.size()]);
|
||||
for (int i = 0; i < s0.size(); i++) {
|
||||
if (!s0a[i].isEquivalentTo(s1a[i])) {
|
||||
debug("different stack element", s0a[i], s1a[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A join in control flow - helper function that makes sure all entry stacks
|
||||
* discovered for the join point so far are equivalent
|
||||
* @param label
|
||||
*
|
||||
* MergeStack: we are about to enter a label. If its stack, label.getStack() is null
|
||||
* we have never been here before. Then we are expected to carry a stack with us.
|
||||
*
|
||||
* @param label label
|
||||
*/
|
||||
private void mergeStackTo(final Label label) {
|
||||
final ArrayDeque<Type> labelStack = label.getStack();
|
||||
//debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
|
||||
//sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
|
||||
//see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
|
||||
//by Lower removing everything after an unconditionally executed terminating statement OR a break
|
||||
//or continue in a block. Previously code left over after breaks and continues was still there
|
||||
//and caused bytecode to be generated - which crashed on stack not being there, as the merge
|
||||
//was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
|
||||
//ATHROW sequences instead of no code being generated at all. This should now be fixed.
|
||||
assert stack != null : label + " entered with no stack. deadcode that remains?";
|
||||
|
||||
final Label.Stack labelStack = label.getStack();
|
||||
if (labelStack == null) {
|
||||
assert stack != null;
|
||||
label.setStack(stack.clone());
|
||||
label.setStack(stack.copy());
|
||||
return;
|
||||
}
|
||||
assert stacksEquivalent(stack, labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
|
||||
assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1548,14 +1536,14 @@ public class MethodEmitter implements Emitter {
|
||||
if (stack == null) {
|
||||
stack = label.getStack();
|
||||
if (stack == null) {
|
||||
stack = new ArrayDeque<>(); //we don't have a stack at this point.
|
||||
newStack();
|
||||
}
|
||||
}
|
||||
debug_label(label);
|
||||
|
||||
mergeStackTo(label); //we have to merge our stack to whatever is in the label
|
||||
|
||||
method.visitLabel(label);
|
||||
method.visitLabel(label.getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1675,11 +1663,10 @@ public class MethodEmitter implements Emitter {
|
||||
* @return array of Types
|
||||
*/
|
||||
protected Type[] getTypesFromStack(final int count) {
|
||||
final Iterator<Type> iter = stack.iterator();
|
||||
final Type[] types = new Type[count];
|
||||
|
||||
final Type[] types = new Type[count];
|
||||
int pos = 0;
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
types[i] = iter.next();
|
||||
types[i] = stack.peek(pos++);
|
||||
}
|
||||
|
||||
return types;
|
||||
@ -1695,11 +1682,11 @@ public class MethodEmitter implements Emitter {
|
||||
* @return function signature for stack contents
|
||||
*/
|
||||
private String getDynamicSignature(final Type returnType, final int argCount) {
|
||||
final Iterator<Type> iter = stack.iterator();
|
||||
final Type[] paramTypes = new Type[argCount];
|
||||
|
||||
int pos = 0;
|
||||
for (int i = argCount - 1; i >= 0; i--) {
|
||||
paramTypes[i] = iter.next();
|
||||
paramTypes[i] = stack.peek(pos++);
|
||||
}
|
||||
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
|
||||
for (int i = 0; i < argCount; i++) {
|
||||
@ -2018,8 +2005,13 @@ public class MethodEmitter implements Emitter {
|
||||
* @param line line number
|
||||
* @param label label
|
||||
*/
|
||||
void lineNumber(final int line, final Label label) {
|
||||
method.visitLineNumber(line, label);
|
||||
void lineNumber(final int line) {
|
||||
if (env._debug_lines) {
|
||||
debug_label("[LINE]", line);
|
||||
final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
|
||||
method.visitLabel(l);
|
||||
method.visitLineNumber(line, l);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2116,12 +2108,12 @@ public class MethodEmitter implements Emitter {
|
||||
pad--;
|
||||
}
|
||||
|
||||
if (!stack.isEmpty()) {
|
||||
if (stack != null && !stack.isEmpty()) {
|
||||
sb.append("{");
|
||||
sb.append(stack.size());
|
||||
sb.append(":");
|
||||
for (final Iterator<Type> iter = stack.iterator(); iter.hasNext();) {
|
||||
final Type t = iter.next();
|
||||
for (int pos = 0; pos < stack.size(); pos++) {
|
||||
final Type t = stack.peek(pos);
|
||||
|
||||
if (t == Type.SCOPE) {
|
||||
sb.append("scope");
|
||||
@ -2147,7 +2139,7 @@ public class MethodEmitter implements Emitter {
|
||||
sb.append(t.getDescriptor());
|
||||
}
|
||||
|
||||
if (iter.hasNext()) {
|
||||
if (pos + 1 < stack.size()) {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,16 @@ public final class ObjectClassGenerator {
|
||||
*/
|
||||
static final String SCOPE_MARKER = "P";
|
||||
|
||||
/**
|
||||
* Minimum number of extra fields in an object.
|
||||
*/
|
||||
static final int FIELD_PADDING = 4;
|
||||
|
||||
/**
|
||||
* Rounding when calculating the number of fields.
|
||||
*/
|
||||
static final int FIELD_ROUNDING = 4;
|
||||
|
||||
/**
|
||||
* Debug field logger
|
||||
* Should we print debugging information for fields when they are generated and getters/setters are called?
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.codegen;
|
||||
|
||||
import java.util.List;
|
||||
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
@ -50,6 +51,7 @@ public abstract class ObjectCreator {
|
||||
private final boolean isScope;
|
||||
private final boolean hasArguments;
|
||||
private int fieldCount;
|
||||
private int paddedFieldCount;
|
||||
private int paramCount;
|
||||
private String fieldObjectClassName;
|
||||
private Class<?> fieldObjectClass;
|
||||
@ -88,6 +90,8 @@ public abstract class ObjectCreator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paddedFieldCount = fieldCount + FIELD_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +100,7 @@ public abstract class ObjectCreator {
|
||||
private void findClass() {
|
||||
fieldObjectClassName = isScope() ?
|
||||
ObjectClassGenerator.getClassName(fieldCount, paramCount) :
|
||||
ObjectClassGenerator.getClassName(fieldCount);
|
||||
ObjectClassGenerator.getClassName(paddedFieldCount);
|
||||
|
||||
try {
|
||||
this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
|
||||
@ -125,11 +129,7 @@ public abstract class ObjectCreator {
|
||||
* @return the newly created property map
|
||||
*/
|
||||
protected PropertyMap makeMap() {
|
||||
if (keys.isEmpty()) { //empty map
|
||||
propertyMap = PropertyMap.newMap(fieldObjectClass);
|
||||
} else {
|
||||
propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments());
|
||||
}
|
||||
propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount);
|
||||
return propertyMap;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||
@ -40,9 +41,9 @@ import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.DebugLogger;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.runtime.options.Options;
|
||||
|
||||
/**
|
||||
@ -75,7 +76,7 @@ final class Splitter extends NodeVisitor {
|
||||
*/
|
||||
public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
|
||||
this.compiler = compiler;
|
||||
this.outermost = functionNode;
|
||||
this.outermost = functionNode;
|
||||
this.outermostCompileUnit = outermostCompileUnit;
|
||||
}
|
||||
|
||||
@ -95,7 +96,7 @@ final class Splitter extends NodeVisitor {
|
||||
final LexicalContext lc = getLexicalContext();
|
||||
|
||||
long weight = WeighNodes.weigh(functionNode);
|
||||
final boolean top = compiler.getFunctionNode() == outermost;
|
||||
final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost;
|
||||
|
||||
if (weight >= SPLIT_THRESHOLD) {
|
||||
LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
|
||||
@ -127,18 +128,18 @@ final class Splitter extends NodeVisitor {
|
||||
final List<FunctionNode> dc = directChildren(functionNode);
|
||||
|
||||
final Block newBody = (Block)body.accept(new NodeVisitor() {
|
||||
@Override
|
||||
public boolean enterFunctionNode(final FunctionNode nestedFunction) {
|
||||
return dc.contains(nestedFunction);
|
||||
}
|
||||
@Override
|
||||
public boolean enterFunctionNode(final FunctionNode nestedFunction) {
|
||||
return dc.contains(nestedFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node leaveFunctionNode(final FunctionNode nestedFunction) {
|
||||
FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
|
||||
getLexicalContext().replace(nestedFunction, split);
|
||||
return split;
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public Node leaveFunctionNode(final FunctionNode nestedFunction) {
|
||||
FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
|
||||
getLexicalContext().replace(nestedFunction, split);
|
||||
return split;
|
||||
}
|
||||
});
|
||||
functionNode = functionNode.setBody(lc, newBody);
|
||||
|
||||
assert functionNode.getCompileUnit() != null;
|
||||
@ -182,11 +183,11 @@ final class Splitter extends NodeVisitor {
|
||||
private Block splitBlock(final Block block, final FunctionNode function) {
|
||||
getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
|
||||
|
||||
final List<Node> splits = new ArrayList<>();
|
||||
List<Node> statements = new ArrayList<>();
|
||||
final List<Statement> splits = new ArrayList<>();
|
||||
List<Statement> statements = new ArrayList<>();
|
||||
long statementsWeight = 0;
|
||||
|
||||
for (final Node statement : block.getStatements()) {
|
||||
for (final Statement statement : block.getStatements()) {
|
||||
final long weight = WeighNodes.weigh(statement, weightCache);
|
||||
|
||||
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
|
||||
@ -220,15 +221,15 @@ final class Splitter extends NodeVisitor {
|
||||
*
|
||||
* @return New split node.
|
||||
*/
|
||||
private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
|
||||
final Source source = parent.getSource();
|
||||
final long token = parent.getToken();
|
||||
final int finish = parent.getFinish();
|
||||
final String name = function.uniqueName(SPLIT_PREFIX.symbolName());
|
||||
private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
|
||||
final int lineNumber = parent.getLineNumber();
|
||||
final long token = parent.getToken();
|
||||
final int finish = parent.getFinish();
|
||||
final String name = function.uniqueName(SPLIT_PREFIX.symbolName());
|
||||
|
||||
final Block newBlock = new Block(source, token, finish, statements);
|
||||
final Block newBlock = new Block(lineNumber, token, finish, statements);
|
||||
|
||||
return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
|
||||
return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -273,7 +274,9 @@ final class Splitter extends NodeVisitor {
|
||||
return literal;
|
||||
}
|
||||
|
||||
getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
|
||||
final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
|
||||
|
||||
getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT);
|
||||
|
||||
if (literal instanceof ArrayLiteralNode) {
|
||||
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
|
||||
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of a property access (period operator.)
|
||||
@ -41,14 +40,13 @@ public final class AccessNode extends BaseNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param base base node
|
||||
* @param property property
|
||||
*/
|
||||
public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) {
|
||||
super(source, token, finish, base, false, false);
|
||||
public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
|
||||
super(token, finish, base, false, false);
|
||||
this.property = property.setIsPropertyName();
|
||||
}
|
||||
|
||||
@ -121,10 +119,10 @@ public final class AccessNode extends BaseNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessNode setType(final Type type) {
|
||||
public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
|
||||
logTypeChange(type);
|
||||
getSymbol().setTypeOverride(type); //always a temp so this is fine.
|
||||
return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType());
|
||||
final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
|
||||
return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
|
||||
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR base for accessing/indexing nodes.
|
||||
@ -50,15 +49,14 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param base base node
|
||||
* @param isFunction is this a function
|
||||
* @param hasCallSiteType does this access have a callsite type
|
||||
*/
|
||||
public BaseNode(final Source source, final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
|
||||
super(source, token, base.getStart(), finish);
|
||||
public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
|
||||
super(token, base.getStart(), finish);
|
||||
this.base = base;
|
||||
this.isFunction = isFunction;
|
||||
this.hasCallSiteType = hasCallSiteType;
|
||||
|
@ -29,7 +29,6 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* BinaryNode nodes represent two operand operations.
|
||||
@ -44,13 +43,12 @@ public final class BinaryNode extends Node implements Assignment<Node> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param lhs left hand side
|
||||
* @param rhs right hand side
|
||||
*/
|
||||
public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) {
|
||||
super(source, token, lhs.getStart(), rhs.getFinish());
|
||||
public BinaryNode(final long token, final Node lhs, final Node rhs) {
|
||||
super(token, lhs.getStart(), rhs.getFinish());
|
||||
this.lhs = lhs;
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
@ -30,14 +30,12 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for a list of statements and functions. All provides the
|
||||
@ -46,7 +44,7 @@ import jdk.nashorn.internal.runtime.Source;
|
||||
@Immutable
|
||||
public class Block extends BreakableNode implements Flags<Block> {
|
||||
/** List of statements */
|
||||
protected final List<Node> statements;
|
||||
protected final List<Statement> statements;
|
||||
|
||||
/** Symbol table - keys must be returned in the order they were put in. */
|
||||
protected final Map<String, Symbol> symbols;
|
||||
@ -78,13 +76,13 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param statements statements
|
||||
*/
|
||||
public Block(final Source source, final long token, final int finish, final Node... statements) {
|
||||
super(source, token, finish, new Label("block_break"));
|
||||
public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
|
||||
super(lineNumber, token, finish, new Label("block_break"));
|
||||
|
||||
this.statements = Arrays.asList(statements);
|
||||
this.symbols = new LinkedHashMap<>();
|
||||
@ -95,27 +93,35 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param statements statements
|
||||
*/
|
||||
public Block(final Source source, final long token, final int finish, final List<Node> statements) {
|
||||
this(source, token, finish, statements.toArray(new Node[statements.size()]));
|
||||
public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
|
||||
this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()]));
|
||||
}
|
||||
|
||||
private Block(final Block block, final int finish, final List<Node> statements, final int flags) {
|
||||
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols) {
|
||||
super(block);
|
||||
this.statements = statements;
|
||||
this.flags = flags;
|
||||
this.symbols = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
|
||||
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
|
||||
this.entryLabel = new Label(block.entryLabel);
|
||||
this.finish = finish;
|
||||
this.finish = finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the symbols in a block
|
||||
* TODO: make this immutable
|
||||
*/
|
||||
public void clearSymbols() {
|
||||
symbols.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node ensureUniqueLabels(final LexicalContext lc) {
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +133,7 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
@Override
|
||||
public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
|
||||
if (visitor.enterBlock(this)) {
|
||||
return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
|
||||
return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements)));
|
||||
}
|
||||
|
||||
return this;
|
||||
@ -137,15 +143,15 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
* Get an iterator for all the symbols defined in this block
|
||||
* @return symbol iterator
|
||||
*/
|
||||
public Iterator<Symbol> symbolIterator() {
|
||||
return symbols.values().iterator();
|
||||
public List<Symbol> getSymbols() {
|
||||
return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an existing symbol defined in the current block.
|
||||
* @param name the name of the symbol
|
||||
* @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
|
||||
* define a symbol with this name.
|
||||
* define a symbol with this name.T
|
||||
*/
|
||||
public Symbol getExistingSymbol(final String name) {
|
||||
return symbols.get(name);
|
||||
@ -222,7 +228,7 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
*
|
||||
* @return a list of statements
|
||||
*/
|
||||
public List<Node> getStatements() {
|
||||
public List<Statement> getStatements() {
|
||||
return Collections.unmodifiableList(statements);
|
||||
}
|
||||
|
||||
@ -233,7 +239,7 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
* @param statements new statement list
|
||||
* @return new block if statements changed, identity of statements == block.statements
|
||||
*/
|
||||
public Block setStatements(final LexicalContext lc, final List<Node> statements) {
|
||||
public Block setStatements(final LexicalContext lc, final List<Statement> statements) {
|
||||
if (this.statements == statements) {
|
||||
return this;
|
||||
}
|
||||
@ -241,17 +247,17 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
if (!statements.isEmpty()) {
|
||||
lastFinish = statements.get(statements.size() - 1).getFinish();
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags));
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or overwrite an existing symbol in the block
|
||||
*
|
||||
* @param name name of symbol
|
||||
* @param lc get lexical context
|
||||
* @param symbol symbol
|
||||
*/
|
||||
public void putSymbol(final String name, final Symbol symbol) {
|
||||
symbols.put(name, symbol);
|
||||
public void putSymbol(final LexicalContext lc, final Symbol symbol) {
|
||||
symbols.put(symbol.getName(), symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,7 +274,7 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
if (this.flags == flags) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -296,7 +302,7 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
return this;
|
||||
}
|
||||
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE));
|
||||
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,13 +312,11 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
* @return next slot
|
||||
*/
|
||||
public int nextSlot() {
|
||||
final Iterator<Symbol> iter = symbolIterator();
|
||||
int next = 0;
|
||||
while (iter.hasNext()) {
|
||||
final Symbol symbol = iter.next();
|
||||
if (symbol.hasSlot()) {
|
||||
next += symbol.slotCount();
|
||||
}
|
||||
for (final Symbol symbol : getSymbols()) {
|
||||
if (symbol.hasSlot()) {
|
||||
next += symbol.slotCount();
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
@ -41,16 +41,16 @@ import java.util.ListIterator;
|
||||
public class BlockLexicalContext extends LexicalContext {
|
||||
/** statement stack, each block on the lexical context maintains one of these, which is
|
||||
* committed to the block on pop */
|
||||
private Deque<List<Node>> sstack = new ArrayDeque<>();
|
||||
private Deque<List<Statement>> sstack = new ArrayDeque<>();
|
||||
|
||||
/** Last non debug statement emitted in this context */
|
||||
protected Node lastStatement;
|
||||
protected Statement lastStatement;
|
||||
|
||||
@Override
|
||||
public <T extends LexicalContextNode> T push(final T node) {
|
||||
T pushed = super.push(node);
|
||||
if (node instanceof Block) {
|
||||
sstack.push(new ArrayList<Node>());
|
||||
sstack.push(new ArrayList<Statement>());
|
||||
}
|
||||
return pushed;
|
||||
}
|
||||
@ -59,16 +59,16 @@ public class BlockLexicalContext extends LexicalContext {
|
||||
* Get the statement list from the stack, possibly filtered
|
||||
* @return statement list
|
||||
*/
|
||||
protected List<Node> popStatements() {
|
||||
protected List<Statement> popStatements() {
|
||||
return sstack.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends LexicalContextNode> T pop(final T node) {
|
||||
T expected = node;
|
||||
if (node instanceof Block) {
|
||||
final List<Node> newStatements = popStatements();
|
||||
final List<Statement> newStatements = popStatements();
|
||||
expected = (T)((Block)node).setStatements(this, newStatements);
|
||||
if (!sstack.isEmpty()) {
|
||||
lastStatement = lastStatement(sstack.peek());
|
||||
@ -81,12 +81,10 @@ public class BlockLexicalContext extends LexicalContext {
|
||||
* Append a statement to the block being generated
|
||||
* @param statement statement to add
|
||||
*/
|
||||
public void appendStatement(final Node statement) {
|
||||
public void appendStatement(final Statement statement) {
|
||||
assert statement != null;
|
||||
sstack.peek().add(statement);
|
||||
if (!statement.isDebug()) {
|
||||
lastStatement = statement;
|
||||
}
|
||||
lastStatement = statement;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,26 +92,24 @@ public class BlockLexicalContext extends LexicalContext {
|
||||
* @param statement statement to prepend
|
||||
* @return the prepended statement
|
||||
*/
|
||||
public Node prependStatement(final Node statement) {
|
||||
public Node prependStatement(final Statement statement) {
|
||||
assert statement != null;
|
||||
sstack.peek().add(0, statement);
|
||||
return statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last (non debug) statement that was emitted into a block
|
||||
* Get the last statement that was emitted into a block
|
||||
* @return the last statement emitted
|
||||
*/
|
||||
public Node getLastStatement() {
|
||||
public Statement getLastStatement() {
|
||||
return lastStatement;
|
||||
}
|
||||
|
||||
private static Node lastStatement(final List<Node> statements) {
|
||||
for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
|
||||
final Node node = iter.previous();
|
||||
if (!node.isDebug()) {
|
||||
return node;
|
||||
}
|
||||
private static Statement lastStatement(final List<Statement> statements) {
|
||||
for (final ListIterator<Statement> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
|
||||
final Statement node = iter.previous();
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for {@code break} statements.
|
||||
*/
|
||||
@Immutable
|
||||
public final class BreakNode extends Node {
|
||||
public final class BreakNode extends Statement {
|
||||
|
||||
private final IdentNode label;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label for break or null if none
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label for break or null if none
|
||||
*/
|
||||
public BreakNode(final Source source, final long token, final int finish, final IdentNode label) {
|
||||
super(source, token, finish);
|
||||
public BreakNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
|
||||
super(lineNumber, token, finish);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@ import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* This class represents a node from which control flow can execute
|
||||
@ -45,13 +44,13 @@ public abstract class BreakableNode extends LexicalContextNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param breakLabel break label
|
||||
*/
|
||||
protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) {
|
||||
super(source, token, finish);
|
||||
protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
|
||||
super(lineNumber, token, finish);
|
||||
this.breakLabel = breakLabel;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Ignore;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for a function call.
|
||||
@ -137,14 +136,14 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
|
||||
/**
|
||||
* Constructors
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param function the function to call
|
||||
* @param args args to the call
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param function the function to call
|
||||
* @param args args to the call
|
||||
*/
|
||||
public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) {
|
||||
super(source, token, finish);
|
||||
public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
|
||||
super(lineNumber, token, finish);
|
||||
|
||||
this.function = function;
|
||||
this.args = args;
|
||||
@ -171,7 +170,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallNode setType(final Type type) {
|
||||
public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
|
||||
if (this.type == type) {
|
||||
return this;
|
||||
}
|
||||
@ -201,7 +200,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
|
||||
setFunction(function.accept(visitor)).
|
||||
setArgs(Node.accept(visitor, Node.class, args)).
|
||||
setFlags(flags).
|
||||
setType(type).
|
||||
setType(null, lc, type).
|
||||
setEvalArgs(evalArgs == null ?
|
||||
null :
|
||||
evalArgs.setCode(evalArgs.getCode().accept(visitor)).
|
||||
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of CASE clause.
|
||||
@ -48,14 +47,13 @@ public final class CaseNode extends Node {
|
||||
/**
|
||||
* Constructors
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param test case test node, can be any node in JavaScript
|
||||
* @param body case body
|
||||
*/
|
||||
public CaseNode(final Source source, final long token, final int finish, final Node test, final Block body) {
|
||||
super(source, token, finish);
|
||||
public CaseNode(final long token, final int finish, final Node test, final Block body) {
|
||||
super(token, finish);
|
||||
|
||||
this.test = test;
|
||||
this.body = body;
|
||||
|
@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of a catch clause.
|
||||
*/
|
||||
@Immutable
|
||||
public final class CatchNode extends Node {
|
||||
public final class CatchNode extends Statement {
|
||||
/** Exception identifier. */
|
||||
private final IdentNode exception;
|
||||
|
||||
@ -46,16 +45,15 @@ public final class CatchNode extends Node {
|
||||
/**
|
||||
* Constructors
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber lineNumber
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param exception variable name of exception
|
||||
* @param exceptionCondition exception condition
|
||||
* @param body catch body
|
||||
*/
|
||||
public CatchNode(final Source source, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
|
||||
super(source, token, finish);
|
||||
|
||||
public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
|
||||
super(lineNumber, token, finish);
|
||||
this.exception = exception;
|
||||
this.exceptionCondition = exceptionCondition;
|
||||
this.body = body;
|
||||
@ -63,7 +61,6 @@ public final class CatchNode extends Node {
|
||||
|
||||
private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
|
||||
super(catchNode);
|
||||
|
||||
this.exception = exception;
|
||||
this.exceptionCondition = exceptionCondition;
|
||||
this.body = body;
|
||||
@ -138,7 +135,12 @@ public final class CatchNode extends Node {
|
||||
return body;
|
||||
}
|
||||
|
||||
private CatchNode setException(final IdentNode exception) {
|
||||
/**
|
||||
* Resets the exception of a catch block
|
||||
* @param exception new exception
|
||||
* @return new catch node if changed, same otherwise
|
||||
*/
|
||||
public CatchNode setException(final IdentNode exception) {
|
||||
if (this.exception == exception) {
|
||||
return this;
|
||||
}
|
||||
|
@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for CONTINUE statements.
|
||||
*/
|
||||
@Immutable
|
||||
public class ContinueNode extends Node {
|
||||
public class ContinueNode extends Statement {
|
||||
|
||||
private IdentNode label;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source code
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label for break or null if none
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label for break or null if none
|
||||
*/
|
||||
public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) {
|
||||
super(source, token, finish);
|
||||
public ContinueNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
|
||||
super(lineNumber, token, finish);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
@ -27,32 +27,31 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for an empty statement.
|
||||
*/
|
||||
@Immutable
|
||||
public final class EmptyNode extends Node {
|
||||
public final class EmptyNode extends Statement {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param node node to wrap
|
||||
*/
|
||||
public EmptyNode(final Node node) {
|
||||
public EmptyNode(final Statement node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
*/
|
||||
public EmptyNode(final Source source, final long token, final int finish) {
|
||||
super(source, token, finish);
|
||||
public EmptyNode(final int lineNumber, final long token, final int finish) {
|
||||
super(lineNumber, token, finish);
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for executing bare expressions. Basically, an expression
|
||||
@ -35,20 +34,20 @@ import jdk.nashorn.internal.runtime.Source;
|
||||
* statements being added to the IR
|
||||
*/
|
||||
@Immutable
|
||||
public final class ExecuteNode extends Node {
|
||||
public final class ExecuteNode extends Statement {
|
||||
/** Expression to execute. */
|
||||
private final Node expression;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param expression the expression to execute
|
||||
*/
|
||||
public ExecuteNode(final Source source, final long token, final int finish, final Node expression) {
|
||||
super(source, token, finish);
|
||||
public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
|
||||
super(lineNumber, token, finish);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@ -57,16 +56,6 @@ public final class ExecuteNode extends Node {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param expression an expression to wrap, from which source, tokens and finish are also inherited
|
||||
*/
|
||||
public ExecuteNode(final Node expression) {
|
||||
super(expression.getSource(), expression.getToken(), expression.getFinish());
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTerminal() {
|
||||
return expression.isTerminal();
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representing a FOR statement.
|
||||
@ -57,17 +56,17 @@ public final class ForNode extends LoopNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param init init
|
||||
* @param test test
|
||||
* @param body body
|
||||
* @param modify modify
|
||||
* @param flags flags
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param init initialization expression
|
||||
* @param test test
|
||||
* @param body body
|
||||
* @param modify modify
|
||||
* @param flags flags
|
||||
*/
|
||||
public ForNode(final Source source, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
|
||||
super(source, token, finish, test, body, false);
|
||||
public ForNode(final int lineNumber, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
|
||||
super(lineNumber, token, finish, test, body, false);
|
||||
this.init = init;
|
||||
this.modify = modify;
|
||||
this.flags = flags;
|
||||
|
@ -25,16 +25,12 @@
|
||||
|
||||
package jdk.nashorn.internal.ir;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.nashorn.internal.codegen.CompileUnit;
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
@ -90,11 +86,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
/** method has been emitted to bytecode */
|
||||
EMITTED
|
||||
}
|
||||
/** Source of entity. */
|
||||
private final Source source;
|
||||
|
||||
/** External function identifier. */
|
||||
@Ignore
|
||||
private final IdentNode ident;
|
||||
|
||||
/** Parsed version of functionNode */
|
||||
@Ignore
|
||||
private final FunctionNode snapshot;
|
||||
|
||||
/** The body of the function node */
|
||||
private final Block body;
|
||||
|
||||
@ -127,6 +129,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
@Ignore
|
||||
private final EnumSet<CompilationState> compilationState;
|
||||
|
||||
@Ignore
|
||||
private final Compiler.Hints hints;
|
||||
|
||||
/** Function flags. */
|
||||
private final int flags;
|
||||
|
||||
@ -176,6 +181,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
/** Does this function have nested declarations? */
|
||||
public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13;
|
||||
|
||||
/** Can this function be specialized? */
|
||||
public static final int CAN_SPECIALIZE = 1 << 14;
|
||||
|
||||
/** Does this function or any nested functions contain an eval? */
|
||||
private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
|
||||
|
||||
@ -196,6 +204,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param firstToken first token of the funtion node (including the function declaration)
|
||||
@ -208,6 +217,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
*/
|
||||
public FunctionNode(
|
||||
final Source source,
|
||||
final int lineNumber,
|
||||
final long token,
|
||||
final int finish,
|
||||
final long firstToken,
|
||||
@ -217,39 +227,56 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
final List<IdentNode> parameters,
|
||||
final FunctionNode.Kind kind,
|
||||
final int flags) {
|
||||
super(source, token, finish);
|
||||
super(lineNumber, token, finish);
|
||||
|
||||
this.ident = ident;
|
||||
this.name = name;
|
||||
this.kind = kind;
|
||||
this.parameters = parameters;
|
||||
this.firstToken = firstToken;
|
||||
this.lastToken = token;
|
||||
this.namespace = namespace;
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
|
||||
this.declaredSymbols = new HashSet<>();
|
||||
this.flags = flags;
|
||||
this.compileUnit = null;
|
||||
this.body = null;
|
||||
this.source = source;
|
||||
this.ident = ident;
|
||||
this.name = name;
|
||||
this.kind = kind;
|
||||
this.parameters = parameters;
|
||||
this.firstToken = firstToken;
|
||||
this.lastToken = token;
|
||||
this.namespace = namespace;
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
|
||||
this.declaredSymbols = new HashSet<>();
|
||||
this.flags = flags;
|
||||
this.compileUnit = null;
|
||||
this.body = null;
|
||||
this.snapshot = null;
|
||||
this.hints = null;
|
||||
}
|
||||
|
||||
private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
|
||||
private FunctionNode(
|
||||
final FunctionNode functionNode,
|
||||
final long lastToken,
|
||||
final int flags,
|
||||
final Type returnType,
|
||||
final CompileUnit compileUnit,
|
||||
final EnumSet<CompilationState> compilationState,
|
||||
final Block body,
|
||||
final List<IdentNode> parameters,
|
||||
final FunctionNode snapshot,
|
||||
final Compiler.Hints hints) {
|
||||
super(functionNode);
|
||||
this.flags = flags;
|
||||
this.returnType = returnType;
|
||||
this.compileUnit = compileUnit;
|
||||
this.lastToken = lastToken;
|
||||
|
||||
this.flags = flags;
|
||||
this.returnType = returnType;
|
||||
this.compileUnit = compileUnit;
|
||||
this.lastToken = lastToken;
|
||||
this.compilationState = compilationState;
|
||||
this.body = body;
|
||||
this.body = body;
|
||||
this.parameters = parameters;
|
||||
this.snapshot = snapshot;
|
||||
this.hints = hints;
|
||||
|
||||
// the fields below never change - they are final and assigned in constructor
|
||||
this.name = functionNode.name;
|
||||
this.ident = functionNode.ident;
|
||||
this.namespace = functionNode.namespace;
|
||||
this.source = functionNode.source;
|
||||
this.name = functionNode.name;
|
||||
this.ident = functionNode.ident;
|
||||
this.namespace = functionNode.namespace;
|
||||
this.declaredSymbols = functionNode.declaredSymbols;
|
||||
this.kind = functionNode.kind;
|
||||
this.parameters = functionNode.parameters;
|
||||
this.firstToken = functionNode.firstToken;
|
||||
this.kind = functionNode.kind;
|
||||
this.firstToken = functionNode.firstToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -260,6 +287,61 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source for this function
|
||||
* @return the source
|
||||
*/
|
||||
public Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the version of this function node's code as it looked upon construction
|
||||
* i.e typically parsed and nothing else
|
||||
* @return initial version of function node
|
||||
*/
|
||||
public FunctionNode getSnapshot() {
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw away the snapshot, if any, to save memory. Used when heuristic
|
||||
* determines that a method is not worth specializing
|
||||
*
|
||||
* @param lc lexical context
|
||||
* @return new function node if a snapshot was present, now with snapsnot null
|
||||
*/
|
||||
public FunctionNode clearSnapshot(final LexicalContext lc) {
|
||||
if (this.snapshot == null) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a snapshot of this function node at a given point in time
|
||||
* and store it in the function node
|
||||
* @param lc lexical context
|
||||
* @return function node
|
||||
*/
|
||||
public FunctionNode snapshot(final LexicalContext lc) {
|
||||
if (this.snapshot == this) {
|
||||
return this;
|
||||
}
|
||||
if (isProgram() || parameters.isEmpty()) {
|
||||
return this; //never specialize anything that won't be recompiled
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this function node be regenerated with more specific type args?
|
||||
* @return true if specialization is possible
|
||||
*/
|
||||
public boolean canSpecialize() {
|
||||
return getFlag(CAN_SPECIALIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compilation state of this function
|
||||
* @return the compilation state
|
||||
@ -307,7 +389,28 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
}
|
||||
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
|
||||
newState.add(state);
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any compiler hints that may associated with the function
|
||||
* @return compiler hints
|
||||
*/
|
||||
public Compiler.Hints getHints() {
|
||||
return this.hints == null ? Compiler.Hints.EMPTY : hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set compiler hints for this function
|
||||
* @param lc lexical context
|
||||
* @param hints compiler hints
|
||||
* @return new function if hints changed
|
||||
*/
|
||||
public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) {
|
||||
if (this.hints == hints) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -319,20 +422,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
return namespace.uniqueName(base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a virtual symbol for a literal.
|
||||
*
|
||||
* @param literalNode Primary node to use symbol.
|
||||
*
|
||||
* @return Symbol used.
|
||||
*/
|
||||
public Symbol newLiteral(final LiteralNode<?> literalNode) {
|
||||
final String uname = uniqueName(LITERAL_PREFIX.symbolName());
|
||||
final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
|
||||
literalNode.setSymbol(symbol);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
@ -374,7 +463,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
if (this.flags == flags) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -483,7 +572,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
if(this.body == body) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -551,7 +640,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
if (this.lastToken == lastToken) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -599,13 +688,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specialized type for an identity, if one exists
|
||||
* @param node node to check specialized type for
|
||||
* @return null if no specialization exists, otherwise type
|
||||
* Reset the compile unit used to compile this function
|
||||
* @see Compiler
|
||||
* @param lc lexical context
|
||||
* @param parameters the compile unit
|
||||
* @return function node or a new one if state was changed
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
public Type getSpecializedType(final IdentNode node) {
|
||||
return null; //TODO implement specialized types later
|
||||
public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
|
||||
if (this.parameters == parameters) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -674,7 +767,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
returnType),
|
||||
compileUnit,
|
||||
compilationState,
|
||||
body));
|
||||
body,
|
||||
parameters,
|
||||
snapshot,
|
||||
hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -705,7 +801,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
if (this.compileUnit == compileUnit) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -717,19 +813,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
*
|
||||
* @return Symbol used.
|
||||
*/
|
||||
public Symbol ensureSymbol(final Block block, final Type type, final Node node) {
|
||||
Symbol symbol = node.getSymbol();
|
||||
|
||||
// If no symbol already present.
|
||||
if (symbol == null) {
|
||||
final String uname = uniqueName(TEMP_PREFIX.symbolName());
|
||||
symbol = new Symbol(uname, IS_TEMP, type);
|
||||
block.putSymbol(uname, symbol);
|
||||
node.setSymbol(symbol);
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the symbol for a compiler constant, or null if not available (yet)
|
||||
@ -739,5 +822,4 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
public Symbol compilerConstant(final CompilerConstants cc) {
|
||||
return body.getExistingSymbol(cc.symbolName());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for an identifier.
|
||||
@ -56,14 +55,13 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish position
|
||||
* @param name name of identifier
|
||||
*/
|
||||
public IdentNode(final Source source, final long token, final int finish, final String name) {
|
||||
super(source, token, finish);
|
||||
this.name = name;
|
||||
public IdentNode(final long token, final int finish, final String name) {
|
||||
super(token, finish);
|
||||
this.name = name.intern();
|
||||
this.callSiteType = null;
|
||||
this.flags = 0;
|
||||
}
|
||||
@ -103,7 +101,7 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentNode setType(final Type type) {
|
||||
public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
|
||||
// do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
|
||||
if (this.callSiteType == type) {
|
||||
return this;
|
||||
|
@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for an IF statement.
|
||||
*/
|
||||
@Immutable
|
||||
public final class IfNode extends Node {
|
||||
public final class IfNode extends Statement {
|
||||
/** Test expression. */
|
||||
private final Node test;
|
||||
|
||||
@ -46,15 +45,15 @@ public final class IfNode extends Node {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param test test
|
||||
* @param pass block to execute when test passes
|
||||
* @param fail block to execute when test fails or null
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param test test
|
||||
* @param pass block to execute when test passes
|
||||
* @param fail block to execute when test fails or null
|
||||
*/
|
||||
public IfNode(final Source source, final long token, final int finish, final Node test, final Block pass, final Block fail) {
|
||||
super(source, token, finish);
|
||||
public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
|
||||
super(lineNumber, token, finish);
|
||||
this.test = test;
|
||||
this.pass = pass;
|
||||
this.fail = fail;
|
||||
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of an indexed access (brackets operator.)
|
||||
@ -41,14 +40,13 @@ public final class IndexNode extends BaseNode {
|
||||
/**
|
||||
* Constructors
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param base base node for access
|
||||
* @param index index for access
|
||||
*/
|
||||
public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) {
|
||||
super(source, token, finish, base, false, false);
|
||||
public IndexNode(final long token, final int finish, final Node base, final Node index) {
|
||||
super(token, finish, base, false, false);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@ -108,6 +106,18 @@ public final class IndexNode extends BaseNode {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index expression for this node
|
||||
* @param index new index expression
|
||||
* @return a node equivalent to this one except for the requested change.
|
||||
*/
|
||||
public IndexNode setIndex(Node index) {
|
||||
if(this.index == index) {
|
||||
return this;
|
||||
}
|
||||
return new IndexNode(this, base, index, isFunction(), hasCallSiteType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseNode setIsFunction() {
|
||||
if (isFunction()) {
|
||||
@ -117,10 +127,10 @@ public final class IndexNode extends BaseNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexNode setType(final Type type) {
|
||||
public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
|
||||
logTypeChange(type);
|
||||
getSymbol().setTypeOverride(type); //always a temp so this is fine.
|
||||
return new IndexNode(this, base, index, isFunction(), true);
|
||||
final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
|
||||
return new IndexNode(newIndexNode, base, index, isFunction(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for a labeled statement.
|
||||
@ -43,14 +42,14 @@ public final class LabelNode extends LexicalContextNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label identifier
|
||||
* @param body body of label node
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param label label identifier
|
||||
* @param body body of label node
|
||||
*/
|
||||
public LabelNode(final Source source, final long token, final int finish, final IdentNode label, final Block body) {
|
||||
super(source, token, finish);
|
||||
public LabelNode(final int lineNumber, final long token, final int finish, final IdentNode label, final Block body) {
|
||||
super(lineNumber, token, finish);
|
||||
|
||||
this.label = label;
|
||||
this.body = body;
|
||||
|
@ -64,7 +64,6 @@ public class LexicalContext {
|
||||
for (int i = sp - 1; i >= 0; i--) {
|
||||
if (stack[i] == node) {
|
||||
flags[i] |= flag;
|
||||
//System.err.println("Setting flag " + node + " " + flag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -117,8 +116,6 @@ public class LexicalContext {
|
||||
return (FunctionNode)stack[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Pushes a new block on top of the context, making it the innermost open block.
|
||||
* @param node the new node
|
||||
@ -395,8 +392,7 @@ public class LexicalContext {
|
||||
*/
|
||||
public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) {
|
||||
final LexicalContextNode parent = stack[sp - 2];
|
||||
if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
|
||||
assert functionNode.getSource() == peek().getSource();
|
||||
if (parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -543,13 +539,16 @@ public class LexicalContext {
|
||||
sb.append('@');
|
||||
sb.append(Debug.id(node));
|
||||
sb.append(':');
|
||||
final Source source = node.getSource();
|
||||
String src = source.toString();
|
||||
if (src.indexOf(File.pathSeparator) != -1) {
|
||||
src = src.substring(src.lastIndexOf(File.pathSeparator));
|
||||
if (node instanceof FunctionNode) {
|
||||
final Source source = ((FunctionNode)node).getSource();
|
||||
String src = source.toString();
|
||||
if (src.indexOf(File.pathSeparator) != -1) {
|
||||
src = src.substring(src.lastIndexOf(File.pathSeparator));
|
||||
}
|
||||
src += ' ';
|
||||
src += source.getLine(node.getStart());
|
||||
sb.append(src);
|
||||
}
|
||||
src += ' ';
|
||||
src += source.getLine(node.getStart());
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(" ==> ]");
|
||||
|
@ -25,22 +25,21 @@
|
||||
package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Superclass for nodes that can be part of the lexical context
|
||||
* @see LexicalContext
|
||||
*/
|
||||
public abstract class LexicalContextNode extends Node {
|
||||
public abstract class LexicalContextNode extends Statement {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
*/
|
||||
protected LexicalContextNode(final Source source, final long token, final int finish) {
|
||||
super(source, token, finish);
|
||||
protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
|
||||
super(lineNumber, token, finish);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,4 +69,16 @@ public abstract class LexicalContextNode extends Node {
|
||||
final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
|
||||
return lc.pop(newNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the symbol and replace in lexical context if applicable
|
||||
* @param lc lexical context
|
||||
* @param symbol symbol
|
||||
* @return new node if symbol changed
|
||||
*/
|
||||
@Override
|
||||
public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
|
||||
return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
|
||||
/**
|
||||
@ -50,16 +49,15 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/** Literal value */
|
||||
protected final T value;
|
||||
|
||||
/**
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value the value of the literal
|
||||
*/
|
||||
protected LiteralNode(final Source source, final long token, final int finish, final T value) {
|
||||
super(source, token, finish);
|
||||
protected LiteralNode(final long token, final int finish, final T value) {
|
||||
super(token, finish);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@ -238,14 +236,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new null literal
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) {
|
||||
return new NodeLiteralNode(source, token, finish);
|
||||
public static LiteralNode<Node> newInstance(final long token, final int finish) {
|
||||
return new NodeLiteralNode(token, finish);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -256,14 +253,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent) {
|
||||
return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
|
||||
return new NodeLiteralNode(parent.getToken(), parent.getFinish());
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
|
||||
|
||||
private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) {
|
||||
super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
|
||||
private BooleanLiteralNode(final long token, final int finish, final boolean value) {
|
||||
super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
|
||||
}
|
||||
|
||||
private BooleanLiteralNode(final BooleanLiteralNode literalNode) {
|
||||
@ -289,15 +286,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new boolean literal
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value true or false
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) {
|
||||
return new BooleanLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<Boolean> newInstance(final long token, final int finish, final boolean value) {
|
||||
return new BooleanLiteralNode(token, finish, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,7 +305,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final boolean value) {
|
||||
return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
|
||||
return new BooleanLiteralNode(parent.getToken(), parent.getFinish(), value);
|
||||
}
|
||||
|
||||
@Immutable
|
||||
@ -317,8 +313,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
|
||||
private final Type type = numberGetType(value);
|
||||
|
||||
private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) {
|
||||
super(source, Token.recast(token, TokenType.DECIMAL), finish, value);
|
||||
private NumberLiteralNode(final long token, final int finish, final Number value) {
|
||||
super(Token.recast(token, TokenType.DECIMAL), finish, value);
|
||||
}
|
||||
|
||||
private NumberLiteralNode(final NumberLiteralNode literalNode) {
|
||||
@ -353,15 +349,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new number literal
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value literal value
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) {
|
||||
return new NumberLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<Number> newInstance(final long token, final int finish, final Number value) {
|
||||
return new NumberLiteralNode(token, finish, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -373,12 +368,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final Number value) {
|
||||
return new NumberLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
|
||||
return new NumberLiteralNode(parent.getToken(), parent.getFinish(), value);
|
||||
}
|
||||
|
||||
private static class UndefinedLiteralNode extends LiteralNode<Undefined> {
|
||||
private UndefinedLiteralNode(final Source source, final long token, final int finish) {
|
||||
super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
|
||||
private UndefinedLiteralNode(final long token, final int finish) {
|
||||
super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
|
||||
}
|
||||
|
||||
private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
|
||||
@ -389,15 +384,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new undefined literal
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value undefined value, passed only for polymorphisism discrimination
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) {
|
||||
return new UndefinedLiteralNode(source, token, finish);
|
||||
public static LiteralNode<Undefined> newInstance(final long token, final int finish, final Undefined value) {
|
||||
return new UndefinedLiteralNode(token, finish);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -409,13 +403,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final Undefined value) {
|
||||
return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
|
||||
return new UndefinedLiteralNode(parent.getToken(), parent.getFinish());
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static class StringLiteralNode extends LiteralNode<String> {
|
||||
private StringLiteralNode(final Source source, final long token, final int finish, final String value) {
|
||||
super(source, Token.recast(token, TokenType.STRING), finish, value);
|
||||
private StringLiteralNode(final long token, final int finish, final String value) {
|
||||
super(Token.recast(token, TokenType.STRING), finish, value);
|
||||
}
|
||||
|
||||
private StringLiteralNode(final StringLiteralNode literalNode) {
|
||||
@ -433,15 +427,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new string literal
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value string value
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) {
|
||||
return new StringLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<String> newInstance(final long token, final int finish, final String value) {
|
||||
return new StringLiteralNode(token, finish, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,13 +446,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final String value) {
|
||||
return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
|
||||
return new StringLiteralNode(parent.getToken(), parent.getFinish(), value);
|
||||
}
|
||||
|
||||
@Immutable
|
||||
private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
|
||||
private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) {
|
||||
super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
|
||||
private LexerTokenLiteralNode(final long token, final int finish, final LexerToken value) {
|
||||
super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
|
||||
}
|
||||
|
||||
private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) {
|
||||
@ -480,15 +473,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new literal node for a lexer token
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value lexer token value
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) {
|
||||
return new LexerTokenLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<LexerToken> newInstance(final long token, final int finish, final LexerToken value) {
|
||||
return new LexerTokenLiteralNode(token, finish, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,17 +492,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) {
|
||||
return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
|
||||
return new LexerTokenLiteralNode(parent.getToken(), parent.getFinish(), value);
|
||||
}
|
||||
|
||||
private static final class NodeLiteralNode extends LiteralNode<Node> {
|
||||
|
||||
private NodeLiteralNode(final Source source, final long token, final int finish) {
|
||||
this(source, token, finish, null);
|
||||
private NodeLiteralNode(final long token, final int finish) {
|
||||
this(token, finish, null);
|
||||
}
|
||||
|
||||
private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) {
|
||||
super(source, Token.recast(token, TokenType.OBJECT), finish, value);
|
||||
private NodeLiteralNode(final long token, final int finish, final Node value) {
|
||||
super(Token.recast(token, TokenType.OBJECT), finish, value);
|
||||
}
|
||||
|
||||
private NodeLiteralNode(final LiteralNode<Node> literalNode) {
|
||||
@ -550,15 +542,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new node literal for an arbitrary node
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value the literal value node
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) {
|
||||
return new NodeLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<Node> newInstance(final long token, final int finish, final Node value) {
|
||||
return new NodeLiteralNode(token, finish, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -570,7 +561,7 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final Node value) {
|
||||
return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
|
||||
return new NodeLiteralNode(parent.getToken(), parent.getFinish(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -645,13 +636,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value array literal value, a Node array
|
||||
*/
|
||||
protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) {
|
||||
super(source, Token.recast(token, TokenType.ARRAY), finish, value);
|
||||
protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
|
||||
super(Token.recast(token, TokenType.ARRAY), finish, value);
|
||||
this.elementType = Type.UNKNOWN;
|
||||
}
|
||||
|
||||
@ -659,9 +649,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* Copy constructor
|
||||
* @param node source array literal node
|
||||
*/
|
||||
protected ArrayLiteralNode(final ArrayLiteralNode node) {
|
||||
super(node);
|
||||
private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
|
||||
super(node, value);
|
||||
this.elementType = node.elementType;
|
||||
this.presets = node.presets;
|
||||
this.postsets = node.postsets;
|
||||
this.units = node.units;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -750,9 +743,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
break;
|
||||
}
|
||||
|
||||
final Symbol symbol = node.getSymbol();
|
||||
assert symbol != null; //don't run this on unresolved nodes or you are in trouble
|
||||
Type symbolType = symbol.getSymbolType();
|
||||
assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble
|
||||
Type symbolType = node.getSymbol().getSymbolType();
|
||||
if (symbolType.isUnknown()) {
|
||||
symbolType = Type.OBJECT;
|
||||
}
|
||||
@ -813,7 +805,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get indices of arrays containing computed post sets
|
||||
* Get indices of arrays containing computed post sets. post sets
|
||||
* are things like non literals e.g. "x+y" instead of i or 17
|
||||
* @return post set indices
|
||||
*/
|
||||
public int[] getPostsets() {
|
||||
@ -849,17 +842,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
@Override
|
||||
public Node accept(final NodeVisitor visitor) {
|
||||
if (visitor.enterLiteralNode(this)) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
final Node element = value[i];
|
||||
if (element != null) {
|
||||
value[i] = element.accept(visitor);
|
||||
}
|
||||
}
|
||||
return visitor.leaveLiteralNode(this);
|
||||
final List<Node> oldValue = Arrays.asList(value);
|
||||
final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
|
||||
return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private ArrayLiteralNode setValue(final List<Node> value) {
|
||||
return new ArrayLiteralNode(this, value.toArray(new Node[value.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
sb.append('[');
|
||||
@ -883,15 +876,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
/**
|
||||
* Create a new array literal of Nodes from a list of Node values
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value literal value list
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) {
|
||||
return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()]));
|
||||
public static LiteralNode<Node[]> newInstance(final long token, final int finish, final List<Node> value) {
|
||||
return new ArrayLiteralNode(token, finish, value.toArray(new Node[value.size()]));
|
||||
}
|
||||
|
||||
|
||||
@ -904,20 +896,19 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) {
|
||||
return new ArrayLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
|
||||
return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Node[value.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new array literal of Nodes
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param value literal value array
|
||||
*
|
||||
* @return the new literal node
|
||||
*/
|
||||
public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) {
|
||||
return new ArrayLiteralNode(source, token, finish, value);
|
||||
public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
|
||||
return new ArrayLiteralNode(token, finish, value);
|
||||
}
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Used to locate an entity back to it's source file.
|
||||
*/
|
||||
public class Location implements Cloneable {
|
||||
/** Source of entity. */
|
||||
private final Source source;
|
||||
|
||||
/** Token descriptor. */
|
||||
private final long token;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
*/
|
||||
public Location(final Source source, final long token) {
|
||||
this.source = source;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
*
|
||||
* @param location source node
|
||||
*/
|
||||
protected Location(final Location location) {
|
||||
this.source = location.source;
|
||||
this.token = location.token;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(final Object other) {
|
||||
return super.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token position from a token descriptor.
|
||||
*
|
||||
* @return Start position of the token in the source.
|
||||
*/
|
||||
public int position() {
|
||||
return Token.descPosition(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token length from a token descriptor.
|
||||
*
|
||||
* @return Length of the token.
|
||||
*/
|
||||
public int length() {
|
||||
return Token.descLength(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token tokenType from a token descriptor.
|
||||
*
|
||||
* @return Type of token.
|
||||
*/
|
||||
public TokenType tokenType() {
|
||||
return Token.descType(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test token tokenType.
|
||||
*
|
||||
* @param type a type to check this token against
|
||||
* @return true if token types match.
|
||||
*/
|
||||
public boolean isTokenType(final TokenType type) {
|
||||
return Token.descType(token) == type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source for this location
|
||||
* @return the source
|
||||
*/
|
||||
public Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token for this location
|
||||
* @return the token
|
||||
*/
|
||||
public long getToken() {
|
||||
return token;
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* A loop node, for example a while node, do while node or for node
|
||||
@ -50,15 +49,15 @@ public abstract class LoopNode extends BreakableNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param test test, or null if infinite loop
|
||||
* @param body loop body
|
||||
* @param lineNumber lineNumber
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param test test, or null if infinite loop
|
||||
* @param body loop body
|
||||
* @param controlFlowEscapes controlFlowEscapes
|
||||
*/
|
||||
protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
|
||||
super(source, token, finish, new Label("while_break"));
|
||||
protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
|
||||
super(lineNumber, token, finish, new Label("while_break"));
|
||||
this.continueLabel = new Label("while_continue");
|
||||
this.test = test;
|
||||
this.body = body;
|
||||
|
@ -27,16 +27,15 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
|
||||
/**
|
||||
* Nodes are used to compose Abstract Syntax Trees.
|
||||
*/
|
||||
public abstract class Node extends Location {
|
||||
public abstract class Node implements Cloneable {
|
||||
/** Node symbol. */
|
||||
private Symbol symbol;
|
||||
|
||||
@ -46,16 +45,17 @@ public abstract class Node extends Location {
|
||||
/** End of source range. */
|
||||
protected int finish;
|
||||
|
||||
/** Token descriptor. */
|
||||
private final long token;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
*/
|
||||
public Node(final Source source, final long token, final int finish) {
|
||||
super(source, token);
|
||||
|
||||
public Node(final long token, final int finish) {
|
||||
this.token = token;
|
||||
this.start = Token.descPosition(token);
|
||||
this.finish = finish;
|
||||
}
|
||||
@ -63,16 +63,14 @@ public abstract class Node extends Location {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source source
|
||||
* @param token token
|
||||
* @param start start
|
||||
* @param finish finish
|
||||
*/
|
||||
protected Node(final Source source, final long token, final int start, final int finish) {
|
||||
super(source, token);
|
||||
|
||||
protected Node(final long token, final int start, final int finish) {
|
||||
this.start = start;
|
||||
this.finish = finish;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,8 +79,7 @@ public abstract class Node extends Location {
|
||||
* @param node source node
|
||||
*/
|
||||
protected Node(final Node node) {
|
||||
super(node);
|
||||
|
||||
this.token = node.token;
|
||||
this.symbol = node.symbol;
|
||||
this.start = node.start;
|
||||
this.finish = node.finish;
|
||||
@ -155,15 +152,6 @@ public abstract class Node extends Location {
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a debug info node like LineNumberNode etc?
|
||||
*
|
||||
* @return true if this is a debug node
|
||||
*/
|
||||
public boolean isDebug() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For reference copies - ensure that labels in the copy node are unique
|
||||
* using an appropriate copy constructor
|
||||
@ -248,14 +236,86 @@ public abstract class Node extends Location {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (final CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
|
||||
* of what a symbol is
|
||||
*
|
||||
* @param lc lexical context
|
||||
* @param symbol the symbol
|
||||
* @return new node
|
||||
*/
|
||||
public void setSymbol(final Symbol symbol) {
|
||||
this.symbol = symbol;
|
||||
public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
|
||||
if (this.symbol == symbol) {
|
||||
return this;
|
||||
}
|
||||
final Node newNode = (Node)clone();
|
||||
newNode.symbol = symbol;
|
||||
return newNode;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean equals(final Object other) {
|
||||
return super.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token position from a token descriptor.
|
||||
*
|
||||
* @return Start position of the token in the source.
|
||||
*/
|
||||
public int position() {
|
||||
return Token.descPosition(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token length from a token descriptor.
|
||||
*
|
||||
* @return Length of the token.
|
||||
*/
|
||||
public int length() {
|
||||
return Token.descLength(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token tokenType from a token descriptor.
|
||||
*
|
||||
* @return Type of token.
|
||||
*/
|
||||
public TokenType tokenType() {
|
||||
return Token.descType(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test token tokenType.
|
||||
*
|
||||
* @param type a type to check this token against
|
||||
* @return true if token types match.
|
||||
*/
|
||||
public boolean isTokenType(final TokenType type) {
|
||||
return Token.descType(token) == type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token for this location
|
||||
* @return the token
|
||||
*/
|
||||
public long getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +334,7 @@ public abstract class Node extends Location {
|
||||
final List<T> newList = new ArrayList<>();
|
||||
|
||||
for (final Node node : list) {
|
||||
final T newNode = clazz.cast(node.accept(visitor));
|
||||
final T newNode = node == null ? null : clazz.cast(node.accept(visitor));
|
||||
if (newNode != node) {
|
||||
changed = true;
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of an object literal.
|
||||
@ -44,13 +43,12 @@ public final class ObjectNode extends Node {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param elements the elements used to initialize this ObjectNode
|
||||
*/
|
||||
public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) {
|
||||
super(source, token, finish);
|
||||
public ObjectNode(final long token, final int finish, final List<Node> elements) {
|
||||
super(token, finish);
|
||||
this.elements = elements;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of an object literal property.
|
||||
@ -50,7 +49,6 @@ public final class PropertyNode extends Node {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param key the key of this property
|
||||
@ -58,8 +56,8 @@ public final class PropertyNode extends Node {
|
||||
* @param getter getter function body
|
||||
* @param setter setter function body
|
||||
*/
|
||||
public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
|
||||
super(source, token, finish);
|
||||
public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
|
||||
super(token, finish);
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.getter = getter;
|
||||
|
@ -29,26 +29,25 @@ import static jdk.nashorn.internal.parser.TokenType.RETURN;
|
||||
import static jdk.nashorn.internal.parser.TokenType.YIELD;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for RETURN or YIELD statements.
|
||||
*/
|
||||
@Immutable
|
||||
public class ReturnNode extends Node {
|
||||
public class ReturnNode extends Statement {
|
||||
/** Optional expression. */
|
||||
private final Node expression;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param expression expression to return
|
||||
*/
|
||||
public ReturnNode(final Source source, final long token, final int finish, final Node expression) {
|
||||
super(source, token, finish);
|
||||
public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
|
||||
super(lineNumber, token, finish);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@ -101,9 +100,9 @@ public class ReturnNode extends Node {
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
sb.append(isYield() ? "yield" : "return ");
|
||||
|
||||
sb.append(isYield() ? "yield" : "return");
|
||||
if (expression != null) {
|
||||
sb.append(' ');
|
||||
expression.toString(sb);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for a runtime call.
|
||||
@ -280,14 +279,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param request the request
|
||||
* @param args arguments to request
|
||||
*/
|
||||
public RuntimeNode(final Source source, final long token, final int finish, final Request request, final List<Node> args) {
|
||||
super(source, token, finish);
|
||||
public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
|
||||
super(token, finish);
|
||||
|
||||
this.request = request;
|
||||
this.args = args;
|
||||
@ -307,14 +305,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param request the request
|
||||
* @param args arguments to request
|
||||
*/
|
||||
public RuntimeNode(final Source source, final long token, final int finish, final Request request, final Node... args) {
|
||||
this(source, token, finish, request, Arrays.asList(args));
|
||||
public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
|
||||
this(token, finish, request, Arrays.asList(args));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -393,7 +390,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeNode setType(final Type type) {
|
||||
public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
|
||||
if (this.callSiteType == type) {
|
||||
return this;
|
||||
}
|
||||
|
@ -46,12 +46,13 @@ public class SplitNode extends LexicalContextNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param lineNumber lineNumber
|
||||
* @param name name of split node
|
||||
* @param body body of split code
|
||||
* @param compileUnit compile unit to use for the body
|
||||
*/
|
||||
public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
|
||||
super(body.getSource(), body.getToken(), body.getFinish());
|
||||
public SplitNode(final int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
|
||||
super(lineNumber, body.getToken(), body.getFinish());
|
||||
this.name = name;
|
||||
this.body = body;
|
||||
this.compileUnit = compileUnit;
|
||||
|
@ -25,67 +25,56 @@
|
||||
|
||||
package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR Node representing a line number
|
||||
* Statement is something that becomes code and can be stepped past. A block is
|
||||
* made up of statements. The only node subclass that needs to keep token and
|
||||
* location information is the Statement
|
||||
*/
|
||||
@Immutable
|
||||
public final class LineNumberNode extends Node {
|
||||
/** Line number */
|
||||
public abstract class Statement extends Node {
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param lineNumber the line number
|
||||
* @param finish finish
|
||||
*/
|
||||
public LineNumberNode(final Source source, final long token, final int lineNumber) {
|
||||
super(source, token, Token.descPosition(token));
|
||||
public Statement(final int lineNumber, final long token, final int finish) {
|
||||
super(token, finish);
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
private LineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
super(lineNumberNode);
|
||||
this.lineNumber = lineNumberNode.getLineNumber();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node accept(final NodeVisitor visitor) {
|
||||
if (visitor.enterLineNumberNode(this)) {
|
||||
return visitor.leaveLineNumberNode(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
sb.append("[|");
|
||||
sb.append(lineNumber);
|
||||
sb.append("|]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAtom() {
|
||||
return true;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param start start
|
||||
* @param finish finish
|
||||
*/
|
||||
protected Statement(final int lineNumber, final long token, final int start, final int finish) {
|
||||
super(token, start, finish);
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line number
|
||||
* Copy constructor
|
||||
*
|
||||
* @param node source node
|
||||
*/
|
||||
protected Statement(final Statement node) {
|
||||
super(node);
|
||||
this.lineNumber = node.lineNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the line number
|
||||
* @return line number
|
||||
*/
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -32,7 +32,6 @@ import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of a SWITCH statement.
|
||||
@ -54,15 +53,15 @@ public final class SwitchNode extends BreakableNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber lineNumber
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param expression switch expression
|
||||
* @param cases cases
|
||||
* @param defaultCase the default case node - null if none, otherwise has to be present in cases list
|
||||
*/
|
||||
public SwitchNode(final Source source, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
|
||||
super(source, token, finish, new Label("switch_break"));
|
||||
public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
|
||||
super(lineNumber, token, finish, new Label("switch_break"));
|
||||
this.expression = expression;
|
||||
this.cases = cases;
|
||||
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
|
||||
|
@ -29,7 +29,6 @@ import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
@ -67,6 +66,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
public static final int IS_INTERNAL = 1 << 9;
|
||||
/** Is this a function self-reference symbol */
|
||||
public static final int IS_FUNCTION_SELF = 1 << 10;
|
||||
/** Is this a specialized param? */
|
||||
public static final int IS_SPECIALIZED_PARAM = 1 << 11;
|
||||
/** Is this symbol a shared temporary? */
|
||||
public static final int IS_SHARED = 1 << 12;
|
||||
|
||||
/** Null or name identifying symbol. */
|
||||
private final String name;
|
||||
@ -152,6 +155,16 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
this(name, flags, type, -1);
|
||||
}
|
||||
|
||||
private Symbol(final Symbol base, final String name, final int flags) {
|
||||
this.flags = flags;
|
||||
this.name = name;
|
||||
|
||||
this.fieldIndex = base.fieldIndex;
|
||||
this.slot = base.slot;
|
||||
this.type = base.type;
|
||||
this.useCount = base.useCount;
|
||||
}
|
||||
|
||||
private static String align(final String string, final int max) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(string.substring(0, Math.min(string.length(), max)));
|
||||
@ -261,32 +274,14 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
return type.isCategory2() ? 2 : 1;
|
||||
}
|
||||
|
||||
private static String type(final String desc) {
|
||||
switch (desc.charAt(desc.length() - 1)) {
|
||||
case ';':
|
||||
return desc;//"obj";
|
||||
case 'D':
|
||||
return "double";
|
||||
case 'I':
|
||||
return "int";
|
||||
case 'J':
|
||||
return "long";
|
||||
case 'Z':
|
||||
return "boolean";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final String desc = getSymbolType().getDescriptor();
|
||||
|
||||
sb.append(name).
|
||||
append(' ').
|
||||
append('(').
|
||||
append(type(desc)).
|
||||
append(getSymbolType().getTypeClass().getSimpleName()).
|
||||
append(')');
|
||||
|
||||
if (hasSlot()) {
|
||||
@ -346,6 +341,24 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
return (flags & IS_SCOPE) == IS_SCOPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this symbol is a temporary that is being shared across expressions.
|
||||
* @return true if this symbol is a temporary that is being shared across expressions.
|
||||
*/
|
||||
public boolean isShared() {
|
||||
return (flags & IS_SHARED) == IS_SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an unshared copy of a symbol. The symbol must be currently shared.
|
||||
* @param newName the name for the new symbol.
|
||||
* @return a new, unshared symbol.
|
||||
*/
|
||||
public Symbol createUnshared(final String newName) {
|
||||
assert isShared();
|
||||
return new Symbol(this, newName, flags & ~IS_SHARED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this symbol as scope as described in {@link Symbol#isScope()}
|
||||
*/
|
||||
@ -355,10 +368,23 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
public void setIsScope() {
|
||||
if (!isScope()) {
|
||||
trace("SET IS SCOPE");
|
||||
assert !isShared();
|
||||
flags |= IS_SCOPE;
|
||||
}
|
||||
flags |= IS_SCOPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary.
|
||||
*/
|
||||
public void setIsShared() {
|
||||
if(!isShared()) {
|
||||
assert isTemp();
|
||||
trace("SET IS SHARED");
|
||||
flags |= IS_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if this symbol is a variable
|
||||
* @return true if variable
|
||||
@ -383,6 +409,15 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
return (flags & KINDMASK) == IS_PARAM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this symbol is a function parameter of known
|
||||
* narrowest type
|
||||
* @return true if parameter
|
||||
*/
|
||||
public boolean isSpecializedParam() {
|
||||
return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this symbol ever has primitive assignments. Conservative
|
||||
* @return true if primitive assignments exist
|
||||
@ -404,7 +439,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
*/
|
||||
public void setCanBeUndefined() {
|
||||
assert type.isObject() : type;
|
||||
flags |= CAN_BE_UNDEFINED;
|
||||
if(!canBeUndefined()) {
|
||||
assert !isShared();
|
||||
flags |= CAN_BE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,7 +450,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
* @param type the primitive type it occurs with, currently unused but can be used for width guesses
|
||||
*/
|
||||
public void setCanBePrimitive(final Type type) {
|
||||
flags |= CAN_BE_PRIMITIVE;
|
||||
if(!canBePrimitive()) {
|
||||
assert !isShared();
|
||||
flags |= CAN_BE_PRIMITIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -452,7 +493,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
* Flag this symbol as a let
|
||||
*/
|
||||
public void setIsLet() {
|
||||
flags |= IS_LET;
|
||||
if(!isLet()) {
|
||||
assert !isShared();
|
||||
flags |= IS_LET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -481,7 +525,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
* @param fieldIndex field index - a positive integer
|
||||
*/
|
||||
public void setFieldIndex(final int fieldIndex) {
|
||||
this.fieldIndex = fieldIndex;
|
||||
if(this.fieldIndex != fieldIndex) {
|
||||
assert !isShared();
|
||||
this.fieldIndex = fieldIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -497,7 +544,10 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
* @param flags flags
|
||||
*/
|
||||
public void setFlags(final int flags) {
|
||||
this.flags = flags;
|
||||
if(this.flags != flags) {
|
||||
assert !isShared();
|
||||
this.flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -537,6 +587,7 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
*/
|
||||
public void setSlot(final int slot) {
|
||||
if (slot != this.slot) {
|
||||
assert !isShared();
|
||||
trace("SET SLOT " + slot);
|
||||
this.slot = slot;
|
||||
}
|
||||
@ -561,6 +612,15 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
setTypeOverride(Type.widest(this.type, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if calling {@link #setType(Type)} on this symbol would effectively change its type.
|
||||
* @param newType the new type to test for
|
||||
* @return true if setting this symbols type to a new value would effectively change its type.
|
||||
*/
|
||||
public boolean wouldChangeType(final Type newType) {
|
||||
return Type.widest(this.type, newType) != this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only use this if you know about an existing type
|
||||
* constraint - otherwise a type can only be
|
||||
@ -571,11 +631,32 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
public void setTypeOverride(final Type type) {
|
||||
final Type old = this.type;
|
||||
if (old != type) {
|
||||
assert !isShared();
|
||||
trace("TYPE CHANGE: " + old + "=>" + type + " == " + type);
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of the symbol to the specified type. If the type would be changed, but this symbol is a shared
|
||||
* temporary, it will instead return a different temporary symbol of the requested type from the passed temporary
|
||||
* symbols. That way, it never mutates the type of a shared temporary.
|
||||
* @param type the new type for the symbol
|
||||
* @param ts a holder of temporary symbols
|
||||
* @return either this symbol, or a different symbol if this symbol is a shared temporary and it type would have to
|
||||
* be changed.
|
||||
*/
|
||||
public Symbol setTypeOverrideShared(final Type type, final TemporarySymbols ts) {
|
||||
if(getSymbolType() != type) {
|
||||
if(isShared()) {
|
||||
assert !hasSlot();
|
||||
return ts.getTypedTemporarySymbol(type);
|
||||
}
|
||||
setTypeOverride(type);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* From a lexical context, set this symbol as needing scope, which
|
||||
* will set flags for the defining block that will be written when
|
||||
|
169
nashorn/src/jdk/nashorn/internal/ir/TemporarySymbols.java
Normal file
169
nashorn/src/jdk/nashorn/internal/ir/TemporarySymbols.java
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.ir;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
|
||||
import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
|
||||
/**
|
||||
* Class that holds reusable temporary symbols by type.
|
||||
*
|
||||
*/
|
||||
public class TemporarySymbols {
|
||||
private static final String prefix = TEMP_PREFIX.symbolName() + "$";
|
||||
|
||||
private int totalSymbolCount;
|
||||
private final Map<Type, TypedTemporarySymbols> temporarySymbolsByType = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Associates a temporary symbol of a given type with a node, if the node doesn't already have any symbol.
|
||||
* @param lc the current lexical context
|
||||
* @param type the type of the temporary symbol
|
||||
* @param node the node
|
||||
* @return the node that is guaranteed to have a symbol.
|
||||
*/
|
||||
public Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) {
|
||||
final Symbol symbol = node.getSymbol();
|
||||
if (symbol != null) {
|
||||
return node;
|
||||
}
|
||||
return node.setSymbol(lc, getTypedTemporarySymbol(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a type, returns a temporary symbol of that type.
|
||||
* @param type the required type of the symbol.
|
||||
* @return a temporary symbol of the required type.
|
||||
*/
|
||||
public Symbol getTypedTemporarySymbol(final Type type) {
|
||||
return getTypedTemporarySymbols(type).getTemporarySymbol(type);
|
||||
}
|
||||
|
||||
private TypedTemporarySymbols getTypedTemporarySymbols(final Type type) {
|
||||
TypedTemporarySymbols temporarySymbols = temporarySymbolsByType.get(type);
|
||||
if(temporarySymbols == null) {
|
||||
temporarySymbols = new TypedTemporarySymbols();
|
||||
temporarySymbolsByType.put(type, temporarySymbols);
|
||||
}
|
||||
return temporarySymbols;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to signal to this object that all the symbols it holds can be reused now.
|
||||
*/
|
||||
public void reuse() {
|
||||
for(TypedTemporarySymbols ts: temporarySymbolsByType.values()) {
|
||||
ts.reuse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a shared symbol, creates an unshared copy of it with a unique name.
|
||||
* @param symbol the shared symbol
|
||||
* @return the unshared, uniquely named copy of the symbol
|
||||
*/
|
||||
public Symbol createUnshared(Symbol symbol) {
|
||||
return symbol.createUnshared(getUniqueName());
|
||||
}
|
||||
|
||||
private String getUniqueName() {
|
||||
return prefix + (++totalSymbolCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of symbols this object created during its lifetime.
|
||||
* @return the total number of symbols this object created during its lifetime.
|
||||
*/
|
||||
public int getTotalSymbolCount() {
|
||||
return totalSymbolCount;
|
||||
}
|
||||
|
||||
private class TypedTemporarySymbols {
|
||||
private Symbol[] symbols = new Symbol[16];
|
||||
private int nextFreeSymbol = 0;
|
||||
private int symbolCount = 0;
|
||||
|
||||
Symbol getTemporarySymbol(final Type type) {
|
||||
while(nextFreeSymbol < symbolCount) {
|
||||
final Symbol nextSymbol = symbols[nextFreeSymbol];
|
||||
assert nextSymbol != null;
|
||||
// If it has a slot, we can't reuse it.
|
||||
if(!nextSymbol.hasSlot()) {
|
||||
final Type symbolType = nextSymbol.getSymbolType();
|
||||
if(symbolType == type) {
|
||||
assert nextSymbol.isTemp();
|
||||
assert !nextSymbol.isScope();
|
||||
// If types match, we can reuse it.
|
||||
nextSymbol.setIsShared();
|
||||
nextFreeSymbol++;
|
||||
return nextSymbol;
|
||||
}
|
||||
// If its type changed, but it doesn't have a slot then move it to its new home according to its
|
||||
// new type.
|
||||
getTypedTemporarySymbols(symbolType).addSymbol(nextSymbol);
|
||||
}
|
||||
// If we can move another symbol into its place, do that and repeat the analysis for this symbol.
|
||||
--symbolCount;
|
||||
if(symbolCount != nextFreeSymbol) {
|
||||
final Symbol lastFreeSymbol = symbols[symbolCount];
|
||||
symbols[nextFreeSymbol] = lastFreeSymbol;
|
||||
}
|
||||
symbols[symbolCount] = null;
|
||||
}
|
||||
return createNewSymbol(type);
|
||||
}
|
||||
|
||||
private Symbol createNewSymbol(final Type type) {
|
||||
ensureCapacity();
|
||||
final Symbol symbol = symbols[nextFreeSymbol] = new Symbol(getUniqueName(), IS_TEMP, type);
|
||||
nextFreeSymbol++;
|
||||
symbolCount++;
|
||||
return symbol;
|
||||
}
|
||||
|
||||
private void addSymbol(Symbol symbol) {
|
||||
ensureCapacity();
|
||||
symbols[symbolCount++] = symbol;
|
||||
}
|
||||
|
||||
void reuse() {
|
||||
nextFreeSymbol = 0;
|
||||
}
|
||||
|
||||
private void ensureCapacity() {
|
||||
if(symbolCount == symbols.length) {
|
||||
final Symbol[] newSymbols = new Symbol[symbolCount * 2];
|
||||
System.arraycopy(symbols, 0, newSymbols, 0, symbolCount);
|
||||
symbols = newSymbols;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* TernaryNode nodes represent three operand operations (?:).
|
||||
@ -44,14 +43,13 @@ public final class TernaryNode extends Node {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param lhs left hand side node
|
||||
* @param rhs right hand side node
|
||||
* @param third third node
|
||||
*/
|
||||
public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) {
|
||||
super(source, token, third.getFinish());
|
||||
public TernaryNode(final long token, final Node lhs, final Node rhs, final Node third) {
|
||||
super(token, third.getFinish());
|
||||
this.lhs = lhs;
|
||||
this.rhs = rhs;
|
||||
this.third = third;
|
||||
|
@ -27,31 +27,29 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for THROW statements.
|
||||
*/
|
||||
@Immutable
|
||||
public final class ThrowNode extends Node {
|
||||
public final class ThrowNode extends Statement {
|
||||
/** Exception expression. */
|
||||
private final Node expression;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param expression expression to throw
|
||||
*/
|
||||
public ThrowNode(final Source source, final long token, final int finish, final Node expression) {
|
||||
super(source, token, finish);
|
||||
|
||||
public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) {
|
||||
super(lineNumber, token, finish);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
private ThrowNode(final Node node, final Node expression) {
|
||||
private ThrowNode(final ThrowNode node, final Node expression) {
|
||||
super(node);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
@ -32,13 +32,12 @@ import java.util.List;
|
||||
import jdk.nashorn.internal.codegen.Label;
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation of a TRY statement.
|
||||
*/
|
||||
@Immutable
|
||||
public final class TryNode extends Node {
|
||||
public final class TryNode extends Statement {
|
||||
/** Try statements. */
|
||||
private final Block body;
|
||||
|
||||
@ -60,27 +59,27 @@ public final class TryNode extends Node {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber lineNumber
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param body try node body
|
||||
* @param catchBlocks list of catch blocks in order
|
||||
* @param finallyBody body of finally block or null if none
|
||||
*/
|
||||
public TryNode(final Source source, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
|
||||
super(source, token, finish);
|
||||
this.body = body;
|
||||
public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
|
||||
super(lineNumber, token, finish);
|
||||
this.body = body;
|
||||
this.catchBlocks = catchBlocks;
|
||||
this.finallyBody = finallyBody;
|
||||
this.exit = new Label("exit");
|
||||
this.exit = new Label("exit");
|
||||
}
|
||||
|
||||
private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
|
||||
super(tryNode);
|
||||
this.body = body;
|
||||
this.body = body;
|
||||
this.catchBlocks = catchBlocks;
|
||||
this.finallyBody = finallyBody;
|
||||
this.exit = new Label(tryNode.exit);
|
||||
this.exit = new Label(tryNode.exit);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,10 +43,12 @@ public interface TypeOverride<T extends Node> {
|
||||
/**
|
||||
* Set the override type
|
||||
*
|
||||
* @param type the type
|
||||
* @param ts temporary symbols
|
||||
* @param lc the current lexical context
|
||||
* @param type the type
|
||||
* @return a node equivalent to this one except for the requested change.
|
||||
*/
|
||||
public T setType(final Type type);
|
||||
public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
|
||||
|
||||
/**
|
||||
* Returns true if this node can have a callsite override, e.g. all scope ident nodes
|
||||
|
@ -35,7 +35,6 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
import jdk.nashorn.internal.parser.TokenType;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* UnaryNode nodes represent single operand operations.
|
||||
@ -48,24 +47,23 @@ public final class UnaryNode extends Node implements Assignment<Node> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param rhs expression
|
||||
*/
|
||||
public UnaryNode(final Source source, final long token, final Node rhs) {
|
||||
this(source, token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
|
||||
public UnaryNode(final long token, final Node rhs) {
|
||||
this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param source the source
|
||||
*
|
||||
* @param token token
|
||||
* @param start start
|
||||
* @param finish finish
|
||||
* @param rhs expression
|
||||
*/
|
||||
public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) {
|
||||
super(source, token, start, finish);
|
||||
public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
|
||||
super(token, start, finish);
|
||||
this.rhs = rhs;
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* Node represents a var/let declaration.
|
||||
*/
|
||||
@Immutable
|
||||
public final class VarNode extends Node implements Assignment<IdentNode> {
|
||||
public final class VarNode extends Statement implements Assignment<IdentNode> {
|
||||
/** Var name. */
|
||||
private final IdentNode name;
|
||||
|
||||
@ -54,14 +53,14 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param name name of variable
|
||||
* @param init init node or null if just a declaration
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param name name of variable
|
||||
* @param init init node or null if just a declaration
|
||||
*/
|
||||
public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
|
||||
this(source, token, finish, name, init, IS_STATEMENT);
|
||||
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
|
||||
this(lineNumber, token, finish, name, init, IS_STATEMENT);
|
||||
}
|
||||
|
||||
private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
|
||||
@ -74,15 +73,15 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param name name of variable
|
||||
* @param init init node or null if just a declaration
|
||||
* @param flags flags
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param name name of variable
|
||||
* @param init init node or null if just a declaration
|
||||
* @param flags flags
|
||||
*/
|
||||
public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
|
||||
super(source, token, finish);
|
||||
public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
|
||||
super(lineNumber, token, finish);
|
||||
|
||||
this.name = init == null ? name : name.setIsInitializedHere();
|
||||
this.init = init;
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for a WHILE statement. This is the superclass of all
|
||||
@ -42,13 +41,13 @@ public final class WhileNode extends LoopNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param isDoWhile is this a do while loop?
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
* @param isDoWhile is this a do while loop?
|
||||
*/
|
||||
public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) {
|
||||
super(source, token, finish, null, null, false);
|
||||
public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
|
||||
super(lineNumber, token, finish, null, null, false);
|
||||
this.isDoWhile = isDoWhile;
|
||||
}
|
||||
|
||||
@ -135,17 +134,9 @@ public final class WhileNode extends LoopNode {
|
||||
|
||||
@Override
|
||||
public void toString(final StringBuilder sb) {
|
||||
if (isDoWhile()) {
|
||||
sb.append("do {");
|
||||
body.toString(sb);
|
||||
sb.append("} while (");
|
||||
test.toString(sb);
|
||||
sb.append(')');
|
||||
} else {
|
||||
sb.append("while (");
|
||||
test.toString(sb);
|
||||
sb.append(')');
|
||||
}
|
||||
sb.append("while (");
|
||||
test.toString(sb);
|
||||
sb.append(')');
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Immutable;
|
||||
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
import jdk.nashorn.internal.runtime.Source;
|
||||
|
||||
/**
|
||||
* IR representation for {@code with} statements.
|
||||
@ -43,20 +42,18 @@ public final class WithNode extends LexicalContextNode {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param source the source
|
||||
* @param lineNumber line number
|
||||
* @param token token
|
||||
* @param finish finish
|
||||
*/
|
||||
public WithNode(final Source source, final long token, final int finish) {
|
||||
super(source, token, finish);
|
||||
|
||||
public WithNode(final int lineNumber, final long token, final int finish) {
|
||||
super(lineNumber, token, finish);
|
||||
this.expression = null;
|
||||
this.body = null;
|
||||
}
|
||||
|
||||
private WithNode(final WithNode node, final Node expression, final Block body) {
|
||||
super(node);
|
||||
|
||||
this.expression = expression;
|
||||
this.body = body;
|
||||
}
|
||||
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.ir.debug;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Class histogram element for IR / Java object instrumentation
|
||||
*/
|
||||
public class ClassHistogramElement {
|
||||
/**
|
||||
* Instance comparator
|
||||
*/
|
||||
public static final Comparator<ClassHistogramElement> COMPARE_INSTANCES = new Comparator<ClassHistogramElement>() {
|
||||
@Override
|
||||
public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
|
||||
return (int)Math.abs(o1.instances - o2.instances);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Bytes comparator
|
||||
*/
|
||||
public static final Comparator<ClassHistogramElement> COMPARE_BYTES = new Comparator<ClassHistogramElement>() {
|
||||
@Override
|
||||
public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
|
||||
return (int)Math.abs(o1.bytes - o2.bytes);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Classname comparator
|
||||
*/
|
||||
public static final Comparator<ClassHistogramElement> COMPARE_CLASSNAMES = new Comparator<ClassHistogramElement>() {
|
||||
@Override
|
||||
public int compare(final ClassHistogramElement o1, final ClassHistogramElement o2) {
|
||||
return o1.clazz.getCanonicalName().compareTo(o2.clazz.getCanonicalName());
|
||||
}
|
||||
};
|
||||
|
||||
private final Class<?> clazz;
|
||||
private long instances;
|
||||
private long bytes;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param clazz class for which to construct histogram
|
||||
*/
|
||||
public ClassHistogramElement(final Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an instance
|
||||
* @param sizeInBytes byte count
|
||||
*/
|
||||
public void addInstance(final long sizeInBytes) {
|
||||
instances++;
|
||||
this.bytes += sizeInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size in bytes
|
||||
* @return size in bytes
|
||||
*/
|
||||
public long getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class
|
||||
* @return class
|
||||
*/
|
||||
public Class<?> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of instances
|
||||
* @return number of instances
|
||||
*/
|
||||
public long getInstances() {
|
||||
return instances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassHistogramElement[class=" + clazz.getCanonicalName() + ", instances=" + instances + ", bytes=" + bytes + "]";
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir.debug;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
@ -44,7 +45,6 @@ import jdk.nashorn.internal.ir.IdentNode;
|
||||
import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.ObjectNode;
|
||||
@ -52,6 +52,7 @@ import jdk.nashorn.internal.ir.PropertyNode;
|
||||
import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.TernaryNode;
|
||||
import jdk.nashorn.internal.ir.ThrowNode;
|
||||
@ -406,17 +407,15 @@ public final class JSONWriter extends NodeVisitor {
|
||||
}
|
||||
|
||||
// body consists of nested functions and statements
|
||||
final List<Node> stats = functionNode.getBody().getStatements();
|
||||
final List<Statement> stats = functionNode.getBody().getStatements();
|
||||
final int size = stats.size();
|
||||
int idx = 0;
|
||||
arrayStart("body");
|
||||
|
||||
for (final Node stat : stats) {
|
||||
if (! stat.isDebug()) {
|
||||
stat.accept(this);
|
||||
if (idx != (size - 1)) {
|
||||
comma();
|
||||
}
|
||||
stat.accept(this);
|
||||
if (idx != (size - 1)) {
|
||||
comma();
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
@ -504,11 +503,6 @@ public final class JSONWriter extends NodeVisitor {
|
||||
return leave();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean enterLiteralNode(final LiteralNode literalNode) {
|
||||
@ -931,15 +925,13 @@ public final class JSONWriter extends NodeVisitor {
|
||||
int idx = 0;
|
||||
arrayStart(name);
|
||||
for (final Node node : nodes) {
|
||||
if (node == null || !node.isDebug()) {
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
} else {
|
||||
nullValue();
|
||||
}
|
||||
if (idx != (size - 1)) {
|
||||
comma();
|
||||
}
|
||||
if (node != null) {
|
||||
node.accept(this);
|
||||
} else {
|
||||
nullValue();
|
||||
}
|
||||
if (idx != (size - 1)) {
|
||||
comma();
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
@ -971,7 +963,7 @@ public final class JSONWriter extends NodeVisitor {
|
||||
objectStart("loc");
|
||||
|
||||
// source name
|
||||
final Source src = node.getSource();
|
||||
final Source src = getLexicalContext().getCurrentFunction().getSource();
|
||||
property("source", src.getName());
|
||||
comma();
|
||||
|
||||
|
@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.ir.debug;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Contains utility methods for calculating the memory usage of objects. It
|
||||
* only works on the HotSpot JVM, and infers the actual memory layout (32 bit
|
||||
* vs. 64 bit word size, compressed object pointers vs. uncompressed) from
|
||||
* best available indicators. It can reliably detect a 32 bit vs. 64 bit JVM.
|
||||
* It can only make an educated guess at whether compressed OOPs are used,
|
||||
* though; specifically, it knows what the JVM's default choice of OOP
|
||||
* compression would be based on HotSpot version and maximum heap sizes, but if
|
||||
* the choice is explicitly overridden with the <tt>-XX:{+|-}UseCompressedOops</tt> command line
|
||||
* switch, it can not detect
|
||||
* this fact and will report incorrect sizes, as it will presume the default JVM
|
||||
* behavior.
|
||||
*
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
public class ObjectSizeCalculator {
|
||||
|
||||
/**
|
||||
* Describes constant memory overheads for various constructs in a JVM implementation.
|
||||
*/
|
||||
public interface MemoryLayoutSpecification {
|
||||
|
||||
/**
|
||||
* Returns the fixed overhead of an array of any type or length in this JVM.
|
||||
*
|
||||
* @return the fixed overhead of an array.
|
||||
*/
|
||||
int getArrayHeaderSize();
|
||||
|
||||
/**
|
||||
* Returns the fixed overhead of for any {@link Object} subclass in this JVM.
|
||||
*
|
||||
* @return the fixed overhead of any object.
|
||||
*/
|
||||
int getObjectHeaderSize();
|
||||
|
||||
/**
|
||||
* Returns the quantum field size for a field owned by an object in this JVM.
|
||||
*
|
||||
* @return the quantum field size for an object.
|
||||
*/
|
||||
int getObjectPadding();
|
||||
|
||||
/**
|
||||
* Returns the fixed size of an object reference in this JVM.
|
||||
*
|
||||
* @return the size of all object references.
|
||||
*/
|
||||
int getReferenceSize();
|
||||
|
||||
/**
|
||||
* Returns the quantum field size for a field owned by one of an object's ancestor superclasses
|
||||
* in this JVM.
|
||||
*
|
||||
* @return the quantum field size for a superclass field.
|
||||
*/
|
||||
int getSuperclassFieldPadding();
|
||||
}
|
||||
|
||||
private static class CurrentLayout {
|
||||
private static final MemoryLayoutSpecification SPEC =
|
||||
getEffectiveMemoryLayoutSpecification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object, returns the total allocated size, in bytes, of the object
|
||||
* and all other objects reachable from it. Attempts to to detect the current JVM memory layout,
|
||||
* but may fail with {@link UnsupportedOperationException};
|
||||
*
|
||||
* @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
|
||||
* anything special, it measures the size of all objects
|
||||
* reachable through it (which will include its class loader, and by
|
||||
* extension, all other Class objects loaded by
|
||||
* the same loader, and all the parent class loaders). It doesn't provide the
|
||||
* size of the static fields in the JVM class that the Class object
|
||||
* represents.
|
||||
* @return the total allocated size of the object and all other objects it
|
||||
* retains.
|
||||
* @throws UnsupportedOperationException if the current vm memory layout cannot be detected.
|
||||
*/
|
||||
public static long getObjectSize(final Object obj) throws UnsupportedOperationException {
|
||||
return obj == null ? 0 : new ObjectSizeCalculator(CurrentLayout.SPEC).calculateObjectSize(obj);
|
||||
}
|
||||
|
||||
// Fixed object header size for arrays.
|
||||
private final int arrayHeaderSize;
|
||||
// Fixed object header size for non-array objects.
|
||||
private final int objectHeaderSize;
|
||||
// Padding for the object size - if the object size is not an exact multiple
|
||||
// of this, it is padded to the next multiple.
|
||||
private final int objectPadding;
|
||||
// Size of reference (pointer) fields.
|
||||
private final int referenceSize;
|
||||
// Padding for the fields of superclass before fields of subclasses are
|
||||
// added.
|
||||
private final int superclassFieldPadding;
|
||||
|
||||
private final Map<Class<?>, ClassSizeInfo> classSizeInfos = new IdentityHashMap<>();
|
||||
|
||||
|
||||
private final Map<Object, Object> alreadyVisited = new IdentityHashMap<>();
|
||||
private final Map<Class<?>, ClassHistogramElement> histogram = new IdentityHashMap<>();
|
||||
|
||||
private final Deque<Object> pending = new ArrayDeque<>(16 * 1024);
|
||||
private long size;
|
||||
|
||||
/**
|
||||
* Creates an object size calculator that can calculate object sizes for a given
|
||||
* {@code memoryLayoutSpecification}.
|
||||
*
|
||||
* @param memoryLayoutSpecification a description of the JVM memory layout.
|
||||
*/
|
||||
public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
|
||||
memoryLayoutSpecification.getClass();
|
||||
arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
|
||||
objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
|
||||
objectPadding = memoryLayoutSpecification.getObjectPadding();
|
||||
referenceSize = memoryLayoutSpecification.getReferenceSize();
|
||||
superclassFieldPadding = memoryLayoutSpecification.getSuperclassFieldPadding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an object, returns the total allocated size, in bytes, of the object
|
||||
* and all other objects reachable from it.
|
||||
*
|
||||
* @param obj the object; can be null. Passing in a {@link java.lang.Class} object doesn't do
|
||||
* anything special, it measures the size of all objects
|
||||
* reachable through it (which will include its class loader, and by
|
||||
* extension, all other Class objects loaded by
|
||||
* the same loader, and all the parent class loaders). It doesn't provide the
|
||||
* size of the static fields in the JVM class that the Class object
|
||||
* represents.
|
||||
* @return the total allocated size of the object and all other objects it
|
||||
* retains.
|
||||
*/
|
||||
public synchronized long calculateObjectSize(final Object obj) {
|
||||
// Breadth-first traversal instead of naive depth-first with recursive
|
||||
// implementation, so we don't blow the stack traversing long linked lists.
|
||||
histogram.clear();
|
||||
try {
|
||||
for (Object o = obj;;) {
|
||||
visit(o);
|
||||
if (pending.isEmpty()) {
|
||||
return size;
|
||||
}
|
||||
o = pending.removeFirst();
|
||||
}
|
||||
} finally {
|
||||
alreadyVisited.clear();
|
||||
pending.clear();
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class histograpm
|
||||
* @return class histogram element list
|
||||
*/
|
||||
public List<ClassHistogramElement> getClassHistogram() {
|
||||
return new ArrayList<>(histogram.values());
|
||||
}
|
||||
|
||||
private ClassSizeInfo getClassSizeInfo(final Class<?> clazz) {
|
||||
ClassSizeInfo csi = classSizeInfos.get(clazz);
|
||||
if(csi == null) {
|
||||
csi = new ClassSizeInfo(clazz);
|
||||
classSizeInfos.put(clazz, csi);
|
||||
}
|
||||
return csi;
|
||||
}
|
||||
|
||||
private void visit(final Object obj) {
|
||||
if (alreadyVisited.containsKey(obj)) {
|
||||
return;
|
||||
}
|
||||
final Class<?> clazz = obj.getClass();
|
||||
if (clazz == ArrayElementsVisitor.class) {
|
||||
((ArrayElementsVisitor) obj).visit(this);
|
||||
} else {
|
||||
alreadyVisited.put(obj, obj);
|
||||
if (clazz.isArray()) {
|
||||
visitArray(obj);
|
||||
} else {
|
||||
getClassSizeInfo(clazz).visit(obj, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void visitArray(final Object array) {
|
||||
final Class<?> arrayClass = array.getClass();
|
||||
final Class<?> componentType = arrayClass.getComponentType();
|
||||
final int length = Array.getLength(array);
|
||||
if (componentType.isPrimitive()) {
|
||||
increaseByArraySize(arrayClass, length, getPrimitiveFieldSize(componentType));
|
||||
} else {
|
||||
increaseByArraySize(arrayClass, length, referenceSize);
|
||||
// If we didn't use an ArrayElementsVisitor, we would be enqueueing every
|
||||
// element of the array here instead. For large arrays, it would
|
||||
// tremendously enlarge the queue. In essence, we're compressing it into
|
||||
// a small command object instead. This is different than immediately
|
||||
// visiting the elements, as their visiting is scheduled for the end of
|
||||
// the current queue.
|
||||
switch (length) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
enqueue(Array.get(array, 0));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
enqueue(new ArrayElementsVisitor((Object[]) array));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void increaseByArraySize(final Class<?> clazz, final int length, final long elementSize) {
|
||||
increaseSize(clazz, roundTo(arrayHeaderSize + length * elementSize, objectPadding));
|
||||
}
|
||||
|
||||
private static class ArrayElementsVisitor {
|
||||
private final Object[] array;
|
||||
|
||||
ArrayElementsVisitor(final Object[] array) {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
public void visit(final ObjectSizeCalculator calc) {
|
||||
for (final Object elem : array) {
|
||||
if (elem != null) {
|
||||
calc.visit(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enqueue(final Object obj) {
|
||||
if (obj != null) {
|
||||
pending.addLast(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void increaseSize(final Class<?> clazz, final long objectSize) {
|
||||
ClassHistogramElement he = histogram.get(clazz);
|
||||
if(he == null) {
|
||||
he = new ClassHistogramElement(clazz);
|
||||
histogram.put(clazz, he);
|
||||
}
|
||||
he.addInstance(objectSize);
|
||||
size += objectSize;
|
||||
}
|
||||
|
||||
static long roundTo(final long x, final int multiple) {
|
||||
return ((x + multiple - 1) / multiple) * multiple;
|
||||
}
|
||||
|
||||
private class ClassSizeInfo {
|
||||
// Padded fields + header size
|
||||
private final long objectSize;
|
||||
// Only the fields size - used to calculate the subclasses' memory
|
||||
// footprint.
|
||||
private final long fieldsSize;
|
||||
private final Field[] referenceFields;
|
||||
|
||||
public ClassSizeInfo(final Class<?> clazz) {
|
||||
long newFieldsSize = 0;
|
||||
final List<Field> newReferenceFields = new LinkedList<>();
|
||||
for (Field f : clazz.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(f.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
final Class<?> type = f.getType();
|
||||
if (type.isPrimitive()) {
|
||||
newFieldsSize += getPrimitiveFieldSize(type);
|
||||
} else {
|
||||
f.setAccessible(true);
|
||||
newReferenceFields.add(f);
|
||||
newFieldsSize += referenceSize;
|
||||
}
|
||||
}
|
||||
final Class<?> superClass = clazz.getSuperclass();
|
||||
if (superClass != null) {
|
||||
final ClassSizeInfo superClassInfo = getClassSizeInfo(superClass);
|
||||
newFieldsSize += roundTo(superClassInfo.fieldsSize, superclassFieldPadding);
|
||||
newReferenceFields.addAll(Arrays.asList(superClassInfo.referenceFields));
|
||||
}
|
||||
this.fieldsSize = newFieldsSize;
|
||||
this.objectSize = roundTo(objectHeaderSize + newFieldsSize, objectPadding);
|
||||
this.referenceFields = newReferenceFields.toArray(
|
||||
new Field[newReferenceFields.size()]);
|
||||
}
|
||||
|
||||
void visit(final Object obj, final ObjectSizeCalculator calc) {
|
||||
calc.increaseSize(obj.getClass(), objectSize);
|
||||
enqueueReferencedObjects(obj, calc);
|
||||
}
|
||||
|
||||
public void enqueueReferencedObjects(final Object obj, final ObjectSizeCalculator calc) {
|
||||
for (Field f : referenceFields) {
|
||||
try {
|
||||
calc.enqueue(f.get(obj));
|
||||
} catch (IllegalAccessException e) {
|
||||
final AssertionError ae = new AssertionError(
|
||||
"Unexpected denial of access to " + f);
|
||||
ae.initCause(e);
|
||||
throw ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long getPrimitiveFieldSize(final Class<?> type) {
|
||||
if (type == boolean.class || type == byte.class) {
|
||||
return 1;
|
||||
}
|
||||
if (type == char.class || type == short.class) {
|
||||
return 2;
|
||||
}
|
||||
if (type == int.class || type == float.class) {
|
||||
return 4;
|
||||
}
|
||||
if (type == long.class || type == double.class) {
|
||||
return 8;
|
||||
}
|
||||
throw new AssertionError("Encountered unexpected primitive type " +
|
||||
type.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current memory usage
|
||||
* @return current memory usage derived from system configuration
|
||||
*/
|
||||
public static MemoryLayoutSpecification getEffectiveMemoryLayoutSpecification() {
|
||||
final String vmName = System.getProperty("java.vm.name");
|
||||
if (vmName == null || !vmName.startsWith("Java HotSpot(TM) ")) {
|
||||
throw new UnsupportedOperationException(
|
||||
"ObjectSizeCalculator only supported on HotSpot VM");
|
||||
}
|
||||
|
||||
final String dataModel = System.getProperty("sun.arch.data.model");
|
||||
if ("32".equals(dataModel)) {
|
||||
// Running with 32-bit data model
|
||||
return new MemoryLayoutSpecification() {
|
||||
@Override public int getArrayHeaderSize() {
|
||||
return 12;
|
||||
}
|
||||
@Override public int getObjectHeaderSize() {
|
||||
return 8;
|
||||
}
|
||||
@Override public int getObjectPadding() {
|
||||
return 8;
|
||||
}
|
||||
@Override public int getReferenceSize() {
|
||||
return 4;
|
||||
}
|
||||
@Override public int getSuperclassFieldPadding() {
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
} else if (!"64".equals(dataModel)) {
|
||||
throw new UnsupportedOperationException("Unrecognized value '" +
|
||||
dataModel + "' of sun.arch.data.model system property");
|
||||
}
|
||||
|
||||
final String strVmVersion = System.getProperty("java.vm.version");
|
||||
final int vmVersion = Integer.parseInt(strVmVersion.substring(0,
|
||||
strVmVersion.indexOf('.')));
|
||||
if (vmVersion >= 17) {
|
||||
long maxMemory = 0;
|
||||
for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
maxMemory += mp.getUsage().getMax();
|
||||
}
|
||||
if (maxMemory < 30L * 1024 * 1024 * 1024) {
|
||||
// HotSpot 17.0 and above use compressed OOPs below 30GB of RAM total
|
||||
// for all memory pools (yes, including code cache).
|
||||
return new MemoryLayoutSpecification() {
|
||||
@Override public int getArrayHeaderSize() {
|
||||
return 16;
|
||||
}
|
||||
@Override public int getObjectHeaderSize() {
|
||||
return 12;
|
||||
}
|
||||
@Override public int getObjectPadding() {
|
||||
return 8;
|
||||
}
|
||||
@Override public int getReferenceSize() {
|
||||
return 4;
|
||||
}
|
||||
@Override public int getSuperclassFieldPadding() {
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// In other cases, it's a 64-bit uncompressed OOPs object model
|
||||
return new MemoryLayoutSpecification() {
|
||||
@Override public int getArrayHeaderSize() {
|
||||
return 24;
|
||||
}
|
||||
@Override public int getObjectHeaderSize() {
|
||||
return 16;
|
||||
}
|
||||
@Override public int getObjectPadding() {
|
||||
return 8;
|
||||
}
|
||||
@Override public int getReferenceSize() {
|
||||
return 8;
|
||||
}
|
||||
@Override public int getSuperclassFieldPadding() {
|
||||
return 8;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -36,9 +36,9 @@ import jdk.nashorn.internal.ir.ForNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.SplitNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.ir.TryNode;
|
||||
@ -55,7 +55,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
|
||||
*/
|
||||
public final class PrintVisitor extends NodeVisitor {
|
||||
/** Tab width */
|
||||
private static final int TABWIDTH = 1;
|
||||
private static final int TABWIDTH = 4;
|
||||
|
||||
/** Composing buffer. */
|
||||
private final StringBuilder sb;
|
||||
@ -69,6 +69,8 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
/** Print line numbers */
|
||||
private final boolean printLineNumbers;
|
||||
|
||||
private int lastLineNumber = -1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@ -138,24 +140,27 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
@Override
|
||||
public boolean enterBlock(final Block block) {
|
||||
sb.append(' ');
|
||||
//sb.append(Debug.id(block));
|
||||
sb.append('{');
|
||||
|
||||
indent += TABWIDTH;
|
||||
|
||||
final List<Node> statements = block.getStatements();
|
||||
|
||||
boolean lastLineNumber = false;
|
||||
final List<Statement> statements = block.getStatements();
|
||||
|
||||
for (final Node statement : statements) {
|
||||
if (printLineNumbers || !lastLineNumber) {
|
||||
sb.append(EOLN);
|
||||
indent();
|
||||
if (printLineNumbers && (statement instanceof Statement)) {
|
||||
final int lineNumber = ((Statement)statement).getLineNumber();
|
||||
sb.append('\n');
|
||||
if (lineNumber != lastLineNumber) {
|
||||
indent();
|
||||
sb.append("[|").append(lineNumber).append("|];").append('\n');
|
||||
}
|
||||
lastLineNumber = lineNumber;
|
||||
}
|
||||
indent();
|
||||
|
||||
statement.accept(this);
|
||||
|
||||
lastLineNumber = statement instanceof LineNumberNode;
|
||||
|
||||
if (statement instanceof FunctionNode) {
|
||||
continue;
|
||||
}
|
||||
@ -168,12 +173,14 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
sb.append(']');
|
||||
}
|
||||
|
||||
final char lastChar = sb.charAt(sb.length() - 1);
|
||||
int lastIndex = sb.length() - 1;
|
||||
char lastChar = sb.charAt(lastIndex);
|
||||
while (Character.isWhitespace(lastChar) && lastIndex >= 0) {
|
||||
lastChar = sb.charAt(--lastIndex);
|
||||
}
|
||||
|
||||
if (lastChar != '}' && lastChar != ';') {
|
||||
if (printLineNumbers || !lastLineNumber) {
|
||||
sb.append(';');
|
||||
}
|
||||
sb.append(';');
|
||||
}
|
||||
|
||||
if (statement.hasGoto()) {
|
||||
@ -189,7 +196,8 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
|
||||
sb.append(EOLN);
|
||||
indent();
|
||||
sb.append("}");
|
||||
sb.append('}');
|
||||
// sb.append(Debug.id(block));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -221,7 +229,7 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
public boolean enterFunctionNode(final FunctionNode functionNode) {
|
||||
functionNode.toString(sb);
|
||||
enterBlock(functionNode.getBody());
|
||||
sb.append(EOLN);
|
||||
//sb.append(EOLN);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -251,15 +259,6 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
if (printLineNumbers) {
|
||||
lineNumberNode.toString(sb);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterSplitNode(final SplitNode splitNode) {
|
||||
splitNode.toString(sb);
|
||||
@ -334,6 +333,7 @@ public final class PrintVisitor extends NodeVisitor {
|
||||
sb.append(" = ");
|
||||
init.accept(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
|
||||
return enterASSIGN_SUB(binaryNode);
|
||||
case BIND:
|
||||
return enterBIND(binaryNode);
|
||||
case BIT_AND:
|
||||
case BIT_AND:
|
||||
return enterBIT_AND(binaryNode);
|
||||
case BIT_OR:
|
||||
return enterBIT_OR(binaryNode);
|
||||
|
@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
import jdk.nashorn.internal.ir.ObjectNode;
|
||||
@ -453,26 +452,6 @@ public abstract class NodeVisitor {
|
||||
return leaveDefault(labelNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for entering a LineNumberNode
|
||||
*
|
||||
* @param lineNumberNode the node
|
||||
* @return true if traversal should continue and node children be traversed, false otherwise
|
||||
*/
|
||||
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
return enterDefault(lineNumberNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for leaving a LineNumberNode
|
||||
*
|
||||
* @param lineNumberNode the node
|
||||
* @return processed node, which will replace the original one, or the original node
|
||||
*/
|
||||
public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
|
||||
return leaveDefault(lineNumberNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for entering a LiteralNode
|
||||
*
|
||||
|
@ -297,7 +297,7 @@ public final class NativeArray extends ScriptObject {
|
||||
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
|
||||
public static Object length(final Object self) {
|
||||
if (isArray(self)) {
|
||||
return ((NativeArray) self).getArray().length() & JSType.MAX_UINT;
|
||||
return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -311,7 +311,7 @@ public final class NativeArray extends ScriptObject {
|
||||
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
|
||||
public static void length(final Object self, final Object length) {
|
||||
if (isArray(self)) {
|
||||
((NativeArray) self).setLength(validLength(length, true));
|
||||
((ScriptObject) self).setLength(validLength(length, true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,10 +642,9 @@ public final class NativeArray extends ScriptObject {
|
||||
final boolean strict = sobj.isStrictContext();
|
||||
|
||||
if (bulkable(sobj)) {
|
||||
final NativeArray nativeArray = (NativeArray)sobj;
|
||||
if (nativeArray.getArray().length() + args.length <= JSType.MAX_UINT) {
|
||||
final ArrayData newData = nativeArray.getArray().push(nativeArray.isStrictContext(), args);
|
||||
nativeArray.setArray(newData);
|
||||
if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
|
||||
final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args);
|
||||
sobj.setArray(newData);
|
||||
return newData.length();
|
||||
}
|
||||
//fallthru
|
||||
@ -780,8 +779,7 @@ public final class NativeArray extends ScriptObject {
|
||||
}
|
||||
|
||||
if (bulkable(sobj)) {
|
||||
final NativeArray narray = (NativeArray) sobj;
|
||||
return new NativeArray(narray.getArray().slice(k, finale));
|
||||
return new NativeArray(sobj.getArray().slice(k, finale));
|
||||
}
|
||||
|
||||
final NativeArray copy = new NativeArray(0);
|
||||
@ -1001,11 +999,10 @@ public final class NativeArray extends ScriptObject {
|
||||
}
|
||||
|
||||
if (bulkable(sobj)) {
|
||||
final NativeArray nativeArray = (NativeArray) sobj;
|
||||
nativeArray.getArray().shiftRight(items.length);
|
||||
sobj.getArray().shiftRight(items.length);
|
||||
|
||||
for (int j = 0; j < items.length; j++) {
|
||||
nativeArray.setArray(nativeArray.getArray().set(j, items[j], sobj.isStrictContext()));
|
||||
sobj.setArray(sobj.getArray().set(j, items[j], sobj.isStrictContext()));
|
||||
}
|
||||
} else {
|
||||
for (long k = len; k > 0; k--) {
|
||||
|
@ -86,66 +86,6 @@ public final class NativeDebug extends ScriptObject {
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: get embed0 from {@link ScriptObject}
|
||||
*
|
||||
* @param self self reference
|
||||
* @param obj script object
|
||||
* @return the embed0 property value for the given ScriptObject
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object embed0(final Object self, final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ((ScriptObject)obj).embed0;
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: get embed1 from {@link ScriptObject}
|
||||
*
|
||||
* @param self self reference
|
||||
* @param obj script object
|
||||
* @return the embed1 property value for the given ScriptObject
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object embed1(final Object self, final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ((ScriptObject)obj).embed1;
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: get embed2 from {@link ScriptObject}
|
||||
*
|
||||
* @param self self reference
|
||||
* @param obj script object
|
||||
* @return the embed2 property value for the given ScriptObject
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object embed2(final Object self, final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ((ScriptObject)obj).embed2;
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: get embed3 from {@link ScriptObject}
|
||||
*
|
||||
* @param self self reference
|
||||
* @param obj script object
|
||||
* @return the embed3 property value for the given ScriptObject
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static Object embed3(final Object self, final Object obj) {
|
||||
if (obj instanceof ScriptObject) {
|
||||
return ((ScriptObject)obj).embed3;
|
||||
}
|
||||
return UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nashorn extension: get spill vector from {@link ScriptObject}
|
||||
*
|
||||
|
@ -620,7 +620,7 @@ public final class NativeJSAdapter extends ScriptObject {
|
||||
// to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
|
||||
return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
|
||||
func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
|
||||
adaptee.getMap().getProtoGetSwitchPoint(__call__), testJSAdaptor(adaptee, null, null, null));
|
||||
adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), __call__), testJSAdaptor(adaptee, null, null, null));
|
||||
}
|
||||
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
|
||||
default:
|
||||
@ -687,7 +687,7 @@ public final class NativeJSAdapter extends ScriptObject {
|
||||
if (methodHandle != null) {
|
||||
return new GuardedInvocation(
|
||||
methodHandle,
|
||||
adaptee.getMap().getProtoGetSwitchPoint(hook),
|
||||
adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
|
||||
testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func));
|
||||
}
|
||||
}
|
||||
@ -699,7 +699,7 @@ public final class NativeJSAdapter extends ScriptObject {
|
||||
final MethodHandle methodHandle = hook.equals(__put__) ?
|
||||
MH.asType(Lookup.EMPTY_SETTER, type) :
|
||||
Lookup.emptyGetter(type.returnType());
|
||||
return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(hook), testJSAdaptor(adaptee, null, null, null));
|
||||
return new GuardedInvocation(methodHandle, adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook), testJSAdaptor(adaptee, null, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -794,15 +794,15 @@ public final class NativeRegExp extends ScriptObject {
|
||||
|
||||
RegExpResult match;
|
||||
final int inputLength = string.length();
|
||||
int lastLength = -1;
|
||||
int lastIndex = 0;
|
||||
int lastLastIndex = 0;
|
||||
int splitLastLength = -1;
|
||||
int splitLastIndex = 0;
|
||||
int splitLastLastIndex = 0;
|
||||
|
||||
while ((match = execSplit(string, lastIndex)) != null) {
|
||||
lastIndex = match.getIndex() + match.length();
|
||||
while ((match = execSplit(string, splitLastIndex)) != null) {
|
||||
splitLastIndex = match.getIndex() + match.length();
|
||||
|
||||
if (lastIndex > lastLastIndex) {
|
||||
matches.add(string.substring(lastLastIndex, match.getIndex()));
|
||||
if (splitLastIndex > splitLastLastIndex) {
|
||||
matches.add(string.substring(splitLastLastIndex, match.getIndex()));
|
||||
final Object[] groups = match.getGroups();
|
||||
if (groups.length > 1 && match.getIndex() < inputLength) {
|
||||
for (int index = 1; index < groups.length && matches.size() < limit; index++) {
|
||||
@ -810,7 +810,7 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
lastLength = match.length();
|
||||
splitLastLength = match.length();
|
||||
|
||||
if (matches.size() >= limit) {
|
||||
break;
|
||||
@ -818,10 +818,10 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
|
||||
// bump the index to avoid infinite loop
|
||||
if (lastIndex == lastLastIndex) {
|
||||
lastIndex++;
|
||||
if (splitLastIndex == splitLastLastIndex) {
|
||||
splitLastIndex++;
|
||||
} else {
|
||||
lastLastIndex = lastIndex;
|
||||
splitLastLastIndex = splitLastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,12 +829,12 @@ public final class NativeRegExp extends ScriptObject {
|
||||
// check special case if we need to append an empty string at the
|
||||
// end of the match
|
||||
// if the lastIndex was the entire string
|
||||
if (lastLastIndex == string.length()) {
|
||||
if (lastLength > 0 || execSplit("", 0) == null) {
|
||||
if (splitLastLastIndex == string.length()) {
|
||||
if (splitLastLength > 0 || execSplit("", 0) == null) {
|
||||
matches.add("");
|
||||
}
|
||||
} else {
|
||||
matches.add(string.substring(lastLastIndex, inputLength));
|
||||
matches.add(string.substring(splitLastLastIndex, inputLength));
|
||||
}
|
||||
}
|
||||
|
||||
@ -899,10 +899,6 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
private void setGlobal(final boolean global) {
|
||||
regexp.setGlobal(global);
|
||||
}
|
||||
|
||||
boolean getGlobal() {
|
||||
return regexp.isGlobal();
|
||||
}
|
||||
|
@ -249,6 +249,7 @@ public abstract class AbstractParser {
|
||||
*
|
||||
* @param errorType The error type of the warning
|
||||
* @param message Warning message.
|
||||
* @param errorToken error token
|
||||
*/
|
||||
protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
|
||||
errors.warning(error(errorType, message, errorToken));
|
||||
@ -363,7 +364,7 @@ public abstract class AbstractParser {
|
||||
next();
|
||||
|
||||
// Create IDENT node.
|
||||
return new IdentNode(source, identToken, finish, ident);
|
||||
return new IdentNode(identToken, finish, ident);
|
||||
}
|
||||
|
||||
// Get IDENT.
|
||||
@ -372,7 +373,7 @@ public abstract class AbstractParser {
|
||||
return null;
|
||||
}
|
||||
// Create IDENT node.
|
||||
return new IdentNode(source, identToken, finish, ident);
|
||||
return new IdentNode(identToken, finish, ident);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,7 +408,7 @@ public abstract class AbstractParser {
|
||||
final String ident = (String)getValue(identToken);
|
||||
next();
|
||||
// Create IDENT node.
|
||||
return new IdentNode(source, identToken, finish, ident);
|
||||
return new IdentNode(identToken, finish, ident);
|
||||
} else {
|
||||
expect(IDENT);
|
||||
return null;
|
||||
@ -432,11 +433,11 @@ public abstract class AbstractParser {
|
||||
LiteralNode<?> node = null;
|
||||
|
||||
if (value == null) {
|
||||
node = LiteralNode.newInstance(source, literalToken, finish);
|
||||
node = LiteralNode.newInstance(literalToken, finish);
|
||||
} else if (value instanceof Number) {
|
||||
node = LiteralNode.newInstance(source, literalToken, finish, (Number)value);
|
||||
node = LiteralNode.newInstance(literalToken, finish, (Number)value);
|
||||
} else if (value instanceof String) {
|
||||
node = LiteralNode.newInstance(source, literalToken, finish, (String)value);
|
||||
node = LiteralNode.newInstance(literalToken, finish, (String)value);
|
||||
} else if (value instanceof LexerToken) {
|
||||
if (value instanceof RegexToken) {
|
||||
final RegexToken regex = (RegexToken)value;
|
||||
@ -446,7 +447,7 @@ public abstract class AbstractParser {
|
||||
throw error(e.getMessage());
|
||||
}
|
||||
}
|
||||
node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value);
|
||||
node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value);
|
||||
} else {
|
||||
assert false : "unknown type for LiteralNode: " + value.getClass();
|
||||
}
|
||||
|
@ -193,13 +193,13 @@ public class JSONParser extends AbstractParser {
|
||||
return getLiteral();
|
||||
case FALSE:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, literalToken, finish, false);
|
||||
return LiteralNode.newInstance(literalToken, finish, false);
|
||||
case TRUE:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, literalToken, finish, true);
|
||||
return LiteralNode.newInstance(literalToken, finish, true);
|
||||
case NULL:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, literalToken, finish);
|
||||
return LiteralNode.newInstance(literalToken, finish);
|
||||
case LBRACKET:
|
||||
return arrayLiteral();
|
||||
case LBRACE:
|
||||
@ -218,7 +218,7 @@ public class JSONParser extends AbstractParser {
|
||||
|
||||
if (value instanceof Number) {
|
||||
next();
|
||||
return new UnaryNode(source, literalToken, LiteralNode.newInstance(source, realToken, finish, (Number)value));
|
||||
return new UnaryNode(literalToken, LiteralNode.newInstance(realToken, finish, (Number)value));
|
||||
}
|
||||
|
||||
throw error(AbstractParser.message("expected", "number", type.getNameOrType()));
|
||||
@ -250,7 +250,7 @@ loop:
|
||||
switch (type) {
|
||||
case RBRACKET:
|
||||
next();
|
||||
result = LiteralNode.newInstance(source, arrayToken, finish, elements);
|
||||
result = LiteralNode.newInstance(arrayToken, finish, elements);
|
||||
break loop;
|
||||
|
||||
case COMMARIGHT:
|
||||
@ -310,7 +310,7 @@ loop:
|
||||
}
|
||||
|
||||
// Construct new object literal.
|
||||
return new ObjectNode(source, objectToken, finish, elements);
|
||||
return new ObjectNode(objectToken, finish, elements);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,7 +331,7 @@ loop:
|
||||
if (name != null) {
|
||||
expect(COLON);
|
||||
final Node value = jsonLiteral();
|
||||
return new PropertyNode(source, propertyToken, value.getFinish(), name, value, null, null);
|
||||
return new PropertyNode(propertyToken, value.getFinish(), name, value, null, null);
|
||||
}
|
||||
|
||||
// Raise an error.
|
||||
|
@ -59,9 +59,11 @@ import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.Namespace;
|
||||
import jdk.nashorn.internal.ir.AccessNode;
|
||||
import jdk.nashorn.internal.ir.BaseNode;
|
||||
import jdk.nashorn.internal.ir.BinaryNode;
|
||||
import jdk.nashorn.internal.ir.Block;
|
||||
import jdk.nashorn.internal.ir.BlockLexicalContext;
|
||||
@ -81,7 +83,6 @@ import jdk.nashorn.internal.ir.IfNode;
|
||||
import jdk.nashorn.internal.ir.IndexNode;
|
||||
import jdk.nashorn.internal.ir.LabelNode;
|
||||
import jdk.nashorn.internal.ir.LexicalContext;
|
||||
import jdk.nashorn.internal.ir.LineNumberNode;
|
||||
import jdk.nashorn.internal.ir.LiteralNode;
|
||||
import jdk.nashorn.internal.ir.LoopNode;
|
||||
import jdk.nashorn.internal.ir.Node;
|
||||
@ -90,6 +91,7 @@ import jdk.nashorn.internal.ir.PropertyKey;
|
||||
import jdk.nashorn.internal.ir.PropertyNode;
|
||||
import jdk.nashorn.internal.ir.ReturnNode;
|
||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
||||
import jdk.nashorn.internal.ir.Statement;
|
||||
import jdk.nashorn.internal.ir.SwitchNode;
|
||||
import jdk.nashorn.internal.ir.TernaryNode;
|
||||
import jdk.nashorn.internal.ir.ThrowNode;
|
||||
@ -117,7 +119,7 @@ public class Parser extends AbstractParser {
|
||||
/** Is scripting mode. */
|
||||
private final boolean scripting;
|
||||
|
||||
private List<Node> functionDeclarations;
|
||||
private List<Statement> functionDeclarations;
|
||||
|
||||
private final BlockLexicalContext lc = new BlockLexicalContext();
|
||||
|
||||
@ -275,8 +277,7 @@ loop:
|
||||
* @return New block.
|
||||
*/
|
||||
private Block newBlock() {
|
||||
final Block block = new Block(source, token, Token.descPosition(token));
|
||||
return lc.push(block);
|
||||
return lc.push(new Block(line, token, Token.descPosition(token)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,11 +306,17 @@ loop:
|
||||
if (isStrictMode) {
|
||||
flags |= FunctionNode.IS_STRICT;
|
||||
}
|
||||
if (env._specialize_calls != null) {
|
||||
if (env._specialize_calls.contains(name)) {
|
||||
flags |= FunctionNode.CAN_SPECIALIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// Start new block.
|
||||
FunctionNode functionNode =
|
||||
new FunctionNode(
|
||||
source,
|
||||
line, //TODO?
|
||||
token,
|
||||
Token.descPosition(token),
|
||||
startToken,
|
||||
@ -320,11 +327,11 @@ loop:
|
||||
kind,
|
||||
flags);
|
||||
|
||||
functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
|
||||
lc.push(functionNode);
|
||||
// Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
|
||||
// FunctionNode.
|
||||
newBlock();
|
||||
|
||||
return functionNode;
|
||||
}
|
||||
|
||||
@ -332,14 +339,19 @@ loop:
|
||||
* Restore the current block.
|
||||
*/
|
||||
private Block restoreBlock(final Block block) {
|
||||
return lc.pop(block);//.setFlag(lc, flags);
|
||||
return lc.pop(block);
|
||||
}
|
||||
|
||||
|
||||
private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
|
||||
final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
|
||||
|
||||
return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
|
||||
}
|
||||
return lc.pop(functionNode).
|
||||
setBody(lc, newBody).
|
||||
setLastToken(lc, lastToken).
|
||||
setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED).
|
||||
snapshot(lc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the statements in a block.
|
||||
@ -469,7 +481,7 @@ loop:
|
||||
}
|
||||
|
||||
// Build up node.
|
||||
return new BinaryNode(source, op, lhs, rhs);
|
||||
return new BinaryNode(op, lhs, rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,12 +492,12 @@ loop:
|
||||
* @param isPostfix Prefix or postfix.
|
||||
* @return Reduced expression.
|
||||
*/
|
||||
private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
|
||||
private static Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
|
||||
if (isPostfix) {
|
||||
return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
|
||||
return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
|
||||
}
|
||||
|
||||
return new UnaryNode(source, firstToken, expression);
|
||||
return new UnaryNode(firstToken, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -514,7 +526,7 @@ loop:
|
||||
|
||||
FunctionNode script = newFunctionNode(
|
||||
functionToken,
|
||||
new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
|
||||
new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
|
||||
new ArrayList<IdentNode>(),
|
||||
FunctionNode.Kind.SCRIPT);
|
||||
|
||||
@ -529,6 +541,7 @@ loop:
|
||||
|
||||
script = restoreFunctionNode(script, token); //commit code
|
||||
script = script.setBody(lc, script.getBody().setNeedsScope(lc));
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -670,8 +683,6 @@ loop:
|
||||
* @param topLevel does this statement occur at the "top level" of a script or a function?
|
||||
*/
|
||||
private void statement(final boolean topLevel) {
|
||||
final LineNumberNode lineNumberNode = lineNumber();
|
||||
|
||||
if (type == FUNCTION) {
|
||||
// As per spec (ECMA section 12), function declarations as arbitrary statement
|
||||
// is not "portable". Implementation can issue a warning or disallow the same.
|
||||
@ -679,10 +690,6 @@ loop:
|
||||
return;
|
||||
}
|
||||
|
||||
if (lineNumberNode != null) {
|
||||
appendStatement(lineNumberNode);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case LBRACE:
|
||||
block();
|
||||
@ -763,7 +770,7 @@ loop:
|
||||
private void block() {
|
||||
final Block newBlock = getBlock(true);
|
||||
// Force block execution.
|
||||
appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
|
||||
appendStatement(new ExecuteNode(newBlock.getLineNumber(), newBlock.getToken(), finish, newBlock));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -800,7 +807,6 @@ loop:
|
||||
* @param ident Identifier that is verified
|
||||
* @param contextString String used in error message to give context to the user
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
private void verifyStrictIdent(final IdentNode ident, final String contextString) {
|
||||
if (isStrictMode) {
|
||||
switch (ident.getName()) {
|
||||
@ -840,6 +846,7 @@ loop:
|
||||
|
||||
while (true) {
|
||||
// Get starting token.
|
||||
final int varLine = line;
|
||||
final long varToken = token;
|
||||
// Get name of var.
|
||||
final IdentNode name = getIdent();
|
||||
@ -857,7 +864,7 @@ loop:
|
||||
}
|
||||
|
||||
// Allocate var node.
|
||||
final VarNode var = new VarNode(source, varToken, finish, name, init);
|
||||
final VarNode var = new VarNode(varLine, varToken, finish, name, init);
|
||||
vars.add(var);
|
||||
appendStatement(var);
|
||||
|
||||
@ -889,7 +896,7 @@ loop:
|
||||
*/
|
||||
private void emptyStatement() {
|
||||
if (env._empty_statements) {
|
||||
appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
|
||||
appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
|
||||
}
|
||||
|
||||
// SEMICOLON checked in caller.
|
||||
@ -906,6 +913,7 @@ loop:
|
||||
*/
|
||||
private void expressionStatement() {
|
||||
// Lookahead checked in caller.
|
||||
final int expressionLine = line;
|
||||
final long expressionToken = token;
|
||||
|
||||
// Get expression and add as statement.
|
||||
@ -913,7 +921,7 @@ loop:
|
||||
|
||||
ExecuteNode executeNode = null;
|
||||
if (expression != null) {
|
||||
executeNode = new ExecuteNode(source, expressionToken, finish, expression);
|
||||
executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
|
||||
appendStatement(executeNode);
|
||||
} else {
|
||||
expect(null);
|
||||
@ -938,6 +946,7 @@ loop:
|
||||
*/
|
||||
private void ifStatement() {
|
||||
// Capture IF token.
|
||||
final int ifLine = line;
|
||||
final long ifToken = token;
|
||||
// IF tested in caller.
|
||||
next();
|
||||
@ -953,7 +962,7 @@ loop:
|
||||
fail = getStatement();
|
||||
}
|
||||
|
||||
appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
|
||||
appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -970,8 +979,7 @@ loop:
|
||||
*/
|
||||
private void forStatement() {
|
||||
// Create FOR node, capturing FOR token.
|
||||
ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
|
||||
|
||||
ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
|
||||
|
||||
// Set up new block for scope of vars. Captures first token.
|
||||
Block outer = newBlock();
|
||||
@ -1074,7 +1082,7 @@ loop:
|
||||
outer = restoreBlock(outer);
|
||||
}
|
||||
|
||||
appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
|
||||
appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1105,12 +1113,13 @@ loop:
|
||||
*/
|
||||
private void whileStatement() {
|
||||
// Capture WHILE token.
|
||||
final int whileLine = line;
|
||||
final long whileToken = token;
|
||||
// WHILE tested in caller.
|
||||
next();
|
||||
|
||||
// Construct WHILE node.
|
||||
WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
|
||||
WhileNode whileNode = new WhileNode(whileLine, whileToken, Token.descPosition(whileToken), false);
|
||||
lc.push(whileNode);
|
||||
|
||||
try {
|
||||
@ -1136,11 +1145,12 @@ loop:
|
||||
*/
|
||||
private void doStatement() {
|
||||
// Capture DO token.
|
||||
final int doLine = line;
|
||||
final long doToken = token;
|
||||
// DO tested in the caller.
|
||||
next();
|
||||
|
||||
WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
|
||||
WhileNode doWhileNode = new WhileNode(doLine, doToken, Token.descPosition(doToken), true);
|
||||
lc.push(doWhileNode);
|
||||
|
||||
try {
|
||||
@ -1172,6 +1182,7 @@ loop:
|
||||
*/
|
||||
private void continueStatement() {
|
||||
// Capture CONTINUE token.
|
||||
final int continueLine = line;
|
||||
final long continueToken = token;
|
||||
// CONTINUE tested in caller.
|
||||
nextOrEOL();
|
||||
@ -1206,7 +1217,7 @@ loop:
|
||||
endOfLine();
|
||||
|
||||
// Construct and add CONTINUE node.
|
||||
appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
|
||||
appendStatement(new ContinueNode(continueLine, continueToken, finish, label == null ? null : new IdentNode(label)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1218,6 +1229,7 @@ loop:
|
||||
*/
|
||||
private void breakStatement() {
|
||||
// Capture BREAK token.
|
||||
final int breakLine = line;
|
||||
final long breakToken = token;
|
||||
// BREAK tested in caller.
|
||||
nextOrEOL();
|
||||
@ -1253,7 +1265,7 @@ loop:
|
||||
endOfLine();
|
||||
|
||||
// Construct and add BREAK node.
|
||||
appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
|
||||
appendStatement(new BreakNode(breakLine, breakToken, finish, label == null ? null : new IdentNode(label)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1271,6 +1283,7 @@ loop:
|
||||
}
|
||||
|
||||
// Capture RETURN token.
|
||||
final int returnLine = line;
|
||||
final long returnToken = token;
|
||||
// RETURN tested in caller.
|
||||
nextOrEOL();
|
||||
@ -1292,7 +1305,7 @@ loop:
|
||||
endOfLine();
|
||||
|
||||
// Construct and add RETURN node.
|
||||
appendStatement(new ReturnNode(source, returnToken, finish, expression));
|
||||
appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1305,6 +1318,7 @@ loop:
|
||||
*/
|
||||
private void yieldStatement() {
|
||||
// Capture YIELD token.
|
||||
final int yieldLine = line;
|
||||
final long yieldToken = token;
|
||||
// YIELD tested in caller.
|
||||
nextOrEOL();
|
||||
@ -1326,7 +1340,7 @@ loop:
|
||||
endOfLine();
|
||||
|
||||
// Construct and add YIELD node.
|
||||
appendStatement(new ReturnNode(source, yieldToken, finish, expression));
|
||||
appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1339,6 +1353,7 @@ loop:
|
||||
*/
|
||||
private void withStatement() {
|
||||
// Capture WITH token.
|
||||
final int withLine = line;
|
||||
final long withToken = token;
|
||||
// WITH tested in caller.
|
||||
next();
|
||||
@ -1349,7 +1364,7 @@ loop:
|
||||
}
|
||||
|
||||
// Get WITH expression.
|
||||
WithNode withNode = new WithNode(source, withToken, finish);
|
||||
WithNode withNode = new WithNode(withLine, withToken, finish);
|
||||
|
||||
try {
|
||||
lc.push(withNode);
|
||||
@ -1387,12 +1402,13 @@ loop:
|
||||
* Parse SWITCH statement.
|
||||
*/
|
||||
private void switchStatement() {
|
||||
final int switchLine = line;
|
||||
final long switchToken = token;
|
||||
// SWITCH tested in caller.
|
||||
next();
|
||||
|
||||
// Create and add switch statement.
|
||||
SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
|
||||
SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
|
||||
lc.push(switchNode);
|
||||
|
||||
try {
|
||||
@ -1434,7 +1450,7 @@ loop:
|
||||
|
||||
// Get CASE body.
|
||||
final Block statements = getBlock(false);
|
||||
final CaseNode caseNode = new CaseNode(source, caseToken, finish, caseExpression, statements);
|
||||
final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
|
||||
statements.setFinish(finish);
|
||||
|
||||
if (caseExpression == null) {
|
||||
@ -1474,7 +1490,7 @@ loop:
|
||||
throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
|
||||
}
|
||||
|
||||
LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
|
||||
LabelNode labelNode = new LabelNode(line, labelToken, finish, ident, null);
|
||||
try {
|
||||
lc.push(labelNode);
|
||||
labelNode = labelNode.setBody(lc, getStatement());
|
||||
@ -1496,6 +1512,7 @@ loop:
|
||||
*/
|
||||
private void throwStatement() {
|
||||
// Capture THROW token.
|
||||
final int throwLine = line;
|
||||
final long throwToken = token;
|
||||
// THROW tested in caller.
|
||||
nextOrEOL();
|
||||
@ -1520,7 +1537,7 @@ loop:
|
||||
|
||||
endOfLine();
|
||||
|
||||
appendStatement(new ThrowNode(source, throwToken, finish, expression));
|
||||
appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1542,6 +1559,7 @@ loop:
|
||||
*/
|
||||
private void tryStatement() {
|
||||
// Capture TRY token.
|
||||
final int tryLine = line;
|
||||
final long tryToken = token;
|
||||
// TRY tested in caller.
|
||||
next();
|
||||
@ -1556,6 +1574,7 @@ loop:
|
||||
final List<Block> catchBlocks = new ArrayList<>();
|
||||
|
||||
while (type == CATCH) {
|
||||
final int catchLine = line;
|
||||
final long catchToken = token;
|
||||
next();
|
||||
expect(LPAREN);
|
||||
@ -1578,7 +1597,7 @@ loop:
|
||||
try {
|
||||
// Get CATCH body.
|
||||
final Block catchBody = getBlock(true);
|
||||
final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
|
||||
final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody);
|
||||
appendStatement(catchNode);
|
||||
} finally {
|
||||
catchBlock = restoreBlock(catchBlock);
|
||||
@ -1604,7 +1623,7 @@ loop:
|
||||
throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
|
||||
}
|
||||
|
||||
final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
|
||||
final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
|
||||
// Add try.
|
||||
assert lc.peek() == outer;
|
||||
appendStatement(tryNode);
|
||||
@ -1616,7 +1635,7 @@ loop:
|
||||
outer = restoreBlock(outer);
|
||||
}
|
||||
|
||||
appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
|
||||
appendStatement(new ExecuteNode(outer.getLineNumber(), outer.getToken(), outer.getFinish(), outer));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1629,11 +1648,12 @@ loop:
|
||||
*/
|
||||
private void debuggerStatement() {
|
||||
// Capture DEBUGGER token.
|
||||
final int debuggerLine = line;
|
||||
final long debuggerToken = token;
|
||||
// DEBUGGER tested in caller.
|
||||
next();
|
||||
endOfLine();
|
||||
appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
|
||||
appendStatement(new ExecuteNode(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1653,13 +1673,14 @@ loop:
|
||||
@SuppressWarnings("fallthrough")
|
||||
private Node primaryExpression() {
|
||||
// Capture first token.
|
||||
final int primaryLine = line;
|
||||
final long primaryToken = token;
|
||||
|
||||
switch (type) {
|
||||
case THIS:
|
||||
final String name = type.getName();
|
||||
next();
|
||||
return new IdentNode(source, primaryToken, finish, name);
|
||||
return new IdentNode(primaryToken, finish, name);
|
||||
case IDENT:
|
||||
final IdentNode ident = getIdent();
|
||||
if (ident == null) {
|
||||
@ -1680,16 +1701,16 @@ loop:
|
||||
case XML:
|
||||
return getLiteral();
|
||||
case EXECSTRING:
|
||||
return execString(primaryToken);
|
||||
return execString(primaryLine, primaryToken);
|
||||
case FALSE:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, primaryToken, finish, false);
|
||||
return LiteralNode.newInstance(primaryToken, finish, false);
|
||||
case TRUE:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, primaryToken, finish, true);
|
||||
return LiteralNode.newInstance(primaryToken, finish, true);
|
||||
case NULL:
|
||||
next();
|
||||
return LiteralNode.newInstance(source, primaryToken, finish);
|
||||
return LiteralNode.newInstance(primaryToken, finish);
|
||||
case LBRACKET:
|
||||
return arrayLiteral();
|
||||
case LBRACE:
|
||||
@ -1724,9 +1745,9 @@ loop:
|
||||
* @param primaryToken Original string token.
|
||||
* @return callNode to $EXEC.
|
||||
*/
|
||||
Node execString(final long primaryToken) {
|
||||
Node execString(final int primaryLine, final long primaryToken) {
|
||||
// Synthesize an ident to call $EXEC.
|
||||
final IdentNode execIdent = new IdentNode(source, primaryToken, finish, ScriptingFunctions.EXEC_NAME);
|
||||
final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
|
||||
// Skip over EXECSTRING.
|
||||
next();
|
||||
// Set up argument list for call.
|
||||
@ -1738,7 +1759,7 @@ loop:
|
||||
// Skip ending of edit string expression.
|
||||
expect(RBRACE);
|
||||
|
||||
return new CallNode(source, primaryToken, finish, execIdent, arguments);
|
||||
return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1809,7 +1830,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
return LiteralNode.newInstance(source, arrayToken, finish, elements);
|
||||
return LiteralNode.newInstance(arrayToken, finish, elements);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1916,7 +1937,7 @@ loop:
|
||||
map.put(key, newProperty = newProperty.setValue(value));
|
||||
} else {
|
||||
final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
|
||||
map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
|
||||
map.put(key, newProperty = newProperty.setValue(new BinaryNode(propertyToken, prevValue, value)));
|
||||
}
|
||||
|
||||
map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
|
||||
@ -1933,7 +1954,7 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
|
||||
return new ObjectNode(objectToken, finish, new ArrayList<Node>(map.values()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2003,16 +2024,16 @@ loop:
|
||||
case "get":
|
||||
final PropertyKey getIdent = propertyName();
|
||||
final String getterName = getIdent.getPropertyName();
|
||||
final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
|
||||
final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, "get " + getterName);
|
||||
expect(LPAREN);
|
||||
expect(RPAREN);
|
||||
functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
|
||||
return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
|
||||
return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null);
|
||||
|
||||
case "set":
|
||||
final PropertyKey setIdent = propertyName();
|
||||
final String setterName = setIdent.getPropertyName();
|
||||
final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName);
|
||||
final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, "set " + setterName);
|
||||
expect(LPAREN);
|
||||
final IdentNode argIdent = getIdent();
|
||||
verifyStrictIdent(argIdent, "setter argument");
|
||||
@ -2020,21 +2041,21 @@ loop:
|
||||
List<IdentNode> parameters = new ArrayList<>();
|
||||
parameters.add(argIdent);
|
||||
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
|
||||
return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
|
||||
return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
propertyName = new IdentNode(source, propertyToken, finish, ident);
|
||||
propertyName = new IdentNode(propertyToken, finish, ident);
|
||||
} else {
|
||||
propertyName = propertyName();
|
||||
}
|
||||
|
||||
expect(COLON);
|
||||
|
||||
return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
|
||||
return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2054,6 +2075,7 @@ loop:
|
||||
* @return Expression node.
|
||||
*/
|
||||
private Node leftHandSideExpression() {
|
||||
int callLine = line;
|
||||
long callToken = token;
|
||||
|
||||
Node lhs = memberExpression();
|
||||
@ -2066,12 +2088,13 @@ loop:
|
||||
detectSpecialFunction((IdentNode)lhs);
|
||||
}
|
||||
|
||||
lhs = new CallNode(source, callToken, finish, lhs, arguments);
|
||||
lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
|
||||
}
|
||||
|
||||
loop:
|
||||
while (true) {
|
||||
// Capture token.
|
||||
callLine = line;
|
||||
callToken = token;
|
||||
|
||||
switch (type) {
|
||||
@ -2080,7 +2103,7 @@ loop:
|
||||
final List<Node> arguments = argumentList();
|
||||
|
||||
// Create call node.
|
||||
lhs = new CallNode(source, callToken, finish, lhs, arguments);
|
||||
lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
|
||||
|
||||
break;
|
||||
|
||||
@ -2093,7 +2116,7 @@ loop:
|
||||
expect(RBRACKET);
|
||||
|
||||
// Create indexing node.
|
||||
lhs = new IndexNode(source, callToken, finish, lhs, rhs);
|
||||
lhs = new IndexNode(callToken, finish, lhs, rhs);
|
||||
|
||||
break;
|
||||
|
||||
@ -2103,7 +2126,7 @@ loop:
|
||||
final IdentNode property = getIdentifierName();
|
||||
|
||||
// Create property access node.
|
||||
lhs = new AccessNode(source, callToken, finish, lhs, property);
|
||||
lhs = new AccessNode(callToken, finish, lhs, property);
|
||||
|
||||
break;
|
||||
|
||||
@ -2131,6 +2154,7 @@ loop:
|
||||
next();
|
||||
|
||||
// Get function base.
|
||||
final int callLine = line;
|
||||
final Node constructor = memberExpression();
|
||||
if (constructor == null) {
|
||||
return null;
|
||||
@ -2159,9 +2183,9 @@ loop:
|
||||
arguments.add(objectLiteral());
|
||||
}
|
||||
|
||||
final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments);
|
||||
final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, arguments);
|
||||
|
||||
return new UnaryNode(source, newToken, callNode);
|
||||
return new UnaryNode(newToken, callNode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2213,7 +2237,7 @@ loop:
|
||||
expect(RBRACKET);
|
||||
|
||||
// Create indexing node.
|
||||
lhs = new IndexNode(source, callToken, finish, lhs, index);
|
||||
lhs = new IndexNode(callToken, finish, lhs, index);
|
||||
|
||||
break;
|
||||
|
||||
@ -2227,7 +2251,7 @@ loop:
|
||||
final IdentNode property = getIdentifierName();
|
||||
|
||||
// Create property access node.
|
||||
lhs = new AccessNode(source, callToken, finish, lhs, property);
|
||||
lhs = new AccessNode(callToken, finish, lhs, property);
|
||||
|
||||
break;
|
||||
|
||||
@ -2294,9 +2318,8 @@ loop:
|
||||
* @return Expression node.
|
||||
*/
|
||||
private Node functionExpression(final boolean isStatement, final boolean topLevel) {
|
||||
final LineNumberNode lineNumber = lineNumber();
|
||||
|
||||
final long functionToken = token;
|
||||
final int functionLine = line;
|
||||
// FUNCTION is tested in caller.
|
||||
next();
|
||||
|
||||
@ -2316,7 +2339,7 @@ loop:
|
||||
boolean isAnonymous = false;
|
||||
if (name == null) {
|
||||
final String tmpName = "_L" + source.getLine(Token.descPosition(token));
|
||||
name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName);
|
||||
name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
|
||||
isAnonymous = true;
|
||||
}
|
||||
|
||||
@ -2367,7 +2390,7 @@ loop:
|
||||
// rename in non-strict mode
|
||||
parameterName = functionNode.uniqueName(parameterName);
|
||||
final long parameterToken = parameter.getToken();
|
||||
parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
|
||||
parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
|
||||
}
|
||||
|
||||
parametersSet.add(parameterName);
|
||||
@ -2379,12 +2402,10 @@ loop:
|
||||
}
|
||||
|
||||
if (isStatement) {
|
||||
final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
|
||||
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
|
||||
if (topLevel) {
|
||||
functionDeclarations.add(lineNumber);
|
||||
functionDeclarations.add(varNode);
|
||||
} else {
|
||||
appendStatement(lineNumber);
|
||||
appendStatement(varNode);
|
||||
}
|
||||
}
|
||||
@ -2459,7 +2480,7 @@ loop:
|
||||
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
|
||||
// create a return statement - this creates code in itself and does not need to be
|
||||
// wrapped into an ExecuteNode
|
||||
final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
|
||||
final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), finish, expr);
|
||||
appendStatement(returnNode);
|
||||
lastToken = token;
|
||||
functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
|
||||
@ -2468,7 +2489,7 @@ loop:
|
||||
expect(LBRACE);
|
||||
|
||||
// Gather the function elements.
|
||||
final List<Node> prevFunctionDecls = functionDeclarations;
|
||||
final List<Statement> prevFunctionDecls = functionDeclarations;
|
||||
functionDeclarations = new ArrayList<>();
|
||||
try {
|
||||
sourceElements();
|
||||
@ -2492,7 +2513,7 @@ loop:
|
||||
assert lc.peek() == lc.getFunctionBody(functionNode);
|
||||
VarNode lastDecl = null;
|
||||
for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
|
||||
Node decl = functionDeclarations.get(i);
|
||||
Statement decl = functionDeclarations.get(i);
|
||||
if (lastDecl == null && decl instanceof VarNode) {
|
||||
decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
|
||||
lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
|
||||
@ -2501,16 +2522,16 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeNode referenceError(final Node lhs, final Node rhs) {
|
||||
private static RuntimeNode referenceError(final Node lhs, final Node rhs) {
|
||||
final ArrayList<Node> args = new ArrayList<>();
|
||||
args.add(lhs);
|
||||
if (rhs == null) {
|
||||
args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish()));
|
||||
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
|
||||
} else {
|
||||
args.add(rhs);
|
||||
}
|
||||
args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
|
||||
return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
|
||||
args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
|
||||
return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2548,10 +2569,19 @@ loop:
|
||||
* @return Expression node.
|
||||
*/
|
||||
private Node unaryExpression() {
|
||||
final int unaryLine = line;
|
||||
final long unaryToken = token;
|
||||
|
||||
switch (type) {
|
||||
case DELETE:
|
||||
case DELETE: {
|
||||
next();
|
||||
final Node expr = unaryExpression();
|
||||
if (expr instanceof BaseNode || expr instanceof IdentNode) {
|
||||
return new UnaryNode(unaryToken, expr);
|
||||
}
|
||||
appendStatement(new ExecuteNode(unaryLine, unaryToken, finish, expr));
|
||||
return LiteralNode.newInstance(unaryToken, finish, true);
|
||||
}
|
||||
case VOID:
|
||||
case TYPEOF:
|
||||
case ADD:
|
||||
@ -2560,7 +2590,7 @@ loop:
|
||||
case NOT:
|
||||
next();
|
||||
final Node expr = unaryExpression();
|
||||
return new UnaryNode(source, unaryToken, expr);
|
||||
return new UnaryNode(unaryToken, expr);
|
||||
|
||||
case INCPREFIX:
|
||||
case DECPREFIX:
|
||||
@ -2749,7 +2779,7 @@ loop:
|
||||
final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
|
||||
|
||||
// Build up node.
|
||||
lhs = new TernaryNode(source, op, lhs, rhs, third);
|
||||
lhs = new TernaryNode(op, lhs, rhs, third);
|
||||
} else {
|
||||
// Skip operator.
|
||||
next();
|
||||
@ -2805,16 +2835,6 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a line number node at current position
|
||||
*/
|
||||
private LineNumberNode lineNumber() {
|
||||
if (env._debug_lines) {
|
||||
return new LineNumberNode(source, token, line);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[JavaScript Parsing]";
|
||||
@ -2835,11 +2855,11 @@ loop:
|
||||
}
|
||||
}
|
||||
|
||||
private void prependStatement(final Node statement) {
|
||||
private void prependStatement(final Statement statement) {
|
||||
lc.prependStatement(statement);
|
||||
}
|
||||
|
||||
private void appendStatement(final Node statement) {
|
||||
private void appendStatement(final Statement statement) {
|
||||
lc.appendStatement(statement);
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
/**
|
||||
* An AccessorProperty is the most generic property type. An AccessorProperty is
|
||||
* represented as fields in a ScriptObject class.
|
||||
*
|
||||
* @see SpillProperty
|
||||
*/
|
||||
public class AccessorProperty extends Property {
|
||||
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
@ -77,6 +75,7 @@ public class AccessorProperty extends Property {
|
||||
|
||||
private static final MethodType[] ACCESSOR_GETTER_TYPES = new MethodType[NOOF_TYPES];
|
||||
private static final MethodType[] ACCESSOR_SETTER_TYPES = new MethodType[NOOF_TYPES];
|
||||
private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
|
||||
|
||||
/** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
|
||||
private MethodHandle primitiveGetter;
|
||||
@ -285,7 +284,7 @@ public class AccessorProperty extends Property {
|
||||
"get");
|
||||
}
|
||||
|
||||
return getters[i];
|
||||
return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
|
||||
}
|
||||
|
||||
private Property getWiderProperty(final Class<?> type) {
|
||||
@ -327,6 +326,7 @@ public class AccessorProperty extends Property {
|
||||
final Class<?> forType = currentType == null ? type : currentType;
|
||||
|
||||
//if we are asking for an object setter, but are still a primitive type, we might try to box it
|
||||
MethodHandle mh;
|
||||
|
||||
if (needsInvalidator(i, ci)) {
|
||||
final Property newProperty = getWiderProperty(type);
|
||||
@ -335,12 +335,15 @@ public class AccessorProperty extends Property {
|
||||
final MethodHandle explodeTypeSetter = MH.filterArguments(widerSetter, 0, MH.insertArguments(REPLACE_MAP, 1, newMap, getKey(), currentType, type));
|
||||
if (currentType != null && currentType.isPrimitive() && type == Object.class) {
|
||||
//might try a box check on this to avoid widening field to object storage
|
||||
return createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter);
|
||||
mh = createGuardBoxedPrimitiveSetter(currentType, generateSetter(currentType, currentType), explodeTypeSetter);
|
||||
} else {
|
||||
mh = explodeTypeSetter;
|
||||
}
|
||||
return explodeTypeSetter;
|
||||
} else {
|
||||
mh = generateSetter(forType, type);
|
||||
}
|
||||
|
||||
return generateSetter(forType, type);
|
||||
return isSpill() ? MH.filterArguments(mh, 0, SPILLGETTER) : mh;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,7 +88,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
|
||||
|
||||
int weight = Type.typeFor(type.returnType()).getWeight();
|
||||
for (final Class<?> paramType : type.parameterArray()) {
|
||||
final int pweight = Type.typeFor(paramType).getWeight();
|
||||
final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized
|
||||
weight += pweight;
|
||||
}
|
||||
return weight;
|
||||
|
@ -69,5 +69,4 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
|
||||
return best(type).moreGenericThan(type);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -201,9 +201,6 @@ public final class Context {
|
||||
/** Current error manager. */
|
||||
private final ErrorManager errors;
|
||||
|
||||
/** Empty map used for seed map for JO objects */
|
||||
final PropertyMap emptyMap = PropertyMap.newEmptyMap(this);
|
||||
|
||||
private static final ClassLoader myLoader = Context.class.getClassLoader();
|
||||
private static final StructureLoader sharedLoader;
|
||||
|
||||
@ -414,7 +411,7 @@ public final class Context {
|
||||
return ScriptRuntime.apply(func, evalThis);
|
||||
}
|
||||
|
||||
private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
|
||||
private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
|
||||
if (srcStr.startsWith(prefix)) {
|
||||
final String resource = resourcePath + srcStr.substring(prefix.length());
|
||||
// NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
|
||||
@ -513,7 +510,7 @@ public final class Context {
|
||||
|
||||
/**
|
||||
* Lookup a Java class. This is used for JSR-223 stuff linking in from
|
||||
* {@link jdk.nashorn.internal.objects.NativeJava} and {@link jdk.nashorn.internal.runtime.NativeJavaPackage}
|
||||
* {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
|
||||
*
|
||||
* @param fullName full name of class to load
|
||||
*
|
||||
@ -762,10 +759,10 @@ public final class Context {
|
||||
final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
|
||||
final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
|
||||
|
||||
final Compiler compiler = new Compiler(installer, functionNode, strict);
|
||||
final Compiler compiler = new Compiler(installer, strict);
|
||||
|
||||
compiler.compile();
|
||||
script = compiler.install();
|
||||
final FunctionNode newFunctionNode = compiler.compile(functionNode);
|
||||
script = compiler.install(newFunctionNode);
|
||||
|
||||
if (global != null) {
|
||||
global.cacheClass(source, script);
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ScriptObject.isArray;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -41,7 +41,6 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
*
|
||||
* @see PropertyMap
|
||||
* @see AccessorProperty
|
||||
* @see SpillProperty
|
||||
* @see UserAccessorProperty
|
||||
*/
|
||||
public abstract class Property {
|
||||
@ -64,7 +63,7 @@ public abstract class Property {
|
||||
|
||||
private static final int MODIFY_MASK = 0b0000_0000_1111;
|
||||
|
||||
/** Is this a spill property? See {@link SpillProperty} */
|
||||
/** Is this a spill property? See {@link AccessorProperty} */
|
||||
public static final int IS_SPILL = 0b0000_0001_0000;
|
||||
|
||||
/** Is this a function parameter? */
|
||||
@ -88,7 +87,7 @@ public abstract class Property {
|
||||
/** Property flags. */
|
||||
protected int flags;
|
||||
|
||||
/** Property field number or spill slot */
|
||||
/** Property field number or spill slot. */
|
||||
private final int slot;
|
||||
|
||||
/**
|
||||
@ -248,7 +247,7 @@ public abstract class Property {
|
||||
* Does this property use any slots in the spill array described in
|
||||
* {@link Property#isSpill}? In that case how many. Currently a property
|
||||
* only uses max one spill slot, but this may change in future representations
|
||||
* Only {@link SpillProperty} instances use spill slots
|
||||
* Only {@link AccessorProperty} instances use spill slots
|
||||
*
|
||||
* @return number of spill slots a property is using
|
||||
*/
|
||||
@ -344,6 +343,14 @@ public abstract class Property {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field number or spill slot
|
||||
* @return number/slot, -1 if none exists
|
||||
*/
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method for retrieving the setter for the property. We do not know
|
||||
* anything about the internal representation when we request the setter, we only
|
||||
@ -388,14 +395,6 @@ public abstract class Property {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field number or spill slot
|
||||
* @return number/slot, -1 if none exists
|
||||
*/
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final Class<?> type = getCurrentType();
|
||||
|
@ -110,7 +110,7 @@ public final class PropertyHashMap implements Map <String, Property> {
|
||||
private static final int LIST_THRESHOLD = 8;
|
||||
|
||||
/** Initial map. */
|
||||
public static final PropertyHashMap EMPTY_MAP = new PropertyHashMap();
|
||||
public static final PropertyHashMap EMPTY_HASHMAP = new PropertyHashMap();
|
||||
|
||||
/** Number of properties in the map. */
|
||||
private final int size;
|
||||
@ -246,7 +246,7 @@ public final class PropertyHashMap implements Map <String, Property> {
|
||||
}
|
||||
} else if (findElement(list, key) != null) {
|
||||
final int newSize = size - 1;
|
||||
return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_MAP;
|
||||
return newSize != 0 ? new PropertyHashMap(newSize, null, removeFromList(list, key)) : EMPTY_HASHMAP;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_MAP;
|
||||
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
@ -49,29 +49,27 @@ import java.util.WeakHashMap;
|
||||
* will return a new map.
|
||||
*/
|
||||
public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
/** Is this a prototype PropertyMap? */
|
||||
public static final int IS_PROTOTYPE = 0b0000_0001;
|
||||
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
|
||||
public static final int NOT_EXTENSIBLE = 0b0000_0010;
|
||||
public static final int NOT_EXTENSIBLE = 0b0000_0001;
|
||||
/** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */
|
||||
private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111;
|
||||
/** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */
|
||||
public static final int IS_LISTENER_ADDED = 0b0001_0000;
|
||||
|
||||
/** Empty map used for seed map for JO$ objects */
|
||||
private static final PropertyMap EMPTY_MAP = new PropertyMap(EMPTY_HASHMAP);
|
||||
|
||||
/** Map status flags. */
|
||||
private int flags;
|
||||
|
||||
/** Class of object referenced.*/
|
||||
private final Class<?> structure;
|
||||
|
||||
/** Context associated with this {@link PropertyMap}. */
|
||||
private final Context context;
|
||||
|
||||
/** Map of properties. */
|
||||
private final PropertyHashMap properties;
|
||||
|
||||
/** objects proto. */
|
||||
private ScriptObject proto;
|
||||
/** Number of fields in use. */
|
||||
private int fieldCount;
|
||||
|
||||
/** Number of fields available. */
|
||||
private int fieldMaximum;
|
||||
|
||||
/** Length of spill in use. */
|
||||
private int spillLength;
|
||||
@ -91,21 +89,30 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param structure Class the map's {@link AccessorProperty}s apply to.
|
||||
* @param context Context associated with this {@link PropertyMap}.
|
||||
* @param properties A {@link PropertyHashMap} with initial contents.
|
||||
* @param properties A {@link PropertyHashMap} with initial contents.
|
||||
* @param fieldCount Number of fields in use.
|
||||
* @param fieldMaximum Number of fields available.
|
||||
*/
|
||||
PropertyMap(final Class<?> structure, final Context context, final PropertyHashMap properties) {
|
||||
this.structure = structure;
|
||||
this.context = context;
|
||||
this.properties = properties;
|
||||
this.hashCode = computeHashCode();
|
||||
private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) {
|
||||
this.properties = properties;
|
||||
this.hashCode = computeHashCode();
|
||||
this.fieldCount = fieldCount;
|
||||
this.fieldMaximum = fieldMaximum;
|
||||
|
||||
if (Context.DEBUG) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param properties A {@link PropertyHashMap} with initial contents.
|
||||
*/
|
||||
private PropertyMap(final PropertyHashMap properties) {
|
||||
this(properties, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning constructor.
|
||||
*
|
||||
@ -113,13 +120,12 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @param properties A {@link PropertyHashMap} with a new set of properties.
|
||||
*/
|
||||
private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
|
||||
this.structure = propertyMap.structure;
|
||||
this.context = propertyMap.context;
|
||||
this.properties = properties;
|
||||
this.flags = propertyMap.getClonedFlags();
|
||||
this.proto = propertyMap.proto;
|
||||
this.spillLength = propertyMap.spillLength;
|
||||
this.hashCode = computeHashCode();
|
||||
this.properties = properties;
|
||||
this.flags = propertyMap.getClonedFlags();
|
||||
this.spillLength = propertyMap.spillLength;
|
||||
this.fieldCount = propertyMap.fieldCount;
|
||||
this.fieldMaximum = propertyMap.fieldMaximum;
|
||||
this.hashCode = computeHashCode();
|
||||
|
||||
if (Context.DEBUG) {
|
||||
count++;
|
||||
@ -127,6 +133,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloning constructor.
|
||||
*
|
||||
* @param propertyMap Existing property map.
|
||||
*/
|
||||
private PropertyMap(final PropertyMap propertyMap) {
|
||||
this(propertyMap, propertyMap.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates this PropertyMap instance. This is used by nasgen generated
|
||||
* prototype and constructor classes. {@link PropertyMap} used for singletons
|
||||
@ -138,7 +153,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @return Duplicated {@link PropertyMap}.
|
||||
*/
|
||||
public PropertyMap duplicate() {
|
||||
return new PropertyMap(this.structure, this.context, this.properties);
|
||||
return new PropertyMap(this.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,20 +161,20 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
*
|
||||
* @param structure Class the map's {@link AccessorProperty}s apply to.
|
||||
* @param properties Collection of initial properties.
|
||||
* @param fieldCount Number of fields in use.
|
||||
* @param fieldMaximum Number of fields available.
|
||||
*
|
||||
* @return New {@link PropertyMap}.
|
||||
*/
|
||||
public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties) {
|
||||
final Context context = Context.fromClass(structure);
|
||||
|
||||
public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties, final int fieldCount, final int fieldMaximum) {
|
||||
// Reduce the number of empty maps in the context.
|
||||
if (structure == jdk.nashorn.internal.scripts.JO.class) {
|
||||
return context.emptyMap;
|
||||
return EMPTY_MAP;
|
||||
}
|
||||
|
||||
PropertyHashMap newProperties = EMPTY_MAP.immutableAdd(properties);
|
||||
PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
|
||||
|
||||
return new PropertyMap(structure, context, newProperties);
|
||||
return new PropertyMap(newProperties, fieldCount, fieldMaximum);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,7 +185,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @return New {@link PropertyMap}.
|
||||
*/
|
||||
public static PropertyMap newMap(final Class<?> structure) {
|
||||
return newMap(structure, null);
|
||||
return newMap(structure, null, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +195,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @return New empty {@link PropertyMap}.
|
||||
*/
|
||||
public static PropertyMap newEmptyMap(final Context context) {
|
||||
return new PropertyMap(jdk.nashorn.internal.scripts.JO.class, context, EMPTY_MAP);
|
||||
return new PropertyMap(EMPTY_HASHMAP);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,11 +210,12 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
/**
|
||||
* Return a SwitchPoint used to track changes of a property in a prototype.
|
||||
*
|
||||
* @param key {@link Property} key.
|
||||
* @param proto Object prototype.
|
||||
* @param key {@link Property} key.
|
||||
*
|
||||
* @return A shared {@link SwitchPoint} for the property.
|
||||
*/
|
||||
public SwitchPoint getProtoGetSwitchPoint(final String key) {
|
||||
public SwitchPoint getProtoGetSwitchPoint(final ScriptObject proto, final String key) {
|
||||
if (proto == null) {
|
||||
return null;
|
||||
}
|
||||
@ -295,6 +311,11 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
final PropertyHashMap newProperties = properties.immutableAdd(property);
|
||||
newMap = new PropertyMap(this, newProperties);
|
||||
addToHistory(property, newMap);
|
||||
|
||||
if(!property.isSpill()) {
|
||||
newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1);
|
||||
}
|
||||
|
||||
newMap.spillLength += property.getSpillCount();
|
||||
}
|
||||
|
||||
@ -355,7 +376,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted";
|
||||
|
||||
newMap.flags = getClonedFlags();
|
||||
newMap.proto = proto;
|
||||
|
||||
/*
|
||||
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
|
||||
@ -411,7 +431,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @return New map with {@link #NOT_EXTENSIBLE} flag set.
|
||||
*/
|
||||
PropertyMap preventExtensions() {
|
||||
final PropertyMap newMap = new PropertyMap(this, this.properties);
|
||||
final PropertyMap newMap = new PropertyMap(this);
|
||||
newMap.flags |= NOT_EXTENSIBLE;
|
||||
return newMap;
|
||||
}
|
||||
@ -423,7 +443,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* {@link Property#NOT_CONFIGURABLE} set.
|
||||
*/
|
||||
PropertyMap seal() {
|
||||
PropertyHashMap newProperties = EMPTY_MAP;
|
||||
PropertyHashMap newProperties = EMPTY_HASHMAP;
|
||||
|
||||
for (final Property oldProperty : properties.getProperties()) {
|
||||
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
|
||||
@ -442,7 +462,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set.
|
||||
*/
|
||||
PropertyMap freeze() {
|
||||
PropertyHashMap newProperties = EMPTY_MAP;
|
||||
PropertyHashMap newProperties = EMPTY_HASHMAP;
|
||||
|
||||
for (Property oldProperty : properties.getProperties()) {
|
||||
int propertyFlags = Property.NOT_CONFIGURABLE;
|
||||
@ -578,11 +598,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
* @return Computed hash code.
|
||||
*/
|
||||
private int computeHashCode() {
|
||||
int hash = structure.hashCode();
|
||||
|
||||
if (proto != null) {
|
||||
hash ^= proto.hashCode();
|
||||
}
|
||||
int hash = 0;
|
||||
|
||||
for (final Property property : getProperties()) {
|
||||
hash = hash << 7 ^ hash >> 7;
|
||||
@ -605,9 +621,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
|
||||
final PropertyMap otherMap = (PropertyMap)other;
|
||||
|
||||
if (structure != otherMap.structure ||
|
||||
proto != otherMap.proto ||
|
||||
properties.size() != otherMap.properties.size()) {
|
||||
if (properties.size() != otherMap.properties.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -658,31 +672,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
return new PropertyMapIterator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return map's {@link Context}.
|
||||
*
|
||||
* @return The {@link Context} where the map originated.
|
||||
*/
|
||||
Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this map is a prototype
|
||||
*
|
||||
* @return {@code true} if is prototype
|
||||
*/
|
||||
public boolean isPrototype() {
|
||||
return (flags & IS_PROTOTYPE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this map as having a prototype.
|
||||
*/
|
||||
private void setIsPrototype() {
|
||||
flags |= IS_PROTOTYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a {@link PropertyListener} has been added to this map.
|
||||
*
|
||||
@ -720,6 +709,22 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
boolean isFrozen() {
|
||||
return !isExtensible() && allFrozen();
|
||||
}
|
||||
/**
|
||||
* Get the number of fields allocated for this {@link PropertyMap}.
|
||||
*
|
||||
* @return Number of fields allocated.
|
||||
*/
|
||||
int getFieldCount() {
|
||||
return fieldCount;
|
||||
}
|
||||
/**
|
||||
* Get maximum number of fields available for this {@link PropertyMap}.
|
||||
*
|
||||
* @return Number of fields available.
|
||||
*/
|
||||
int getFieldMaximum() {
|
||||
return fieldMaximum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of spill area associated with this {@link PropertyMap}.
|
||||
@ -731,24 +736,14 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prototype of objects associated with this {@link PropertyMap}.
|
||||
* Change the prototype of objects associated with this {@link PropertyMap}.
|
||||
*
|
||||
* @return Prototype object.
|
||||
*/
|
||||
ScriptObject getProto() {
|
||||
return proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prototype of objects associated with this {@link PropertyMap}.
|
||||
*
|
||||
* @param newProto Prototype object to use.
|
||||
* @param oldProto Current prototype object.
|
||||
* @param newProto New prototype object to replace oldProto.
|
||||
*
|
||||
* @return New {@link PropertyMap} with prototype changed.
|
||||
*/
|
||||
PropertyMap setProto(final ScriptObject newProto) {
|
||||
final ScriptObject oldProto = this.proto;
|
||||
|
||||
PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) {
|
||||
if (oldProto == newProto) {
|
||||
return this;
|
||||
}
|
||||
@ -761,19 +756,10 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
if (Context.DEBUG) {
|
||||
incrementSetProtoNewMapCount();
|
||||
}
|
||||
final PropertyMap newMap = new PropertyMap(this, this.properties);
|
||||
|
||||
final PropertyMap newMap = new PropertyMap(this);
|
||||
addToProtoHistory(newProto, newMap);
|
||||
|
||||
newMap.proto = newProto;
|
||||
|
||||
if (oldProto != null && newMap.isListenerAdded()) {
|
||||
oldProto.removePropertyListener(newMap);
|
||||
}
|
||||
|
||||
if (newProto != null) {
|
||||
newProto.getMap().setIsPrototype();
|
||||
}
|
||||
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@ -927,4 +913,3 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
|
||||
setProtoNewMapCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.FunctionSignature;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
|
||||
import jdk.nashorn.internal.parser.Token;
|
||||
@ -148,10 +151,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
|
||||
if (functionNode.isLazy()) {
|
||||
Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
|
||||
final Compiler compiler = new Compiler(installer, functionNode);
|
||||
functionNode = compiler.compile();
|
||||
final Compiler compiler = new Compiler(installer);
|
||||
functionNode = compiler.compile(functionNode);
|
||||
assert !functionNode.isLazy();
|
||||
compiler.install();
|
||||
compiler.install(functionNode);
|
||||
|
||||
// we don't need to update any flags - varArgs and needsCallee are instrincic
|
||||
// in the function world we need to get a destination node from the compile instead
|
||||
@ -164,23 +167,118 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
|
||||
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
|
||||
|
||||
// code exists - look it up and add it into the automatically sorted invoker list
|
||||
code.add(
|
||||
new CompiledFunction(
|
||||
MH.findStatic(
|
||||
LOOKUP,
|
||||
functionNode.getCompileUnit().getCode(),
|
||||
functionNode.getName(),
|
||||
new FunctionSignature(functionNode).
|
||||
getMethodType())));
|
||||
addCode(functionNode, null, null);
|
||||
}
|
||||
|
||||
private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
|
||||
final MethodHandle target =
|
||||
MH.findStatic(
|
||||
LOOKUP,
|
||||
fn.getCompileUnit().getCode(),
|
||||
fn.getName(),
|
||||
new FunctionSignature(fn).
|
||||
getMethodType());
|
||||
MethodHandle mh = target;
|
||||
if (guard != null) {
|
||||
try {
|
||||
mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
final CompiledFunction cf = new CompiledFunction(mh);
|
||||
code.add(cf);
|
||||
|
||||
return cf.getInvoker();
|
||||
}
|
||||
|
||||
private static Type runtimeType(final Object arg) {
|
||||
if (arg == null) {
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
final Class<?> clazz = arg.getClass();
|
||||
assert !clazz.isPrimitive() : "always boxed";
|
||||
if (clazz == Double.class) {
|
||||
return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER;
|
||||
} else if (clazz == Integer.class) {
|
||||
return Type.INT;
|
||||
} else if (clazz == Long.class) {
|
||||
return Type.LONG;
|
||||
} else if (clazz == String.class) {
|
||||
return Type.STRING;
|
||||
}
|
||||
return Type.OBJECT;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
|
||||
//System.err.println("Param type guard " + Arrays.asList(args));
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
|
||||
|
||||
@Override
|
||||
MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
|
||||
final MethodHandle mh = super.getBestInvoker(callSiteType, args);
|
||||
if (code.isLessSpecificThan(callSiteType)) {
|
||||
// opportunity for code specialization - we can regenerate a better version of this method
|
||||
|
||||
if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
|
||||
return mh;
|
||||
}
|
||||
return mh;
|
||||
|
||||
final FunctionNode snapshot = functionNode.getSnapshot();
|
||||
if (snapshot == null) {
|
||||
return mh;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
//classes known at runtime
|
||||
final LinkedList<Type> runtimeArgs = new LinkedList<>();
|
||||
for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
|
||||
runtimeArgs.addLast(runtimeType(args[i]));
|
||||
}
|
||||
|
||||
//classes known at compile time
|
||||
final LinkedList<Type> compileTimeArgs = new LinkedList<>();
|
||||
for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
|
||||
compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
|
||||
}
|
||||
|
||||
//the classes known at compile time are a safe to generate as primitives without parameter guards
|
||||
//the classes known at runtime are safe to generate as primitives IFF there are parameter guards
|
||||
MethodHandle guard = null;
|
||||
for (i = 0; i < compileTimeArgs.size(); i++) {
|
||||
final Type runtimeType = runtimeArgs.get(i);
|
||||
final Type compileType = compileTimeArgs.get(i);
|
||||
|
||||
if (compileType.isObject() && !runtimeType.isObject()) {
|
||||
if (guard == null) {
|
||||
guard = PARAM_TYPE_GUARD;
|
||||
guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
|
||||
|
||||
assert snapshot != null;
|
||||
assert snapshot != functionNode;
|
||||
|
||||
final Compiler compiler = new Compiler(installer);
|
||||
final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
|
||||
|
||||
compiler.install(compiledSnapshot);
|
||||
|
||||
final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
|
||||
|
||||
return nmh;
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,9 +26,13 @@
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import jdk.nashorn.internal.codegen.Namespace;
|
||||
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
|
||||
import jdk.nashorn.internal.runtime.options.KeyValueOption;
|
||||
@ -136,6 +140,9 @@ public final class ScriptEnvironment {
|
||||
/** Print resulting bytecode for script */
|
||||
public final boolean _print_code;
|
||||
|
||||
/** Print memory usage for IR after each phase */
|
||||
public final boolean _print_mem_usage;
|
||||
|
||||
/** Print function will no print newline characters */
|
||||
public final boolean _print_no_newline;
|
||||
|
||||
@ -151,6 +158,9 @@ public final class ScriptEnvironment {
|
||||
/** is this environment in scripting mode? */
|
||||
public final boolean _scripting;
|
||||
|
||||
/** is the JIT allowed to specializ calls based on callsite types? */
|
||||
public final Set<String> _specialize_calls;
|
||||
|
||||
/** is this environment in strict mode? */
|
||||
public final boolean _strict;
|
||||
|
||||
@ -204,6 +214,7 @@ public final class ScriptEnvironment {
|
||||
_print_ast = options.getBoolean("print.ast");
|
||||
_print_lower_ast = options.getBoolean("print.lower.ast");
|
||||
_print_code = options.getBoolean("print.code");
|
||||
_print_mem_usage = options.getBoolean("print.mem.usage");
|
||||
_print_no_newline = options.getBoolean("print.no.newline");
|
||||
_print_parse = options.getBoolean("print.parse");
|
||||
_print_lower_parse = options.getBoolean("print.lower.parse");
|
||||
@ -213,6 +224,17 @@ public final class ScriptEnvironment {
|
||||
_version = options.getBoolean("version");
|
||||
_verify_code = options.getBoolean("verify.code");
|
||||
|
||||
final String specialize = options.getString("specialize.calls");
|
||||
if (specialize == null) {
|
||||
_specialize_calls = null;
|
||||
} else {
|
||||
_specialize_calls = new HashSet<>();
|
||||
final StringTokenizer st = new StringTokenizer(specialize, ",");
|
||||
while (st.hasMoreElements()) {
|
||||
_specialize_calls.add(st.nextToken());
|
||||
}
|
||||
}
|
||||
|
||||
int callSiteFlags = 0;
|
||||
if (options.getBoolean("profile.callsites")) {
|
||||
callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
|
||||
@ -246,6 +268,18 @@ public final class ScriptEnvironment {
|
||||
this._locale = Locale.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we specialize a particular method name?
|
||||
* @param functionName method name
|
||||
* @return true if we are allowed to generate versions of this method
|
||||
*/
|
||||
public boolean canSpecialize(final String functionName) {
|
||||
if (_specialize_calls == null) {
|
||||
return false;
|
||||
}
|
||||
return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output stream for this environment
|
||||
* @return output print writer
|
||||
|
@ -104,34 +104,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
/** Per ScriptObject flag - is this an arguments object? */
|
||||
public static final int IS_ARGUMENTS = 0b0000_0100;
|
||||
|
||||
/** Is this a prototype PropertyMap? */
|
||||
public static final int IS_PROTOTYPE = 0b0000_1000;
|
||||
|
||||
/** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
|
||||
public static final int SPILL_RATE = 8;
|
||||
|
||||
/** Map to property information and accessor functions. Ordered by insertion. */
|
||||
private PropertyMap map;
|
||||
|
||||
/** objects proto. */
|
||||
private ScriptObject proto;
|
||||
|
||||
/** Context of the object, lazily cached. */
|
||||
private Context context;
|
||||
|
||||
/** Object flags. */
|
||||
private int flags;
|
||||
|
||||
/** Area for properties added to object after instantiation, see {@link SpillProperty} */
|
||||
/** Area for properties added to object after instantiation, see {@link AccessorProperty} */
|
||||
public Object[] spill;
|
||||
|
||||
/** Local embed area position 0 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
|
||||
public Object embed0;
|
||||
|
||||
/** Local embed area position 1 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
|
||||
public Object embed1;
|
||||
|
||||
/** Local embed area position 2 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
|
||||
public Object embed2;
|
||||
|
||||
/** Local embed area position 3 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
|
||||
public Object embed3;
|
||||
|
||||
/** Indexed array data. */
|
||||
private ArrayData arrayData;
|
||||
|
||||
static final MethodHandle SETEMBED = findOwnMH("setEmbed", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, int.class, Object.class, Object.class);
|
||||
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
|
||||
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
|
||||
static final MethodHandle SETSPILLWITHNEW = findOwnMH("setSpillWithNew", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
|
||||
static final MethodHandle SETSPILLWITHGROW = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);
|
||||
@ -665,9 +662,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
if (deep) {
|
||||
final ScriptObject proto = getProto();
|
||||
if(proto != null) {
|
||||
return proto.findProperty(key, deep, stopOnNonScope, start);
|
||||
final ScriptObject myProto = getProto();
|
||||
if (myProto != null) {
|
||||
return myProto.findProperty(key, deep, stopOnNonScope, start);
|
||||
}
|
||||
}
|
||||
|
||||
@ -783,8 +780,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
// delete getter and setter function references so that we don't leak
|
||||
if (property instanceof UserAccessorProperty) {
|
||||
final UserAccessorProperty uc = (UserAccessorProperty) property;
|
||||
setEmbedOrSpill(uc.getGetterSlot(), null);
|
||||
setEmbedOrSpill(uc.getSetterSlot(), null);
|
||||
setSpill(uc.getGetterSlot(), null);
|
||||
setSpill(uc.getSetterSlot(), null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -809,7 +806,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
int getterSlot = uc.getGetterSlot();
|
||||
// clear the old getter and set the new getter
|
||||
setEmbedOrSpill(getterSlot, getter);
|
||||
setSpill(getterSlot, getter);
|
||||
// if getter function is null, flag the slot to be negative (less by 1)
|
||||
if (getter == null) {
|
||||
getterSlot = -getterSlot - 1;
|
||||
@ -817,7 +814,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
|
||||
int setterSlot = uc.getSetterSlot();
|
||||
// clear the old setter and set the new setter
|
||||
setEmbedOrSpill(setterSlot, setter);
|
||||
setSpill(setterSlot, setter);
|
||||
// if setter function is null, flag the slot to be negative (less by 1)
|
||||
if (setter == null) {
|
||||
setterSlot = -setterSlot - 1;
|
||||
@ -973,9 +970,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @param bindName null or name to bind to second argument (property not found method.)
|
||||
*
|
||||
* @return value of property as a MethodHandle or null.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
|
||||
return getCallMethodHandle(getObjectValue(find), type, bindName);
|
||||
}
|
||||
@ -1056,8 +1051,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* Return the current context from the object's map.
|
||||
* @return Current context.
|
||||
*/
|
||||
final Context getContext() {
|
||||
return getMap().getContext();
|
||||
protected final Context getContext() {
|
||||
if (context == null) {
|
||||
context = Context.fromClass(getClass());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1097,44 +1095,30 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @return __proto__ object.
|
||||
*/
|
||||
public final ScriptObject getProto() {
|
||||
return getMap().getProto();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a prototype
|
||||
* @return true if {@link PropertyMap#isPrototype()} is true for this ScriptObject
|
||||
*/
|
||||
public final boolean isPrototype() {
|
||||
return getMap().isPrototype();
|
||||
return proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the __proto__ of an object.
|
||||
* @param newProto new __proto__ to set.
|
||||
*/
|
||||
public final void setProto(final ScriptObject newProto) {
|
||||
PropertyMap oldMap = getMap();
|
||||
ScriptObject oldProto = getProto();
|
||||
public synchronized final void setProto(final ScriptObject newProto) {
|
||||
final ScriptObject oldProto = proto;
|
||||
map = map.changeProto(oldProto, newProto);
|
||||
|
||||
while (oldProto != newProto) {
|
||||
final PropertyMap newMap = oldMap.setProto(newProto);
|
||||
if (newProto != null) {
|
||||
newProto.setIsPrototype();
|
||||
}
|
||||
|
||||
if (!compareAndSetMap(oldMap, newMap)) {
|
||||
oldMap = getMap();
|
||||
oldProto = getProto();
|
||||
} else {
|
||||
if (isPrototype()) {
|
||||
proto = newProto;
|
||||
|
||||
if (oldProto != null) {
|
||||
oldProto.removePropertyListener(this);
|
||||
}
|
||||
if (isPrototype()) {
|
||||
if (oldProto != null) {
|
||||
oldProto.removePropertyListener(this);
|
||||
}
|
||||
|
||||
if (newProto != null) {
|
||||
newProto.addPropertyListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
if (newProto != null) {
|
||||
newProto.addPropertyListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1326,6 +1310,25 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
flags |= IS_ARGUMENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this object is a prototype
|
||||
*
|
||||
* @return {@code true} if is prototype
|
||||
*/
|
||||
public boolean isPrototype() {
|
||||
return (flags & IS_PROTOTYPE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag this object as having a prototype.
|
||||
*/
|
||||
public void setIsPrototype() {
|
||||
if (proto != null && !isPrototype()) {
|
||||
proto.addPropertyListener(this);
|
||||
}
|
||||
flags |= IS_PROTOTYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ArrayData} for this ScriptObject if it is an array
|
||||
* @return array data
|
||||
@ -1719,11 +1722,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
if (!property.hasGetterFunction()) {
|
||||
methodHandle = bindTo(methodHandle, prototype);
|
||||
}
|
||||
return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(name), guard);
|
||||
return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(proto, name), guard);
|
||||
}
|
||||
|
||||
assert !NashornCallSiteDescriptor.isFastScope(desc);
|
||||
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(name), guard);
|
||||
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
|
||||
}
|
||||
|
||||
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
|
||||
@ -1822,27 +1825,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
|
||||
final PropertyMap myMap = getMap();
|
||||
return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(myMap));
|
||||
return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(myMap));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void setEmbed(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final int i, final Object self, final Object value) throws Throwable {
|
||||
private static void setField(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final Object self, final Object value) throws Throwable {
|
||||
final ScriptObject obj = (ScriptObject)self;
|
||||
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
|
||||
obj.useEmbed(i);
|
||||
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
|
||||
if (!obj.isExtensible()) {
|
||||
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
|
||||
} else if (obj.compareAndSetMap(oldMap, newMap)) {
|
||||
setter.invokeExact(self, value);
|
||||
} else {
|
||||
obj.set(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND), value, isStrict);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void setSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) {
|
||||
final ScriptObject obj = (ScriptObject)self;
|
||||
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
|
||||
if (obj.trySetSpill(desc, oldMap, newMap, value)) {
|
||||
obj.spill[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean trySetEmbedOrSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
|
||||
private boolean trySetSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
|
||||
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
|
||||
if (!isExtensible() && isStrict) {
|
||||
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(this));
|
||||
@ -1964,7 +1971,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
methodHandle = bindTo(methodHandle, UNDEFINED);
|
||||
}
|
||||
return new GuardedInvocation(methodHandle,
|
||||
find.isInherited()? getMap().getProtoGetSwitchPoint(NO_SUCH_PROPERTY_NAME) : null,
|
||||
find.isInherited()? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null,
|
||||
getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class), find.getOwner(), func));
|
||||
}
|
||||
}
|
||||
@ -1995,7 +2002,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
}
|
||||
|
||||
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
|
||||
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap()));
|
||||
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
|
||||
}
|
||||
|
||||
private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> {
|
||||
@ -2070,36 +2077,39 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
* @return Added property.
|
||||
*/
|
||||
private Property addSpillProperty(final String key, final int propertyFlags) {
|
||||
int i = findEmbed();
|
||||
Property spillProperty;
|
||||
int fieldCount = getMap().getFieldCount();
|
||||
int fieldMaximum = getMap().getFieldMaximum();
|
||||
Property property;
|
||||
|
||||
if (i >= EMBED_SIZE) {
|
||||
i = getMap().getSpillLength();
|
||||
if (fieldCount < fieldMaximum) {
|
||||
property = new AccessorProperty(key, propertyFlags & ~Property.IS_SPILL, getClass(), fieldCount);
|
||||
notifyPropertyAdded(this, property);
|
||||
property = addOwnProperty(property);
|
||||
} else {
|
||||
int i = getMap().getSpillLength();
|
||||
MethodHandle getter = MH.arrayElementGetter(Object[].class);
|
||||
MethodHandle setter = MH.arrayElementSetter(Object[].class);
|
||||
getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE);
|
||||
setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE);
|
||||
spillProperty = new SpillProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
|
||||
notifyPropertyAdded(this, spillProperty);
|
||||
spillProperty = addOwnProperty(spillProperty);
|
||||
i = spillProperty.getSlot();
|
||||
property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
|
||||
notifyPropertyAdded(this, property);
|
||||
property = addOwnProperty(property);
|
||||
i = property.getSlot();
|
||||
|
||||
final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE;
|
||||
final Object[] newSpill = new Object[newLength];
|
||||
|
||||
if (spill != null) {
|
||||
System.arraycopy(spill, 0, newSpill, 0, spill.length);
|
||||
if (spill == null || newLength > spill.length) {
|
||||
final Object[] newSpill = new Object[newLength];
|
||||
|
||||
if (spill != null) {
|
||||
System.arraycopy(spill, 0, newSpill, 0, spill.length);
|
||||
}
|
||||
|
||||
spill = newSpill;
|
||||
}
|
||||
|
||||
spill = newSpill;
|
||||
} else {
|
||||
useEmbed(i);
|
||||
spillProperty = new SpillProperty(key, propertyFlags, i, GET_EMBED[i], SET_EMBED[i]);
|
||||
notifyPropertyAdded(this, spillProperty);
|
||||
spillProperty = addOwnProperty(spillProperty);
|
||||
}
|
||||
|
||||
return spillProperty;
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
@ -3158,41 +3168,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Embed management
|
||||
*/
|
||||
|
||||
/** Number of embed slots */
|
||||
public static final int EMBED_SIZE = 4;
|
||||
/** Embed offset */
|
||||
public static final int EMBED_OFFSET = 32 - EMBED_SIZE;
|
||||
|
||||
static final MethodHandle[] GET_EMBED;
|
||||
static final MethodHandle[] SET_EMBED;
|
||||
|
||||
static {
|
||||
GET_EMBED = new MethodHandle[EMBED_SIZE];
|
||||
SET_EMBED = new MethodHandle[EMBED_SIZE];
|
||||
|
||||
for (int i = 0; i < EMBED_SIZE; i++) {
|
||||
final String name = "embed" + i;
|
||||
GET_EMBED[i] = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.GET_OBJECT_TYPE);
|
||||
SET_EMBED[i] = MH.asType(MH.setter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.SET_OBJECT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
void useEmbed(final int i) {
|
||||
flags |= 1 << (EMBED_OFFSET + i);
|
||||
}
|
||||
|
||||
int findEmbed() {
|
||||
final int bits = ~(flags >>> EMBED_OFFSET);
|
||||
final int least = bits ^ -bits;
|
||||
final int index = Integer.numberOfTrailingZeros(least) - 1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a new UserAccessorProperty property. getter and setter functions are stored in
|
||||
* this ScriptObject and slot values are used in property object.
|
||||
@ -3200,26 +3175,16 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
private UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
|
||||
int oldSpillLength = getMap().getSpillLength();
|
||||
|
||||
int getterSlot = findEmbed();
|
||||
if (getterSlot >= EMBED_SIZE) {
|
||||
getterSlot = oldSpillLength + EMBED_SIZE;
|
||||
++oldSpillLength;
|
||||
} else {
|
||||
useEmbed(getterSlot);
|
||||
}
|
||||
setEmbedOrSpill(getterSlot, getter);
|
||||
int getterSlot = oldSpillLength++;
|
||||
setSpill(getterSlot, getter);
|
||||
// if getter function is null, flag the slot to be negative (less by 1)
|
||||
if (getter == null) {
|
||||
getterSlot = -getterSlot - 1;
|
||||
}
|
||||
|
||||
int setterSlot = findEmbed();
|
||||
if (setterSlot >= EMBED_SIZE) {
|
||||
setterSlot = oldSpillLength + EMBED_SIZE;
|
||||
} else {
|
||||
useEmbed(setterSlot);
|
||||
}
|
||||
setEmbedOrSpill(setterSlot, setter);
|
||||
int setterSlot = oldSpillLength++;
|
||||
|
||||
setSpill(setterSlot, setter);
|
||||
// if setter function is null, flag the slot to be negative (less by 1)
|
||||
if (setter == null) {
|
||||
setterSlot = -setterSlot - 1;
|
||||
@ -3228,56 +3193,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot);
|
||||
}
|
||||
|
||||
private void setEmbedOrSpill(final int slot, final Object value) {
|
||||
switch (slot) {
|
||||
case 0:
|
||||
embed0 = value;
|
||||
break;
|
||||
case 1:
|
||||
embed1 = value;
|
||||
break;
|
||||
case 2:
|
||||
embed2 = value;
|
||||
break;
|
||||
case 3:
|
||||
embed3 = value;
|
||||
break;
|
||||
default:
|
||||
if (slot >= 0) {
|
||||
final int index = (slot - EMBED_SIZE);
|
||||
if (spill == null) {
|
||||
// create new spill.
|
||||
spill = new Object[Math.max(index + 1, SPILL_RATE)];
|
||||
} else if (index >= spill.length) {
|
||||
// grow spill as needed
|
||||
final Object[] newSpill = new Object[index + 1];
|
||||
System.arraycopy(spill, 0, newSpill, 0, spill.length);
|
||||
spill = newSpill;
|
||||
}
|
||||
|
||||
spill[index] = value;
|
||||
private void setSpill(final int slot, final Object value) {
|
||||
if (slot >= 0) {
|
||||
final int index = slot;
|
||||
if (spill == null) {
|
||||
// create new spill.
|
||||
spill = new Object[Math.max(index + 1, SPILL_RATE)];
|
||||
} else if (index >= spill.length) {
|
||||
// grow spill as needed
|
||||
final Object[] newSpill = new Object[index + 1];
|
||||
System.arraycopy(spill, 0, newSpill, 0, spill.length);
|
||||
spill = newSpill;
|
||||
}
|
||||
break;
|
||||
|
||||
spill[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// user accessors are either stored in embed fields or spill array slots
|
||||
// get the accessor value using slot number. Note that slot is either embed
|
||||
// field number or (spill array index + embedSize).
|
||||
Object getEmbedOrSpill(final int slot) {
|
||||
switch (slot) {
|
||||
case 0:
|
||||
return embed0;
|
||||
case 1:
|
||||
return embed1;
|
||||
case 2:
|
||||
return embed2;
|
||||
case 3:
|
||||
return embed3;
|
||||
default:
|
||||
final int index = (slot - EMBED_SIZE);
|
||||
return (index < 0 || (index >= spill.length)) ? null : spill[index];
|
||||
}
|
||||
// user accessors are either stored in spill array slots
|
||||
// get the accessor value using slot number. Note that slot is spill array index.
|
||||
Object getSpill(final int slot) {
|
||||
final int index = slot;
|
||||
return (index < 0 || (index >= spill.length)) ? null : spill[index];
|
||||
}
|
||||
|
||||
// User defined getter and setter are always called by "dyn:call". Note that the user
|
||||
@ -3287,7 +3224,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
@SuppressWarnings("unused")
|
||||
private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
|
||||
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
|
||||
final Object func = container.getEmbedOrSpill(slot);
|
||||
final Object func = container.getSpill(slot);
|
||||
|
||||
if (func instanceof ScriptFunction) {
|
||||
try {
|
||||
@ -3305,7 +3242,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
|
||||
@SuppressWarnings("unused")
|
||||
private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
|
||||
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
|
||||
final Object func = container.getEmbedOrSpill(slot);
|
||||
final Object func = container.getSpill(slot);
|
||||
|
||||
if (func instanceof ScriptFunction) {
|
||||
try {
|
||||
|
@ -166,18 +166,20 @@ final class SetMethodCreator {
|
||||
}
|
||||
|
||||
private SetMethod createNewPropertySetter() {
|
||||
final int nextEmbed = sobj.findEmbed();
|
||||
final SetMethod sm;
|
||||
if (nextEmbed >= ScriptObject.EMBED_SIZE) {
|
||||
sm = createNewSpillPropertySetter();
|
||||
} else {
|
||||
sm = createNewEmbedPropertySetter(nextEmbed);
|
||||
}
|
||||
|
||||
final SetMethod sm = map.getFieldCount() < map.getFieldMaximum() ? createNewFieldSetter() : createNewSpillPropertySetter();
|
||||
sobj.notifyPropertyAdded(sobj, sm.property);
|
||||
return sm;
|
||||
}
|
||||
|
||||
private SetMethod createNewFieldSetter() {
|
||||
final PropertyMap oldMap = getMap();
|
||||
final Property property = new AccessorProperty(getName(), 0, sobj.getClass(), oldMap.getFieldCount());
|
||||
final PropertyMap newMap = oldMap.addProperty(property);
|
||||
MethodHandle setter = MH.insertArguments(ScriptObject.SETFIELD, 0, desc, oldMap, newMap, property.getSetter(Object.class, newMap));
|
||||
|
||||
return new SetMethod(MH.asType(setter, Lookup.SET_OBJECT_TYPE), property);
|
||||
}
|
||||
|
||||
private SetMethod createNewSpillPropertySetter() {
|
||||
final int nextSpill = getMap().getSpillLength();
|
||||
|
||||
@ -189,7 +191,7 @@ final class SetMethodCreator {
|
||||
final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE);
|
||||
final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE);
|
||||
|
||||
return new SpillProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
|
||||
return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
|
||||
}
|
||||
|
||||
private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) {
|
||||
@ -207,14 +209,6 @@ final class SetMethodCreator {
|
||||
}
|
||||
}
|
||||
|
||||
private SetMethod createNewEmbedPropertySetter(final int nextEmbed) {
|
||||
sobj.useEmbed(nextEmbed);
|
||||
final Property property = new SpillProperty(getName(), 0, nextEmbed, ScriptObject.GET_EMBED[nextEmbed], ScriptObject.SET_EMBED[nextEmbed]);
|
||||
//TODO specfields
|
||||
final MethodHandle methodHandle = MH.insertArguments(ScriptObject.SETEMBED, 0, desc, getMap(), getNewMap(property), property.getSetter(Object.class, getMap()), nextEmbed);
|
||||
return new SetMethod(methodHandle, property);
|
||||
}
|
||||
|
||||
private PropertyMap getNewMap(Property property) {
|
||||
return getMap().addProperty(property);
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import jdk.nashorn.internal.lookup.Lookup;
|
||||
|
||||
/**
|
||||
* The SpillProperty is a subclass of AccessorProperties. Anything not in the initial property map
|
||||
* will end up in the embed fields of the ScriptObject or in the Spill, which currently is a growing
|
||||
* Object only array in ScriptObject
|
||||
*
|
||||
* @see AccessorProperty
|
||||
* @see ScriptObject
|
||||
*/
|
||||
public final class SpillProperty extends AccessorProperty {
|
||||
private static final MethodHandle SPILLGETTER = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, "spill", Object[].class), Lookup.GET_OBJECT_TYPE);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param key property key
|
||||
* @param flags property flags
|
||||
* @param slot property slot/index
|
||||
* @param getter getter for property
|
||||
* @param setter setter for property, or null if not configurable and writable
|
||||
*/
|
||||
public SpillProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
|
||||
super(key, flags, slot, getter, setter);
|
||||
}
|
||||
|
||||
private SpillProperty(final SpillProperty property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Property copy() {
|
||||
return new SpillProperty(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle getGetter(final Class<?> type) {
|
||||
if (isSpill()) {
|
||||
return MH.filterArguments(super.getGetter(type), 0, SPILLGETTER);
|
||||
}
|
||||
|
||||
return super.getGetter(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
|
||||
if (isSpill()) {
|
||||
return MH.filterArguments(super.getSetter(type, currentMap), 0, SPILLGETTER);
|
||||
}
|
||||
|
||||
return super.getSetter(type, currentMap);
|
||||
}
|
||||
|
||||
}
|
@ -110,8 +110,7 @@ final class StructureLoader extends NashornLoader {
|
||||
@Override
|
||||
protected Class<?> findClass(final String name) throws ClassNotFoundException {
|
||||
if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
|
||||
final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length();
|
||||
return generateClass(name, name.substring(start, name.length()));
|
||||
return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
|
||||
}
|
||||
return super.findClass(name);
|
||||
}
|
||||
|
@ -67,7 +67,6 @@ public final class UserAccessorProperty extends Property {
|
||||
|
||||
private UserAccessorProperty(final UserAccessorProperty property) {
|
||||
super(property);
|
||||
|
||||
this.getterSlot = property.getterSlot;
|
||||
this.setterSlot = property.setterSlot;
|
||||
}
|
||||
@ -115,10 +114,10 @@ public final class UserAccessorProperty extends Property {
|
||||
public int getSpillCount() {
|
||||
// calculate how many spill array slots used by this propery.
|
||||
int count = 0;
|
||||
if (getGetterSlot() >= ScriptObject.EMBED_SIZE) {
|
||||
if (getGetterSlot() >= 0) {
|
||||
count++;
|
||||
}
|
||||
if (getSetterSlot() >= ScriptObject.EMBED_SIZE) {
|
||||
if (getSetterSlot() >= 0) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
@ -141,7 +140,7 @@ public final class UserAccessorProperty extends Property {
|
||||
|
||||
@Override
|
||||
public ScriptFunction getGetterFunction(final ScriptObject obj) {
|
||||
final Object value = obj.getEmbedOrSpill(getterSlot);
|
||||
final Object value = obj.getSpill(getterSlot);
|
||||
return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
|
||||
}
|
||||
|
||||
@ -152,7 +151,7 @@ public final class UserAccessorProperty extends Property {
|
||||
|
||||
@Override
|
||||
public ScriptFunction getSetterFunction(final ScriptObject obj) {
|
||||
final Object value = obj.getEmbedOrSpill(setterSlot);
|
||||
final Object value = obj.getSpill(setterSlot);
|
||||
return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,6 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
|
||||
* Is this a reverse order iteration?
|
||||
* @return true if reverse
|
||||
*/
|
||||
@SuppressWarnings("static-method")
|
||||
public boolean isReverse() {
|
||||
return false;
|
||||
}
|
||||
|
@ -278,7 +278,7 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public void run() {
|
||||
PrintWriter out = null;
|
||||
PrintWriter out = null;
|
||||
boolean fileOutput = false;
|
||||
|
||||
try {
|
||||
|
@ -44,11 +44,9 @@ import jdk.nashorn.internal.runtime.Undefined;
|
||||
|
||||
/**
|
||||
* This is the main dynamic linker for Nashorn. It is used for linking all {@link ScriptObject} and its subclasses (this
|
||||
* includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}. This linker is exported to other
|
||||
* language runtimes by being declared in {@code META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
|
||||
* file of Nashorn's distribution.
|
||||
* includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
|
||||
*/
|
||||
final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
|
||||
public final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
|
||||
/**
|
||||
* Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
|
||||
*/
|
||||
|
@ -243,7 +243,7 @@ public final class Options {
|
||||
*/
|
||||
public String getString(final String key) {
|
||||
final Option<?> option = get(key);
|
||||
if(option != null) {
|
||||
if (option != null) {
|
||||
final String value = (String)option.getValue();
|
||||
if(value != null) {
|
||||
return value.intern();
|
||||
|
@ -107,16 +107,16 @@ public class DefaultRegExp extends RegExp {
|
||||
|
||||
class DefaultMatcher implements RegExpMatcher {
|
||||
final String input;
|
||||
final Matcher matcher;
|
||||
final Matcher defaultMatcher;
|
||||
|
||||
DefaultMatcher(final String input) {
|
||||
this.input = input;
|
||||
this.matcher = pattern.matcher(input);
|
||||
this.defaultMatcher = pattern.matcher(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean search(final int start) {
|
||||
return matcher.find(start);
|
||||
return defaultMatcher.find(start);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,37 +126,37 @@ public class DefaultRegExp extends RegExp {
|
||||
|
||||
@Override
|
||||
public int start() {
|
||||
return matcher.start();
|
||||
return defaultMatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(final int group) {
|
||||
return matcher.start(group);
|
||||
return defaultMatcher.start(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end() {
|
||||
return matcher.end();
|
||||
return defaultMatcher.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end(final int group) {
|
||||
return matcher.end(group);
|
||||
return defaultMatcher.end(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group() {
|
||||
return matcher.group();
|
||||
return defaultMatcher.group();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group(final int group) {
|
||||
return matcher.group(group);
|
||||
return defaultMatcher.group(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int groupCount() {
|
||||
return matcher.groupCount();
|
||||
return defaultMatcher.groupCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,16 +121,16 @@ public class JoniRegExp extends RegExp {
|
||||
|
||||
class JoniMatcher implements RegExpMatcher {
|
||||
final String input;
|
||||
final Matcher matcher;
|
||||
final Matcher joniMatcher;
|
||||
|
||||
JoniMatcher(final String input) {
|
||||
this.input = input;
|
||||
this.matcher = regex.matcher(input.toCharArray());
|
||||
this.joniMatcher = regex.matcher(input.toCharArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean search(final int start) {
|
||||
return matcher.search(start, input.length(), Option.NONE) > -1;
|
||||
return joniMatcher.search(start, input.length(), Option.NONE) > -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -140,27 +140,27 @@ public class JoniRegExp extends RegExp {
|
||||
|
||||
@Override
|
||||
public int start() {
|
||||
return matcher.getBegin();
|
||||
return joniMatcher.getBegin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(final int group) {
|
||||
return group == 0 ? start() : matcher.getRegion().beg[group];
|
||||
return group == 0 ? start() : joniMatcher.getRegion().beg[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end() {
|
||||
return matcher.getEnd();
|
||||
return joniMatcher.getEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end(final int group) {
|
||||
return group == 0 ? end() : matcher.getRegion().end[group];
|
||||
return group == 0 ? end() : joniMatcher.getRegion().end[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group() {
|
||||
return input.substring(matcher.getBegin(), matcher.getEnd());
|
||||
return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,13 +168,13 @@ public class JoniRegExp extends RegExp {
|
||||
if (group == 0) {
|
||||
return group();
|
||||
}
|
||||
final Region region = matcher.getRegion();
|
||||
final Region region = joniMatcher.getRegion();
|
||||
return input.substring(region.beg[group], region.end[group]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int groupCount() {
|
||||
final Region region = matcher.getRegion();
|
||||
final Region region = joniMatcher.getRegion();
|
||||
return region == null ? 0 : region.numRegs - 1;
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ final class RegExpScanner extends Scanner {
|
||||
/** Are we currently inside a negated character class? */
|
||||
private boolean inNegativeClass = false;
|
||||
|
||||
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?";
|
||||
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
|
||||
|
||||
private static class Capture {
|
||||
/**
|
||||
@ -934,7 +934,7 @@ final class RegExpScanner extends Scanner {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void unicode(final int value, final StringBuilder buffer) {
|
||||
private static void unicode(final int value, final StringBuilder buffer) {
|
||||
final String hex = Integer.toHexString(value);
|
||||
buffer.append('u');
|
||||
for (int i = 0; i < 4 - hex.length(); i++) {
|
||||
@ -944,7 +944,7 @@ final class RegExpScanner extends Scanner {
|
||||
}
|
||||
|
||||
// Convert what would have been a backreference into a unicode escape, or a number literal, or both.
|
||||
private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
|
||||
private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
|
||||
final int length = numberLiteral.length();
|
||||
int octalValue = 0;
|
||||
int pos = 0;
|
||||
|
@ -247,6 +247,12 @@ nashorn.option.print.code = { \
|
||||
desc="Print bytecode." \
|
||||
}
|
||||
|
||||
nashorn.option.print.mem.usage = { \
|
||||
name="--print-mem-usage", \
|
||||
is_undocumented=true, \
|
||||
desc="Print memory usage of IR after each compile stage." \
|
||||
}
|
||||
|
||||
nashorn.option.print.no.newline = { \
|
||||
name="--print-no-newline", \
|
||||
is_undocumented=true, \
|
||||
@ -288,12 +294,12 @@ nashorn.option.scripting = { \
|
||||
dependency="--anon-functions=true" \
|
||||
}
|
||||
|
||||
nashorn.option.timezone = { \
|
||||
name="-timezone", \
|
||||
short_name="-t", \
|
||||
params="<timezone>", \
|
||||
desc="Set timezone for script execution.", \
|
||||
type=TimeZone \
|
||||
nashorn.option.specialize.calls = { \
|
||||
name="--specialize-calls", \
|
||||
is_undocumented=true, \
|
||||
type=String, \
|
||||
params="[=function_1,...,function_n]", \
|
||||
desc="Specialize all or a set of method according to callsite parameter types" \
|
||||
}
|
||||
|
||||
nashorn.option.stdout = { \
|
||||
@ -312,6 +318,14 @@ nashorn.option.stderr = { \
|
||||
desc="Redirect stderr to a filename or to another tty, e.g. stdout" \
|
||||
}
|
||||
|
||||
nashorn.option.timezone = { \
|
||||
name="-timezone", \
|
||||
short_name="-t", \
|
||||
params="<timezone>", \
|
||||
desc="Set timezone for script execution.", \
|
||||
type=TimeZone \
|
||||
}
|
||||
|
||||
nashorn.option.trace.callsites = { \
|
||||
name="--trace-callsites", \
|
||||
short_name="-tcs", \
|
||||
|
@ -35,8 +35,6 @@ com.sun.javafx.application.LauncherImpl.launchApplication((Java.extend(javafx.ap
|
||||
init: function() {
|
||||
// Java FX packages and classes must be defined here because
|
||||
// they may not be viable until launch time due to clinit ordering.
|
||||
|
||||
load("fx:base.js");
|
||||
},
|
||||
|
||||
// Overridden javafx.application.Application.start(Stage stage);
|
||||
|
@ -32,12 +32,11 @@ import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
* Empty object class.
|
||||
*/
|
||||
public class JO extends ScriptObject {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public JO() {
|
||||
super();
|
||||
super(PropertyMap.newMap(JO.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,9 +173,9 @@ public class Shell {
|
||||
|
||||
if (env._fx) {
|
||||
return runFXScripts(context, global, files);
|
||||
} else {
|
||||
return runScripts(context, global, files);
|
||||
}
|
||||
|
||||
return runScripts(context, global, files);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,7 +270,7 @@ public class Shell {
|
||||
}
|
||||
|
||||
//null - pass no code installer - this is compile only
|
||||
new Compiler(env, functionNode).compile();
|
||||
new Compiler(env).compile(functionNode);
|
||||
}
|
||||
} finally {
|
||||
env.getOut().flush();
|
||||
@ -343,7 +343,7 @@ public class Shell {
|
||||
* @return error code
|
||||
* @throws IOException when any script file read results in I/O error
|
||||
*/
|
||||
private int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
|
||||
private static int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
|
||||
final ScriptObject oldGlobal = Context.getGlobal();
|
||||
final boolean globalChanged = (oldGlobal != global);
|
||||
try {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user