This commit is contained in:
Jim Laskey 2013-05-14 09:05:03 -03:00
commit bfc562f5b0
118 changed files with 3433 additions and 2140 deletions

View File

@ -8,6 +8,7 @@ private.xml
private.properties private.properties
webrev/* webrev/*
webrev.zip webrev.zip
.classpath
*.class *.class
*.clazz *.clazz
*.log *.log

View File

@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; [ -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 $*

View File

@ -194,6 +194,8 @@ test262-test-sys-prop.test.js.enable.strict.mode=true
test262-test-sys-prop.test.js.exclude.dir=\ test262-test-sys-prop.test.js.exclude.dir=\
${test262.suite.dir}/intl402/ ${test262.suite.dir}/intl402/
test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
# test262 test frameworks # test262 test frameworks
test262-test-sys-prop.test.js.framework=\ test262-test-sys-prop.test.js.framework=\
-timezone=PST \ -timezone=PST \
@ -214,7 +216,7 @@ run.test.xms=2G
# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
# add '-Dtest.js.outofprocess' to run each test in a new sub-process # 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 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}

View File

@ -78,7 +78,6 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
this(factory, DEFAULT_OPTIONS, appLoader); this(factory, DEFAULT_OPTIONS, appLoader);
} }
@SuppressWarnings("LeakingThisInConstructor")
NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) { NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
this.factory = factory; this.factory = factory;
final Options options = new Options("nashorn"); final Options options = new Options("nashorn");
@ -102,7 +101,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}); });
// create new global object // create new global object
this.global = createNashornGlobal(); this.global = createNashornGlobal();
// set the default engine scope for the default context // set the default engine scope for the default context
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE); context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);

View File

@ -31,7 +31,6 @@ import java.util.List;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineFactory;
import jdk.nashorn.internal.runtime.Version; import jdk.nashorn.internal.runtime.Version;
import sun.reflect.Reflection;
/** /**
* JSR-223 compliant script engine factory for Nashorn. The engine answers for: * JSR-223 compliant script engine factory for Nashorn. The engine answers for:

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; 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.IndexNode;
import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode; import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 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;
import jdk.nashorn.internal.ir.RuntimeNode.Request; import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.TernaryNode;
@ -191,6 +192,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** Current compile unit */ /** Current compile unit */
private CompileUnit unit; private CompileUnit unit;
private int lastLineNumber = -1;
/** When should we stop caching regexp expressions in fields to limit bytecode size? */ /** When should we stop caching regexp expressions in fields to limit bytecode size? */
private static final int MAX_REGEX_FIELDS = 2 * 1024; private static final int MAX_REGEX_FIELDS = 2 * 1024;
@ -261,14 +264,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
return method.load(symbol); 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)) { if (CompilerConstants.__FILE__.name().equals(name)) {
return method.load(identNode.getSource().getName()); return method.load(source.getName());
} else if (CompilerConstants.__DIR__.name().equals(name)) { } 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)) { } 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 { } else {
assert identNode.getSymbol().isScope() : identNode + " is not in scope!"; assert identNode.getSymbol().isScope() : identNode + " is not in scope!";
@ -568,8 +572,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @param block block containing symbols. * @param block block containing symbols.
*/ */
private void symbolInfo(final Block block) { private void symbolInfo(final Block block) {
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { for (final Symbol symbol : block.getSymbols()) {
final Symbol symbol = iter.next();
if (symbol.hasSlot()) { if (symbol.hasSlot()) {
method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
} }
@ -619,6 +622,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterBreakNode(final BreakNode breakNode) { public boolean enterBreakNode(final BreakNode breakNode) {
lineNumber(breakNode);
final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel()); final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) { for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
closeWith(); closeWith();
@ -663,6 +668,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterCallNode(final CallNode callNode) { public boolean enterCallNode(final CallNode callNode) {
lineNumber(callNode);
final List<Node> args = callNode.getArgs(); final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction(); final Node function = callNode.getFunction();
final Block currentBlock = getLexicalContext().getCurrentBlock(); final Block currentBlock = getLexicalContext().getCurrentBlock();
@ -836,6 +843,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterContinueNode(final ContinueNode continueNode) { public boolean enterContinueNode(final ContinueNode continueNode) {
lineNumber(continueNode);
final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel()); final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) { for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
closeWith(); closeWith();
@ -847,11 +856,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterEmptyNode(final EmptyNode emptyNode) { public boolean enterEmptyNode(final EmptyNode emptyNode) {
lineNumber(emptyNode);
return false; return false;
} }
@Override @Override
public boolean enterExecuteNode(final ExecuteNode executeNode) { public boolean enterExecuteNode(final ExecuteNode executeNode) {
lineNumber(executeNode);
final Node expression = executeNode.getExpression(); final Node expression = executeNode.getExpression();
expression.accept(this); expression.accept(this);
@ -860,6 +873,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterForNode(final ForNode forNode) { public boolean enterForNode(final ForNode forNode) {
lineNumber(forNode);
final Node test = forNode.getTest(); final Node test = forNode.getTest();
final Block body = forNode.getBody(); final Block body = forNode.getBody();
final Node modify = forNode.getModify(); final Node modify = forNode.getModify();
@ -937,11 +952,10 @@ final class CodeGenerator extends NodeOperatorVisitor {
private static int assignSlots(final Block block, final int firstSlot) { private static int assignSlots(final Block block, final int firstSlot) {
int nextSlot = firstSlot; int nextSlot = firstSlot;
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { for (final Symbol symbol : block.getSymbols()) {
final Symbol next = iter.next(); if (symbol.hasSlot()) {
if (next.hasSlot()) { symbol.setSlot(nextSlot);
next.setSlot(nextSlot); nextSlot += symbol.slotCount();
nextSlot += next.slotCount();
} }
} }
return nextSlot; return nextSlot;
@ -1002,10 +1016,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
final boolean hasArguments = function.needsArguments(); final boolean hasArguments = function.needsArguments();
final Iterator<Symbol> symbols = block.symbolIterator(); for (final Symbol symbol : block.getSymbols()) {
while (symbols.hasNext()) {
final Symbol symbol = symbols.next();
if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
continue; continue;
@ -1076,12 +1087,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
} }
} }
final Iterator<Symbol> iter = block.symbolIterator(); initSymbols(block.getSymbols());
final List<Symbol> symbols = new ArrayList<>();
while (iter.hasNext()) {
symbols.add(iter.next());
}
initSymbols(symbols);
} }
// Debugging: print symbols? @see --print-symbols flag // Debugging: print symbols? @see --print-symbols flag
@ -1157,6 +1163,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterIfNode(final IfNode ifNode) { public boolean enterIfNode(final IfNode ifNode) {
lineNumber(ifNode);
final Node test = ifNode.getTest(); final Node test = ifNode.getTest();
final Block pass = ifNode.getPass(); final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail(); final Block fail = ifNode.getFail();
@ -1196,12 +1204,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
return false; return false;
} }
@Override private void lineNumber(final Statement statement) {
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { final int lineNumber = statement.getLineNumber();
final Label label = new Label((String)null); if (lineNumber != lastLineNumber) {
method.label(label); method.lineNumber(statement.getLineNumber());
method.lineNumber(lineNumberNode.getLineNumber(), label); }
return false; lastLineNumber = lineNumber;
} }
/** /**
@ -1533,6 +1541,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterReturnNode(final ReturnNode returnNode) { public boolean enterReturnNode(final ReturnNode returnNode) {
lineNumber(returnNode);
method.registerReturn(); method.registerReturn();
final Type returnType = getLexicalContext().getCurrentFunction().getReturnType(); final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
@ -1742,6 +1752,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterSplitNode(final SplitNode splitNode) { public boolean enterSplitNode(final SplitNode splitNode) {
lineNumber(splitNode);
final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
final FunctionNode fn = getLexicalContext().getCurrentFunction(); final FunctionNode fn = getLexicalContext().getCurrentFunction();
@ -1885,6 +1897,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterSwitchNode(final SwitchNode switchNode) { public boolean enterSwitchNode(final SwitchNode switchNode) {
lineNumber(switchNode);
final Node expression = switchNode.getExpression(); final Node expression = switchNode.getExpression();
final Symbol tag = switchNode.getTag(); final Symbol tag = switchNode.getTag();
final boolean allInteger = tag.getSymbolType().isInteger(); final boolean allInteger = tag.getSymbolType().isInteger();
@ -1967,7 +1981,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.tableswitch(lo, hi, defaultLabel, table); method.tableswitch(lo, hi, defaultLabel, table);
} else { } else {
final int[] ints = new int[size]; final int[] ints = new int[size];
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
ints[i] = values[i]; ints[i] = values[i];
} }
@ -2013,10 +2026,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterThrowNode(final ThrowNode throwNode) { public boolean enterThrowNode(final ThrowNode throwNode) {
lineNumber(throwNode);
method._new(ECMAException.class).dup(); method._new(ECMAException.class).dup();
final Source source = getLexicalContext().getCurrentFunction().getSource();
final Node expression = throwNode.getExpression(); final Node expression = throwNode.getExpression();
final Source source = throwNode.getSource();
final int position = throwNode.position(); final int position = throwNode.position();
final int line = source.getLine(position); final int line = source.getLine(position);
final int column = source.getColumn(position); final int column = source.getColumn(position);
@ -2036,6 +2052,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterTryNode(final TryNode tryNode) { public boolean enterTryNode(final TryNode tryNode) {
lineNumber(tryNode);
final Block body = tryNode.getBody(); final Block body = tryNode.getBody();
final List<Block> catchBlocks = tryNode.getCatchBlocks(); final List<Block> catchBlocks = tryNode.getCatchBlocks();
final Symbol symbol = tryNode.getException(); final Symbol symbol = tryNode.getException();
@ -2132,12 +2150,15 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterVarNode(final VarNode varNode) { public boolean enterVarNode(final VarNode varNode) {
final Node init = varNode.getInit(); final Node init = varNode.getInit();
if (init == null) { if (init == null) {
return false; return false;
} }
lineNumber(varNode);
final Symbol varSymbol = varNode.getSymbol(); final Symbol varSymbol = varNode.getSymbol();
assert varSymbol != null : "variable node " + varNode + " requires a symbol"; assert varSymbol != null : "variable node " + varNode + " requires a symbol";
@ -2170,6 +2191,8 @@ final class CodeGenerator extends NodeOperatorVisitor {
@Override @Override
public boolean enterWhileNode(final WhileNode whileNode) { public boolean enterWhileNode(final WhileNode whileNode) {
lineNumber(whileNode);
final Node test = whileNode.getTest(); final Node test = whileNode.getTest();
final Block body = whileNode.getBody(); final Block body = whileNode.getBody();
final Label breakLabel = whileNode.getBreakLabel(); final Label breakLabel = whileNode.getBreakLabel();
@ -2192,7 +2215,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
} }
private void closeWith() { private void closeWith() {
if(method.hasScope()) { if (method.hasScope()) {
method.loadCompilerConstant(SCOPE); method.loadCompilerConstant(SCOPE);
method.invoke(ScriptRuntime.CLOSE_WITH); method.invoke(ScriptRuntime.CLOSE_WITH);
method.storeCompilerConstant(SCOPE); method.storeCompilerConstant(SCOPE);
@ -2235,7 +2258,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Always process body // Always process body
body.accept(this); body.accept(this);
if(hasScope) { if (hasScope) {
// Ensure we always close the WithObject // Ensure we always close the WithObject
final Label endLabel = new Label("with_end"); final Label endLabel = new Label("with_end");
final Label catchLabel = new Label("with_catch"); final Label catchLabel = new Label("with_catch");
@ -2364,7 +2387,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
public boolean enterDISCARD(final UnaryNode unaryNode) { public boolean enterDISCARD(final UnaryNode unaryNode) {
final Node rhs = unaryNode.rhs(); final Node rhs = unaryNode.rhs();
// System.err.println("**** Enter discard " + unaryNode);
discard.push(rhs); discard.push(rhs);
load(rhs); load(rhs);
@ -2373,7 +2395,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
method.pop(); method.pop();
discard.pop(); discard.pop();
} }
// System.err.println("**** Leave discard " + unaryNode);
return false; return false;
} }
@ -3019,12 +3041,12 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @param block the block we are in * @param block the block we are in
* @param ident identifier for block or function where applicable * @param ident identifier for block or function where applicable
*/ */
@SuppressWarnings("resource")
private void printSymbols(final Block block, final String ident) { private void printSymbols(final Block block, final String ident) {
if (!compiler.getEnv()._print_symbols) { if (!compiler.getEnv()._print_symbols) {
return; return;
} }
@SuppressWarnings("resource")
final PrintWriter out = compiler.getEnv().getErr(); final PrintWriter out = compiler.getEnv().getErr();
out.println("[BLOCK in '" + ident + "']"); out.println("[BLOCK in '" + ident + "']");
if (!block.printSymbols(out)) { if (!block.printSymbols(out)) {
@ -3200,9 +3222,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
return; return;
} }
//System.err.println("Store with out discard that shouldn't just return " + assignNode);
//new Throwable().printStackTrace();
final Symbol symbol = assignNode.getSymbol(); final Symbol symbol = assignNode.getSymbol();
if (symbol.hasSlot()) { if (symbol.hasSlot()) {
method.dup().store(symbol); 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 // 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 // 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. // static method's parameter list.
if(lc.getOutermostFunction() == functionNode || if (lc.getOutermostFunction() == functionNode ||
(!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) { (!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) {
return; return;
} }

View File

@ -21,6 +21,7 @@ import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node; 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.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor; import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
@ -42,7 +43,7 @@ enum CompilationPhase {
*/ */
LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
@Override @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 * For lazy compilation, we might be given a node previously marked
@ -58,8 +59,7 @@ enum CompilationPhase {
* function from a trampoline * function from a trampoline
*/ */
final FunctionNode outermostFunctionNode = compiler.getFunctionNode(); final FunctionNode outermostFunctionNode = fn;
assert outermostFunctionNode == fn0;
final Set<FunctionNode> neverLazy = new HashSet<>(); final Set<FunctionNode> neverLazy = new HashSet<>();
final Set<FunctionNode> lazy = new HashSet<>(); final Set<FunctionNode> lazy = new HashSet<>();
@ -172,20 +172,31 @@ enum CompilationPhase {
ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
@Override @Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 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 * Pessimistically set all lazy functions' return types to Object
* and the function symbols to object
* @param functionNode node where to start iterating * @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() { return (FunctionNode)functionNode.accept(new NodeVisitor() {
@Override @Override
public Node leaveFunctionNode(final FunctionNode node) { public Node leaveFunctionNode(final FunctionNode node) {
return node.isLazy() ? final LexicalContext lc = getLexicalContext();
node.setReturnType(getLexicalContext(), Type.OBJECT) : if (node.isLazy()) {
node.setReturnType(getLexicalContext(), Type.UNKNOWN); 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) { FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
// assert fn.isProgram() ;
final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
@ -216,15 +228,6 @@ enum CompilationPhase {
compiler.setStrictMode(true); 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; return newFunctionNode;
} }
@ -252,7 +255,7 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) { FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv(); 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) { if (env._print_lower_ast) {
env.getErr().println(new ASTWriter(newFunctionNode)); env.getErr().println(new ASTWriter(newFunctionNode));

View File

@ -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.THIS;
import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
import jdk.nashorn.internal.ir.TemporarySymbols;
import java.io.File; import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import jdk.internal.dynalink.support.NameCodec; import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 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.CodeInstaller;
import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptEnvironment;
@ -77,6 +83,8 @@ public final class Compiler {
/** Name of the objects package */ /** Name of the objects package */
public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
private Source source;
private final Map<String, byte[]> bytecode; private final Map<String, byte[]> bytecode;
private final Set<CompileUnit> compileUnits; private final Set<CompileUnit> compileUnits;
@ -87,14 +95,14 @@ public final class Compiler {
private final ScriptEnvironment env; private final ScriptEnvironment env;
private final String scriptName; private String scriptName;
private boolean strict; private boolean strict;
private FunctionNode functionNode;
private CodeInstaller<ScriptEnvironment> installer; private CodeInstaller<ScriptEnvironment> installer;
private final TemporarySymbols temporarySymbols = new TemporarySymbols();
/** logger for compiler, trampolines, splits and related code generation events /** logger for compiler, trampolines, splits and related code generation events
* that affect classes */ * that affect classes */
public static final DebugLogger LOG = new DebugLogger("compiler"); 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 * 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 * 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 * @param strict should this compilation use strict mode semantics
*/ */
//TODO support an array of FunctionNodes for batch lazy compilation //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.env = env;
this.functionNode = functionNode;
this.sequence = sequence; this.sequence = sequence;
this.installer = installer; this.installer = installer;
this.strict = strict || functionNode.isStrict();
this.constantData = new ConstantData(); this.constantData = new ConstantData();
this.compileUnits = new HashSet<>(); this.compileUnits = new HashSet<>();
this.bytecode = new HashMap<>(); this.bytecode = new HashMap<>();
}
private void initCompiler(final FunctionNode functionNode) {
this.strict = strict || functionNode.isStrict();
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))). sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
append('$'). append('$').
append(safeSourceName(functionNode.getSource())); append(safeSourceName(functionNode.getSource()));
this.source = functionNode.getSource();
this.scriptName = sb.toString(); this.scriptName = sb.toString();
} }
@ -229,52 +273,79 @@ public final class Compiler {
* Constructor * Constructor
* *
* @param installer code installer * @param installer code installer
* @param functionNode function node (in any available {@link CompilationState}) to compile
* @param strict should this compilation use strict mode semantics * @param strict should this compilation use strict mode semantics
*/ */
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) { public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict); this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
} }
/** /**
* Constructor - compilation will use the same strict semantics as in script environment * Constructor - compilation will use the same strict semantics as in script environment
* *
* @param installer code installer * @param installer code installer
* @param functionNode function node (in any available {@link CompilationState}) to compile
*/ */
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) { public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
} }
/** /**
* Constructor - compilation needs no installer, but uses a script environment * Constructor - compilation needs no installer, but uses a script environment
* Used in "compile only" scenarios * Used in "compile only" scenarios
* @param env a script environment * @param env a script environment
* @param functionNode functionNode to compile
*/ */
public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) { public Compiler(final ScriptEnvironment env) {
this(env, null, functionNode, sequence(env._lazy_compilation), env._strict); 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 * 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 * @throws CompilationException if something goes wrong
* @return function node that results from code transforms * @return function node that results from code transforms
*/ */
public FunctionNode compile() throws CompilationException { public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
return compile(null); 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) { for (final String reservedName : RESERVED_NAMES) {
functionNode.uniqueName(reservedName); newFunctionNode.uniqueName(reservedName);
} }
final boolean fine = !LOG.levelAbove(Level.FINE); final boolean fine = !LOG.levelAbove(Level.FINE);
@ -283,7 +354,11 @@ public final class Compiler {
long time = 0L; long time = 0L;
for (final CompilationPhase phase : sequence) { 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; final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
time += duration; time += duration;
@ -293,7 +368,7 @@ public final class Compiler {
sb.append(phase.toString()). sb.append(phase.toString()).
append(" done for function '"). append(" done for function '").
append(functionNode.getName()). append(newFunctionNode.getName()).
append('\''); append('\'');
if (duration > 0L) { if (duration > 0L) {
@ -309,7 +384,7 @@ public final class Compiler {
if (info) { if (info) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("Compile job for '"). sb.append("Compile job for '").
append(functionNode.getName()). append(newFunctionNode.getName()).
append("' finished"); append("' finished");
if (time > 0L) { if (time > 0L) {
@ -321,7 +396,7 @@ public final class Compiler {
LOG.info(sb); LOG.info(sb);
} }
return functionNode; return newFunctionNode;
} }
private Class<?> install(final String className, final byte[] code) { 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); final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
try { try {
final Source source = getSource();
final Object[] constants = getConstantData().toArray(); final Object[] constants = getConstantData().toArray();
// Need doPrivileged because these fields are private // Need doPrivileged because these fields are private
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@ -355,9 +429,10 @@ public final class Compiler {
/** /**
* Install compiled classes into a given loader * 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 * @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; final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; 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; this.strict = strict;
} }
FunctionNode getFunctionNode() {
return functionNode;
}
ConstantData getConstantData() { ConstantData getConstantData() {
return constantData; return constantData;
} }
@ -442,8 +513,8 @@ public final class Compiler {
return installer; return installer;
} }
Source getSource() { TemporarySymbols getTemporarySymbols() {
return functionNode.getSource(); return temporarySymbols;
} }
void addClass(final String name, final byte[] code) { 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) { 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); final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
classEmitter.begin(); classEmitter.begin();
@ -550,6 +621,4 @@ public final class Compiler {
USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic"); USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic");
assert !USE_INT_ARITH : "Integer arithmetic is not enabled"; assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
} }
} }

View File

@ -105,25 +105,25 @@ public enum CompilerConstants {
ARGUMENTS("arguments", Object.class, 2), ARGUMENTS("arguments", Object.class, 2),
/** prefix for iterators for for (x in ...) */ /** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX(":iter"), ITERATOR_PREFIX(":i"),
/** prefix for tag variable used for switch evaluation */ /** prefix for tag variable used for switch evaluation */
SWITCH_TAG_PREFIX(":tag"), SWITCH_TAG_PREFIX(":s"),
/** prefix for all exceptions */ /** prefix for all exceptions */
EXCEPTION_PREFIX(":exception"), EXCEPTION_PREFIX(":e"),
/** prefix for quick slots generated in Store */ /** prefix for quick slots generated in Store */
QUICK_PREFIX(":quick"), QUICK_PREFIX(":q"),
/** prefix for temporary variables */ /** prefix for temporary variables */
TEMP_PREFIX(":temp"), TEMP_PREFIX(":t"),
/** prefix for literals */ /** prefix for literals */
LITERAL_PREFIX(":lit"), LITERAL_PREFIX(":l"),
/** prefix for regexps */ /** prefix for regexps */
REGEX_PREFIX(":regex"), REGEX_PREFIX(":r"),
/** "this" used in non-static Java methods; always in slot 0 */ /** "this" used in non-static Java methods; always in slot 0 */
JAVA_THIS(null, 0), JAVA_THIS(null, 0),

View File

@ -30,7 +30,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode; 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.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TypeOverride; import jdk.nashorn.internal.ir.TypeOverride;
@ -88,7 +88,10 @@ final class FinalizeTypes extends NodeOperatorVisitor {
private static final DebugLogger LOG = new DebugLogger("finalize"); private static final DebugLogger LOG = new DebugLogger("finalize");
FinalizeTypes() { private final TemporarySymbols temporarySymbols;
FinalizeTypes(final TemporarySymbols temporarySymbols) {
this.temporarySymbols = temporarySymbols;
} }
@Override @Override
@ -228,21 +231,27 @@ final class FinalizeTypes extends NodeOperatorVisitor {
return leaveASSIGN(binaryNode); 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 @Override
public Node leaveBIT_AND(BinaryNode binaryNode) { public Node leaveBIT_AND(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT); return leaveBinary(binaryNode, Type.INT, Type.INT);
} }
@Override @Override
public Node leaveBIT_OR(BinaryNode binaryNode) { public Node leaveBIT_OR(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT); return leaveBinary(binaryNode, Type.INT, Type.INT);
} }
@Override @Override
public Node leaveBIT_XOR(BinaryNode binaryNode) { public Node leaveBIT_XOR(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); assert symbolIsInteger(binaryNode);
return leaveBinary(binaryNode, Type.INT, Type.INT); return leaveBinary(binaryNode, Type.INT, Type.INT);
} }
@ -252,8 +261,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs())); final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
// AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed // 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 // in that case, update the node type as well
propagateType(newBinaryNode, newBinaryNode.lhs().getType()); return propagateType(newBinaryNode, newBinaryNode.lhs().getType());
return newBinaryNode;
} }
@Override @Override
@ -262,8 +270,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs())); final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
// AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed // 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 // in that case, update the node type as well
propagateType(newBinaryNode, newBinaryNode.rhs().getType()); return propagateType(newBinaryNode, newBinaryNode.rhs().getType());
return newBinaryNode;
} }
@Override @Override
@ -354,13 +361,6 @@ final class FinalizeTypes extends NodeOperatorVisitor {
return true; return true;
} }
/*
@Override
public Node leaveBlock(final Block block) {
final LexicalContext lc = getLexicalContext();
return block;//.setFlag(lc, lc.getFlags(block));
}*/
@Override @Override
public Node leaveCatchNode(final CatchNode catchNode) { public Node leaveCatchNode(final CatchNode catchNode) {
final Node exceptionCondition = catchNode.getExceptionCondition(); final Node exceptionCondition = catchNode.getExceptionCondition();
@ -372,6 +372,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override @Override
public Node leaveExecuteNode(final ExecuteNode executeNode) { public Node leaveExecuteNode(final ExecuteNode executeNode) {
temporarySymbols.reuse();
return executeNode.setExpression(discard(executeNode.getExpression())); return executeNode.setExpression(discard(executeNode.getExpression()));
} }
@ -497,8 +498,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override @Override
public Node leaveVarNode(final VarNode varNode) { public Node leaveVarNode(final VarNode varNode) {
final Node rhs = varNode.getInit(); final Node init = varNode.getInit();
if (rhs != null) { if (init != null) {
final SpecializedNode specialized = specialize(varNode); final SpecializedNode specialized = specialize(varNode);
final VarNode specVarNode = (VarNode)specialized.node; final VarNode specVarNode = (VarNode)specialized.node;
Type destType = specialized.type; Type destType = specialized.type;
@ -506,8 +507,11 @@ final class FinalizeTypes extends NodeOperatorVisitor {
destType = specVarNode.getType(); destType = specVarNode.getType();
} }
assert specVarNode.hasType() : specVarNode + " doesn't have a type"; 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; return varNode;
} }
@ -551,8 +555,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
final boolean allVarsInScope = functionNode.allVarsInScope(); final boolean allVarsInScope = functionNode.allVarsInScope();
final boolean isVarArg = functionNode.isVarArg(); final boolean isVarArg = functionNode.isVarArg();
for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { for (final Symbol symbol : block.getSymbols()) {
final Symbol symbol = iter.next();
if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
continue; 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 Node node = ((Node)assignment);
final T lhs = assignment.getAssignmentDest(); final T lhs = assignment.getAssignmentDest();
final Node rhs = assignment.getAssignmentSource(); final Node rhs = assignment.getAssignmentSource();
@ -709,9 +712,9 @@ final class FinalizeTypes extends NodeOperatorVisitor {
} }
final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); 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 * @param to new type
*/ */
@SuppressWarnings("unchecked") @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(); final Type from = node.getType();
if (!node.getType().equals(to)) { if (!node.getType().equals(to)) {
LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", 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); 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) { private Node convert(final Node node, final Type to) {
assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
assert node != null : "node is null"; 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(); assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
final Type from = node.getType(); final Type from = node.getType();
@ -807,24 +810,22 @@ final class FinalizeTypes extends NodeOperatorVisitor {
assert node instanceof TypeOverride; assert node instanceof TypeOverride;
return setTypeOverride(node, to); 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, "'"); LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
assert !node.isTerminal();
final LexicalContext lc = getLexicalContext(); final LexicalContext lc = getLexicalContext();
//This is the only place in this file that can create new temporaries //This is the only place in this file that can create new temporaries
//FinalizeTypes may not introduce ANY node that is not a conversion. //FinalizeTypes may not introduce ANY node that is not a conversion.
lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode); return temporarySymbols.ensureSymbol(lc, to, resultNode);
assert !node.isTerminal();
return resultNode;
} }
private static Node discard(final Node node) { private static Node discard(final Node node) {
if (node.getSymbol() != null) { 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 //discard never has a symbol in the discard node - then it would be a nop
assert !node.isTerminal(); assert !node.isTerminal();
return discard; return discard;
@ -847,12 +848,13 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @param node * @param node
* @param to * @param to
*/ */
private static void propagateType(final Node node, final Type to) { private Node propagateType(final Node node, final Type to) {
final Symbol symbol = node.getSymbol(); Symbol symbol = node.getSymbol();
if (symbol.isTemp()) { if (symbol.isTemp() && symbol.getSymbolType() != to) {
symbol.setTypeOverride(to); symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
LOG.info("Type override for temporary in '", node, "' => ", to); 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 * Whenever an explicit conversion is needed and the convertee is a literal, we can
* just change the literal * just change the literal
*/ */
static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> { class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> {
private final Type type; private final Type type;
LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) { LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) {
@ -892,20 +894,20 @@ final class FinalizeTypes extends NodeOperatorVisitor {
LiteralNode<?> literalNode = null; LiteralNode<?> literalNode = null;
if (type.isString()) { if (type.isString()) {
literalNode = LiteralNode.newInstance(source, token, finish, JSType.toString(value)); literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value));
} else if (type.isBoolean()) { } 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()) { } 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()) { } 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()) { } 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) { if (literalNode != null) {
//inherit literal symbol for attr. //inherit literal symbol for attr.
literalNode.setSymbol(parent.getSymbol()); literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol());
} }
return literalNode; return literalNode;

View File

@ -41,7 +41,6 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
/** /**
* Simple constant folding pass, executed before IR is starting to be lowered. * 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) { if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail(); final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
if (shortCut != null) { if (shortCut != null) {
return new ExecuteNode(shortCut); return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
} }
return new EmptyNode(ifNode); return new EmptyNode(ifNode);
} }
@ -112,13 +111,11 @@ final class FoldConstants extends NodeVisitor {
*/ */
abstract static class ConstantEvaluator<T extends Node> { abstract static class ConstantEvaluator<T extends Node> {
protected T parent; protected T parent;
protected final Source source;
protected final long token; protected final long token;
protected final int finish; protected final int finish;
protected ConstantEvaluator(final T parent) { protected ConstantEvaluator(final T parent) {
this.parent = parent; this.parent = parent;
this.source = parent.getSource();
this.token = parent.getToken(); this.token = parent.getToken();
this.finish = parent.getFinish(); this.finish = parent.getFinish();
} }
@ -152,23 +149,23 @@ final class FoldConstants extends NodeVisitor {
switch (parent.tokenType()) { switch (parent.tokenType()) {
case ADD: case ADD:
if (rhsInteger) { if (rhsInteger) {
literalNode = LiteralNode.newInstance(source, token, finish, rhs.getInt32()); literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
} else { } else {
literalNode = LiteralNode.newInstance(source, token, finish, rhs.getNumber()); literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
} }
break; break;
case SUB: case SUB:
if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js 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 { } else {
literalNode = LiteralNode.newInstance(source, token, finish, -rhs.getNumber()); literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
} }
break; break;
case NOT: case NOT:
literalNode = LiteralNode.newInstance(source, token, finish, !rhs.getBoolean()); literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
break; break;
case BIT_NOT: case BIT_NOT:
literalNode = LiteralNode.newInstance(source, token, finish, ~rhs.getInt32()); literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
break; break;
default: default:
return null; return null;
@ -234,7 +231,7 @@ final class FoldConstants extends NodeVisitor {
break; break;
} }
assert res instanceof CharSequence : res + " was not a CharSequence, it was a " + res.getClass(); 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; return null;
case MUL: case MUL:
@ -247,33 +244,33 @@ final class FoldConstants extends NodeVisitor {
value = lhs.getNumber() - rhs.getNumber(); value = lhs.getNumber() - rhs.getNumber();
break; break;
case SHR: 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: case SAR:
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32()); return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
case SHL: case SHL:
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() << rhs.getInt32()); return LiteralNode.newInstance(token, finish, lhs.getInt32() << rhs.getInt32());
case BIT_XOR: 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: 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: case BIT_OR:
return LiteralNode.newInstance(source, token, finish, lhs.getInt32() | rhs.getInt32()); return LiteralNode.newInstance(token, finish, lhs.getInt32() | rhs.getInt32());
case GE: 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: 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: 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: 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: 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: 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: 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: 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: default:
return null; return null;
} }
@ -282,12 +279,12 @@ final class FoldConstants extends NodeVisitor {
isLong &= value != 0.0 && JSType.isRepresentableAsLong(value); isLong &= value != 0.0 && JSType.isRepresentableAsLong(value);
if (isInteger) { if (isInteger) {
return LiteralNode.newInstance(source, token, finish, JSType.toInt32(value)); return LiteralNode.newInstance(token, finish, JSType.toInt32(value));
} else if (isLong) { } 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);
} }
} }
} }

View File

@ -24,9 +24,8 @@
*/ */
package jdk.nashorn.internal.codegen; package jdk.nashorn.internal.codegen;
import java.util.ArrayDeque;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Debug;
/** /**
* Abstraction for labels, separating a label from the underlying * 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 * 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 */ /** Name of this label */
private final String name; private final String name;
/** Type stack at this label */ /** 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 * Constructor
@ -62,22 +136,24 @@ public class Label extends jdk.internal.org.objectweb.asm.Label {
this.name = label.name; 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; return stack;
} }
void setStack(final ArrayDeque<Type> stack) { void setStack(final Label.Stack stack) {
this.stack = stack; this.stack = stack;
} }
@Override @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); return name + '_' + Debug.id(this);
String s = super.toString();
s = s.substring(1, s.length());
sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s)));
return sb.toString();
} }
} }

View File

@ -32,6 +32,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.ir.BaseNode; import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block; 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.IfNode;
import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LoopNode; import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode; import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode; import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode; import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode; import jdk.nashorn.internal.ir.WithNode;
@ -93,21 +93,25 @@ final class Lower extends NodeOperatorVisitor {
super(new BlockLexicalContext() { super(new BlockLexicalContext() {
@Override @Override
public List<Node> popStatements() { public List<Statement> popStatements() {
List<Node> newStatements = new ArrayList<>(); final List<Statement> newStatements = new ArrayList<>();
boolean terminated = false; boolean terminated = false;
final List<Node> statements = super.popStatements(); final List<Statement> statements = super.popStatements();
for (final Node statement : statements) { for (final Statement statement : statements) {
if (!terminated) { if (!terminated) {
newStatements.add(statement); 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; terminated = true;
} }
} else { } else {
if (statement instanceof VarNode) { statement.accept(new NodeVisitor() {
newStatements.add(((VarNode)statement).setInit(null)); @Override
} public boolean enterVarNode(final VarNode varNode) {
newStatements.add(varNode.setInit(null));
return false;
}
});
} }
} }
return newStatements; return newStatements;
@ -118,8 +122,9 @@ final class Lower extends NodeOperatorVisitor {
@Override @Override
public boolean enterBlock(final Block block) { public boolean enterBlock(final Block block) {
final LexicalContext lc = getLexicalContext(); final LexicalContext lc = getLexicalContext();
if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) { final FunctionNode function = lc.getCurrentFunction();
new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
} }
return true; return true;
} }
@ -131,20 +136,20 @@ final class Lower extends NodeOperatorVisitor {
final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext(); final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
Node last = lc.getLastStatement(); Statement last = lc.getLastStatement();
if (lc.isFunctionBody()) { if (lc.isFunctionBody()) {
final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
final boolean isProgram = currentFunction.isProgram(); final boolean isProgram = currentFunction.isProgram();
final ReturnNode returnNode = new ReturnNode( final ReturnNode returnNode = new ReturnNode(
currentFunction.getSource(), last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
currentFunction.getToken(), currentFunction.getToken(),
currentFunction.getFinish(), currentFunction.getFinish(),
isProgram ? isProgram ?
compilerConstant(RETURN) : compilerConstant(RETURN) :
LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)); LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
last = returnNode.accept(this); last = (Statement)returnNode.accept(this);
} }
if (last != null && last.isTerminal()) { if (last != null && last.isTerminal()) {
@ -193,7 +198,6 @@ final class Lower extends NodeOperatorVisitor {
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
node = executeNode.setExpression( node = executeNode.setExpression(
new BinaryNode( new BinaryNode(
executeNode.getSource(),
Token.recast( Token.recast(
executeNode.getToken(), executeNode.getToken(),
TokenType.ASSIGN), TokenType.ASSIGN),
@ -239,12 +243,6 @@ final class Lower extends NodeOperatorVisitor {
return addStatement(labelNode); return addStatement(labelNode);
} }
@Override
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
addStatement(lineNumberNode); // don't put it in lastStatement cache
return false;
}
@Override @Override
public Node leaveReturnNode(final ReturnNode returnNode) { public Node leaveReturnNode(final ReturnNode returnNode) {
addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor 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) { private static List<Statement> copyFinally(final Block finallyBody) {
final List<Node> newStatements = new ArrayList<>(); final List<Statement> newStatements = new ArrayList<>();
for (final Node statement : finallyBody.getStatements()) { for (final Statement statement : finallyBody.getStatements()) {
newStatements.add(ensureUniqueLabelsIn(statement)); newStatements.add((Statement)ensureUniqueLabelsIn(statement));
if (statement.hasTerminalFlags()) { if (statement.hasTerminalFlags()) {
return newStatements; return newStatements;
} }
@ -284,17 +282,17 @@ final class Lower extends NodeOperatorVisitor {
} }
private Block catchAllBlock(final TryNode tryNode) { private Block catchAllBlock(final TryNode tryNode) {
final Source source = tryNode.getSource(); final int lineNumber = tryNode.getLineNumber();
final long token = tryNode.getToken(); final long token = tryNode.getToken();
final int finish = tryNode.getFinish(); 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 setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
final CatchNode catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody); final CatchNode catchAllNode = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody);
final Block catchAllBlock = new Block(source, token, finish, catchAllNode); final Block catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
//catchallblock -> catchallnode (catchnode) -> exception -> throw //catchallblock -> catchallnode (catchnode) -> exception -> throw
@ -303,10 +301,10 @@ final class Lower extends NodeOperatorVisitor {
private IdentNode compilerConstant(final CompilerConstants cc) { private IdentNode compilerConstant(final CompilerConstants cc) {
final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 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(); 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) * @return new try node after splicing finally code (same if nop)
*/ */
private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) { 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; assert tryNode.getFinallyBody() == null;
@ -341,11 +338,11 @@ final class Lower extends NodeOperatorVisitor {
@Override @Override
public Node leaveThrowNode(final ThrowNode throwNode) { public Node leaveThrowNode(final ThrowNode throwNode) {
if (rethrows.contains(throwNode)) { if (rethrows.contains(throwNode)) {
final List<Node> newStatements = copyFinally(finallyBody); final List<Statement> newStatements = copyFinally(finallyBody);
if (!isTerminal(newStatements)) { if (!isTerminal(newStatements)) {
newStatements.add(throwNode); newStatements.add(throwNode);
} }
return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements); return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
} }
return throwNode; return throwNode;
} }
@ -363,14 +360,14 @@ final class Lower extends NodeOperatorVisitor {
@Override @Override
public Node leaveReturnNode(final ReturnNode returnNode) { public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression(); final Node expr = returnNode.getExpression();
final List<Node> newStatements = new ArrayList<>(); final List<Statement> newStatements = new ArrayList<>();
final Node resultNode; final Node resultNode;
if (expr != null) { if (expr != null) {
//we need to evaluate the result of the return in case it is complex while //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 //still in the try block, store it in a result value and return it afterwards
resultNode = new IdentNode(Lower.this.compilerConstant(RETURN)); 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 { } else {
resultNode = null; resultNode = null;
} }
@ -380,16 +377,16 @@ final class Lower extends NodeOperatorVisitor {
newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); 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)) { if (!insideTry.contains(targetNode)) {
final List<Node> newStatements = copyFinally(finallyBody); final List<Statement> newStatements = copyFinally(finallyBody);
if (!isTerminal(newStatements)) { if (!isTerminal(newStatements)) {
newStatements.add(endpoint); 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; return endpoint;
} }
@ -397,7 +394,7 @@ final class Lower extends NodeOperatorVisitor {
addStatement(newTryNode); addStatement(newTryNode);
for (final Node statement : finallyBody.getStatements()) { for (final Node statement : finallyBody.getStatements()) {
addStatement(statement); addStatement((Statement)statement);
} }
return newTryNode; return newTryNode;
@ -451,7 +448,7 @@ final class Lower extends NodeOperatorVisitor {
if (tryNode.getCatchBlocks().isEmpty()) { if (tryNode.getCatchBlocks().isEmpty()) {
newTryNode = tryNode.setFinallyBody(null); newTryNode = tryNode.setFinallyBody(null);
} else { } 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); newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
} }
@ -468,19 +465,19 @@ final class Lower extends NodeOperatorVisitor {
public Node leaveVarNode(final VarNode varNode) { public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode); addStatement(varNode);
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) { 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; return varNode;
} }
@Override @Override
public Node leaveWhileNode(final WhileNode whileNode) { public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest(); final Node test = whileNode.getTest();
final Block body = whileNode.getBody(); final Block body = whileNode.getBody();
if (conservativeAlwaysTrue(test)) { if (conservativeAlwaysTrue(test)) {
//turn it into a for node without a 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); getLexicalContext().replace(whileNode, forNode);
return forNode; return forNode;
} }
@ -493,16 +490,6 @@ final class Lower extends NodeOperatorVisitor {
return addStatement(withNode); 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 * Given a function node that is a callee in a CallNode, replace it with
* the appropriate marker function. This is used by {@link CodeGenerator} * the appropriate marker function. This is used by {@link CodeGenerator}
@ -525,11 +512,12 @@ final class Lower extends NodeOperatorVisitor {
* @param node a node * @param node a node
* @return eval location * @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(). return new StringBuilder().
append(node.getSource().getName()). append(source.getName()).
append('#'). append('#').
append(node.getSource().getLine(node.position())). append(source.getLine(node.position())).
append("<eval>"). append("<eval>").
toString(); 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); ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
return statement; return statement;
} }

View File

@ -65,10 +65,12 @@ public class MapCreator {
* Constructs a property map based on a set of fields. * Constructs a property map based on a set of fields.
* *
* @param hasArguments does the created object have an "arguments" property * @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. * @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<>(); final List<Property> properties = new ArrayList<>();
assert keys != null; assert keys != null;
@ -82,7 +84,7 @@ public class MapCreator {
} }
} }
return PropertyMap.newMap(structure, properties); return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
} }
/** /**

View File

@ -67,10 +67,9 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
import java.io.PrintStream; import java.io.PrintStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.ArrayDeque;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import jdk.internal.dynalink.support.NameCodec; import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -114,7 +113,7 @@ public class MethodEmitter implements Emitter {
private final MethodVisitor method; private final MethodVisitor method;
/** Current type stack for current evaluation */ /** Current type stack for current evaluation */
private ArrayDeque<Type> stack; private Label.Stack stack;
/** Parent classEmitter representing the class of this method */ /** Parent classEmitter representing the class of this method */
private final ClassEmitter classEmitter; private final ClassEmitter classEmitter;
@ -189,7 +188,7 @@ public class MethodEmitter implements Emitter {
@Override @Override
public void begin() { public void begin() {
classEmitter.beginMethod(this); classEmitter.beginMethod(this);
stack = new ArrayDeque<>(); newStack();
method.visitCode(); method.visitCode();
} }
@ -205,6 +204,10 @@ public class MethodEmitter implements Emitter {
classEmitter.endMethod(this); classEmitter.endMethod(this);
} }
private void newStack() {
stack = new Label.Stack();
}
@Override @Override
public String toString() { public String toString() {
return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this); 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 * @return the type at position "pos" on the stack
*/ */
final Type peekType(final int pos) { final Type peekType(final int pos) {
final Iterator<Type> iter = stack.iterator(); return stack.peek(pos);
for (int i = 0; i < pos; i++) {
iter.next();
}
return iter.next();
} }
/** /**
@ -484,7 +483,7 @@ public class MethodEmitter implements Emitter {
name = THIS_DEBUGGER.symbolName(); 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)); 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 * Pops two integer types from the stack, performs a bitwise and and pushes
* the result * the result
@ -626,7 +614,7 @@ public class MethodEmitter implements Emitter {
* @param typeDescriptor type descriptor for exception * @param typeDescriptor type descriptor for exception
*/ */
void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) { 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 * @param clazz exception class
*/ */
void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) { 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) { private boolean isThisSlot(final int slot) {
if(functionNode == null) { if (functionNode == null) {
return slot == CompilerConstants.JAVA_THIS.slot(); return slot == CompilerConstants.JAVA_THIS.slot();
} }
final int thisSlot = compilerConstant(THIS).getSlot(); final int thisSlot = compilerConstant(THIS).getSlot();
@ -915,7 +903,6 @@ public class MethodEmitter implements Emitter {
dup(); dup();
return this; return this;
} }
debug("load compiler constant ", symbol);
return load(symbol); return load(symbol);
} }
@ -1228,6 +1215,14 @@ public class MethodEmitter implements Emitter {
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true); 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 * 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 values case values for the table
* @param table default label * @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()); debug("lookupswitch", peekType());
popType(Type.INT); 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 defaultLabel default label
* @param table label table * @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()); debug("tableswitch", peekType());
popType(Type.INT); 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(); popType();
} }
mergeStackTo(label); mergeStackTo(label);
method.visitJumpInsn(opcode, label); method.visitJumpInsn(opcode, label.getLabel());
} }
/** /**
@ -1487,9 +1482,9 @@ public class MethodEmitter implements Emitter {
* @param label destination label * @param label destination label
*/ */
void _goto(final Label label) { void _goto(final Label label) {
debug("goto", label); //debug("goto", label);
jump(GOTO, label, 0); 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 * @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 * A join in control flow - helper function that makes sure all entry stacks
* discovered for the join point so far are equivalent * 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) { private void mergeStackTo(final Label label) {
final ArrayDeque<Type> labelStack = label.getStack(); //sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
//debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label); //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) { if (labelStack == null) {
assert stack != null; label.setStack(stack.copy());
label.setStack(stack.clone());
return; 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) { if (stack == null) {
stack = label.getStack(); stack = label.getStack();
if (stack == null) { if (stack == null) {
stack = new ArrayDeque<>(); //we don't have a stack at this point. newStack();
} }
} }
debug_label(label); debug_label(label);
mergeStackTo(label); //we have to merge our stack to whatever is in the 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 * @return array of Types
*/ */
protected Type[] getTypesFromStack(final int count) { 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--) { for (int i = count - 1; i >= 0; i--) {
types[i] = iter.next(); types[i] = stack.peek(pos++);
} }
return types; return types;
@ -1695,11 +1682,11 @@ public class MethodEmitter implements Emitter {
* @return function signature for stack contents * @return function signature for stack contents
*/ */
private String getDynamicSignature(final Type returnType, final int argCount) { private String getDynamicSignature(final Type returnType, final int argCount) {
final Iterator<Type> iter = stack.iterator();
final Type[] paramTypes = new Type[argCount]; final Type[] paramTypes = new Type[argCount];
int pos = 0;
for (int i = argCount - 1; i >= 0; i--) { for (int i = argCount - 1; i >= 0; i--) {
paramTypes[i] = iter.next(); paramTypes[i] = stack.peek(pos++);
} }
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes); final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
for (int i = 0; i < argCount; i++) { for (int i = 0; i < argCount; i++) {
@ -2018,8 +2005,13 @@ public class MethodEmitter implements Emitter {
* @param line line number * @param line line number
* @param label label * @param label label
*/ */
void lineNumber(final int line, final Label label) { void lineNumber(final int line) {
method.visitLineNumber(line, label); 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--; pad--;
} }
if (!stack.isEmpty()) { if (stack != null && !stack.isEmpty()) {
sb.append("{"); sb.append("{");
sb.append(stack.size()); sb.append(stack.size());
sb.append(":"); sb.append(":");
for (final Iterator<Type> iter = stack.iterator(); iter.hasNext();) { for (int pos = 0; pos < stack.size(); pos++) {
final Type t = iter.next(); final Type t = stack.peek(pos);
if (t == Type.SCOPE) { if (t == Type.SCOPE) {
sb.append("scope"); sb.append("scope");
@ -2147,7 +2139,7 @@ public class MethodEmitter implements Emitter {
sb.append(t.getDescriptor()); sb.append(t.getDescriptor());
} }
if (iter.hasNext()) { if (pos + 1 < stack.size()) {
sb.append(' '); sb.append(' ');
} }
} }

View File

@ -68,6 +68,16 @@ public final class ObjectClassGenerator {
*/ */
static final String SCOPE_MARKER = "P"; 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 * Debug field logger
* Should we print debugging information for fields when they are generated and getters/setters are called? * Should we print debugging information for fields when they are generated and getters/setters are called?

View File

@ -26,6 +26,7 @@
package jdk.nashorn.internal.codegen; package jdk.nashorn.internal.codegen;
import java.util.List; import java.util.List;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.PropertyMap;
@ -50,6 +51,7 @@ public abstract class ObjectCreator {
private final boolean isScope; private final boolean isScope;
private final boolean hasArguments; private final boolean hasArguments;
private int fieldCount; private int fieldCount;
private int paddedFieldCount;
private int paramCount; private int paramCount;
private String fieldObjectClassName; private String fieldObjectClassName;
private Class<?> fieldObjectClass; 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() { private void findClass() {
fieldObjectClassName = isScope() ? fieldObjectClassName = isScope() ?
ObjectClassGenerator.getClassName(fieldCount, paramCount) : ObjectClassGenerator.getClassName(fieldCount, paramCount) :
ObjectClassGenerator.getClassName(fieldCount); ObjectClassGenerator.getClassName(paddedFieldCount);
try { try {
this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName)); this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
@ -125,11 +129,7 @@ public abstract class ObjectCreator {
* @return the newly created property map * @return the newly created property map
*/ */
protected PropertyMap makeMap() { protected PropertyMap makeMap() {
if (keys.isEmpty()) { //empty map propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount);
propertyMap = PropertyMap.newMap(fieldObjectClass);
} else {
propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments());
}
return propertyMap; return propertyMap;
} }

View File

@ -31,6 +31,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 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.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger; import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; 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) { public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
this.compiler = compiler; this.compiler = compiler;
this.outermost = functionNode; this.outermost = functionNode;
this.outermostCompileUnit = outermostCompileUnit; this.outermostCompileUnit = outermostCompileUnit;
} }
@ -95,7 +96,7 @@ final class Splitter extends NodeVisitor {
final LexicalContext lc = getLexicalContext(); final LexicalContext lc = getLexicalContext();
long weight = WeighNodes.weigh(functionNode); long weight = WeighNodes.weigh(functionNode);
final boolean top = compiler.getFunctionNode() == outermost; final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost;
if (weight >= SPLIT_THRESHOLD) { if (weight >= SPLIT_THRESHOLD) {
LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", 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 List<FunctionNode> dc = directChildren(functionNode);
final Block newBody = (Block)body.accept(new NodeVisitor() { final Block newBody = (Block)body.accept(new NodeVisitor() {
@Override @Override
public boolean enterFunctionNode(final FunctionNode nestedFunction) { public boolean enterFunctionNode(final FunctionNode nestedFunction) {
return dc.contains(nestedFunction); return dc.contains(nestedFunction);
} }
@Override @Override
public Node leaveFunctionNode(final FunctionNode nestedFunction) { public Node leaveFunctionNode(final FunctionNode nestedFunction) {
FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
getLexicalContext().replace(nestedFunction, split); getLexicalContext().replace(nestedFunction, split);
return split; return split;
} }
}); });
functionNode = functionNode.setBody(lc, newBody); functionNode = functionNode.setBody(lc, newBody);
assert functionNode.getCompileUnit() != null; assert functionNode.getCompileUnit() != null;
@ -182,11 +183,11 @@ final class Splitter extends NodeVisitor {
private Block splitBlock(final Block block, final FunctionNode function) { private Block splitBlock(final Block block, final FunctionNode function) {
getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
final List<Node> splits = new ArrayList<>(); final List<Statement> splits = new ArrayList<>();
List<Node> statements = new ArrayList<>(); List<Statement> statements = new ArrayList<>();
long statementsWeight = 0; long statementsWeight = 0;
for (final Node statement : block.getStatements()) { for (final Statement statement : block.getStatements()) {
final long weight = WeighNodes.weigh(statement, weightCache); final long weight = WeighNodes.weigh(statement, weightCache);
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) { if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
@ -220,15 +221,15 @@ final class Splitter extends NodeVisitor {
* *
* @return New split node. * @return New split node.
*/ */
private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) { private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Statement> statements, final long weight) {
final Source source = parent.getSource(); final int lineNumber = parent.getLineNumber();
final long token = parent.getToken(); final long token = parent.getToken();
final int finish = parent.getFinish(); final int finish = parent.getFinish();
final String name = function.uniqueName(SPLIT_PREFIX.symbolName()); 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 @Override
@ -273,7 +274,9 @@ final class Splitter extends NodeVisitor {
return literal; return literal;
} }
getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT);
if (literal instanceof ArrayLiteralNode) { if (literal instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of a property access (period operator.) * IR representation of a property access (period operator.)
@ -41,14 +40,13 @@ public final class AccessNode extends BaseNode {
/** /**
* Constructor * Constructor
* *
* @param source source code
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param base base node * @param base base node
* @param property property * @param property property
*/ */
public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) { public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
super(source, token, finish, base, false, false); super(token, finish, base, false, false);
this.property = property.setIsPropertyName(); this.property = property.setIsPropertyName();
} }
@ -121,10 +119,10 @@ public final class AccessNode extends BaseNode {
} }
@Override @Override
public AccessNode setType(final Type type) { public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
logTypeChange(type); logTypeChange(type);
getSymbol().setTypeOverride(type); //always a temp so this is fine. final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType()); return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType());
} }
@Override @Override

View File

@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR base for accessing/indexing nodes. * IR base for accessing/indexing nodes.
@ -50,15 +49,14 @@ public abstract class BaseNode extends Node implements FunctionCall, TypeOverrid
/** /**
* Constructor * Constructor
* *
* @param source source code
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param base base node * @param base base node
* @param isFunction is this a function * @param isFunction is this a function
* @param hasCallSiteType does this access have a callsite type * @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) { public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
super(source, token, base.getStart(), finish); super(token, base.getStart(), finish);
this.base = base; this.base = base;
this.isFunction = isFunction; this.isFunction = isFunction;
this.hasCallSiteType = hasCallSiteType; this.hasCallSiteType = hasCallSiteType;

View File

@ -29,7 +29,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Source;
/** /**
* BinaryNode nodes represent two operand operations. * BinaryNode nodes represent two operand operations.
@ -44,13 +43,12 @@ public final class BinaryNode extends Node implements Assignment<Node> {
/** /**
* Constructor * Constructor
* *
* @param source source code
* @param token token * @param token token
* @param lhs left hand side * @param lhs left hand side
* @param rhs right hand side * @param rhs right hand side
*/ */
public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) { public BinaryNode(final long token, final Node lhs, final Node rhs) {
super(source, token, lhs.getStart(), rhs.getFinish()); super(token, lhs.getStart(), rhs.getFinish());
this.lhs = lhs; this.lhs = lhs;
this.rhs = rhs; this.rhs = rhs;
} }

View File

@ -30,14 +30,12 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; 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 * IR representation for a list of statements and functions. All provides the
@ -46,7 +44,7 @@ import jdk.nashorn.internal.runtime.Source;
@Immutable @Immutable
public class Block extends BreakableNode implements Flags<Block> { public class Block extends BreakableNode implements Flags<Block> {
/** List of statements */ /** 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. */ /** Symbol table - keys must be returned in the order they were put in. */
protected final Map<String, Symbol> symbols; protected final Map<String, Symbol> symbols;
@ -78,13 +76,13 @@ public class Block extends BreakableNode implements Flags<Block> {
/** /**
* Constructor * Constructor
* *
* @param source source code * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param statements statements * @param statements statements
*/ */
public Block(final Source source, final long token, final int finish, final Node... statements) { public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
super(source, token, finish, new Label("block_break")); super(lineNumber, token, finish, new Label("block_break"));
this.statements = Arrays.asList(statements); this.statements = Arrays.asList(statements);
this.symbols = new LinkedHashMap<>(); this.symbols = new LinkedHashMap<>();
@ -95,27 +93,35 @@ public class Block extends BreakableNode implements Flags<Block> {
/** /**
* Constructor * Constructor
* *
* @param source source code * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param statements statements * @param statements statements
*/ */
public Block(final Source source, final long token, final int finish, final List<Node> statements) { public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
this(source, token, finish, statements.toArray(new Node[statements.size()])); 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); super(block);
this.statements = statements; this.statements = statements;
this.flags = flags; 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.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 @Override
public Node ensureUniqueLabels(final LexicalContext lc) { 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 @Override
public Node accept(final LexicalContext lc, final NodeVisitor visitor) { public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
if (visitor.enterBlock(this)) { 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; 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 * Get an iterator for all the symbols defined in this block
* @return symbol iterator * @return symbol iterator
*/ */
public Iterator<Symbol> symbolIterator() { public List<Symbol> getSymbols() {
return symbols.values().iterator(); return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
} }
/** /**
* Retrieves an existing symbol defined in the current block. * Retrieves an existing symbol defined in the current block.
* @param name the name of the symbol * @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 * @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) { public Symbol getExistingSymbol(final String name) {
return symbols.get(name); return symbols.get(name);
@ -222,7 +228,7 @@ public class Block extends BreakableNode implements Flags<Block> {
* *
* @return a list of statements * @return a list of statements
*/ */
public List<Node> getStatements() { public List<Statement> getStatements() {
return Collections.unmodifiableList(statements); return Collections.unmodifiableList(statements);
} }
@ -233,7 +239,7 @@ public class Block extends BreakableNode implements Flags<Block> {
* @param statements new statement list * @param statements new statement list
* @return new block if statements changed, identity of statements == block.statements * @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) { if (this.statements == statements) {
return this; return this;
} }
@ -241,17 +247,17 @@ public class Block extends BreakableNode implements Flags<Block> {
if (!statements.isEmpty()) { if (!statements.isEmpty()) {
lastFinish = statements.get(statements.size() - 1).getFinish(); 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 * Add or overwrite an existing symbol in the block
* *
* @param name name of symbol * @param lc get lexical context
* @param symbol symbol * @param symbol symbol
*/ */
public void putSymbol(final String name, final Symbol symbol) { public void putSymbol(final LexicalContext lc, final Symbol symbol) {
symbols.put(name, symbol); symbols.put(symbol.getName(), symbol);
} }
/** /**
@ -268,7 +274,7 @@ public class Block extends BreakableNode implements Flags<Block> {
if (this.flags == flags) { if (this.flags == flags) {
return this; 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 @Override
@ -296,7 +302,7 @@ public class Block extends BreakableNode implements Flags<Block> {
return this; 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 * @return next slot
*/ */
public int nextSlot() { public int nextSlot() {
final Iterator<Symbol> iter = symbolIterator();
int next = 0; int next = 0;
while (iter.hasNext()) { for (final Symbol symbol : getSymbols()) {
final Symbol symbol = iter.next(); if (symbol.hasSlot()) {
if (symbol.hasSlot()) { next += symbol.slotCount();
next += symbol.slotCount(); }
}
} }
return next; return next;
} }

View File

@ -41,16 +41,16 @@ import java.util.ListIterator;
public class BlockLexicalContext extends LexicalContext { public class BlockLexicalContext extends LexicalContext {
/** statement stack, each block on the lexical context maintains one of these, which is /** statement stack, each block on the lexical context maintains one of these, which is
* committed to the block on pop */ * 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 */ /** Last non debug statement emitted in this context */
protected Node lastStatement; protected Statement lastStatement;
@Override @Override
public <T extends LexicalContextNode> T push(final T node) { public <T extends LexicalContextNode> T push(final T node) {
T pushed = super.push(node); T pushed = super.push(node);
if (node instanceof Block) { if (node instanceof Block) {
sstack.push(new ArrayList<Node>()); sstack.push(new ArrayList<Statement>());
} }
return pushed; return pushed;
} }
@ -59,16 +59,16 @@ public class BlockLexicalContext extends LexicalContext {
* Get the statement list from the stack, possibly filtered * Get the statement list from the stack, possibly filtered
* @return statement list * @return statement list
*/ */
protected List<Node> popStatements() { protected List<Statement> popStatements() {
return sstack.pop(); return sstack.pop();
} }
@Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override
public <T extends LexicalContextNode> T pop(final T node) { public <T extends LexicalContextNode> T pop(final T node) {
T expected = node; T expected = node;
if (node instanceof Block) { if (node instanceof Block) {
final List<Node> newStatements = popStatements(); final List<Statement> newStatements = popStatements();
expected = (T)((Block)node).setStatements(this, newStatements); expected = (T)((Block)node).setStatements(this, newStatements);
if (!sstack.isEmpty()) { if (!sstack.isEmpty()) {
lastStatement = lastStatement(sstack.peek()); lastStatement = lastStatement(sstack.peek());
@ -81,12 +81,10 @@ public class BlockLexicalContext extends LexicalContext {
* Append a statement to the block being generated * Append a statement to the block being generated
* @param statement statement to add * @param statement statement to add
*/ */
public void appendStatement(final Node statement) { public void appendStatement(final Statement statement) {
assert statement != null; assert statement != null;
sstack.peek().add(statement); 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 * @param statement statement to prepend
* @return the prepended statement * @return the prepended statement
*/ */
public Node prependStatement(final Node statement) { public Node prependStatement(final Statement statement) {
assert statement != null; assert statement != null;
sstack.peek().add(0, statement); sstack.peek().add(0, statement);
return 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 * @return the last statement emitted
*/ */
public Node getLastStatement() { public Statement getLastStatement() {
return lastStatement; return lastStatement;
} }
private static Node lastStatement(final List<Node> statements) { private static Statement lastStatement(final List<Statement> statements) {
for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) { for (final ListIterator<Statement> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
final Node node = iter.previous(); final Statement node = iter.previous();
if (!node.isDebug()) { return node;
return node;
}
} }
return null; return null;
} }

View File

@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for {@code break} statements. * IR representation for {@code break} statements.
*/ */
@Immutable @Immutable
public final class BreakNode extends Node { public final class BreakNode extends Statement {
private final IdentNode label; private final IdentNode label;
/** /**
* Constructor * Constructor
* *
* @param source source code * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param label label for break or null if none * @param label label for break or null if none
*/ */
public BreakNode(final Source source, final long token, final int finish, final IdentNode label) { public BreakNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
super(source, token, finish); super(lineNumber, token, finish);
this.label = label; this.label = label;
} }

View File

@ -30,7 +30,6 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.runtime.Source;
/** /**
* This class represents a node from which control flow can execute * This class represents a node from which control flow can execute
@ -45,13 +44,13 @@ public abstract class BreakableNode extends LexicalContextNode {
/** /**
* Constructor * Constructor
* *
* @param source source code * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param breakLabel break label * @param breakLabel break label
*/ */
protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) { protected BreakableNode(final int lineNumber, final long token, final int finish, final Label breakLabel) {
super(source, token, finish); super(lineNumber, token, finish);
this.breakLabel = breakLabel; this.breakLabel = breakLabel;
} }

View File

@ -31,7 +31,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore; import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for a function call. * IR representation for a function call.
@ -137,14 +136,14 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
/** /**
* Constructors * Constructors
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param function the function to call * @param function the function to call
* @param args args to the 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) { public CallNode(final int lineNumber, final long token, final int finish, final Node function, final List<Node> args) {
super(source, token, finish); super(lineNumber, token, finish);
this.function = function; this.function = function;
this.args = args; this.args = args;
@ -171,7 +170,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
} }
@Override @Override
public CallNode setType(final Type type) { public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
if (this.type == type) { if (this.type == type) {
return this; return this;
} }
@ -201,7 +200,7 @@ public final class CallNode extends LexicalContextNode implements TypeOverride<C
setFunction(function.accept(visitor)). setFunction(function.accept(visitor)).
setArgs(Node.accept(visitor, Node.class, args)). setArgs(Node.accept(visitor, Node.class, args)).
setFlags(flags). setFlags(flags).
setType(type). setType(null, lc, type).
setEvalArgs(evalArgs == null ? setEvalArgs(evalArgs == null ?
null : null :
evalArgs.setCode(evalArgs.getCode().accept(visitor)). evalArgs.setCode(evalArgs.getCode().accept(visitor)).

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of CASE clause. * IR representation of CASE clause.
@ -48,14 +47,13 @@ public final class CaseNode extends Node {
/** /**
* Constructors * Constructors
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param test case test node, can be any node in JavaScript * @param test case test node, can be any node in JavaScript
* @param body case body * @param body case body
*/ */
public CaseNode(final Source source, final long token, final int finish, final Node test, final Block body) { public CaseNode(final long token, final int finish, final Node test, final Block body) {
super(source, token, finish); super(token, finish);
this.test = test; this.test = test;
this.body = body; this.body = body;

View File

@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of a catch clause. * IR representation of a catch clause.
*/ */
@Immutable @Immutable
public final class CatchNode extends Node { public final class CatchNode extends Statement {
/** Exception identifier. */ /** Exception identifier. */
private final IdentNode exception; private final IdentNode exception;
@ -46,16 +45,15 @@ public final class CatchNode extends Node {
/** /**
* Constructors * Constructors
* *
* @param source the source * @param lineNumber lineNumber
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param exception variable name of exception * @param exception variable name of exception
* @param exceptionCondition exception condition * @param exceptionCondition exception condition
* @param body catch body * @param body catch body
*/ */
public CatchNode(final Source source, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) { public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception, final Node exceptionCondition, final Block body) {
super(source, token, finish); super(lineNumber, token, finish);
this.exception = exception; this.exception = exception;
this.exceptionCondition = exceptionCondition; this.exceptionCondition = exceptionCondition;
this.body = body; 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) { private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
super(catchNode); super(catchNode);
this.exception = exception; this.exception = exception;
this.exceptionCondition = exceptionCondition; this.exceptionCondition = exceptionCondition;
this.body = body; this.body = body;
@ -138,7 +135,12 @@ public final class CatchNode extends Node {
return body; 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) { if (this.exception == exception) {
return this; return this;
} }

View File

@ -27,26 +27,25 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for CONTINUE statements. * IR representation for CONTINUE statements.
*/ */
@Immutable @Immutable
public class ContinueNode extends Node { public class ContinueNode extends Statement {
private IdentNode label; private IdentNode label;
/** /**
* Constructor * Constructor
* *
* @param source source code * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param label label for break or null if none * @param label label for break or null if none
*/ */
public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) { public ContinueNode(final int lineNumber, final long token, final int finish, final IdentNode label) {
super(source, token, finish); super(lineNumber, token, finish);
this.label = label; this.label = label;
} }

View File

@ -27,32 +27,31 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for an empty statement. * IR representation for an empty statement.
*/ */
@Immutable @Immutable
public final class EmptyNode extends Node { public final class EmptyNode extends Statement {
/** /**
* Constructor * Constructor
* *
* @param node node to wrap * @param node node to wrap
*/ */
public EmptyNode(final Node node) { public EmptyNode(final Statement node) {
super(node); super(node);
} }
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
*/ */
public EmptyNode(final Source source, final long token, final int finish) { public EmptyNode(final int lineNumber, final long token, final int finish) {
super(source, token, finish); super(lineNumber, token, finish);
} }

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for executing bare expressions. Basically, an expression * 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 * statements being added to the IR
*/ */
@Immutable @Immutable
public final class ExecuteNode extends Node { public final class ExecuteNode extends Statement {
/** Expression to execute. */ /** Expression to execute. */
private final Node expression; private final Node expression;
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param expression the expression to execute * @param expression the expression to execute
*/ */
public ExecuteNode(final Source source, final long token, final int finish, final Node expression) { public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
super(source, token, finish); super(lineNumber, token, finish);
this.expression = expression; this.expression = expression;
} }
@ -57,16 +56,6 @@ public final class ExecuteNode extends Node {
this.expression = expression; 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 @Override
public boolean isTerminal() { public boolean isTerminal() {
return expression.isTerminal(); return expression.isTerminal();

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representing a FOR statement. * IR representing a FOR statement.
@ -57,17 +56,17 @@ public final class ForNode extends LoopNode {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param init init * @param init initialization expression
* @param test test * @param test test
* @param body body * @param body body
* @param modify modify * @param modify modify
* @param flags flags * @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) { 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(source, token, finish, test, body, false); super(lineNumber, token, finish, test, body, false);
this.init = init; this.init = init;
this.modify = modify; this.modify = modify;
this.flags = flags; this.flags = flags;

View File

@ -25,16 +25,12 @@
package jdk.nashorn.internal.ir; 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.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants; 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 */ /** method has been emitted to bytecode */
EMITTED EMITTED
} }
/** Source of entity. */
private final Source source;
/** External function identifier. */ /** External function identifier. */
@Ignore @Ignore
private final IdentNode ident; private final IdentNode ident;
/** Parsed version of functionNode */
@Ignore
private final FunctionNode snapshot;
/** The body of the function node */ /** The body of the function node */
private final Block body; private final Block body;
@ -127,6 +129,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
@Ignore @Ignore
private final EnumSet<CompilationState> compilationState; private final EnumSet<CompilationState> compilationState;
@Ignore
private final Compiler.Hints hints;
/** Function flags. */ /** Function flags. */
private final int flags; private final int flags;
@ -176,6 +181,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** Does this function have nested declarations? */ /** Does this function have nested declarations? */
public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13; 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? */ /** Does this function or any nested functions contain an eval? */
private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_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 * Constructor
* *
* @param source the source * @param source the source
* @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param firstToken first token of the funtion node (including the function declaration) * @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( public FunctionNode(
final Source source, final Source source,
final int lineNumber,
final long token, final long token,
final int finish, final int finish,
final long firstToken, final long firstToken,
@ -217,39 +227,56 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final List<IdentNode> parameters, final List<IdentNode> parameters,
final FunctionNode.Kind kind, final FunctionNode.Kind kind,
final int flags) { final int flags) {
super(source, token, finish); super(lineNumber, token, finish);
this.ident = ident; this.source = source;
this.name = name; this.ident = ident;
this.kind = kind; this.name = name;
this.parameters = parameters; this.kind = kind;
this.firstToken = firstToken; this.parameters = parameters;
this.lastToken = token; this.firstToken = firstToken;
this.namespace = namespace; this.lastToken = token;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED); this.namespace = namespace;
this.declaredSymbols = new HashSet<>(); this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.flags = flags; this.declaredSymbols = new HashSet<>();
this.compileUnit = null; this.flags = flags;
this.body = null; 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); super(functionNode);
this.flags = flags;
this.returnType = returnType; this.flags = flags;
this.compileUnit = compileUnit; this.returnType = returnType;
this.lastToken = lastToken; this.compileUnit = compileUnit;
this.lastToken = lastToken;
this.compilationState = compilationState; 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 // the fields below never change - they are final and assigned in constructor
this.name = functionNode.name; this.source = functionNode.source;
this.ident = functionNode.ident; this.name = functionNode.name;
this.namespace = functionNode.namespace; this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
this.declaredSymbols = functionNode.declaredSymbols; this.declaredSymbols = functionNode.declaredSymbols;
this.kind = functionNode.kind; this.kind = functionNode.kind;
this.parameters = functionNode.parameters; this.firstToken = functionNode.firstToken;
this.firstToken = functionNode.firstToken;
} }
@Override @Override
@ -260,6 +287,61 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
return this; 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 * Get the compilation state of this function
* @return the compilation state * @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); final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
newState.add(state); 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); 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 @Override
public void toString(final StringBuilder sb) { public void toString(final StringBuilder sb) {
@ -374,7 +463,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.flags == flags) { if (this.flags == flags) {
return this; 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 @Override
@ -483,7 +572,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if(this.body == body) { if(this.body == body) {
return this; 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) { if (this.lastToken == lastToken) {
return this; 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 * Reset the compile unit used to compile this function
* @param node node to check specialized type for * @see Compiler
* @return null if no specialization exists, otherwise type * @param lc lexical context
* @param parameters the compile unit
* @return function node or a new one if state was changed
*/ */
@SuppressWarnings("static-method") public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
public Type getSpecializedType(final IdentNode node) { if (this.parameters == parameters) {
return null; //TODO implement specialized types later 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), returnType),
compileUnit, compileUnit,
compilationState, compilationState,
body)); body,
parameters,
snapshot,
hints));
} }
/** /**
@ -705,7 +801,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.compileUnit == compileUnit) { if (this.compileUnit == compileUnit) {
return this; 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. * @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) * 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) { public Symbol compilerConstant(final CompilerConstants cc) {
return body.getExistingSymbol(cc.symbolName()); return body.getExistingSymbol(cc.symbolName());
} }
} }

View File

@ -34,7 +34,6 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for an identifier. * IR representation for an identifier.
@ -56,14 +55,13 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish position * @param finish finish position
* @param name name of identifier * @param name name of identifier
*/ */
public IdentNode(final Source source, final long token, final int finish, final String name) { public IdentNode(final long token, final int finish, final String name) {
super(source, token, finish); super(token, finish);
this.name = name; this.name = name.intern();
this.callSiteType = null; this.callSiteType = null;
this.flags = 0; this.flags = 0;
} }
@ -103,7 +101,7 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
} }
@Override @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 // 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) { if (this.callSiteType == type) {
return this; return this;

View File

@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for an IF statement. * IR representation for an IF statement.
*/ */
@Immutable @Immutable
public final class IfNode extends Node { public final class IfNode extends Statement {
/** Test expression. */ /** Test expression. */
private final Node test; private final Node test;
@ -46,15 +45,15 @@ public final class IfNode extends Node {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param test test * @param test test
* @param pass block to execute when test passes * @param pass block to execute when test passes
* @param fail block to execute when test fails or null * @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) { public IfNode(final int lineNumber, final long token, final int finish, final Node test, final Block pass, final Block fail) {
super(source, token, finish); super(lineNumber, token, finish);
this.test = test; this.test = test;
this.pass = pass; this.pass = pass;
this.fail = fail; this.fail = fail;

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of an indexed access (brackets operator.) * IR representation of an indexed access (brackets operator.)
@ -41,14 +40,13 @@ public final class IndexNode extends BaseNode {
/** /**
* Constructors * Constructors
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param base base node for access * @param base base node for access
* @param index index for access * @param index index for access
*/ */
public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) { public IndexNode(final long token, final int finish, final Node base, final Node index) {
super(source, token, finish, base, false, false); super(token, finish, base, false, false);
this.index = index; this.index = index;
} }
@ -108,6 +106,18 @@ public final class IndexNode extends BaseNode {
return index; 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 @Override
public BaseNode setIsFunction() { public BaseNode setIsFunction() {
if (isFunction()) { if (isFunction()) {
@ -117,10 +127,10 @@ public final class IndexNode extends BaseNode {
} }
@Override @Override
public IndexNode setType(final Type type) { public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
logTypeChange(type); logTypeChange(type);
getSymbol().setTypeOverride(type); //always a temp so this is fine. final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts));
return new IndexNode(this, base, index, isFunction(), true); return new IndexNode(newIndexNode, base, index, isFunction(), true);
} }
} }

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for a labeled statement. * IR representation for a labeled statement.
@ -43,14 +42,14 @@ public final class LabelNode extends LexicalContextNode {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param label label identifier * @param label label identifier
* @param body body of label node * @param body body of label node
*/ */
public LabelNode(final Source source, final long token, final int finish, final IdentNode label, final Block body) { public LabelNode(final int lineNumber, final long token, final int finish, final IdentNode label, final Block body) {
super(source, token, finish); super(lineNumber, token, finish);
this.label = label; this.label = label;
this.body = body; this.body = body;

View File

@ -64,7 +64,6 @@ public class LexicalContext {
for (int i = sp - 1; i >= 0; i--) { for (int i = sp - 1; i >= 0; i--) {
if (stack[i] == node) { if (stack[i] == node) {
flags[i] |= flag; flags[i] |= flag;
//System.err.println("Setting flag " + node + " " + flag);
return; return;
} }
} }
@ -117,8 +116,6 @@ public class LexicalContext {
return (FunctionNode)stack[0]; return (FunctionNode)stack[0];
} }
/** /**
* Pushes a new block on top of the context, making it the innermost open block. * Pushes a new block on top of the context, making it the innermost open block.
* @param node the new node * @param node the new node
@ -395,8 +392,7 @@ public class LexicalContext {
*/ */
public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) { public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) {
final LexicalContextNode parent = stack[sp - 2]; final LexicalContextNode parent = stack[sp - 2];
if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) { if (parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
assert functionNode.getSource() == peek().getSource();
return true; return true;
} }
return false; return false;
@ -543,13 +539,16 @@ public class LexicalContext {
sb.append('@'); sb.append('@');
sb.append(Debug.id(node)); sb.append(Debug.id(node));
sb.append(':'); sb.append(':');
final Source source = node.getSource(); if (node instanceof FunctionNode) {
String src = source.toString(); final Source source = ((FunctionNode)node).getSource();
if (src.indexOf(File.pathSeparator) != -1) { String src = source.toString();
src = src.substring(src.lastIndexOf(File.pathSeparator)); 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(' ');
} }
sb.append(" ==> ]"); sb.append(" ==> ]");

View File

@ -25,22 +25,21 @@
package jdk.nashorn.internal.ir; package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* Superclass for nodes that can be part of the lexical context * Superclass for nodes that can be part of the lexical context
* @see LexicalContext * @see LexicalContext
*/ */
public abstract class LexicalContextNode extends Node { public abstract class LexicalContextNode extends Statement {
/** /**
* Constructor * Constructor
* *
* @param source source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
*/ */
protected LexicalContextNode(final Source source, final long token, final int finish) { protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
super(source, token, finish); super(lineNumber, token, finish);
} }
/** /**
@ -70,4 +69,16 @@ public abstract class LexicalContextNode extends Node {
final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
return lc.pop(newNode); 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));
}
} }

View File

@ -37,7 +37,6 @@ import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.Undefined; import jdk.nashorn.internal.runtime.Undefined;
/** /**
@ -50,16 +49,15 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** Literal value */ /** Literal value */
protected final T value; protected final T value;
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value the value of the literal * @param value the value of the literal
*/ */
protected LiteralNode(final Source source, final long token, final int finish, final T value) { protected LiteralNode(final long token, final int finish, final T value) {
super(source, token, finish); super(token, finish);
this.value = value; this.value = value;
} }
@ -238,14 +236,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** /**
* Create a new null literal * Create a new null literal
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish) { public static LiteralNode<Node> newInstance(final long token, final int finish) {
return new NodeLiteralNode(source, token, finish); return new NodeLiteralNode(token, finish);
} }
/** /**
@ -256,14 +253,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent) { public static LiteralNode<?> newInstance(final Node parent) {
return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish()); return new NodeLiteralNode(parent.getToken(), parent.getFinish());
} }
@Immutable @Immutable
private static final class BooleanLiteralNode extends LiteralNode<Boolean> { private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) { private BooleanLiteralNode(final long token, final int finish, final boolean value) {
super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value); super(Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
} }
private BooleanLiteralNode(final BooleanLiteralNode literalNode) { private BooleanLiteralNode(final BooleanLiteralNode literalNode) {
@ -289,15 +286,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** /**
* Create a new boolean literal * Create a new boolean literal
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value true or false * @param value true or false
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Boolean> newInstance(final Source source, final long token, final int finish, final boolean value) { public static LiteralNode<Boolean> newInstance(final long token, final int finish, final boolean value) {
return new BooleanLiteralNode(source, token, finish, 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final boolean value) { 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 @Immutable
@ -317,8 +313,8 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
private final Type type = numberGetType(value); private final Type type = numberGetType(value);
private NumberLiteralNode(final Source source, final long token, final int finish, final Number value) { private NumberLiteralNode(final long token, final int finish, final Number value) {
super(source, Token.recast(token, TokenType.DECIMAL), finish, value); super(Token.recast(token, TokenType.DECIMAL), finish, value);
} }
private NumberLiteralNode(final NumberLiteralNode literalNode) { private NumberLiteralNode(final NumberLiteralNode literalNode) {
@ -353,15 +349,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** /**
* Create a new number literal * Create a new number literal
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value literal value * @param value literal value
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Number> newInstance(final Source source, final long token, final int finish, final Number value) { public static LiteralNode<Number> newInstance(final long token, final int finish, final Number value) {
return new NumberLiteralNode(source, token, finish, 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final Number value) { 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 static class UndefinedLiteralNode extends LiteralNode<Undefined> {
private UndefinedLiteralNode(final Source source, final long token, final int finish) { private UndefinedLiteralNode(final long token, final int finish) {
super(source, Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED); super(Token.recast(token, TokenType.OBJECT), finish, ScriptRuntime.UNDEFINED);
} }
private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) { private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
@ -389,15 +384,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** /**
* Create a new undefined literal * Create a new undefined literal
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value undefined value, passed only for polymorphisism discrimination * @param value undefined value, passed only for polymorphisism discrimination
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Undefined> newInstance(final Source source, final long token, final int finish, final Undefined value) { public static LiteralNode<Undefined> newInstance(final long token, final int finish, final Undefined value) {
return new UndefinedLiteralNode(source, token, finish); return new UndefinedLiteralNode(token, finish);
} }
/** /**
@ -409,13 +403,13 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final Undefined value) { 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 @Immutable
private static class StringLiteralNode extends LiteralNode<String> { private static class StringLiteralNode extends LiteralNode<String> {
private StringLiteralNode(final Source source, final long token, final int finish, final String value) { private StringLiteralNode(final long token, final int finish, final String value) {
super(source, Token.recast(token, TokenType.STRING), finish, value); super(Token.recast(token, TokenType.STRING), finish, value);
} }
private StringLiteralNode(final StringLiteralNode literalNode) { private StringLiteralNode(final StringLiteralNode literalNode) {
@ -433,15 +427,14 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** /**
* Create a new string literal * Create a new string literal
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value string value * @param value string value
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<String> newInstance(final Source source, final long token, final int finish, final String value) { public static LiteralNode<String> newInstance(final long token, final int finish, final String value) {
return new StringLiteralNode(source, token, finish, 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final String value) { 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 @Immutable
private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> { private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) { private LexerTokenLiteralNode(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? super(Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
} }
private LexerTokenLiteralNode(final LexerTokenLiteralNode literalNode) { 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 * Create a new literal node for a lexer token
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value lexer token value * @param value lexer token value
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<LexerToken> newInstance(final Source source, final long token, final int finish, final LexerToken value) { public static LiteralNode<LexerToken> newInstance(final long token, final int finish, final LexerToken value) {
return new LexerTokenLiteralNode(source, token, finish, 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final LexerToken value) { 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 static final class NodeLiteralNode extends LiteralNode<Node> {
private NodeLiteralNode(final Source source, final long token, final int finish) { private NodeLiteralNode(final long token, final int finish) {
this(source, token, finish, null); this(token, finish, null);
} }
private NodeLiteralNode(final Source source, final long token, final int finish, final Node value) { private NodeLiteralNode(final long token, final int finish, final Node value) {
super(source, Token.recast(token, TokenType.OBJECT), finish, value); super(Token.recast(token, TokenType.OBJECT), finish, value);
} }
private NodeLiteralNode(final LiteralNode<Node> literalNode) { 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 * Create a new node literal for an arbitrary node
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value the literal value node * @param value the literal value node
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Node> newInstance(final Source source, final long token, final int finish, final Node value) { public static LiteralNode<Node> newInstance(final long token, final int finish, final Node value) {
return new NodeLiteralNode(source, token, finish, 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final Node value) { 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 * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value array literal value, a Node array * @param value array literal value, a Node array
*/ */
protected ArrayLiteralNode(final Source source, final long token, final int finish, final Node[] value) { protected ArrayLiteralNode(final long token, final int finish, final Node[] value) {
super(source, Token.recast(token, TokenType.ARRAY), finish, value); super(Token.recast(token, TokenType.ARRAY), finish, value);
this.elementType = Type.UNKNOWN; this.elementType = Type.UNKNOWN;
} }
@ -659,9 +649,12 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* Copy constructor * Copy constructor
* @param node source array literal node * @param node source array literal node
*/ */
protected ArrayLiteralNode(final ArrayLiteralNode node) { private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) {
super(node); super(node, value);
this.elementType = node.elementType; 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; break;
} }
final Symbol symbol = node.getSymbol(); assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble
assert symbol != null; //don't run this on unresolved nodes or you are in trouble Type symbolType = node.getSymbol().getSymbolType();
Type symbolType = symbol.getSymbolType();
if (symbolType.isUnknown()) { if (symbolType.isUnknown()) {
symbolType = Type.OBJECT; 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 * @return post set indices
*/ */
public int[] getPostsets() { public int[] getPostsets() {
@ -849,17 +842,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@Override @Override
public Node accept(final NodeVisitor visitor) { public Node accept(final NodeVisitor visitor) {
if (visitor.enterLiteralNode(this)) { if (visitor.enterLiteralNode(this)) {
for (int i = 0; i < value.length; i++) { final List<Node> oldValue = Arrays.asList(value);
final Node element = value[i]; final List<Node> newValue = Node.accept(visitor, Node.class, oldValue);
if (element != null) { return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this);
value[i] = element.accept(visitor);
}
}
return visitor.leaveLiteralNode(this);
} }
return this; return this;
} }
private ArrayLiteralNode setValue(final List<Node> value) {
return new ArrayLiteralNode(this, value.toArray(new Node[value.size()]));
}
@Override @Override
public void toString(final StringBuilder sb) { public void toString(final StringBuilder sb) {
sb.append('['); 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 * Create a new array literal of Nodes from a list of Node values
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value literal value list * @param value literal value list
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final List<Node> value) { public static LiteralNode<Node[]> newInstance(final long token, final int finish, final List<Node> value) {
return new ArrayLiteralNode(source, token, finish, value.toArray(new Node[value.size()])); 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 * @return the new literal node
*/ */
public static LiteralNode<?> newInstance(final Node parent, final List<Node> value) { 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 * Create a new array literal of Nodes
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param value literal value array * @param value literal value array
* *
* @return the new literal node * @return the new literal node
*/ */
public static LiteralNode<Node[]> newInstance(final Source source, final long token, final int finish, final Node[] value) { public static LiteralNode<Node[]> newInstance(final long token, final int finish, final Node[] value) {
return new ArrayLiteralNode(source, token, finish, value); return new ArrayLiteralNode(token, finish, value);
} }
} }

View File

@ -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;
}
}

View File

@ -29,7 +29,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.codegen.Label; 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 * 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 * Constructor
* *
* @param source source * @param lineNumber lineNumber
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param test test, or null if infinite loop * @param test test, or null if infinite loop
* @param body loop body * @param body loop body
* @param controlFlowEscapes controlFlowEscapes * @param controlFlowEscapes controlFlowEscapes
*/ */
protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) { protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
super(source, token, finish, new Label("while_break")); super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue"); this.continueLabel = new Label("while_continue");
this.test = test; this.test = test;
this.body = body; this.body = body;

View File

@ -27,16 +27,15 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token; 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. * Nodes are used to compose Abstract Syntax Trees.
*/ */
public abstract class Node extends Location { public abstract class Node implements Cloneable {
/** Node symbol. */ /** Node symbol. */
private Symbol symbol; private Symbol symbol;
@ -46,16 +45,17 @@ public abstract class Node extends Location {
/** End of source range. */ /** End of source range. */
protected int finish; protected int finish;
/** Token descriptor. */
private final long token;
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
*/ */
public Node(final Source source, final long token, final int finish) { public Node(final long token, final int finish) {
super(source, token); this.token = token;
this.start = Token.descPosition(token); this.start = Token.descPosition(token);
this.finish = finish; this.finish = finish;
} }
@ -63,16 +63,14 @@ public abstract class Node extends Location {
/** /**
* Constructor * Constructor
* *
* @param source source
* @param token token * @param token token
* @param start start * @param start start
* @param finish finish * @param finish finish
*/ */
protected Node(final Source source, final long token, final int start, final int finish) { protected Node(final long token, final int start, final int finish) {
super(source, token);
this.start = start; this.start = start;
this.finish = finish; this.finish = finish;
this.token = token;
} }
/** /**
@ -81,8 +79,7 @@ public abstract class Node extends Location {
* @param node source node * @param node source node
*/ */
protected Node(final Node node) { protected Node(final Node node) {
super(node); this.token = node.token;
this.symbol = node.symbol; this.symbol = node.symbol;
this.start = node.start; this.start = node.start;
this.finish = node.finish; this.finish = node.finish;
@ -155,15 +152,6 @@ public abstract class Node extends Location {
return Type.OBJECT; 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 * For reference copies - ensure that labels in the copy node are unique
* using an appropriate copy constructor * using an appropriate copy constructor
@ -248,14 +236,86 @@ public abstract class Node extends Location {
return symbol; 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 * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
* of what a symbol is * of what a symbol is
* *
* @param lc lexical context
* @param symbol the symbol * @param symbol the symbol
* @return new node
*/ */
public void setSymbol(final Symbol symbol) { public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
this.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<>(); final List<T> newList = new ArrayList<>();
for (final Node node : list) { 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) { if (newNode != node) {
changed = true; changed = true;
} }

View File

@ -30,7 +30,6 @@ import java.util.List;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of an object literal. * IR representation of an object literal.
@ -44,13 +43,12 @@ public final class ObjectNode extends Node {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param elements the elements used to initialize this ObjectNode * @param elements the elements used to initialize this ObjectNode
*/ */
public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) { public ObjectNode(final long token, final int finish, final List<Node> elements) {
super(source, token, finish); super(token, finish);
this.elements = elements; this.elements = elements;
} }

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of an object literal property. * IR representation of an object literal property.
@ -50,7 +49,6 @@ public final class PropertyNode extends Node {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param key the key of this property * @param key the key of this property
@ -58,8 +56,8 @@ public final class PropertyNode extends Node {
* @param getter getter function body * @param getter getter function body
* @param setter setter 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) { public PropertyNode(final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
super(source, token, finish); super(token, finish);
this.key = key; this.key = key;
this.value = value; this.value = value;
this.getter = getter; this.getter = getter;

View File

@ -29,26 +29,25 @@ import static jdk.nashorn.internal.parser.TokenType.RETURN;
import static jdk.nashorn.internal.parser.TokenType.YIELD; import static jdk.nashorn.internal.parser.TokenType.YIELD;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for RETURN or YIELD statements. * IR representation for RETURN or YIELD statements.
*/ */
@Immutable @Immutable
public class ReturnNode extends Node { public class ReturnNode extends Statement {
/** Optional expression. */ /** Optional expression. */
private final Node expression; private final Node expression;
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param expression expression to return * @param expression expression to return
*/ */
public ReturnNode(final Source source, final long token, final int finish, final Node expression) { public ReturnNode(final int lineNumber, final long token, final int finish, final Node expression) {
super(source, token, finish); super(lineNumber, token, finish);
this.expression = expression; this.expression = expression;
} }
@ -101,9 +100,9 @@ public class ReturnNode extends Node {
@Override @Override
public void toString(final StringBuilder sb) { public void toString(final StringBuilder sb) {
sb.append(isYield() ? "yield" : "return "); sb.append(isYield() ? "yield" : "return");
if (expression != null) { if (expression != null) {
sb.append(' ');
expression.toString(sb); expression.toString(sb);
} }
} }

View File

@ -33,7 +33,6 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for a runtime call. * IR representation for a runtime call.
@ -280,14 +279,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param request the request * @param request the request
* @param args arguments to request * @param args arguments to request
*/ */
public RuntimeNode(final Source source, final long token, final int finish, final Request request, final List<Node> args) { public RuntimeNode(final long token, final int finish, final Request request, final List<Node> args) {
super(source, token, finish); super(token, finish);
this.request = request; this.request = request;
this.args = args; this.args = args;
@ -307,14 +305,13 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param request the request * @param request the request
* @param args arguments to request * @param args arguments to request
*/ */
public RuntimeNode(final Source source, final long token, final int finish, final Request request, final Node... args) { public RuntimeNode(final long token, final int finish, final Request request, final Node... args) {
this(source, token, finish, request, Arrays.asList(args)); this(token, finish, request, Arrays.asList(args));
} }
/** /**
@ -393,7 +390,7 @@ public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
} }
@Override @Override
public RuntimeNode setType(final Type type) { public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
if (this.callSiteType == type) { if (this.callSiteType == type) {
return this; return this;
} }

View File

@ -46,12 +46,13 @@ public class SplitNode extends LexicalContextNode {
/** /**
* Constructor * Constructor
* *
* @param lineNumber lineNumber
* @param name name of split node * @param name name of split node
* @param body body of split code * @param body body of split code
* @param compileUnit compile unit to use for the body * @param compileUnit compile unit to use for the body
*/ */
public SplitNode(final String name, final Node body, final CompileUnit compileUnit) { public SplitNode(final int lineNumber, final String name, final Node body, final CompileUnit compileUnit) {
super(body.getSource(), body.getToken(), body.getFinish()); super(lineNumber, body.getToken(), body.getFinish());
this.name = name; this.name = name;
this.body = body; this.body = body;
this.compileUnit = compileUnit; this.compileUnit = compileUnit;

View File

@ -25,67 +25,56 @@
package jdk.nashorn.internal.ir; 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 abstract class Statement extends Node {
public final class LineNumberNode extends Node {
/** Line number */
private final int lineNumber; private final int lineNumber;
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param lineNumber the line number * @param finish finish
*/ */
public LineNumberNode(final Source source, final long token, final int lineNumber) { public Statement(final int lineNumber, final long token, final int finish) {
super(source, token, Token.descPosition(token)); super(token, finish);
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
} }
private LineNumberNode(final LineNumberNode lineNumberNode) { /**
super(lineNumberNode); * Constructor
this.lineNumber = lineNumberNode.getLineNumber(); *
} * @param lineNumber line number
* @param token token
@Override * @param start start
public Node accept(final NodeVisitor visitor) { * @param finish finish
if (visitor.enterLineNumberNode(this)) { */
return visitor.leaveLineNumberNode(this); protected Statement(final int lineNumber, final long token, final int start, final int finish) {
} super(token, start, finish);
this.lineNumber = lineNumber;
return this;
}
@Override
public void toString(final StringBuilder sb) {
sb.append("[|");
sb.append(lineNumber);
sb.append("|]");
}
@Override
public boolean isAtom() {
return true;
} }
/** /**
* 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 * @return line number
*/ */
public int getLineNumber() { public int getLineNumber() {
return lineNumber; return lineNumber;
} }
@Override
public boolean isDebug() {
return true;
}
} }

View File

@ -32,7 +32,6 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of a SWITCH statement. * IR representation of a SWITCH statement.
@ -54,15 +53,15 @@ public final class SwitchNode extends BreakableNode {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber lineNumber
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param expression switch expression * @param expression switch expression
* @param cases cases * @param cases cases
* @param defaultCase the default case node - null if none, otherwise has to be present in cases list * @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) { public SwitchNode(final int lineNumber, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
super(source, token, finish, new Label("switch_break")); super(lineNumber, token, finish, new Label("switch_break"));
this.expression = expression; this.expression = expression;
this.cases = cases; this.cases = cases;
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase); this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);

View File

@ -29,7 +29,6 @@ import java.io.PrintWriter;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug; 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; public static final int IS_INTERNAL = 1 << 9;
/** Is this a function self-reference symbol */ /** Is this a function self-reference symbol */
public static final int IS_FUNCTION_SELF = 1 << 10; 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. */ /** Null or name identifying symbol. */
private final String name; private final String name;
@ -152,6 +155,16 @@ public final class Symbol implements Comparable<Symbol> {
this(name, flags, type, -1); 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) { private static String align(final String string, final int max) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append(string.substring(0, Math.min(string.length(), max))); 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; 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 @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final String desc = getSymbolType().getDescriptor();
sb.append(name). sb.append(name).
append(' '). append(' ').
append('('). append('(').
append(type(desc)). append(getSymbolType().getTypeClass().getSimpleName()).
append(')'); append(')');
if (hasSlot()) { if (hasSlot()) {
@ -346,6 +341,24 @@ public final class Symbol implements Comparable<Symbol> {
return (flags & IS_SCOPE) == IS_SCOPE; 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()} * 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() { public void setIsScope() {
if (!isScope()) { if (!isScope()) {
trace("SET IS SCOPE"); 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 * Check if this symbol is a variable
* @return true if variable * @return true if variable
@ -383,6 +409,15 @@ public final class Symbol implements Comparable<Symbol> {
return (flags & KINDMASK) == IS_PARAM; 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 * Check whether this symbol ever has primitive assignments. Conservative
* @return true if primitive assignments exist * @return true if primitive assignments exist
@ -404,7 +439,10 @@ public final class Symbol implements Comparable<Symbol> {
*/ */
public void setCanBeUndefined() { public void setCanBeUndefined() {
assert type.isObject() : type; 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 * @param type the primitive type it occurs with, currently unused but can be used for width guesses
*/ */
public void setCanBePrimitive(final Type type) { 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 * Flag this symbol as a let
*/ */
public void setIsLet() { 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 * @param fieldIndex field index - a positive integer
*/ */
public void setFieldIndex(final int fieldIndex) { 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 * @param flags flags
*/ */
public void setFlags(final int 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) { public void setSlot(final int slot) {
if (slot != this.slot) { if (slot != this.slot) {
assert !isShared();
trace("SET SLOT " + slot); trace("SET SLOT " + slot);
this.slot = slot; this.slot = slot;
} }
@ -561,6 +612,15 @@ public final class Symbol implements Comparable<Symbol> {
setTypeOverride(Type.widest(this.type, type)); 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 * Only use this if you know about an existing type
* constraint - otherwise a type can only be * constraint - otherwise a type can only be
@ -571,11 +631,32 @@ public final class Symbol implements Comparable<Symbol> {
public void setTypeOverride(final Type type) { public void setTypeOverride(final Type type) {
final Type old = this.type; final Type old = this.type;
if (old != type) { if (old != type) {
assert !isShared();
trace("TYPE CHANGE: " + old + "=>" + type + " == " + type); trace("TYPE CHANGE: " + old + "=>" + type + " == " + type);
this.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 * From a lexical context, set this symbol as needing scope, which
* will set flags for the defining block that will be written when * will set flags for the defining block that will be written when

View 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;
}
}
}
}

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* TernaryNode nodes represent three operand operations (?:). * TernaryNode nodes represent three operand operations (?:).
@ -44,14 +43,13 @@ public final class TernaryNode extends Node {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param lhs left hand side node * @param lhs left hand side node
* @param rhs right hand side node * @param rhs right hand side node
* @param third third node * @param third third node
*/ */
public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) { public TernaryNode(final long token, final Node lhs, final Node rhs, final Node third) {
super(source, token, third.getFinish()); super(token, third.getFinish());
this.lhs = lhs; this.lhs = lhs;
this.rhs = rhs; this.rhs = rhs;
this.third = third; this.third = third;

View File

@ -27,31 +27,29 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for THROW statements. * IR representation for THROW statements.
*/ */
@Immutable @Immutable
public final class ThrowNode extends Node { public final class ThrowNode extends Statement {
/** Exception expression. */ /** Exception expression. */
private final Node expression; private final Node expression;
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param expression expression to throw * @param expression expression to throw
*/ */
public ThrowNode(final Source source, final long token, final int finish, final Node expression) { public ThrowNode(final int lineNumber, final long token, final int finish, final Node expression) {
super(source, token, finish); super(lineNumber, token, finish);
this.expression = expression; this.expression = expression;
} }
private ThrowNode(final Node node, final Node expression) { private ThrowNode(final ThrowNode node, final Node expression) {
super(node); super(node);
this.expression = expression; this.expression = expression;
} }

View File

@ -32,13 +32,12 @@ import java.util.List;
import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation of a TRY statement. * IR representation of a TRY statement.
*/ */
@Immutable @Immutable
public final class TryNode extends Node { public final class TryNode extends Statement {
/** Try statements. */ /** Try statements. */
private final Block body; private final Block body;
@ -60,27 +59,27 @@ public final class TryNode extends Node {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber lineNumber
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param body try node body * @param body try node body
* @param catchBlocks list of catch blocks in order * @param catchBlocks list of catch blocks in order
* @param finallyBody body of finally block or null if none * @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) { public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
super(source, token, finish); super(lineNumber, token, finish);
this.body = body; this.body = body;
this.catchBlocks = catchBlocks; this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody; 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) { private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
super(tryNode); super(tryNode);
this.body = body; this.body = body;
this.catchBlocks = catchBlocks; this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody; this.finallyBody = finallyBody;
this.exit = new Label(tryNode.exit); this.exit = new Label(tryNode.exit);
} }
@Override @Override

View File

@ -43,10 +43,12 @@ public interface TypeOverride<T extends Node> {
/** /**
* Set the override type * 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. * @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 * Returns true if this node can have a callsite override, e.g. all scope ident nodes

View File

@ -35,7 +35,6 @@ import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType; import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Source;
/** /**
* UnaryNode nodes represent single operand operations. * UnaryNode nodes represent single operand operations.
@ -48,24 +47,23 @@ public final class UnaryNode extends Node implements Assignment<Node> {
/** /**
* Constructor * Constructor
* *
* @param source the source
* @param token token * @param token token
* @param rhs expression * @param rhs expression
*/ */
public UnaryNode(final Source source, final long token, final Node rhs) { public UnaryNode(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); this(token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
} }
/** /**
* Constructor * Constructor
* @param source the source *
* @param token token * @param token token
* @param start start * @param start start
* @param finish finish * @param finish finish
* @param rhs expression * @param rhs expression
*/ */
public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) { public UnaryNode(final long token, final int start, final int finish, final Node rhs) {
super(source, token, start, finish); super(token, start, finish);
this.rhs = rhs; this.rhs = rhs;
} }

View File

@ -27,13 +27,12 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* Node represents a var/let declaration. * Node represents a var/let declaration.
*/ */
@Immutable @Immutable
public final class VarNode extends Node implements Assignment<IdentNode> { public final class VarNode extends Statement implements Assignment<IdentNode> {
/** Var name. */ /** Var name. */
private final IdentNode name; private final IdentNode name;
@ -54,14 +53,14 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param name name of variable * @param name name of variable
* @param init init node or null if just a declaration * @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) { public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init) {
this(source, token, finish, name, init, IS_STATEMENT); this(lineNumber, token, finish, name, init, IS_STATEMENT);
} }
private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) { private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
@ -74,15 +73,15 @@ public final class VarNode extends Node implements Assignment<IdentNode> {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param name name of variable * @param name name of variable
* @param init init node or null if just a declaration * @param init init node or null if just a declaration
* @param flags flags * @param flags flags
*/ */
public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) { public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
super(source, token, finish); super(lineNumber, token, finish);
this.name = init == null ? name : name.setIsInitializedHere(); this.name = init == null ? name : name.setIsInitializedHere();
this.init = init; this.init = init;

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; 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 * IR representation for a WHILE statement. This is the superclass of all
@ -42,13 +41,13 @@ public final class WhileNode extends LoopNode {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
* @param isDoWhile is this a do while loop? * @param isDoWhile is this a do while loop?
*/ */
public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) { public WhileNode(final int lineNumber, final long token, final int finish, final boolean isDoWhile) {
super(source, token, finish, null, null, false); super(lineNumber, token, finish, null, null, false);
this.isDoWhile = isDoWhile; this.isDoWhile = isDoWhile;
} }
@ -135,17 +134,9 @@ public final class WhileNode extends LoopNode {
@Override @Override
public void toString(final StringBuilder sb) { public void toString(final StringBuilder sb) {
if (isDoWhile()) { sb.append("while (");
sb.append("do {"); test.toString(sb);
body.toString(sb); sb.append(')');
sb.append("} while (");
test.toString(sb);
sb.append(')');
} else {
sb.append("while (");
test.toString(sb);
sb.append(')');
}
} }
@Override @Override

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/** /**
* IR representation for {@code with} statements. * IR representation for {@code with} statements.
@ -43,20 +42,18 @@ public final class WithNode extends LexicalContextNode {
/** /**
* Constructor * Constructor
* *
* @param source the source * @param lineNumber line number
* @param token token * @param token token
* @param finish finish * @param finish finish
*/ */
public WithNode(final Source source, final long token, final int finish) { public WithNode(final int lineNumber, final long token, final int finish) {
super(source, token, finish); super(lineNumber, token, finish);
this.expression = null; this.expression = null;
this.body = null; this.body = null;
} }
private WithNode(final WithNode node, final Node expression, final Block body) { private WithNode(final WithNode node, final Node expression, final Block body) {
super(node); super(node);
this.expression = expression; this.expression = expression;
this.body = body; this.body = body;
} }

View File

@ -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 + "]";
}
}

View File

@ -27,6 +27,7 @@ package jdk.nashorn.internal.ir.debug;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode; 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.IfNode;
import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode; 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.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.ThrowNode;
@ -406,17 +407,15 @@ public final class JSONWriter extends NodeVisitor {
} }
// body consists of nested functions and statements // 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(); final int size = stats.size();
int idx = 0; int idx = 0;
arrayStart("body"); arrayStart("body");
for (final Node stat : stats) { for (final Node stat : stats) {
if (! stat.isDebug()) { stat.accept(this);
stat.accept(this); if (idx != (size - 1)) {
if (idx != (size - 1)) { comma();
comma();
}
} }
idx++; idx++;
} }
@ -504,11 +503,6 @@ public final class JSONWriter extends NodeVisitor {
return leave(); return leave();
} }
@Override
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
return false;
}
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
@Override @Override
public boolean enterLiteralNode(final LiteralNode literalNode) { public boolean enterLiteralNode(final LiteralNode literalNode) {
@ -931,15 +925,13 @@ public final class JSONWriter extends NodeVisitor {
int idx = 0; int idx = 0;
arrayStart(name); arrayStart(name);
for (final Node node : nodes) { for (final Node node : nodes) {
if (node == null || !node.isDebug()) { if (node != null) {
if (node != null) { node.accept(this);
node.accept(this); } else {
} else { nullValue();
nullValue(); }
} if (idx != (size - 1)) {
if (idx != (size - 1)) { comma();
comma();
}
} }
idx++; idx++;
} }
@ -971,7 +963,7 @@ public final class JSONWriter extends NodeVisitor {
objectStart("loc"); objectStart("loc");
// source name // source name
final Source src = node.getSource(); final Source src = getLexicalContext().getCurrentFunction().getSource();
property("source", src.getName()); property("source", src.getName());
comma(); comma();

View File

@ -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;
}
};
}
}

View File

@ -36,9 +36,9 @@ import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IfNode; import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode; import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol; import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode; import jdk.nashorn.internal.ir.TryNode;
@ -55,7 +55,7 @@ import jdk.nashorn.internal.ir.visitor.NodeVisitor;
*/ */
public final class PrintVisitor extends NodeVisitor { public final class PrintVisitor extends NodeVisitor {
/** Tab width */ /** Tab width */
private static final int TABWIDTH = 1; private static final int TABWIDTH = 4;
/** Composing buffer. */ /** Composing buffer. */
private final StringBuilder sb; private final StringBuilder sb;
@ -69,6 +69,8 @@ public final class PrintVisitor extends NodeVisitor {
/** Print line numbers */ /** Print line numbers */
private final boolean printLineNumbers; private final boolean printLineNumbers;
private int lastLineNumber = -1;
/** /**
* Constructor. * Constructor.
*/ */
@ -138,24 +140,27 @@ public final class PrintVisitor extends NodeVisitor {
@Override @Override
public boolean enterBlock(final Block block) { public boolean enterBlock(final Block block) {
sb.append(' '); sb.append(' ');
//sb.append(Debug.id(block));
sb.append('{'); sb.append('{');
indent += TABWIDTH; indent += TABWIDTH;
final List<Node> statements = block.getStatements(); final List<Statement> statements = block.getStatements();
boolean lastLineNumber = false;
for (final Node statement : statements) { for (final Node statement : statements) {
if (printLineNumbers || !lastLineNumber) { if (printLineNumbers && (statement instanceof Statement)) {
sb.append(EOLN); final int lineNumber = ((Statement)statement).getLineNumber();
indent(); sb.append('\n');
if (lineNumber != lastLineNumber) {
indent();
sb.append("[|").append(lineNumber).append("|];").append('\n');
}
lastLineNumber = lineNumber;
} }
indent();
statement.accept(this); statement.accept(this);
lastLineNumber = statement instanceof LineNumberNode;
if (statement instanceof FunctionNode) { if (statement instanceof FunctionNode) {
continue; continue;
} }
@ -168,12 +173,14 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(']'); 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 (lastChar != '}' && lastChar != ';') {
if (printLineNumbers || !lastLineNumber) { sb.append(';');
sb.append(';');
}
} }
if (statement.hasGoto()) { if (statement.hasGoto()) {
@ -189,7 +196,8 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(EOLN); sb.append(EOLN);
indent(); indent();
sb.append("}"); sb.append('}');
// sb.append(Debug.id(block));
return false; return false;
} }
@ -221,7 +229,7 @@ public final class PrintVisitor extends NodeVisitor {
public boolean enterFunctionNode(final FunctionNode functionNode) { public boolean enterFunctionNode(final FunctionNode functionNode) {
functionNode.toString(sb); functionNode.toString(sb);
enterBlock(functionNode.getBody()); enterBlock(functionNode.getBody());
sb.append(EOLN); //sb.append(EOLN);
return false; return false;
} }
@ -251,15 +259,6 @@ public final class PrintVisitor extends NodeVisitor {
return false; return false;
} }
@Override
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (printLineNumbers) {
lineNumberNode.toString(sb);
}
return false;
}
@Override @Override
public boolean enterSplitNode(final SplitNode splitNode) { public boolean enterSplitNode(final SplitNode splitNode) {
splitNode.toString(sb); splitNode.toString(sb);
@ -334,6 +333,7 @@ public final class PrintVisitor extends NodeVisitor {
sb.append(" = "); sb.append(" = ");
init.accept(this); init.accept(this);
} }
return false; return false;
} }

View File

@ -149,7 +149,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
return enterASSIGN_SUB(binaryNode); return enterASSIGN_SUB(binaryNode);
case BIND: case BIND:
return enterBIND(binaryNode); return enterBIND(binaryNode);
case BIT_AND: case BIT_AND:
return enterBIT_AND(binaryNode); return enterBIT_AND(binaryNode);
case BIT_OR: case BIT_OR:
return enterBIT_OR(binaryNode); return enterBIT_OR(binaryNode);

View File

@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode; import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode; import jdk.nashorn.internal.ir.ObjectNode;
@ -453,26 +452,6 @@ public abstract class NodeVisitor {
return leaveDefault(labelNode); 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 * Callback for entering a LiteralNode
* *

View File

@ -297,7 +297,7 @@ public final class NativeArray extends ScriptObject {
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static Object length(final Object self) { public static Object length(final Object self) {
if (isArray(self)) { if (isArray(self)) {
return ((NativeArray) self).getArray().length() & JSType.MAX_UINT; return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT;
} }
return 0; return 0;
@ -311,7 +311,7 @@ public final class NativeArray extends ScriptObject {
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) { public static void length(final Object self, final Object length) {
if (isArray(self)) { 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(); final boolean strict = sobj.isStrictContext();
if (bulkable(sobj)) { if (bulkable(sobj)) {
final NativeArray nativeArray = (NativeArray)sobj; if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
if (nativeArray.getArray().length() + args.length <= JSType.MAX_UINT) { final ArrayData newData = sobj.getArray().push(sobj.isStrictContext(), args);
final ArrayData newData = nativeArray.getArray().push(nativeArray.isStrictContext(), args); sobj.setArray(newData);
nativeArray.setArray(newData);
return newData.length(); return newData.length();
} }
//fallthru //fallthru
@ -780,8 +779,7 @@ public final class NativeArray extends ScriptObject {
} }
if (bulkable(sobj)) { if (bulkable(sobj)) {
final NativeArray narray = (NativeArray) sobj; return new NativeArray(sobj.getArray().slice(k, finale));
return new NativeArray(narray.getArray().slice(k, finale));
} }
final NativeArray copy = new NativeArray(0); final NativeArray copy = new NativeArray(0);
@ -1001,11 +999,10 @@ public final class NativeArray extends ScriptObject {
} }
if (bulkable(sobj)) { if (bulkable(sobj)) {
final NativeArray nativeArray = (NativeArray) sobj; sobj.getArray().shiftRight(items.length);
nativeArray.getArray().shiftRight(items.length);
for (int j = 0; j < items.length; j++) { 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 { } else {
for (long k = len; k > 0; k--) { for (long k = len; k > 0; k--) {

View File

@ -86,66 +86,6 @@ public final class NativeDebug extends ScriptObject {
return UNDEFINED; 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} * Nashorn extension: get spill vector from {@link ScriptObject}
* *

View File

@ -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. // 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, return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
func.makeBoundFunction(this, new Object[] { name })), 0, 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)); throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
default: default:
@ -687,7 +687,7 @@ public final class NativeJSAdapter extends ScriptObject {
if (methodHandle != null) { if (methodHandle != null) {
return new GuardedInvocation( return new GuardedInvocation(
methodHandle, methodHandle,
adaptee.getMap().getProtoGetSwitchPoint(hook), adaptee.getMap().getProtoGetSwitchPoint(adaptee.getProto(), hook),
testJSAdaptor(adaptee, findData.getGetter(Object.class), findData.getOwner(), func)); 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__) ? final MethodHandle methodHandle = hook.equals(__put__) ?
MH.asType(Lookup.EMPTY_SETTER, type) : MH.asType(Lookup.EMPTY_SETTER, type) :
Lookup.emptyGetter(type.returnType()); 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));
} }
} }

View File

@ -794,15 +794,15 @@ public final class NativeRegExp extends ScriptObject {
RegExpResult match; RegExpResult match;
final int inputLength = string.length(); final int inputLength = string.length();
int lastLength = -1; int splitLastLength = -1;
int lastIndex = 0; int splitLastIndex = 0;
int lastLastIndex = 0; int splitLastLastIndex = 0;
while ((match = execSplit(string, lastIndex)) != null) { while ((match = execSplit(string, splitLastIndex)) != null) {
lastIndex = match.getIndex() + match.length(); splitLastIndex = match.getIndex() + match.length();
if (lastIndex > lastLastIndex) { if (splitLastIndex > splitLastLastIndex) {
matches.add(string.substring(lastLastIndex, match.getIndex())); matches.add(string.substring(splitLastLastIndex, match.getIndex()));
final Object[] groups = match.getGroups(); final Object[] groups = match.getGroups();
if (groups.length > 1 && match.getIndex() < inputLength) { if (groups.length > 1 && match.getIndex() < inputLength) {
for (int index = 1; index < groups.length && matches.size() < limit; index++) { 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) { if (matches.size() >= limit) {
break; break;
@ -818,10 +818,10 @@ public final class NativeRegExp extends ScriptObject {
} }
// bump the index to avoid infinite loop // bump the index to avoid infinite loop
if (lastIndex == lastLastIndex) { if (splitLastIndex == splitLastLastIndex) {
lastIndex++; splitLastIndex++;
} else { } 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 // check special case if we need to append an empty string at the
// end of the match // end of the match
// if the lastIndex was the entire string // if the lastIndex was the entire string
if (lastLastIndex == string.length()) { if (splitLastLastIndex == string.length()) {
if (lastLength > 0 || execSplit("", 0) == null) { if (splitLastLength > 0 || execSplit("", 0) == null) {
matches.add(""); matches.add("");
} }
} else { } 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() { boolean getGlobal() {
return regexp.isGlobal(); return regexp.isGlobal();
} }

View File

@ -249,6 +249,7 @@ public abstract class AbstractParser {
* *
* @param errorType The error type of the warning * @param errorType The error type of the warning
* @param message Warning message. * @param message Warning message.
* @param errorToken error token
*/ */
protected final void warning(final JSErrorType errorType, final String message, final long errorToken) { protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
errors.warning(error(errorType, message, errorToken)); errors.warning(error(errorType, message, errorToken));
@ -363,7 +364,7 @@ public abstract class AbstractParser {
next(); next();
// Create IDENT node. // Create IDENT node.
return new IdentNode(source, identToken, finish, ident); return new IdentNode(identToken, finish, ident);
} }
// Get IDENT. // Get IDENT.
@ -372,7 +373,7 @@ public abstract class AbstractParser {
return null; return null;
} }
// Create IDENT node. // 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); final String ident = (String)getValue(identToken);
next(); next();
// Create IDENT node. // Create IDENT node.
return new IdentNode(source, identToken, finish, ident); return new IdentNode(identToken, finish, ident);
} else { } else {
expect(IDENT); expect(IDENT);
return null; return null;
@ -432,11 +433,11 @@ public abstract class AbstractParser {
LiteralNode<?> node = null; LiteralNode<?> node = null;
if (value == null) { if (value == null) {
node = LiteralNode.newInstance(source, literalToken, finish); node = LiteralNode.newInstance(literalToken, finish);
} else if (value instanceof Number) { } 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) { } 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) { } else if (value instanceof LexerToken) {
if (value instanceof RegexToken) { if (value instanceof RegexToken) {
final RegexToken regex = (RegexToken)value; final RegexToken regex = (RegexToken)value;
@ -446,7 +447,7 @@ public abstract class AbstractParser {
throw error(e.getMessage()); throw error(e.getMessage());
} }
} }
node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value); node = LiteralNode.newInstance(literalToken, finish, (LexerToken)value);
} else { } else {
assert false : "unknown type for LiteralNode: " + value.getClass(); assert false : "unknown type for LiteralNode: " + value.getClass();
} }

View File

@ -193,13 +193,13 @@ public class JSONParser extends AbstractParser {
return getLiteral(); return getLiteral();
case FALSE: case FALSE:
next(); next();
return LiteralNode.newInstance(source, literalToken, finish, false); return LiteralNode.newInstance(literalToken, finish, false);
case TRUE: case TRUE:
next(); next();
return LiteralNode.newInstance(source, literalToken, finish, true); return LiteralNode.newInstance(literalToken, finish, true);
case NULL: case NULL:
next(); next();
return LiteralNode.newInstance(source, literalToken, finish); return LiteralNode.newInstance(literalToken, finish);
case LBRACKET: case LBRACKET:
return arrayLiteral(); return arrayLiteral();
case LBRACE: case LBRACE:
@ -218,7 +218,7 @@ public class JSONParser extends AbstractParser {
if (value instanceof Number) { if (value instanceof Number) {
next(); 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())); throw error(AbstractParser.message("expected", "number", type.getNameOrType()));
@ -250,7 +250,7 @@ loop:
switch (type) { switch (type) {
case RBRACKET: case RBRACKET:
next(); next();
result = LiteralNode.newInstance(source, arrayToken, finish, elements); result = LiteralNode.newInstance(arrayToken, finish, elements);
break loop; break loop;
case COMMARIGHT: case COMMARIGHT:
@ -310,7 +310,7 @@ loop:
} }
// Construct new object literal. // 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) { if (name != null) {
expect(COLON); expect(COLON);
final Node value = jsonLiteral(); 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. // Raise an error.

View File

@ -59,9 +59,11 @@ import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block; import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BlockLexicalContext; 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.IndexNode;
import jdk.nashorn.internal.ir.LabelNode; import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext; import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LoopNode; import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node; 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.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode; import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode; import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode; import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.TernaryNode; import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.ThrowNode; import jdk.nashorn.internal.ir.ThrowNode;
@ -117,7 +119,7 @@ public class Parser extends AbstractParser {
/** Is scripting mode. */ /** Is scripting mode. */
private final boolean scripting; private final boolean scripting;
private List<Node> functionDeclarations; private List<Statement> functionDeclarations;
private final BlockLexicalContext lc = new BlockLexicalContext(); private final BlockLexicalContext lc = new BlockLexicalContext();
@ -275,8 +277,7 @@ loop:
* @return New block. * @return New block.
*/ */
private Block newBlock() { private Block newBlock() {
final Block block = new Block(source, token, Token.descPosition(token)); return lc.push(new Block(line, token, Token.descPosition(token)));
return lc.push(block);
} }
/** /**
@ -305,11 +306,17 @@ loop:
if (isStrictMode) { if (isStrictMode) {
flags |= FunctionNode.IS_STRICT; flags |= FunctionNode.IS_STRICT;
} }
if (env._specialize_calls != null) {
if (env._specialize_calls.contains(name)) {
flags |= FunctionNode.CAN_SPECIALIZE;
}
}
// Start new block. // Start new block.
FunctionNode functionNode = FunctionNode functionNode =
new FunctionNode( new FunctionNode(
source, source,
line, //TODO?
token, token,
Token.descPosition(token), Token.descPosition(token),
startToken, startToken,
@ -320,11 +327,11 @@ loop:
kind, kind,
flags); flags);
functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
lc.push(functionNode); lc.push(functionNode);
// Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
// FunctionNode. // FunctionNode.
newBlock(); newBlock();
return functionNode; return functionNode;
} }
@ -332,14 +339,19 @@ loop:
* Restore the current block. * Restore the current block.
*/ */
private Block restoreBlock(final Block 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) { private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); 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. * Get the statements in a block.
@ -469,7 +481,7 @@ loop:
} }
// Build up node. // 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. * @param isPostfix Prefix or postfix.
* @return Reduced expression. * @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) { 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( FunctionNode script = newFunctionNode(
functionToken, functionToken,
new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName), new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
new ArrayList<IdentNode>(), new ArrayList<IdentNode>(),
FunctionNode.Kind.SCRIPT); FunctionNode.Kind.SCRIPT);
@ -529,6 +541,7 @@ loop:
script = restoreFunctionNode(script, token); //commit code script = restoreFunctionNode(script, token); //commit code
script = script.setBody(lc, script.getBody().setNeedsScope(lc)); script = script.setBody(lc, script.getBody().setNeedsScope(lc));
return script; return script;
} }
@ -670,8 +683,6 @@ loop:
* @param topLevel does this statement occur at the "top level" of a script or a function? * @param topLevel does this statement occur at the "top level" of a script or a function?
*/ */
private void statement(final boolean topLevel) { private void statement(final boolean topLevel) {
final LineNumberNode lineNumberNode = lineNumber();
if (type == FUNCTION) { if (type == FUNCTION) {
// As per spec (ECMA section 12), function declarations as arbitrary statement // As per spec (ECMA section 12), function declarations as arbitrary statement
// is not "portable". Implementation can issue a warning or disallow the same. // is not "portable". Implementation can issue a warning or disallow the same.
@ -679,10 +690,6 @@ loop:
return; return;
} }
if (lineNumberNode != null) {
appendStatement(lineNumberNode);
}
switch (type) { switch (type) {
case LBRACE: case LBRACE:
block(); block();
@ -763,7 +770,7 @@ loop:
private void block() { private void block() {
final Block newBlock = getBlock(true); final Block newBlock = getBlock(true);
// Force block execution. // 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 ident Identifier that is verified
* @param contextString String used in error message to give context to the user * @param contextString String used in error message to give context to the user
*/ */
@SuppressWarnings("fallthrough")
private void verifyStrictIdent(final IdentNode ident, final String contextString) { private void verifyStrictIdent(final IdentNode ident, final String contextString) {
if (isStrictMode) { if (isStrictMode) {
switch (ident.getName()) { switch (ident.getName()) {
@ -840,6 +846,7 @@ loop:
while (true) { while (true) {
// Get starting token. // Get starting token.
final int varLine = line;
final long varToken = token; final long varToken = token;
// Get name of var. // Get name of var.
final IdentNode name = getIdent(); final IdentNode name = getIdent();
@ -857,7 +864,7 @@ loop:
} }
// Allocate var node. // 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); vars.add(var);
appendStatement(var); appendStatement(var);
@ -889,7 +896,7 @@ loop:
*/ */
private void emptyStatement() { private void emptyStatement() {
if (env._empty_statements) { 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. // SEMICOLON checked in caller.
@ -906,6 +913,7 @@ loop:
*/ */
private void expressionStatement() { private void expressionStatement() {
// Lookahead checked in caller. // Lookahead checked in caller.
final int expressionLine = line;
final long expressionToken = token; final long expressionToken = token;
// Get expression and add as statement. // Get expression and add as statement.
@ -913,7 +921,7 @@ loop:
ExecuteNode executeNode = null; ExecuteNode executeNode = null;
if (expression != null) { if (expression != null) {
executeNode = new ExecuteNode(source, expressionToken, finish, expression); executeNode = new ExecuteNode(expressionLine, expressionToken, finish, expression);
appendStatement(executeNode); appendStatement(executeNode);
} else { } else {
expect(null); expect(null);
@ -938,6 +946,7 @@ loop:
*/ */
private void ifStatement() { private void ifStatement() {
// Capture IF token. // Capture IF token.
final int ifLine = line;
final long ifToken = token; final long ifToken = token;
// IF tested in caller. // IF tested in caller.
next(); next();
@ -953,7 +962,7 @@ loop:
fail = getStatement(); 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() { private void forStatement() {
// Create FOR node, capturing FOR token. // 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. // Set up new block for scope of vars. Captures first token.
Block outer = newBlock(); Block outer = newBlock();
@ -1074,7 +1082,7 @@ loop:
outer = restoreBlock(outer); 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() { private void whileStatement() {
// Capture WHILE token. // Capture WHILE token.
final int whileLine = line;
final long whileToken = token; final long whileToken = token;
// WHILE tested in caller. // WHILE tested in caller.
next(); next();
// Construct WHILE node. // 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); lc.push(whileNode);
try { try {
@ -1136,11 +1145,12 @@ loop:
*/ */
private void doStatement() { private void doStatement() {
// Capture DO token. // Capture DO token.
final int doLine = line;
final long doToken = token; final long doToken = token;
// DO tested in the caller. // DO tested in the caller.
next(); next();
WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true); WhileNode doWhileNode = new WhileNode(doLine, doToken, Token.descPosition(doToken), true);
lc.push(doWhileNode); lc.push(doWhileNode);
try { try {
@ -1172,6 +1182,7 @@ loop:
*/ */
private void continueStatement() { private void continueStatement() {
// Capture CONTINUE token. // Capture CONTINUE token.
final int continueLine = line;
final long continueToken = token; final long continueToken = token;
// CONTINUE tested in caller. // CONTINUE tested in caller.
nextOrEOL(); nextOrEOL();
@ -1206,7 +1217,7 @@ loop:
endOfLine(); endOfLine();
// Construct and add CONTINUE node. // 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() { private void breakStatement() {
// Capture BREAK token. // Capture BREAK token.
final int breakLine = line;
final long breakToken = token; final long breakToken = token;
// BREAK tested in caller. // BREAK tested in caller.
nextOrEOL(); nextOrEOL();
@ -1253,7 +1265,7 @@ loop:
endOfLine(); endOfLine();
// Construct and add BREAK node. // 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. // Capture RETURN token.
final int returnLine = line;
final long returnToken = token; final long returnToken = token;
// RETURN tested in caller. // RETURN tested in caller.
nextOrEOL(); nextOrEOL();
@ -1292,7 +1305,7 @@ loop:
endOfLine(); endOfLine();
// Construct and add RETURN node. // 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() { private void yieldStatement() {
// Capture YIELD token. // Capture YIELD token.
final int yieldLine = line;
final long yieldToken = token; final long yieldToken = token;
// YIELD tested in caller. // YIELD tested in caller.
nextOrEOL(); nextOrEOL();
@ -1326,7 +1340,7 @@ loop:
endOfLine(); endOfLine();
// Construct and add YIELD node. // 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() { private void withStatement() {
// Capture WITH token. // Capture WITH token.
final int withLine = line;
final long withToken = token; final long withToken = token;
// WITH tested in caller. // WITH tested in caller.
next(); next();
@ -1349,7 +1364,7 @@ loop:
} }
// Get WITH expression. // Get WITH expression.
WithNode withNode = new WithNode(source, withToken, finish); WithNode withNode = new WithNode(withLine, withToken, finish);
try { try {
lc.push(withNode); lc.push(withNode);
@ -1387,12 +1402,13 @@ loop:
* Parse SWITCH statement. * Parse SWITCH statement.
*/ */
private void switchStatement() { private void switchStatement() {
final int switchLine = line;
final long switchToken = token; final long switchToken = token;
// SWITCH tested in caller. // SWITCH tested in caller.
next(); next();
// Create and add switch statement. // 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); lc.push(switchNode);
try { try {
@ -1434,7 +1450,7 @@ loop:
// Get CASE body. // Get CASE body.
final Block statements = getBlock(false); 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); statements.setFinish(finish);
if (caseExpression == null) { if (caseExpression == null) {
@ -1474,7 +1490,7 @@ loop:
throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 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 { try {
lc.push(labelNode); lc.push(labelNode);
labelNode = labelNode.setBody(lc, getStatement()); labelNode = labelNode.setBody(lc, getStatement());
@ -1496,6 +1512,7 @@ loop:
*/ */
private void throwStatement() { private void throwStatement() {
// Capture THROW token. // Capture THROW token.
final int throwLine = line;
final long throwToken = token; final long throwToken = token;
// THROW tested in caller. // THROW tested in caller.
nextOrEOL(); nextOrEOL();
@ -1520,7 +1537,7 @@ loop:
endOfLine(); endOfLine();
appendStatement(new ThrowNode(source, throwToken, finish, expression)); appendStatement(new ThrowNode(throwLine, throwToken, finish, expression));
} }
/** /**
@ -1542,6 +1559,7 @@ loop:
*/ */
private void tryStatement() { private void tryStatement() {
// Capture TRY token. // Capture TRY token.
final int tryLine = line;
final long tryToken = token; final long tryToken = token;
// TRY tested in caller. // TRY tested in caller.
next(); next();
@ -1556,6 +1574,7 @@ loop:
final List<Block> catchBlocks = new ArrayList<>(); final List<Block> catchBlocks = new ArrayList<>();
while (type == CATCH) { while (type == CATCH) {
final int catchLine = line;
final long catchToken = token; final long catchToken = token;
next(); next();
expect(LPAREN); expect(LPAREN);
@ -1578,7 +1597,7 @@ loop:
try { try {
// Get CATCH body. // Get CATCH body.
final Block catchBody = getBlock(true); 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); appendStatement(catchNode);
} finally { } finally {
catchBlock = restoreBlock(catchBlock); catchBlock = restoreBlock(catchBlock);
@ -1604,7 +1623,7 @@ loop:
throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 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. // Add try.
assert lc.peek() == outer; assert lc.peek() == outer;
appendStatement(tryNode); appendStatement(tryNode);
@ -1616,7 +1635,7 @@ loop:
outer = restoreBlock(outer); 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() { private void debuggerStatement() {
// Capture DEBUGGER token. // Capture DEBUGGER token.
final int debuggerLine = line;
final long debuggerToken = token; final long debuggerToken = token;
// DEBUGGER tested in caller. // DEBUGGER tested in caller.
next(); next();
endOfLine(); 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") @SuppressWarnings("fallthrough")
private Node primaryExpression() { private Node primaryExpression() {
// Capture first token. // Capture first token.
final int primaryLine = line;
final long primaryToken = token; final long primaryToken = token;
switch (type) { switch (type) {
case THIS: case THIS:
final String name = type.getName(); final String name = type.getName();
next(); next();
return new IdentNode(source, primaryToken, finish, name); return new IdentNode(primaryToken, finish, name);
case IDENT: case IDENT:
final IdentNode ident = getIdent(); final IdentNode ident = getIdent();
if (ident == null) { if (ident == null) {
@ -1680,16 +1701,16 @@ loop:
case XML: case XML:
return getLiteral(); return getLiteral();
case EXECSTRING: case EXECSTRING:
return execString(primaryToken); return execString(primaryLine, primaryToken);
case FALSE: case FALSE:
next(); next();
return LiteralNode.newInstance(source, primaryToken, finish, false); return LiteralNode.newInstance(primaryToken, finish, false);
case TRUE: case TRUE:
next(); next();
return LiteralNode.newInstance(source, primaryToken, finish, true); return LiteralNode.newInstance(primaryToken, finish, true);
case NULL: case NULL:
next(); next();
return LiteralNode.newInstance(source, primaryToken, finish); return LiteralNode.newInstance(primaryToken, finish);
case LBRACKET: case LBRACKET:
return arrayLiteral(); return arrayLiteral();
case LBRACE: case LBRACE:
@ -1724,9 +1745,9 @@ loop:
* @param primaryToken Original string token. * @param primaryToken Original string token.
* @return callNode to $EXEC. * @return callNode to $EXEC.
*/ */
Node execString(final long primaryToken) { Node execString(final int primaryLine, final long primaryToken) {
// Synthesize an ident to call $EXEC. // 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. // Skip over EXECSTRING.
next(); next();
// Set up argument list for call. // Set up argument list for call.
@ -1738,7 +1759,7 @@ loop:
// Skip ending of edit string expression. // Skip ending of edit string expression.
expect(RBRACE); 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)); map.put(key, newProperty = newProperty.setValue(value));
} else { } else {
final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT); 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)); 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": case "get":
final PropertyKey getIdent = propertyName(); final PropertyKey getIdent = propertyName();
final String getterName = getIdent.getPropertyName(); 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(LPAREN);
expect(RPAREN); expect(RPAREN);
functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); 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": case "set":
final PropertyKey setIdent = propertyName(); final PropertyKey setIdent = propertyName();
final String setterName = setIdent.getPropertyName(); 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); expect(LPAREN);
final IdentNode argIdent = getIdent(); final IdentNode argIdent = getIdent();
verifyStrictIdent(argIdent, "setter argument"); verifyStrictIdent(argIdent, "setter argument");
@ -2020,21 +2041,21 @@ loop:
List<IdentNode> parameters = new ArrayList<>(); List<IdentNode> parameters = new ArrayList<>();
parameters.add(argIdent); parameters.add(argIdent);
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); 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: default:
break; break;
} }
} }
propertyName = new IdentNode(source, propertyToken, finish, ident); propertyName = new IdentNode(propertyToken, finish, ident);
} else { } else {
propertyName = propertyName(); propertyName = propertyName();
} }
expect(COLON); 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. * @return Expression node.
*/ */
private Node leftHandSideExpression() { private Node leftHandSideExpression() {
int callLine = line;
long callToken = token; long callToken = token;
Node lhs = memberExpression(); Node lhs = memberExpression();
@ -2066,12 +2088,13 @@ loop:
detectSpecialFunction((IdentNode)lhs); detectSpecialFunction((IdentNode)lhs);
} }
lhs = new CallNode(source, callToken, finish, lhs, arguments); lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
} }
loop: loop:
while (true) { while (true) {
// Capture token. // Capture token.
callLine = line;
callToken = token; callToken = token;
switch (type) { switch (type) {
@ -2080,7 +2103,7 @@ loop:
final List<Node> arguments = argumentList(); final List<Node> arguments = argumentList();
// Create call node. // Create call node.
lhs = new CallNode(source, callToken, finish, lhs, arguments); lhs = new CallNode(callLine, callToken, finish, lhs, arguments);
break; break;
@ -2093,7 +2116,7 @@ loop:
expect(RBRACKET); expect(RBRACKET);
// Create indexing node. // Create indexing node.
lhs = new IndexNode(source, callToken, finish, lhs, rhs); lhs = new IndexNode(callToken, finish, lhs, rhs);
break; break;
@ -2103,7 +2126,7 @@ loop:
final IdentNode property = getIdentifierName(); final IdentNode property = getIdentifierName();
// Create property access node. // Create property access node.
lhs = new AccessNode(source, callToken, finish, lhs, property); lhs = new AccessNode(callToken, finish, lhs, property);
break; break;
@ -2131,6 +2154,7 @@ loop:
next(); next();
// Get function base. // Get function base.
final int callLine = line;
final Node constructor = memberExpression(); final Node constructor = memberExpression();
if (constructor == null) { if (constructor == null) {
return null; return null;
@ -2159,9 +2183,9 @@ loop:
arguments.add(objectLiteral()); 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); expect(RBRACKET);
// Create indexing node. // Create indexing node.
lhs = new IndexNode(source, callToken, finish, lhs, index); lhs = new IndexNode(callToken, finish, lhs, index);
break; break;
@ -2227,7 +2251,7 @@ loop:
final IdentNode property = getIdentifierName(); final IdentNode property = getIdentifierName();
// Create property access node. // Create property access node.
lhs = new AccessNode(source, callToken, finish, lhs, property); lhs = new AccessNode(callToken, finish, lhs, property);
break; break;
@ -2294,9 +2318,8 @@ loop:
* @return Expression node. * @return Expression node.
*/ */
private Node functionExpression(final boolean isStatement, final boolean topLevel) { private Node functionExpression(final boolean isStatement, final boolean topLevel) {
final LineNumberNode lineNumber = lineNumber();
final long functionToken = token; final long functionToken = token;
final int functionLine = line;
// FUNCTION is tested in caller. // FUNCTION is tested in caller.
next(); next();
@ -2316,7 +2339,7 @@ loop:
boolean isAnonymous = false; boolean isAnonymous = false;
if (name == null) { if (name == null) {
final String tmpName = "_L" + source.getLine(Token.descPosition(token)); 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; isAnonymous = true;
} }
@ -2367,7 +2390,7 @@ loop:
// rename in non-strict mode // rename in non-strict mode
parameterName = functionNode.uniqueName(parameterName); parameterName = functionNode.uniqueName(parameterName);
final long parameterToken = parameter.getToken(); 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); parametersSet.add(parameterName);
@ -2379,12 +2402,10 @@ loop:
} }
if (isStatement) { 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) { if (topLevel) {
functionDeclarations.add(lineNumber);
functionDeclarations.add(varNode); functionDeclarations.add(varNode);
} else { } else {
appendStatement(lineNumber);
appendStatement(varNode); appendStatement(varNode);
} }
} }
@ -2459,7 +2480,7 @@ loop:
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
// create a return statement - this creates code in itself and does not need to be // create a return statement - this creates code in itself and does not need to be
// wrapped into an ExecuteNode // 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); appendStatement(returnNode);
lastToken = token; lastToken = token;
functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
@ -2468,7 +2489,7 @@ loop:
expect(LBRACE); expect(LBRACE);
// Gather the function elements. // Gather the function elements.
final List<Node> prevFunctionDecls = functionDeclarations; final List<Statement> prevFunctionDecls = functionDeclarations;
functionDeclarations = new ArrayList<>(); functionDeclarations = new ArrayList<>();
try { try {
sourceElements(); sourceElements();
@ -2492,7 +2513,7 @@ loop:
assert lc.peek() == lc.getFunctionBody(functionNode); assert lc.peek() == lc.getFunctionBody(functionNode);
VarNode lastDecl = null; VarNode lastDecl = null;
for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 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) { if (lastDecl == null && decl instanceof VarNode) {
decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS); 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<>(); final ArrayList<Node> args = new ArrayList<>();
args.add(lhs); args.add(lhs);
if (rhs == null) { if (rhs == null) {
args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish())); args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
} else { } else {
args.add(rhs); args.add(rhs);
} }
args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
} }
/* /*
@ -2548,10 +2569,19 @@ loop:
* @return Expression node. * @return Expression node.
*/ */
private Node unaryExpression() { private Node unaryExpression() {
final int unaryLine = line;
final long unaryToken = token; final long unaryToken = token;
switch (type) { 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 VOID:
case TYPEOF: case TYPEOF:
case ADD: case ADD:
@ -2560,7 +2590,7 @@ loop:
case NOT: case NOT:
next(); next();
final Node expr = unaryExpression(); final Node expr = unaryExpression();
return new UnaryNode(source, unaryToken, expr); return new UnaryNode(unaryToken, expr);
case INCPREFIX: case INCPREFIX:
case DECPREFIX: case DECPREFIX:
@ -2749,7 +2779,7 @@ loop:
final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); final Node third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
// Build up node. // Build up node.
lhs = new TernaryNode(source, op, lhs, rhs, third); lhs = new TernaryNode(op, lhs, rhs, third);
} else { } else {
// Skip operator. // Skip operator.
next(); 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 @Override
public String toString() { public String toString() {
return "[JavaScript Parsing]"; return "[JavaScript Parsing]";
@ -2835,11 +2855,11 @@ loop:
} }
} }
private void prependStatement(final Node statement) { private void prependStatement(final Statement statement) {
lc.prependStatement(statement); lc.prependStatement(statement);
} }
private void appendStatement(final Node statement) { private void appendStatement(final Statement statement) {
lc.appendStatement(statement); lc.appendStatement(statement);
} }
} }

View File

@ -50,8 +50,6 @@ import jdk.nashorn.internal.lookup.MethodHandleFactory;
/** /**
* An AccessorProperty is the most generic property type. An AccessorProperty is * An AccessorProperty is the most generic property type. An AccessorProperty is
* represented as fields in a ScriptObject class. * represented as fields in a ScriptObject class.
*
* @see SpillProperty
*/ */
public class AccessorProperty extends Property { public class AccessorProperty extends Property {
private static final MethodHandles.Lookup lookup = MethodHandles.lookup(); 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_GETTER_TYPES = new MethodType[NOOF_TYPES];
private static final MethodType[] ACCESSOR_SETTER_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) */ /** Seed getter for the primitive version of this field (in -Dnashorn.fields.dual=true mode) */
private MethodHandle primitiveGetter; private MethodHandle primitiveGetter;
@ -285,7 +284,7 @@ public class AccessorProperty extends Property {
"get"); "get");
} }
return getters[i]; return isSpill() ? MH.filterArguments(getters[i], 0, SPILLGETTER) : getters[i];
} }
private Property getWiderProperty(final Class<?> type) { private Property getWiderProperty(final Class<?> type) {
@ -327,6 +326,7 @@ public class AccessorProperty extends Property {
final Class<?> forType = currentType == null ? type : currentType; 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 //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)) { if (needsInvalidator(i, ci)) {
final Property newProperty = getWiderProperty(type); 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)); final MethodHandle explodeTypeSetter = MH.filterArguments(widerSetter, 0, MH.insertArguments(REPLACE_MAP, 1, newMap, getKey(), currentType, type));
if (currentType != null && currentType.isPrimitive() && type == Object.class) { if (currentType != null && currentType.isPrimitive() && type == Object.class) {
//might try a box check on this to avoid widening field to object storage //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 @Override

View File

@ -88,7 +88,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
int weight = Type.typeFor(type.returnType()).getWeight(); int weight = Type.typeFor(type.returnType()).getWeight();
for (final Class<?> paramType : type.parameterArray()) { 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; weight += pweight;
} }
return weight; return weight;

View File

@ -69,5 +69,4 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
return best(type).moreGenericThan(type); return best(type).moreGenericThan(type);
} }
} }

View File

@ -201,9 +201,6 @@ public final class Context {
/** Current error manager. */ /** Current error manager. */
private final ErrorManager errors; 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 ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader; private static final StructureLoader sharedLoader;
@ -414,7 +411,7 @@ public final class Context {
return ScriptRuntime.apply(func, evalThis); 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)) { if (srcStr.startsWith(prefix)) {
final String resource = resourcePath + srcStr.substring(prefix.length()); final String resource = resourcePath + srcStr.substring(prefix.length());
// NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme // 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 * 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 * @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 CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs); 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(); final FunctionNode newFunctionNode = compiler.compile(functionNode);
script = compiler.install(); script = compiler.install(newFunctionNode);
if (global != null) { if (global != null) {
global.cacheClass(source, script); global.cacheClass(source, script);

View File

@ -25,8 +25,6 @@
package jdk.nashorn.internal.runtime; package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.ScriptObject.isArray;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;

View File

@ -41,7 +41,6 @@ import jdk.nashorn.internal.codegen.types.Type;
* *
* @see PropertyMap * @see PropertyMap
* @see AccessorProperty * @see AccessorProperty
* @see SpillProperty
* @see UserAccessorProperty * @see UserAccessorProperty
*/ */
public abstract class Property { public abstract class Property {
@ -64,7 +63,7 @@ public abstract class Property {
private static final int MODIFY_MASK = 0b0000_0000_1111; 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; public static final int IS_SPILL = 0b0000_0001_0000;
/** Is this a function parameter? */ /** Is this a function parameter? */
@ -88,7 +87,7 @@ public abstract class Property {
/** Property flags. */ /** Property flags. */
protected int flags; protected int flags;
/** Property field number or spill slot */ /** Property field number or spill slot. */
private final int 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 * Does this property use any slots in the spill array described in
* {@link Property#isSpill}? In that case how many. Currently a property * {@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 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 * @return number of spill slots a property is using
*/ */
@ -344,6 +343,14 @@ public abstract class Property {
return key; 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 * 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 * anything about the internal representation when we request the setter, we only
@ -388,14 +395,6 @@ public abstract class Property {
return null; return null;
} }
/**
* Get the field number or spill slot
* @return number/slot, -1 if none exists
*/
public int getSlot() {
return slot;
}
@Override @Override
public int hashCode() { public int hashCode() {
final Class<?> type = getCurrentType(); final Class<?> type = getCurrentType();

View File

@ -110,7 +110,7 @@ public final class PropertyHashMap implements Map <String, Property> {
private static final int LIST_THRESHOLD = 8; private static final int LIST_THRESHOLD = 8;
/** Initial map. */ /** Initial map. */
public static final PropertyHashMap EMPTY_MAP = new PropertyHashMap(); public static final PropertyHashMap EMPTY_HASHMAP = new PropertyHashMap();
/** Number of properties in the map. */ /** Number of properties in the map. */
private final int size; private final int size;
@ -246,7 +246,7 @@ public final class PropertyHashMap implements Map <String, Property> {
} }
} else if (findElement(list, key) != null) { } else if (findElement(list, key) != null) {
final int newSize = size - 1; 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; return this;
} }

View File

@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime; 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.MethodHandle;
import java.lang.invoke.SwitchPoint; import java.lang.invoke.SwitchPoint;
@ -49,29 +49,27 @@ import java.util.WeakHashMap;
* will return a new map. * will return a new map.
*/ */
public final class PropertyMap implements Iterable<Object>, PropertyListener { 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()} */ /** 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 */ /** 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; 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} */ /** 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; 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. */ /** Map status flags. */
private int 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. */ /** Map of properties. */
private final PropertyHashMap properties; private final PropertyHashMap properties;
/** objects proto. */ /** Number of fields in use. */
private ScriptObject proto; private int fieldCount;
/** Number of fields available. */
private int fieldMaximum;
/** Length of spill in use. */ /** Length of spill in use. */
private int spillLength; private int spillLength;
@ -91,21 +89,30 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
/** /**
* Constructor. * Constructor.
* *
* @param structure Class the map's {@link AccessorProperty}s apply to. * @param properties A {@link PropertyHashMap} with initial contents.
* @param context Context associated with this {@link PropertyMap}. * @param fieldCount Number of fields in use.
* @param properties A {@link PropertyHashMap} with initial contents. * @param fieldMaximum Number of fields available.
*/ */
PropertyMap(final Class<?> structure, final Context context, final PropertyHashMap properties) { private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) {
this.structure = structure; this.properties = properties;
this.context = context; this.hashCode = computeHashCode();
this.properties = properties; this.fieldCount = fieldCount;
this.hashCode = computeHashCode(); this.fieldMaximum = fieldMaximum;
if (Context.DEBUG) { if (Context.DEBUG) {
count++; count++;
} }
} }
/**
* Constructor.
*
* @param properties A {@link PropertyHashMap} with initial contents.
*/
private PropertyMap(final PropertyHashMap properties) {
this(properties, 0, 0);
}
/** /**
* Cloning constructor. * 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. * @param properties A {@link PropertyHashMap} with a new set of properties.
*/ */
private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) { private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
this.structure = propertyMap.structure; this.properties = properties;
this.context = propertyMap.context; this.flags = propertyMap.getClonedFlags();
this.properties = properties; this.spillLength = propertyMap.spillLength;
this.flags = propertyMap.getClonedFlags(); this.fieldCount = propertyMap.fieldCount;
this.proto = propertyMap.proto; this.fieldMaximum = propertyMap.fieldMaximum;
this.spillLength = propertyMap.spillLength; this.hashCode = computeHashCode();
this.hashCode = computeHashCode();
if (Context.DEBUG) { if (Context.DEBUG) {
count++; 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 * Duplicates this PropertyMap instance. This is used by nasgen generated
* prototype and constructor classes. {@link PropertyMap} used for singletons * 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}. * @return Duplicated {@link PropertyMap}.
*/ */
public PropertyMap duplicate() { 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 structure Class the map's {@link AccessorProperty}s apply to.
* @param properties Collection of initial properties. * @param properties Collection of initial properties.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
* *
* @return New {@link PropertyMap}. * @return New {@link PropertyMap}.
*/ */
public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties) { public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties, final int fieldCount, final int fieldMaximum) {
final Context context = Context.fromClass(structure);
// Reduce the number of empty maps in the context. // Reduce the number of empty maps in the context.
if (structure == jdk.nashorn.internal.scripts.JO.class) { 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}. * @return New {@link PropertyMap}.
*/ */
public static PropertyMap newMap(final Class<?> structure) { 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}. * @return New empty {@link PropertyMap}.
*/ */
public static PropertyMap newEmptyMap(final Context context) { 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. * 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. * @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) { if (proto == null) {
return null; return null;
} }
@ -295,6 +311,11 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyHashMap newProperties = properties.immutableAdd(property); final PropertyHashMap newProperties = properties.immutableAdd(property);
newMap = new PropertyMap(this, newProperties); newMap = new PropertyMap(this, newProperties);
addToHistory(property, newMap); addToHistory(property, newMap);
if(!property.isSpill()) {
newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1);
}
newMap.spillLength += property.getSpillCount(); newMap.spillLength += property.getSpillCount();
} }
@ -355,7 +376,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted"; newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted";
newMap.flags = getClonedFlags(); newMap.flags = getClonedFlags();
newMap.proto = proto;
/* /*
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need * 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. * @return New map with {@link #NOT_EXTENSIBLE} flag set.
*/ */
PropertyMap preventExtensions() { PropertyMap preventExtensions() {
final PropertyMap newMap = new PropertyMap(this, this.properties); final PropertyMap newMap = new PropertyMap(this);
newMap.flags |= NOT_EXTENSIBLE; newMap.flags |= NOT_EXTENSIBLE;
return newMap; return newMap;
} }
@ -423,7 +443,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* {@link Property#NOT_CONFIGURABLE} set. * {@link Property#NOT_CONFIGURABLE} set.
*/ */
PropertyMap seal() { PropertyMap seal() {
PropertyHashMap newProperties = EMPTY_MAP; PropertyHashMap newProperties = EMPTY_HASHMAP;
for (final Property oldProperty : properties.getProperties()) { for (final Property oldProperty : properties.getProperties()) {
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE)); 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. * {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set.
*/ */
PropertyMap freeze() { PropertyMap freeze() {
PropertyHashMap newProperties = EMPTY_MAP; PropertyHashMap newProperties = EMPTY_HASHMAP;
for (Property oldProperty : properties.getProperties()) { for (Property oldProperty : properties.getProperties()) {
int propertyFlags = Property.NOT_CONFIGURABLE; int propertyFlags = Property.NOT_CONFIGURABLE;
@ -578,11 +598,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return Computed hash code. * @return Computed hash code.
*/ */
private int computeHashCode() { private int computeHashCode() {
int hash = structure.hashCode(); int hash = 0;
if (proto != null) {
hash ^= proto.hashCode();
}
for (final Property property : getProperties()) { for (final Property property : getProperties()) {
hash = hash << 7 ^ hash >> 7; hash = hash << 7 ^ hash >> 7;
@ -605,9 +621,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyMap otherMap = (PropertyMap)other; final PropertyMap otherMap = (PropertyMap)other;
if (structure != otherMap.structure || if (properties.size() != otherMap.properties.size()) {
proto != otherMap.proto ||
properties.size() != otherMap.properties.size()) {
return false; return false;
} }
@ -658,31 +672,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
return new PropertyMapIterator(this); 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. * 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() { boolean isFrozen() {
return !isExtensible() && allFrozen(); 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}. * 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. * @param oldProto Current prototype object.
*/ * @param newProto New prototype object to replace oldProto.
ScriptObject getProto() {
return proto;
}
/**
* Set the prototype of objects associated with this {@link PropertyMap}.
*
* @param newProto Prototype object to use.
* *
* @return New {@link PropertyMap} with prototype changed. * @return New {@link PropertyMap} with prototype changed.
*/ */
PropertyMap setProto(final ScriptObject newProto) { PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) {
final ScriptObject oldProto = this.proto;
if (oldProto == newProto) { if (oldProto == newProto) {
return this; return this;
} }
@ -761,19 +756,10 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
if (Context.DEBUG) { if (Context.DEBUG) {
incrementSetProtoNewMapCount(); incrementSetProtoNewMapCount();
} }
final PropertyMap newMap = new PropertyMap(this, this.properties);
final PropertyMap newMap = new PropertyMap(this);
addToProtoHistory(newProto, newMap); addToProtoHistory(newProto, newMap);
newMap.proto = newProto;
if (oldProto != null && newMap.isListenerAdded()) {
oldProto.removePropertyListener(newMap);
}
if (newProto != null) {
newProto.getMap().setIsPrototype();
}
return newMap; return newMap;
} }
@ -927,4 +913,3 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
setProtoNewMapCount++; setProtoNewMapCount++;
} }
} }

View File

@ -30,9 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.LinkedList;
import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.FunctionSignature; 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;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.Token;
@ -148,10 +151,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
if (functionNode.isLazy()) { if (functionNode.isLazy()) {
Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
final Compiler compiler = new Compiler(installer, functionNode); final Compiler compiler = new Compiler(installer);
functionNode = compiler.compile(); functionNode = compiler.compile(functionNode);
assert !functionNode.isLazy(); assert !functionNode.isLazy();
compiler.install(); compiler.install(functionNode);
// we don't need to update any flags - varArgs and needsCallee are instrincic // 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 // 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); 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 exists - look it up and add it into the automatically sorted invoker list
code.add( addCode(functionNode, null, null);
new CompiledFunction(
MH.findStatic(
LOOKUP,
functionNode.getCompileUnit().getCode(),
functionNode.getName(),
new FunctionSignature(functionNode).
getMethodType())));
} }
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 @Override
MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
final MethodHandle mh = super.getBestInvoker(callSiteType, 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));
} }
} }

View File

@ -26,9 +26,13 @@
package jdk.nashorn.internal.runtime; package jdk.nashorn.internal.runtime;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone; import java.util.TimeZone;
import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.options.KeyValueOption; import jdk.nashorn.internal.runtime.options.KeyValueOption;
@ -136,6 +140,9 @@ public final class ScriptEnvironment {
/** Print resulting bytecode for script */ /** Print resulting bytecode for script */
public final boolean _print_code; 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 */ /** Print function will no print newline characters */
public final boolean _print_no_newline; public final boolean _print_no_newline;
@ -151,6 +158,9 @@ public final class ScriptEnvironment {
/** is this environment in scripting mode? */ /** is this environment in scripting mode? */
public final boolean _scripting; 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? */ /** is this environment in strict mode? */
public final boolean _strict; public final boolean _strict;
@ -204,6 +214,7 @@ public final class ScriptEnvironment {
_print_ast = options.getBoolean("print.ast"); _print_ast = options.getBoolean("print.ast");
_print_lower_ast = options.getBoolean("print.lower.ast"); _print_lower_ast = options.getBoolean("print.lower.ast");
_print_code = options.getBoolean("print.code"); _print_code = options.getBoolean("print.code");
_print_mem_usage = options.getBoolean("print.mem.usage");
_print_no_newline = options.getBoolean("print.no.newline"); _print_no_newline = options.getBoolean("print.no.newline");
_print_parse = options.getBoolean("print.parse"); _print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse"); _print_lower_parse = options.getBoolean("print.lower.parse");
@ -213,6 +224,17 @@ public final class ScriptEnvironment {
_version = options.getBoolean("version"); _version = options.getBoolean("version");
_verify_code = options.getBoolean("verify.code"); _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; int callSiteFlags = 0;
if (options.getBoolean("profile.callsites")) { if (options.getBoolean("profile.callsites")) {
callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE; callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
@ -246,6 +268,18 @@ public final class ScriptEnvironment {
this._locale = Locale.getDefault(); 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 * Get the output stream for this environment
* @return output print writer * @return output print writer

View File

@ -104,34 +104,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Per ScriptObject flag - is this an arguments object? */ /** Per ScriptObject flag - is this an arguments object? */
public static final int IS_ARGUMENTS = 0b0000_0100; 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 */ /** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
public static final int SPILL_RATE = 8; public static final int SPILL_RATE = 8;
/** Map to property information and accessor functions. Ordered by insertion. */ /** Map to property information and accessor functions. Ordered by insertion. */
private PropertyMap map; private PropertyMap map;
/** objects proto. */
private ScriptObject proto;
/** Context of the object, lazily cached. */
private Context context;
/** Object flags. */ /** Object flags. */
private int 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; 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. */ /** Indexed array data. */
private ArrayData arrayData; 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 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 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); 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) { if (deep) {
final ScriptObject proto = getProto(); final ScriptObject myProto = getProto();
if(proto != null) { if (myProto != null) {
return proto.findProperty(key, deep, stopOnNonScope, start); 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 // delete getter and setter function references so that we don't leak
if (property instanceof UserAccessorProperty) { if (property instanceof UserAccessorProperty) {
final UserAccessorProperty uc = (UserAccessorProperty) property; final UserAccessorProperty uc = (UserAccessorProperty) property;
setEmbedOrSpill(uc.getGetterSlot(), null); setSpill(uc.getGetterSlot(), null);
setEmbedOrSpill(uc.getSetterSlot(), null); setSpill(uc.getSetterSlot(), null);
} }
return true; return true;
} }
@ -809,7 +806,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int getterSlot = uc.getGetterSlot(); int getterSlot = uc.getGetterSlot();
// clear the old getter and set the new getter // 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 function is null, flag the slot to be negative (less by 1)
if (getter == null) { if (getter == null) {
getterSlot = -getterSlot - 1; getterSlot = -getterSlot - 1;
@ -817,7 +814,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int setterSlot = uc.getSetterSlot(); int setterSlot = uc.getSetterSlot();
// clear the old setter and set the new setter // 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 function is null, flag the slot to be negative (less by 1)
if (setter == null) { if (setter == null) {
setterSlot = -setterSlot - 1; 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.) * @param bindName null or name to bind to second argument (property not found method.)
* *
* @return value of property as a MethodHandle or null. * @return value of property as a MethodHandle or null.
*
*/ */
@SuppressWarnings("static-method")
protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) { protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
return getCallMethodHandle(getObjectValue(find), type, 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 the current context from the object's map.
* @return Current context. * @return Current context.
*/ */
final Context getContext() { protected final Context getContext() {
return getMap().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. * @return __proto__ object.
*/ */
public final ScriptObject getProto() { public final ScriptObject getProto() {
return getMap().getProto(); return proto;
}
/**
* Check if this is a prototype
* @return true if {@link PropertyMap#isPrototype()} is true for this ScriptObject
*/
public final boolean isPrototype() {
return getMap().isPrototype();
} }
/** /**
* Set the __proto__ of an object. * Set the __proto__ of an object.
* @param newProto new __proto__ to set. * @param newProto new __proto__ to set.
*/ */
public final void setProto(final ScriptObject newProto) { public synchronized final void setProto(final ScriptObject newProto) {
PropertyMap oldMap = getMap(); final ScriptObject oldProto = proto;
ScriptObject oldProto = getProto(); map = map.changeProto(oldProto, newProto);
while (oldProto != newProto) { if (newProto != null) {
final PropertyMap newMap = oldMap.setProto(newProto); newProto.setIsPrototype();
}
if (!compareAndSetMap(oldMap, newMap)) { proto = newProto;
oldMap = getMap();
oldProto = getProto();
} else {
if (isPrototype()) {
if (oldProto != null) { if (isPrototype()) {
oldProto.removePropertyListener(this); if (oldProto != null) {
} oldProto.removePropertyListener(this);
}
if (newProto != null) { if (newProto != null) {
newProto.addPropertyListener(this); newProto.addPropertyListener(this);
}
}
return;
} }
} }
} }
@ -1326,6 +1310,25 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
flags |= IS_ARGUMENTS; 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 * Get the {@link ArrayData} for this ScriptObject if it is an array
* @return array data * @return array data
@ -1719,11 +1722,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (!property.hasGetterFunction()) { if (!property.hasGetterFunction()) {
methodHandle = bindTo(methodHandle, prototype); 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); 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) { 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); assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
final PropertyMap myMap = getMap(); 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") @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; final ScriptObject obj = (ScriptObject)self;
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) { final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
obj.useEmbed(i); if (!obj.isExtensible()) {
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
} else if (obj.compareAndSetMap(oldMap, newMap)) {
setter.invokeExact(self, value); setter.invokeExact(self, value);
} else {
obj.set(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND), value, isStrict);
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void setSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) { 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; final ScriptObject obj = (ScriptObject)self;
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) { if (obj.trySetSpill(desc, oldMap, newMap, value)) {
obj.spill[index] = 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); final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
if (!isExtensible() && isStrict) { if (!isExtensible() && isStrict) {
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(this)); 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); methodHandle = bindTo(methodHandle, UNDEFINED);
} }
return new GuardedInvocation(methodHandle, 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)); 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) { 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> { 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. * @return Added property.
*/ */
private Property addSpillProperty(final String key, final int propertyFlags) { private Property addSpillProperty(final String key, final int propertyFlags) {
int i = findEmbed(); int fieldCount = getMap().getFieldCount();
Property spillProperty; int fieldMaximum = getMap().getFieldMaximum();
Property property;
if (i >= EMBED_SIZE) { if (fieldCount < fieldMaximum) {
i = getMap().getSpillLength(); 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 getter = MH.arrayElementGetter(Object[].class);
MethodHandle setter = MH.arrayElementSetter(Object[].class); MethodHandle setter = MH.arrayElementSetter(Object[].class);
getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE); getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE);
setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_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); property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
notifyPropertyAdded(this, spillProperty); notifyPropertyAdded(this, property);
spillProperty = addOwnProperty(spillProperty); property = addOwnProperty(property);
i = spillProperty.getSlot(); i = property.getSlot();
final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE; final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE;
final Object[] newSpill = new Object[newLength];
if (spill != null) { if (spill == null || newLength > spill.length) {
System.arraycopy(spill, 0, newSpill, 0, 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; 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 * Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object. * 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) { private UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
int oldSpillLength = getMap().getSpillLength(); int oldSpillLength = getMap().getSpillLength();
int getterSlot = findEmbed(); int getterSlot = oldSpillLength++;
if (getterSlot >= EMBED_SIZE) { setSpill(getterSlot, getter);
getterSlot = oldSpillLength + EMBED_SIZE;
++oldSpillLength;
} else {
useEmbed(getterSlot);
}
setEmbedOrSpill(getterSlot, getter);
// if getter function is null, flag the slot to be negative (less by 1) // if getter function is null, flag the slot to be negative (less by 1)
if (getter == null) { if (getter == null) {
getterSlot = -getterSlot - 1; getterSlot = -getterSlot - 1;
} }
int setterSlot = findEmbed(); int setterSlot = oldSpillLength++;
if (setterSlot >= EMBED_SIZE) {
setterSlot = oldSpillLength + EMBED_SIZE; setSpill(setterSlot, setter);
} else {
useEmbed(setterSlot);
}
setEmbedOrSpill(setterSlot, setter);
// if setter function is null, flag the slot to be negative (less by 1) // if setter function is null, flag the slot to be negative (less by 1)
if (setter == null) { if (setter == null) {
setterSlot = -setterSlot - 1; setterSlot = -setterSlot - 1;
@ -3228,56 +3193,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot); return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot);
} }
private void setEmbedOrSpill(final int slot, final Object value) { private void setSpill(final int slot, final Object value) {
switch (slot) { if (slot >= 0) {
case 0: final int index = slot;
embed0 = value; if (spill == null) {
break; // create new spill.
case 1: spill = new Object[Math.max(index + 1, SPILL_RATE)];
embed1 = value; } else if (index >= spill.length) {
break; // grow spill as needed
case 2: final Object[] newSpill = new Object[index + 1];
embed2 = value; System.arraycopy(spill, 0, newSpill, 0, spill.length);
break; spill = newSpill;
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;
} }
break;
spill[index] = value;
} }
} }
// user accessors are either stored in embed fields or spill array slots // user accessors are either stored in spill array slots
// get the accessor value using slot number. Note that slot is either embed // get the accessor value using slot number. Note that slot is spill array index.
// field number or (spill array index + embedSize). Object getSpill(final int slot) {
Object getEmbedOrSpill(final int slot) { final int index = slot;
switch (slot) { return (index < 0 || (index >= spill.length)) ? null : spill[index];
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 defined getter and setter are always called by "dyn:call". Note that the user // 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") @SuppressWarnings("unused")
private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) { private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
final ScriptObject container = (proto != null) ? proto : (ScriptObject)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) { if (func instanceof ScriptFunction) {
try { try {
@ -3305,7 +3242,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) { 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 ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
final Object func = container.getEmbedOrSpill(slot); final Object func = container.getSpill(slot);
if (func instanceof ScriptFunction) { if (func instanceof ScriptFunction) {
try { try {

View File

@ -166,18 +166,20 @@ final class SetMethodCreator {
} }
private SetMethod createNewPropertySetter() { private SetMethod createNewPropertySetter() {
final int nextEmbed = sobj.findEmbed(); final SetMethod sm = map.getFieldCount() < map.getFieldMaximum() ? createNewFieldSetter() : createNewSpillPropertySetter();
final SetMethod sm;
if (nextEmbed >= ScriptObject.EMBED_SIZE) {
sm = createNewSpillPropertySetter();
} else {
sm = createNewEmbedPropertySetter(nextEmbed);
}
sobj.notifyPropertyAdded(sobj, sm.property); sobj.notifyPropertyAdded(sobj, sm.property);
return sm; 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() { private SetMethod createNewSpillPropertySetter() {
final int nextSpill = getMap().getSpillLength(); 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 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); 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) { 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) { private PropertyMap getNewMap(Property property) {
return getMap().addProperty(property); return getMap().addProperty(property);
} }

View File

@ -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);
}
}

View File

@ -110,8 +110,7 @@ final class StructureLoader extends NashornLoader {
@Override @Override
protected Class<?> findClass(final String name) throws ClassNotFoundException { protected Class<?> findClass(final String name) throws ClassNotFoundException {
if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) { 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(JS_OBJECT_PREFIX_EXTERNAL.length()));
return generateClass(name, name.substring(start, name.length()));
} }
return super.findClass(name); return super.findClass(name);
} }

View File

@ -67,7 +67,6 @@ public final class UserAccessorProperty extends Property {
private UserAccessorProperty(final UserAccessorProperty property) { private UserAccessorProperty(final UserAccessorProperty property) {
super(property); super(property);
this.getterSlot = property.getterSlot; this.getterSlot = property.getterSlot;
this.setterSlot = property.setterSlot; this.setterSlot = property.setterSlot;
} }
@ -115,10 +114,10 @@ public final class UserAccessorProperty extends Property {
public int getSpillCount() { public int getSpillCount() {
// calculate how many spill array slots used by this propery. // calculate how many spill array slots used by this propery.
int count = 0; int count = 0;
if (getGetterSlot() >= ScriptObject.EMBED_SIZE) { if (getGetterSlot() >= 0) {
count++; count++;
} }
if (getSetterSlot() >= ScriptObject.EMBED_SIZE) { if (getSetterSlot() >= 0) {
count++; count++;
} }
return count; return count;
@ -141,7 +140,7 @@ public final class UserAccessorProperty extends Property {
@Override @Override
public ScriptFunction getGetterFunction(final ScriptObject obj) { 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; return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
} }
@ -152,7 +151,7 @@ public final class UserAccessorProperty extends Property {
@Override @Override
public ScriptFunction getSetterFunction(final ScriptObject obj) { 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; return (value instanceof ScriptFunction) ? (ScriptFunction) value : null;
} }

View File

@ -57,7 +57,6 @@ abstract public class ArrayLikeIterator<T> implements Iterator<T> {
* Is this a reverse order iteration? * Is this a reverse order iteration?
* @return true if reverse * @return true if reverse
*/ */
@SuppressWarnings("static-method")
public boolean isReverse() { public boolean isReverse() {
return false; return false;
} }

View File

@ -278,7 +278,7 @@ public class LinkerCallSite extends ChainedCallSite {
@SuppressWarnings("resource") @SuppressWarnings("resource")
@Override @Override
public void run() { public void run() {
PrintWriter out = null; PrintWriter out = null;
boolean fileOutput = false; boolean fileOutput = false;
try { try {

View File

@ -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 * 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 * includes {@link ScriptFunction} and its subclasses) as well as {@link Undefined}.
* language runtimes by being declared in {@code META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker}
* file of Nashorn's distribution.
*/ */
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}. * Returns true if {@code ScriptObject} is assignable from {@code type}, or it is {@code Undefined}.
*/ */

View File

@ -243,7 +243,7 @@ public final class Options {
*/ */
public String getString(final String key) { public String getString(final String key) {
final Option<?> option = get(key); final Option<?> option = get(key);
if(option != null) { if (option != null) {
final String value = (String)option.getValue(); final String value = (String)option.getValue();
if(value != null) { if(value != null) {
return value.intern(); return value.intern();

View File

@ -107,16 +107,16 @@ public class DefaultRegExp extends RegExp {
class DefaultMatcher implements RegExpMatcher { class DefaultMatcher implements RegExpMatcher {
final String input; final String input;
final Matcher matcher; final Matcher defaultMatcher;
DefaultMatcher(final String input) { DefaultMatcher(final String input) {
this.input = input; this.input = input;
this.matcher = pattern.matcher(input); this.defaultMatcher = pattern.matcher(input);
} }
@Override @Override
public boolean search(final int start) { public boolean search(final int start) {
return matcher.find(start); return defaultMatcher.find(start);
} }
@Override @Override
@ -126,37 +126,37 @@ public class DefaultRegExp extends RegExp {
@Override @Override
public int start() { public int start() {
return matcher.start(); return defaultMatcher.start();
} }
@Override @Override
public int start(final int group) { public int start(final int group) {
return matcher.start(group); return defaultMatcher.start(group);
} }
@Override @Override
public int end() { public int end() {
return matcher.end(); return defaultMatcher.end();
} }
@Override @Override
public int end(final int group) { public int end(final int group) {
return matcher.end(group); return defaultMatcher.end(group);
} }
@Override @Override
public String group() { public String group() {
return matcher.group(); return defaultMatcher.group();
} }
@Override @Override
public String group(final int group) { public String group(final int group) {
return matcher.group(group); return defaultMatcher.group(group);
} }
@Override @Override
public int groupCount() { public int groupCount() {
return matcher.groupCount(); return defaultMatcher.groupCount();
} }
} }

View File

@ -121,16 +121,16 @@ public class JoniRegExp extends RegExp {
class JoniMatcher implements RegExpMatcher { class JoniMatcher implements RegExpMatcher {
final String input; final String input;
final Matcher matcher; final Matcher joniMatcher;
JoniMatcher(final String input) { JoniMatcher(final String input) {
this.input = input; this.input = input;
this.matcher = regex.matcher(input.toCharArray()); this.joniMatcher = regex.matcher(input.toCharArray());
} }
@Override @Override
public boolean search(final int start) { 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 @Override
@ -140,27 +140,27 @@ public class JoniRegExp extends RegExp {
@Override @Override
public int start() { public int start() {
return matcher.getBegin(); return joniMatcher.getBegin();
} }
@Override @Override
public int start(final int group) { public int start(final int group) {
return group == 0 ? start() : matcher.getRegion().beg[group]; return group == 0 ? start() : joniMatcher.getRegion().beg[group];
} }
@Override @Override
public int end() { public int end() {
return matcher.getEnd(); return joniMatcher.getEnd();
} }
@Override @Override
public int end(final int group) { public int end(final int group) {
return group == 0 ? end() : matcher.getRegion().end[group]; return group == 0 ? end() : joniMatcher.getRegion().end[group];
} }
@Override @Override
public String group() { public String group() {
return input.substring(matcher.getBegin(), matcher.getEnd()); return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd());
} }
@Override @Override
@ -168,13 +168,13 @@ public class JoniRegExp extends RegExp {
if (group == 0) { if (group == 0) {
return group(); return group();
} }
final Region region = matcher.getRegion(); final Region region = joniMatcher.getRegion();
return input.substring(region.beg[group], region.end[group]); return input.substring(region.beg[group], region.end[group]);
} }
@Override @Override
public int groupCount() { public int groupCount() {
final Region region = matcher.getRegion(); final Region region = joniMatcher.getRegion();
return region == null ? 0 : region.numRegs - 1; return region == null ? 0 : region.numRegs - 1;
} }
} }

View File

@ -65,7 +65,7 @@ final class RegExpScanner extends Scanner {
/** Are we currently inside a negated character class? */ /** Are we currently inside a negated character class? */
private boolean inNegativeClass = false; private boolean inNegativeClass = false;
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?"; private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
private static class Capture { private static class Capture {
/** /**
@ -934,7 +934,7 @@ final class RegExpScanner extends Scanner {
return true; 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); final String hex = Integer.toHexString(value);
buffer.append('u'); buffer.append('u');
for (int i = 0; i < 4 - hex.length(); i++) { 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. // 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(); final int length = numberLiteral.length();
int octalValue = 0; int octalValue = 0;
int pos = 0; int pos = 0;

View File

@ -247,6 +247,12 @@ nashorn.option.print.code = { \
desc="Print bytecode." \ 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 = { \ nashorn.option.print.no.newline = { \
name="--print-no-newline", \ name="--print-no-newline", \
is_undocumented=true, \ is_undocumented=true, \
@ -288,12 +294,12 @@ nashorn.option.scripting = { \
dependency="--anon-functions=true" \ dependency="--anon-functions=true" \
} }
nashorn.option.timezone = { \ nashorn.option.specialize.calls = { \
name="-timezone", \ name="--specialize-calls", \
short_name="-t", \ is_undocumented=true, \
params="<timezone>", \ type=String, \
desc="Set timezone for script execution.", \ params="[=function_1,...,function_n]", \
type=TimeZone \ desc="Specialize all or a set of method according to callsite parameter types" \
} }
nashorn.option.stdout = { \ nashorn.option.stdout = { \
@ -312,6 +318,14 @@ nashorn.option.stderr = { \
desc="Redirect stderr to a filename or to another tty, e.g. stdout" \ 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 = { \ nashorn.option.trace.callsites = { \
name="--trace-callsites", \ name="--trace-callsites", \
short_name="-tcs", \ short_name="-tcs", \

View File

@ -35,8 +35,6 @@ com.sun.javafx.application.LauncherImpl.launchApplication((Java.extend(javafx.ap
init: function() { init: function() {
// Java FX packages and classes must be defined here because // Java FX packages and classes must be defined here because
// they may not be viable until launch time due to clinit ordering. // they may not be viable until launch time due to clinit ordering.
load("fx:base.js");
}, },
// Overridden javafx.application.Application.start(Stage stage); // Overridden javafx.application.Application.start(Stage stage);

View File

@ -32,12 +32,11 @@ import jdk.nashorn.internal.runtime.ScriptObject;
* Empty object class. * Empty object class.
*/ */
public class JO extends ScriptObject { public class JO extends ScriptObject {
/** /**
* Constructor * Constructor
*/ */
public JO() { public JO() {
super(); super(PropertyMap.newMap(JO.class));
} }
/** /**

View File

@ -173,9 +173,9 @@ public class Shell {
if (env._fx) { if (env._fx) {
return runFXScripts(context, global, files); 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 //null - pass no code installer - this is compile only
new Compiler(env, functionNode).compile(); new Compiler(env).compile(functionNode);
} }
} finally { } finally {
env.getOut().flush(); env.getOut().flush();
@ -343,7 +343,7 @@ public class Shell {
* @return error code * @return error code
* @throws IOException when any script file read results in I/O error * @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 ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global); final boolean globalChanged = (oldGlobal != global);
try { try {

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