This commit is contained in:
Lana Steuck 2013-05-17 10:14:03 -07:00
commit 670660bae0
118 changed files with 3433 additions and 2140 deletions

View File

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

View File

@ -26,4 +26,4 @@
[ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1;
$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -21,6 +21,7 @@ import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TemporarySymbols;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
@ -42,7 +43,7 @@ enum CompilationPhase {
*/
LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn0) {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
/*
* For lazy compilation, we might be given a node previously marked
@ -58,8 +59,7 @@ enum CompilationPhase {
* function from a trampoline
*/
final FunctionNode outermostFunctionNode = compiler.getFunctionNode();
assert outermostFunctionNode == fn0;
final FunctionNode outermostFunctionNode = fn;
final Set<FunctionNode> neverLazy = new HashSet<>();
final Set<FunctionNode> lazy = new HashSet<>();
@ -172,20 +172,31 @@ enum CompilationPhase {
ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
return (FunctionNode)initReturnTypes(fn).accept(new Attr());
final TemporarySymbols ts = compiler.getTemporarySymbols();
final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts));
if(compiler.getEnv()._print_mem_usage) {
Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
}
return newFunctionNode;
}
/**
* Pessimistically set all lazy functions' return types to Object
* and the function symbols to object
* @param functionNode node where to start iterating
*/
private FunctionNode initReturnTypes(final FunctionNode functionNode) {
private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) {
return (FunctionNode)functionNode.accept(new NodeVisitor() {
@Override
public Node leaveFunctionNode(final FunctionNode node) {
return node.isLazy() ?
node.setReturnType(getLexicalContext(), Type.OBJECT) :
node.setReturnType(getLexicalContext(), Type.UNKNOWN);
final LexicalContext lc = getLexicalContext();
if (node.isLazy()) {
FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT);
return ts.ensureSymbol(lc, Type.OBJECT, newNode);
}
//node may have a reference here that needs to be nulled if it was referred to by
//its outer context, if it is lazy and not attributed
return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null);
}
});
}
@ -207,6 +218,7 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
// assert fn.isProgram() ;
final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
@ -216,15 +228,6 @@ enum CompilationPhase {
compiler.setStrictMode(true);
}
/*
newFunctionNode.accept(new NodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit";
return true;
}
});*/
return newFunctionNode;
}
@ -252,7 +255,7 @@ enum CompilationPhase {
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv();
final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes());
final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes(compiler.getTemporarySymbols()));
if (env._print_lower_ast) {
env.getErr().println(new ASTWriter(newFunctionNode));

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.VARARGS;
import jdk.nashorn.internal.ir.TemporarySymbols;
import java.io.File;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
@ -77,6 +83,8 @@ public final class Compiler {
/** Name of the objects package */
public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects";
private Source source;
private final Map<String, byte[]> bytecode;
private final Set<CompileUnit> compileUnits;
@ -87,14 +95,14 @@ public final class Compiler {
private final ScriptEnvironment env;
private final String scriptName;
private String scriptName;
private boolean strict;
private FunctionNode functionNode;
private CodeInstaller<ScriptEnvironment> installer;
private final TemporarySymbols temporarySymbols = new TemporarySymbols();
/** logger for compiler, trampolines, splits and related code generation events
* that affect classes */
public static final DebugLogger LOG = new DebugLogger("compiler");
@ -167,6 +175,41 @@ public final class Compiler {
}
}
/**
* Environment information known to the compile, e.g. params
*/
public static class Hints {
private final Type[] paramTypes;
/** singleton empty hints */
public static final Hints EMPTY = new Hints();
private Hints() {
this.paramTypes = null;
}
/**
* Constructor
* @param paramTypes known parameter types for this callsite
*/
public Hints(final Type[] paramTypes) {
this.paramTypes = paramTypes;
}
/**
* Get the parameter type for this parameter position, or
* null if now known
* @param pos position
* @return parameter type for this callsite if known
*/
public Type getParameterType(final int pos) {
if (paramTypes != null && pos < paramTypes.length) {
return paramTypes[pos];
}
return null;
}
}
/**
* Standard (non-lazy) compilation, that basically will take an entire script
* and JIT it at once. This can lead to long startup time and fewer type
@ -207,21 +250,22 @@ public final class Compiler {
* @param strict should this compilation use strict mode semantics
*/
//TODO support an array of FunctionNodes for batch lazy compilation
Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) {
Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) {
this.env = env;
this.functionNode = functionNode;
this.sequence = sequence;
this.installer = installer;
this.strict = strict || functionNode.isStrict();
this.constantData = new ConstantData();
this.compileUnits = new HashSet<>();
this.bytecode = new HashMap<>();
}
private void initCompiler(final FunctionNode functionNode) {
this.strict = strict || functionNode.isStrict();
final StringBuilder sb = new StringBuilder();
sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
append('$').
append(safeSourceName(functionNode.getSource()));
this.source = functionNode.getSource();
this.scriptName = sb.toString();
}
@ -229,52 +273,79 @@ public final class Compiler {
* Constructor
*
* @param installer code installer
* @param functionNode function node (in any available {@link CompilationState}) to compile
* @param strict should this compilation use strict mode semantics
*/
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) {
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict);
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) {
this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict);
}
/**
* Constructor - compilation will use the same strict semantics as in script environment
*
* @param installer code installer
* @param functionNode function node (in any available {@link CompilationState}) to compile
*/
public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) {
this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
public Compiler(final CodeInstaller<ScriptEnvironment> installer) {
this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict);
}
/**
* Constructor - compilation needs no installer, but uses a script environment
* Used in "compile only" scenarios
* @param env a script environment
* @param functionNode functionNode to compile
*/
public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) {
this(env, null, functionNode, sequence(env._lazy_compilation), env._strict);
public Compiler(final ScriptEnvironment env) {
this(env, null, sequence(env._lazy_compilation), env._strict);
}
private static void printMemoryUsage(final String phaseName, final FunctionNode functionNode) {
LOG.info(phaseName + " finished. Doing IR size calculation...");
final ObjectSizeCalculator osc = new ObjectSizeCalculator(ObjectSizeCalculator.getEffectiveMemoryLayoutSpecification());
osc.calculateObjectSize(functionNode);
final List<ClassHistogramElement> list = osc.getClassHistogram();
final StringBuilder sb = new StringBuilder();
final long totalSize = osc.calculateObjectSize(functionNode);
sb.append(phaseName).append(" Total size = ").append(totalSize / 1024 / 1024).append("MB");
LOG.info(sb);
Collections.sort(list, new Comparator<ClassHistogramElement>() {
@Override
public int compare(ClassHistogramElement o1, ClassHistogramElement o2) {
final long diff = o1.getBytes() - o2.getBytes();
if (diff < 0) {
return 1;
} else if (diff > 0) {
return -1;
} else {
return 0;
}
}
});
for (final ClassHistogramElement e : list) {
final String line = String.format(" %-48s %10d bytes (%8d instances)", e.getClazz(), e.getBytes(), e.getInstances());
LOG.info(line);
if (e.getBytes() < totalSize / 200) {
LOG.info(" ...");
break; // never mind, so little memory anyway
}
}
}
/**
* Execute the compilation this Compiler was created with
* @params param types if known, for specialization
* @param functionNode function node to compile from its current state
* @throws CompilationException if something goes wrong
* @return function node that results from code transforms
*/
public FunctionNode compile() throws CompilationException {
return compile(null);
}
public FunctionNode compile(final FunctionNode functionNode) throws CompilationException {
FunctionNode newFunctionNode = functionNode;
initCompiler(newFunctionNode); //TODO move this state into functionnode?
/**
* Execute the compilation this Compiler was created with
* @param paramTypes param types if known, for specialization
* @throws CompilationException if something goes wrong
* @return function node that results from code transforms
*/
public FunctionNode compile(final Class<?> paramTypes) throws CompilationException {
for (final String reservedName : RESERVED_NAMES) {
functionNode.uniqueName(reservedName);
newFunctionNode.uniqueName(reservedName);
}
final boolean fine = !LOG.levelAbove(Level.FINE);
@ -283,7 +354,11 @@ public final class Compiler {
long time = 0L;
for (final CompilationPhase phase : sequence) {
this.functionNode = phase.apply(this, functionNode);
newFunctionNode = phase.apply(this, newFunctionNode);
if (env._print_mem_usage) {
printMemoryUsage(phase.toString(), newFunctionNode);
}
final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
time += duration;
@ -293,7 +368,7 @@ public final class Compiler {
sb.append(phase.toString()).
append(" done for function '").
append(functionNode.getName()).
append(newFunctionNode.getName()).
append('\'');
if (duration > 0L) {
@ -309,7 +384,7 @@ public final class Compiler {
if (info) {
final StringBuilder sb = new StringBuilder();
sb.append("Compile job for '").
append(functionNode.getName()).
append(newFunctionNode.getName()).
append("' finished");
if (time > 0L) {
@ -321,7 +396,7 @@ public final class Compiler {
LOG.info(sb);
}
return functionNode;
return newFunctionNode;
}
private Class<?> install(final String className, final byte[] code) {
@ -330,7 +405,6 @@ public final class Compiler {
final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
try {
final Source source = getSource();
final Object[] constants = getConstantData().toArray();
// Need doPrivileged because these fields are private
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@ -355,9 +429,10 @@ public final class Compiler {
/**
* Install compiled classes into a given loader
* @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state
* @return root script class - if there are several compile units they will also be installed
*/
public Class<?> install() {
public Class<?> install(final FunctionNode functionNode) {
final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed";
@ -430,10 +505,6 @@ public final class Compiler {
this.strict = strict;
}
FunctionNode getFunctionNode() {
return functionNode;
}
ConstantData getConstantData() {
return constantData;
}
@ -442,8 +513,8 @@ public final class Compiler {
return installer;
}
Source getSource() {
return functionNode.getSource();
TemporarySymbols getTemporarySymbols() {
return temporarySymbols;
}
void addClass(final String name, final byte[] code) {
@ -496,7 +567,7 @@ public final class Compiler {
}
private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict);
final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict);
final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
classEmitter.begin();
@ -550,6 +621,4 @@ public final class Compiler {
USE_INT_ARITH = Options.getBooleanProperty("nashorn.compiler.intarithmetic");
assert !USE_INT_ARITH : "Integer arithmetic is not enabled";
}
}

View File

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

View File

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

View File

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

View File

@ -24,9 +24,8 @@
*/
package jdk.nashorn.internal.codegen;
import java.util.ArrayDeque;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Debug;
/**
* Abstraction for labels, separating a label from the underlying
@ -35,12 +34,87 @@ import jdk.nashorn.internal.codegen.types.Type;
*
* see -Dnashorn.codegen.debug, --log=codegen
*/
public class Label extends jdk.internal.org.objectweb.asm.Label {
public final class Label {
//byte code generation evaluation type stack for consistency check
//and correct opcode selection. one per label as a label may be a
//join point
static final class Stack {
Type[] data = new Type[8];
int sp = 0;
Stack() {
}
private Stack(final Type[] type, final int sp) {
this();
this.data = new Type[type.length];
this.sp = sp;
for (int i = 0; i < sp; i++) {
data[i] = type[i];
}
}
boolean isEmpty() {
return sp == 0;
}
int size() {
return sp;
}
boolean isEquivalentTo(final Stack other) {
if (sp != other.sp) {
return false;
}
for (int i = 0; i < sp; i++) {
if (!data[i].isEquivalentTo(other.data[i])) {
return false;
}
}
return true;
}
void clear() {
sp = 0;
}
void push(final Type type) {
if (data.length == sp) {
final Type[] newData = new Type[sp * 2];
for (int i = 0; i < sp; i++) {
newData[i] = data[i];
}
data = newData;
}
data[sp++] = type;
}
Type peek() {
return peek(0);
}
Type peek(final int n) {
int pos = sp - 1 - n;
return pos < 0 ? null : data[pos];
}
Type pop() {
return data[--sp];
}
Stack copy() {
return new Stack(data, sp);
}
}
/** Name of this label */
private final String name;
/** Type stack at this label */
private ArrayDeque<Type> stack;
private Label.Stack stack;
/** ASM representation of this label */
private jdk.internal.org.objectweb.asm.Label label;
/**
* Constructor
@ -62,22 +136,24 @@ public class Label extends jdk.internal.org.objectweb.asm.Label {
this.name = label.name;
}
ArrayDeque<Type> getStack() {
jdk.internal.org.objectweb.asm.Label getLabel() {
if (this.label == null) {
this.label = new jdk.internal.org.objectweb.asm.Label();
}
return label;
}
Label.Stack getStack() {
return stack;
}
void setStack(final ArrayDeque<Type> stack) {
void setStack(final Label.Stack stack) {
this.stack = stack;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
String s = super.toString();
s = s.substring(1, s.length());
sb.append(name).append('_').append(Long.toHexString(Long.parseLong(s)));
return sb.toString();
return name + '_' + Debug.id(this);
}
}

View File

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

View File

@ -65,10 +65,12 @@ public class MapCreator {
* Constructs a property map based on a set of fields.
*
* @param hasArguments does the created object have an "arguments" property
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
*
* @return New map populated with accessor properties.
*/
PropertyMap makeMap(final boolean hasArguments) {
PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
final List<Property> properties = new ArrayList<>();
assert keys != null;
@ -82,7 +84,7 @@ public class MapCreator {
}
}
return PropertyMap.newMap(structure, properties);
return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
}
/**

View File

@ -67,10 +67,9 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.ArrayDeque;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -114,7 +113,7 @@ public class MethodEmitter implements Emitter {
private final MethodVisitor method;
/** Current type stack for current evaluation */
private ArrayDeque<Type> stack;
private Label.Stack stack;
/** Parent classEmitter representing the class of this method */
private final ClassEmitter classEmitter;
@ -189,7 +188,7 @@ public class MethodEmitter implements Emitter {
@Override
public void begin() {
classEmitter.beginMethod(this);
stack = new ArrayDeque<>();
newStack();
method.visitCode();
}
@ -205,6 +204,10 @@ public class MethodEmitter implements Emitter {
classEmitter.endMethod(this);
}
private void newStack() {
stack = new Label.Stack();
}
@Override
public String toString() {
return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
@ -288,11 +291,7 @@ public class MethodEmitter implements Emitter {
* @return the type at position "pos" on the stack
*/
final Type peekType(final int pos) {
final Iterator<Type> iter = stack.iterator();
for (int i = 0; i < pos; i++) {
iter.next();
}
return iter.next();
return stack.peek(pos);
}
/**
@ -484,7 +483,7 @@ public class MethodEmitter implements Emitter {
name = THIS_DEBUGGER.symbolName();
}
method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start.getLabel(), end.getLabel(), symbol.getSlot());
}
/**
@ -508,17 +507,6 @@ public class MethodEmitter implements Emitter {
return invoke(virtualCallNoLookup(StringBuilder.class, "append", StringBuilder.class, String.class));
}
/**
* Associate a variable with a given range
*
* @param name name of the variable
* @param start start
* @param end end
*/
void markerVariable(final String name, final Label start, final Label end) {
method.visitLocalVariable(name, Type.OBJECT.getDescriptor(), null, start, end, 0);
}
/**
* Pops two integer types from the stack, performs a bitwise and and pushes
* the result
@ -626,7 +614,7 @@ public class MethodEmitter implements Emitter {
* @param typeDescriptor type descriptor for exception
*/
void _try(final Label entry, final Label exit, final Label recovery, final String typeDescriptor) {
method.visitTryCatchBlock(entry, exit, recovery, typeDescriptor);
method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), typeDescriptor);
}
/**
@ -638,7 +626,7 @@ public class MethodEmitter implements Emitter {
* @param clazz exception class
*/
void _try(final Label entry, final Label exit, final Label recovery, final Class<?> clazz) {
method.visitTryCatchBlock(entry, exit, recovery, CompilerConstants.className(clazz));
method.visitTryCatchBlock(entry.getLabel(), exit.getLabel(), recovery.getLabel(), CompilerConstants.className(clazz));
}
/**
@ -871,7 +859,7 @@ public class MethodEmitter implements Emitter {
}
private boolean isThisSlot(final int slot) {
if(functionNode == null) {
if (functionNode == null) {
return slot == CompilerConstants.JAVA_THIS.slot();
}
final int thisSlot = compilerConstant(THIS).getSlot();
@ -915,7 +903,6 @@ public class MethodEmitter implements Emitter {
dup();
return this;
}
debug("load compiler constant ", symbol);
return load(symbol);
}
@ -1228,6 +1215,14 @@ public class MethodEmitter implements Emitter {
return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
}
static jdk.internal.org.objectweb.asm.Label[] getLabels(final Label... table) {
final jdk.internal.org.objectweb.asm.Label[] internalLabels = new jdk.internal.org.objectweb.asm.Label[table.length];
for (int i = 0; i < table.length; i++) {
internalLabels[i] = table[i].getLabel();
}
return internalLabels;
}
/**
* Generate a lookup switch, popping the switch value from the stack
*
@ -1235,10 +1230,10 @@ public class MethodEmitter implements Emitter {
* @param values case values for the table
* @param table default label
*/
void lookupswitch(final Label defaultLabel, final int[] values, final Label[] table) {
void lookupswitch(final Label defaultLabel, final int[] values, final Label... table) {//Collection<Label> table) {
debug("lookupswitch", peekType());
popType(Type.INT);
method.visitLookupSwitchInsn(defaultLabel, values, table);
method.visitLookupSwitchInsn(defaultLabel.getLabel(), values, getLabels(table));
}
/**
@ -1248,10 +1243,10 @@ public class MethodEmitter implements Emitter {
* @param defaultLabel default label
* @param table label table
*/
void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label[] table) {
void tableswitch(final int lo, final int hi, final Label defaultLabel, final Label... table) {
debug("tableswitch", peekType());
popType(Type.INT);
method.visitTableSwitchInsn(lo, hi, defaultLabel, table);
method.visitTableSwitchInsn(lo, hi, defaultLabel.getLabel(), getLabels(table));
}
/**
@ -1358,7 +1353,7 @@ public class MethodEmitter implements Emitter {
popType();
}
mergeStackTo(label);
method.visitJumpInsn(opcode, label);
method.visitJumpInsn(opcode, label.getLabel());
}
/**
@ -1487,9 +1482,9 @@ public class MethodEmitter implements Emitter {
* @param label destination label
*/
void _goto(final Label label) {
debug("goto", label);
//debug("goto", label);
jump(GOTO, label, 0);
stack = null;
stack = null; //whoever reaches the point after us provides the stack, because we don't
}
/**
@ -1500,38 +1495,31 @@ public class MethodEmitter implements Emitter {
*
* @return true if stacks are equivalent, false otherwise
*/
private boolean stacksEquivalent(final ArrayDeque<Type> s0, final ArrayDeque<Type> s1) {
if (s0.size() != s1.size()) {
debug("different stack sizes", s0, s1);
return false;
}
final Type[] s0a = s0.toArray(new Type[s0.size()]);
final Type[] s1a = s1.toArray(new Type[s1.size()]);
for (int i = 0; i < s0.size(); i++) {
if (!s0a[i].isEquivalentTo(s1a[i])) {
debug("different stack element", s0a[i], s1a[i]);
return false;
}
}
return true;
}
/**
* A join in control flow - helper function that makes sure all entry stacks
* discovered for the join point so far are equivalent
* @param label
*
* MergeStack: we are about to enter a label. If its stack, label.getStack() is null
* we have never been here before. Then we are expected to carry a stack with us.
*
* @param label label
*/
private void mergeStackTo(final Label label) {
final ArrayDeque<Type> labelStack = label.getStack();
//debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
//sometimes we can do a merge stack without having a stack - i.e. when jumping ahead to dead code
//see NASHORN-73. So far we had been saved by the line number nodes. This should have been fixed
//by Lower removing everything after an unconditionally executed terminating statement OR a break
//or continue in a block. Previously code left over after breaks and continues was still there
//and caused bytecode to be generated - which crashed on stack not being there, as the merge
//was not in fact preceeded by a visit. Furthermore, this led to ASM putting out its NOP NOP NOP
//ATHROW sequences instead of no code being generated at all. This should now be fixed.
assert stack != null : label + " entered with no stack. deadcode that remains?";
final Label.Stack labelStack = label.getStack();
if (labelStack == null) {
assert stack != null;
label.setStack(stack.clone());
label.setStack(stack.copy());
return;
}
assert stacksEquivalent(stack, labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
assert stack.isEquivalentTo(labelStack) : "stacks " + stack + " is not equivalent with " + labelStack + " at join point";
}
/**
@ -1548,14 +1536,14 @@ public class MethodEmitter implements Emitter {
if (stack == null) {
stack = label.getStack();
if (stack == null) {
stack = new ArrayDeque<>(); //we don't have a stack at this point.
newStack();
}
}
debug_label(label);
mergeStackTo(label); //we have to merge our stack to whatever is in the label
method.visitLabel(label);
method.visitLabel(label.getLabel());
}
/**
@ -1675,11 +1663,10 @@ public class MethodEmitter implements Emitter {
* @return array of Types
*/
protected Type[] getTypesFromStack(final int count) {
final Iterator<Type> iter = stack.iterator();
final Type[] types = new Type[count];
final Type[] types = new Type[count];
int pos = 0;
for (int i = count - 1; i >= 0; i--) {
types[i] = iter.next();
types[i] = stack.peek(pos++);
}
return types;
@ -1695,11 +1682,11 @@ public class MethodEmitter implements Emitter {
* @return function signature for stack contents
*/
private String getDynamicSignature(final Type returnType, final int argCount) {
final Iterator<Type> iter = stack.iterator();
final Type[] paramTypes = new Type[argCount];
int pos = 0;
for (int i = argCount - 1; i >= 0; i--) {
paramTypes[i] = iter.next();
paramTypes[i] = stack.peek(pos++);
}
final String descriptor = Type.getMethodDescriptor(returnType, paramTypes);
for (int i = 0; i < argCount; i++) {
@ -2018,8 +2005,13 @@ public class MethodEmitter implements Emitter {
* @param line line number
* @param label label
*/
void lineNumber(final int line, final Label label) {
method.visitLineNumber(line, label);
void lineNumber(final int line) {
if (env._debug_lines) {
debug_label("[LINE]", line);
final jdk.internal.org.objectweb.asm.Label l = new jdk.internal.org.objectweb.asm.Label();
method.visitLabel(l);
method.visitLineNumber(line, l);
}
}
/*
@ -2116,12 +2108,12 @@ public class MethodEmitter implements Emitter {
pad--;
}
if (!stack.isEmpty()) {
if (stack != null && !stack.isEmpty()) {
sb.append("{");
sb.append(stack.size());
sb.append(":");
for (final Iterator<Type> iter = stack.iterator(); iter.hasNext();) {
final Type t = iter.next();
for (int pos = 0; pos < stack.size(); pos++) {
final Type t = stack.peek(pos);
if (t == Type.SCOPE) {
sb.append("scope");
@ -2147,7 +2139,7 @@ public class MethodEmitter implements Emitter {
sb.append(t.getDescriptor());
}
if (iter.hasNext()) {
if (pos + 1 < stack.size()) {
sb.append(' ');
}
}

View File

@ -68,6 +68,16 @@ public final class ObjectClassGenerator {
*/
static final String SCOPE_MARKER = "P";
/**
* Minimum number of extra fields in an object.
*/
static final int FIELD_PADDING = 4;
/**
* Rounding when calculating the number of fields.
*/
static final int FIELD_ROUNDING = 4;
/**
* Debug field logger
* Should we print debugging information for fields when they are generated and getters/setters are called?

View File

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

View File

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

View File

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

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

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

View File

@ -30,14 +30,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for a list of statements and functions. All provides the
@ -46,7 +44,7 @@ import jdk.nashorn.internal.runtime.Source;
@Immutable
public class Block extends BreakableNode implements Flags<Block> {
/** List of statements */
protected final List<Node> statements;
protected final List<Statement> statements;
/** Symbol table - keys must be returned in the order they were put in. */
protected final Map<String, Symbol> symbols;
@ -78,13 +76,13 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
* @param source source code
* @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
public Block(final Source source, final long token, final int finish, final Node... statements) {
super(source, token, finish, new Label("block_break"));
public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
super(lineNumber, token, finish, new Label("block_break"));
this.statements = Arrays.asList(statements);
this.symbols = new LinkedHashMap<>();
@ -95,27 +93,35 @@ public class Block extends BreakableNode implements Flags<Block> {
/**
* Constructor
*
* @param source source code
* @param lineNumber line number
* @param token token
* @param finish finish
* @param statements statements
*/
public Block(final Source source, final long token, final int finish, final List<Node> statements) {
this(source, token, finish, statements.toArray(new Node[statements.size()]));
public Block(final int lineNumber, final long token, final int finish, final List<Statement> statements) {
this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()]));
}
private Block(final Block block, final int finish, final List<Node> statements, final int flags) {
private Block(final Block block, final int finish, final List<Statement> statements, final int flags, final Map<String, Symbol> symbols) {
super(block);
this.statements = statements;
this.flags = flags;
this.symbols = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
this.entryLabel = new Label(block.entryLabel);
this.finish = finish;
this.finish = finish;
}
/**
* Clear the symbols in a block
* TODO: make this immutable
*/
public void clearSymbols() {
symbols.clear();
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
}
/**
@ -127,7 +133,7 @@ public class Block extends BreakableNode implements Flags<Block> {
@Override
public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
if (visitor.enterBlock(this)) {
return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Statement.class, statements)));
}
return this;
@ -137,15 +143,15 @@ public class Block extends BreakableNode implements Flags<Block> {
* Get an iterator for all the symbols defined in this block
* @return symbol iterator
*/
public Iterator<Symbol> symbolIterator() {
return symbols.values().iterator();
public List<Symbol> getSymbols() {
return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
}
/**
* Retrieves an existing symbol defined in the current block.
* @param name the name of the symbol
* @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
* define a symbol with this name.
* define a symbol with this name.T
*/
public Symbol getExistingSymbol(final String name) {
return symbols.get(name);
@ -222,7 +228,7 @@ public class Block extends BreakableNode implements Flags<Block> {
*
* @return a list of statements
*/
public List<Node> getStatements() {
public List<Statement> getStatements() {
return Collections.unmodifiableList(statements);
}
@ -233,7 +239,7 @@ public class Block extends BreakableNode implements Flags<Block> {
* @param statements new statement list
* @return new block if statements changed, identity of statements == block.statements
*/
public Block setStatements(final LexicalContext lc, final List<Node> statements) {
public Block setStatements(final LexicalContext lc, final List<Statement> statements) {
if (this.statements == statements) {
return this;
}
@ -241,17 +247,17 @@ public class Block extends BreakableNode implements Flags<Block> {
if (!statements.isEmpty()) {
lastFinish = statements.get(statements.size() - 1).getFinish();
}
return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags));
return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols));
}
/**
* Add or overwrite an existing symbol in the block
*
* @param name name of symbol
* @param lc get lexical context
* @param symbol symbol
*/
public void putSymbol(final String name, final Symbol symbol) {
symbols.put(name, symbol);
public void putSymbol(final LexicalContext lc, final Symbol symbol) {
symbols.put(symbol.getName(), symbol);
}
/**
@ -268,7 +274,7 @@ public class Block extends BreakableNode implements Flags<Block> {
if (this.flags == flags) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
}
@Override
@ -296,7 +302,7 @@ public class Block extends BreakableNode implements Flags<Block> {
return this;
}
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE));
return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols));
}
/**
@ -306,13 +312,11 @@ public class Block extends BreakableNode implements Flags<Block> {
* @return next slot
*/
public int nextSlot() {
final Iterator<Symbol> iter = symbolIterator();
int next = 0;
while (iter.hasNext()) {
final Symbol symbol = iter.next();
if (symbol.hasSlot()) {
next += symbol.slotCount();
}
for (final Symbol symbol : getSymbols()) {
if (symbol.hasSlot()) {
next += symbol.slotCount();
}
}
return next;
}

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for executing bare expressions. Basically, an expression
@ -35,20 +34,20 @@ import jdk.nashorn.internal.runtime.Source;
* statements being added to the IR
*/
@Immutable
public final class ExecuteNode extends Node {
public final class ExecuteNode extends Statement {
/** Expression to execute. */
private final Node expression;
/**
* Constructor
*
* @param source the source
* @param lineNumber line number
* @param token token
* @param finish finish
* @param expression the expression to execute
*/
public ExecuteNode(final Source source, final long token, final int finish, final Node expression) {
super(source, token, finish);
public ExecuteNode(final int lineNumber, final long token, final int finish, final Node expression) {
super(lineNumber, token, finish);
this.expression = expression;
}
@ -57,16 +56,6 @@ public final class ExecuteNode extends Node {
this.expression = expression;
}
/**
* Constructor
*
* @param expression an expression to wrap, from which source, tokens and finish are also inherited
*/
public ExecuteNode(final Node expression) {
super(expression.getSource(), expression.getToken(), expression.getFinish());
this.expression = expression;
}
@Override
public boolean isTerminal() {
return expression.isTerminal();

View File

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

View File

@ -25,16 +25,12 @@
package jdk.nashorn.internal.ir;
import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
@ -90,11 +86,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** method has been emitted to bytecode */
EMITTED
}
/** Source of entity. */
private final Source source;
/** External function identifier. */
@Ignore
private final IdentNode ident;
/** Parsed version of functionNode */
@Ignore
private final FunctionNode snapshot;
/** The body of the function node */
private final Block body;
@ -127,6 +129,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
@Ignore
private final EnumSet<CompilationState> compilationState;
@Ignore
private final Compiler.Hints hints;
/** Function flags. */
private final int flags;
@ -176,6 +181,9 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
/** Does this function have nested declarations? */
public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13;
/** Can this function be specialized? */
public static final int CAN_SPECIALIZE = 1 << 14;
/** Does this function or any nested functions contain an eval? */
private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
@ -196,6 +204,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
* Constructor
*
* @param source the source
* @param lineNumber line number
* @param token token
* @param finish finish
* @param firstToken first token of the funtion node (including the function declaration)
@ -208,6 +217,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
*/
public FunctionNode(
final Source source,
final int lineNumber,
final long token,
final int finish,
final long firstToken,
@ -217,39 +227,56 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
final int flags) {
super(source, token, finish);
super(lineNumber, token, finish);
this.ident = ident;
this.name = name;
this.kind = kind;
this.parameters = parameters;
this.firstToken = firstToken;
this.lastToken = token;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.declaredSymbols = new HashSet<>();
this.flags = flags;
this.compileUnit = null;
this.body = null;
this.source = source;
this.ident = ident;
this.name = name;
this.kind = kind;
this.parameters = parameters;
this.firstToken = firstToken;
this.lastToken = token;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.declaredSymbols = new HashSet<>();
this.flags = flags;
this.compileUnit = null;
this.body = null;
this.snapshot = null;
this.hints = null;
}
private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
private FunctionNode(
final FunctionNode functionNode,
final long lastToken,
final int flags,
final Type returnType,
final CompileUnit compileUnit,
final EnumSet<CompilationState> compilationState,
final Block body,
final List<IdentNode> parameters,
final FunctionNode snapshot,
final Compiler.Hints hints) {
super(functionNode);
this.flags = flags;
this.returnType = returnType;
this.compileUnit = compileUnit;
this.lastToken = lastToken;
this.flags = flags;
this.returnType = returnType;
this.compileUnit = compileUnit;
this.lastToken = lastToken;
this.compilationState = compilationState;
this.body = body;
this.body = body;
this.parameters = parameters;
this.snapshot = snapshot;
this.hints = hints;
// the fields below never change - they are final and assigned in constructor
this.name = functionNode.name;
this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
this.source = functionNode.source;
this.name = functionNode.name;
this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
this.declaredSymbols = functionNode.declaredSymbols;
this.kind = functionNode.kind;
this.parameters = functionNode.parameters;
this.firstToken = functionNode.firstToken;
this.kind = functionNode.kind;
this.firstToken = functionNode.firstToken;
}
@Override
@ -260,6 +287,61 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
return this;
}
/**
* Get the source for this function
* @return the source
*/
public Source getSource() {
return source;
}
/**
* Get the version of this function node's code as it looked upon construction
* i.e typically parsed and nothing else
* @return initial version of function node
*/
public FunctionNode getSnapshot() {
return snapshot;
}
/**
* Throw away the snapshot, if any, to save memory. Used when heuristic
* determines that a method is not worth specializing
*
* @param lc lexical context
* @return new function node if a snapshot was present, now with snapsnot null
*/
public FunctionNode clearSnapshot(final LexicalContext lc) {
if (this.snapshot == null) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, null, hints));
}
/**
* Take a snapshot of this function node at a given point in time
* and store it in the function node
* @param lc lexical context
* @return function node
*/
public FunctionNode snapshot(final LexicalContext lc) {
if (this.snapshot == this) {
return this;
}
if (isProgram() || parameters.isEmpty()) {
return this; //never specialize anything that won't be recompiled
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints));
}
/**
* Can this function node be regenerated with more specific type args?
* @return true if specialization is possible
*/
public boolean canSpecialize() {
return getFlag(CAN_SPECIALIZE);
}
/**
* Get the compilation state of this function
* @return the compilation state
@ -307,7 +389,28 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
newState.add(state);
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body));
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints));
}
/**
* Get any compiler hints that may associated with the function
* @return compiler hints
*/
public Compiler.Hints getHints() {
return this.hints == null ? Compiler.Hints.EMPTY : hints;
}
/**
* Set compiler hints for this function
* @param lc lexical context
* @param hints compiler hints
* @return new function if hints changed
*/
public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) {
if (this.hints == hints) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@ -319,20 +422,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
return namespace.uniqueName(base);
}
/**
* Create a virtual symbol for a literal.
*
* @param literalNode Primary node to use symbol.
*
* @return Symbol used.
*/
public Symbol newLiteral(final LiteralNode<?> literalNode) {
final String uname = uniqueName(LITERAL_PREFIX.symbolName());
final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
literalNode.setSymbol(symbol);
return symbol;
}
@Override
public void toString(final StringBuilder sb) {
@ -374,7 +463,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.flags == flags) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
@Override
@ -483,7 +572,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if(this.body == body) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@ -551,7 +640,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.lastToken == lastToken) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@ -599,13 +688,17 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
}
/**
* Get a specialized type for an identity, if one exists
* @param node node to check specialized type for
* @return null if no specialization exists, otherwise type
* Reset the compile unit used to compile this function
* @see Compiler
* @param lc lexical context
* @param parameters the compile unit
* @return function node or a new one if state was changed
*/
@SuppressWarnings("static-method")
public Type getSpecializedType(final IdentNode node) {
return null; //TODO implement specialized types later
public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
if (this.parameters == parameters) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@ -674,7 +767,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
returnType),
compileUnit,
compilationState,
body));
body,
parameters,
snapshot,
hints));
}
/**
@ -705,7 +801,7 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
if (this.compileUnit == compileUnit) {
return this;
}
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
@ -717,19 +813,6 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
*
* @return Symbol used.
*/
public Symbol ensureSymbol(final Block block, final Type type, final Node node) {
Symbol symbol = node.getSymbol();
// If no symbol already present.
if (symbol == null) {
final String uname = uniqueName(TEMP_PREFIX.symbolName());
symbol = new Symbol(uname, IS_TEMP, type);
block.putSymbol(uname, symbol);
node.setSymbol(symbol);
}
return symbol;
}
/**
* Get the symbol for a compiler constant, or null if not available (yet)
@ -739,5 +822,4 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
public Symbol compilerConstant(final CompilerConstants cc) {
return body.getExistingSymbol(cc.symbolName());
}
}

View File

@ -34,7 +34,6 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/**
* IR representation for an identifier.
@ -56,14 +55,13 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
/**
* Constructor
*
* @param source the source
* @param token token
* @param finish finish position
* @param name name of identifier
*/
public IdentNode(final Source source, final long token, final int finish, final String name) {
super(source, token, finish);
this.name = name;
public IdentNode(final long token, final int finish, final String name) {
super(token, finish);
this.name = name.intern();
this.callSiteType = null;
this.flags = 0;
}
@ -103,7 +101,7 @@ public final class IdentNode extends Node implements PropertyKey, TypeOverride<I
}
@Override
public IdentNode setType(final Type type) {
public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) {
// do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
if (this.callSiteType == type) {
return this;

View File

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

View File

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

View File

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

View File

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

View File

@ -25,22 +25,21 @@
package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
/**
* Superclass for nodes that can be part of the lexical context
* @see LexicalContext
*/
public abstract class LexicalContextNode extends Node {
public abstract class LexicalContextNode extends Statement {
/**
* Constructor
*
* @param source source
* @param token token
* @param finish finish
* @param lineNumber line number
* @param token token
* @param finish finish
*/
protected LexicalContextNode(final Source source, final long token, final int finish) {
super(source, token, finish);
protected LexicalContextNode(final int lineNumber, final long token, final int finish) {
super(lineNumber, token, finish);
}
/**
@ -70,4 +69,16 @@ public abstract class LexicalContextNode extends Node {
final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
return lc.pop(newNode);
}
/**
* Set the symbol and replace in lexical context if applicable
* @param lc lexical context
* @param symbol symbol
* @return new node if symbol changed
*/
@Override
public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol));
}
}

View File

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

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 jdk.nashorn.internal.codegen.Label;
import jdk.nashorn.internal.runtime.Source;
/**
* A loop node, for example a while node, do while node or for node
@ -50,15 +49,15 @@ public abstract class LoopNode extends BreakableNode {
/**
* Constructor
*
* @param source source
* @param token token
* @param finish finish
* @param test test, or null if infinite loop
* @param body loop body
* @param lineNumber lineNumber
* @param token token
* @param finish finish
* @param test test, or null if infinite loop
* @param body loop body
* @param controlFlowEscapes controlFlowEscapes
*/
protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
super(source, token, finish, new Label("while_break"));
protected LoopNode(final int lineNumber, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
super(lineNumber, token, finish, new Label("while_break"));
this.continueLabel = new Label("while_continue");
this.test = test;
this.body = body;

View File

@ -27,16 +27,15 @@ package jdk.nashorn.internal.ir;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.parser.TokenType;
/**
* Nodes are used to compose Abstract Syntax Trees.
*/
public abstract class Node extends Location {
public abstract class Node implements Cloneable {
/** Node symbol. */
private Symbol symbol;
@ -46,16 +45,17 @@ public abstract class Node extends Location {
/** End of source range. */
protected int finish;
/** Token descriptor. */
private final long token;
/**
* Constructor
*
* @param source the source
* @param token token
* @param finish finish
*/
public Node(final Source source, final long token, final int finish) {
super(source, token);
public Node(final long token, final int finish) {
this.token = token;
this.start = Token.descPosition(token);
this.finish = finish;
}
@ -63,16 +63,14 @@ public abstract class Node extends Location {
/**
* Constructor
*
* @param source source
* @param token token
* @param start start
* @param finish finish
*/
protected Node(final Source source, final long token, final int start, final int finish) {
super(source, token);
protected Node(final long token, final int start, final int finish) {
this.start = start;
this.finish = finish;
this.token = token;
}
/**
@ -81,8 +79,7 @@ public abstract class Node extends Location {
* @param node source node
*/
protected Node(final Node node) {
super(node);
this.token = node.token;
this.symbol = node.symbol;
this.start = node.start;
this.finish = node.finish;
@ -155,15 +152,6 @@ public abstract class Node extends Location {
return Type.OBJECT;
}
/**
* Is this a debug info node like LineNumberNode etc?
*
* @return true if this is a debug node
*/
public boolean isDebug() {
return false;
}
/**
* For reference copies - ensure that labels in the copy node are unique
* using an appropriate copy constructor
@ -248,14 +236,86 @@ public abstract class Node extends Location {
return symbol;
}
@Override
protected Object clone() {
try {
return super.clone();
} catch (final CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
/**
* Assign a symbol to this node. See {@link Node#getSymbol()} for explanation
* of what a symbol is
*
* @param lc lexical context
* @param symbol the symbol
* @return new node
*/
public void setSymbol(final Symbol symbol) {
this.symbol = symbol;
public Node setSymbol(final LexicalContext lc, final Symbol symbol) {
if (this.symbol == symbol) {
return this;
}
final Node newNode = (Node)clone();
newNode.symbol = symbol;
return newNode;
}
@Override
public final boolean equals(final Object other) {
return super.equals(other);
}
@Override
public final int hashCode() {
return super.hashCode();
}
/**
* Return token position from a token descriptor.
*
* @return Start position of the token in the source.
*/
public int position() {
return Token.descPosition(token);
}
/**
* Return token length from a token descriptor.
*
* @return Length of the token.
*/
public int length() {
return Token.descLength(token);
}
/**
* Return token tokenType from a token descriptor.
*
* @return Type of token.
*/
public TokenType tokenType() {
return Token.descType(token);
}
/**
* Test token tokenType.
*
* @param type a type to check this token against
* @return true if token types match.
*/
public boolean isTokenType(final TokenType type) {
return Token.descType(token) == type;
}
/**
* Get the token for this location
* @return the token
*/
public long getToken() {
return token;
}
/**
@ -274,7 +334,7 @@ public abstract class Node extends Location {
final List<T> newList = new ArrayList<>();
for (final Node node : list) {
final T newNode = clazz.cast(node.accept(visitor));
final T newNode = node == null ? null : clazz.cast(node.accept(visitor));
if (newNode != node) {
changed = true;
}

View File

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

View File

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

View File

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

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

View File

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

View File

@ -25,67 +25,56 @@
package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.runtime.Source;
/**
* IR Node representing a line number
* Statement is something that becomes code and can be stepped past. A block is
* made up of statements. The only node subclass that needs to keep token and
* location information is the Statement
*/
@Immutable
public final class LineNumberNode extends Node {
/** Line number */
public abstract class Statement extends Node {
private final int lineNumber;
/**
* Constructor
*
* @param source the source
* @param lineNumber line number
* @param token token
* @param lineNumber the line number
* @param finish finish
*/
public LineNumberNode(final Source source, final long token, final int lineNumber) {
super(source, token, Token.descPosition(token));
public Statement(final int lineNumber, final long token, final int finish) {
super(token, finish);
this.lineNumber = lineNumber;
}
private LineNumberNode(final LineNumberNode lineNumberNode) {
super(lineNumberNode);
this.lineNumber = lineNumberNode.getLineNumber();
}
@Override
public Node accept(final NodeVisitor visitor) {
if (visitor.enterLineNumberNode(this)) {
return visitor.leaveLineNumberNode(this);
}
return this;
}
@Override
public void toString(final StringBuilder sb) {
sb.append("[|");
sb.append(lineNumber);
sb.append("|]");
}
@Override
public boolean isAtom() {
return true;
/**
* Constructor
*
* @param lineNumber line number
* @param token token
* @param start start
* @param finish finish
*/
protected Statement(final int lineNumber, final long token, final int start, final int finish) {
super(token, start, finish);
this.lineNumber = lineNumber;
}
/**
* Get the line number
* Copy constructor
*
* @param node source node
*/
protected Statement(final Statement node) {
super(node);
this.lineNumber = node.lineNumber;
}
/**
* Return the line number
* @return line number
*/
public int getLineNumber() {
return lineNumber;
}
@Override
public boolean isDebug() {
return true;
}
}

View File

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

View File

@ -29,7 +29,6 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
@ -67,6 +66,10 @@ public final class Symbol implements Comparable<Symbol> {
public static final int IS_INTERNAL = 1 << 9;
/** Is this a function self-reference symbol */
public static final int IS_FUNCTION_SELF = 1 << 10;
/** Is this a specialized param? */
public static final int IS_SPECIALIZED_PARAM = 1 << 11;
/** Is this symbol a shared temporary? */
public static final int IS_SHARED = 1 << 12;
/** Null or name identifying symbol. */
private final String name;
@ -152,6 +155,16 @@ public final class Symbol implements Comparable<Symbol> {
this(name, flags, type, -1);
}
private Symbol(final Symbol base, final String name, final int flags) {
this.flags = flags;
this.name = name;
this.fieldIndex = base.fieldIndex;
this.slot = base.slot;
this.type = base.type;
this.useCount = base.useCount;
}
private static String align(final String string, final int max) {
final StringBuilder sb = new StringBuilder();
sb.append(string.substring(0, Math.min(string.length(), max)));
@ -261,32 +274,14 @@ public final class Symbol implements Comparable<Symbol> {
return type.isCategory2() ? 2 : 1;
}
private static String type(final String desc) {
switch (desc.charAt(desc.length() - 1)) {
case ';':
return desc;//"obj";
case 'D':
return "double";
case 'I':
return "int";
case 'J':
return "long";
case 'Z':
return "boolean";
default:
return "UNKNOWN";
}
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
final String desc = getSymbolType().getDescriptor();
sb.append(name).
append(' ').
append('(').
append(type(desc)).
append(getSymbolType().getTypeClass().getSimpleName()).
append(')');
if (hasSlot()) {
@ -346,6 +341,24 @@ public final class Symbol implements Comparable<Symbol> {
return (flags & IS_SCOPE) == IS_SCOPE;
}
/**
* Returns true if this symbol is a temporary that is being shared across expressions.
* @return true if this symbol is a temporary that is being shared across expressions.
*/
public boolean isShared() {
return (flags & IS_SHARED) == IS_SHARED;
}
/**
* Creates an unshared copy of a symbol. The symbol must be currently shared.
* @param newName the name for the new symbol.
* @return a new, unshared symbol.
*/
public Symbol createUnshared(final String newName) {
assert isShared();
return new Symbol(this, newName, flags & ~IS_SHARED);
}
/**
* Flag this symbol as scope as described in {@link Symbol#isScope()}
*/
@ -355,10 +368,23 @@ public final class Symbol implements Comparable<Symbol> {
public void setIsScope() {
if (!isScope()) {
trace("SET IS SCOPE");
assert !isShared();
flags |= IS_SCOPE;
}
flags |= IS_SCOPE;
}
/**
* Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary.
*/
public void setIsShared() {
if(!isShared()) {
assert isTemp();
trace("SET IS SHARED");
flags |= IS_SHARED;
}
}
/**
* Check if this symbol is a variable
* @return true if variable
@ -383,6 +409,15 @@ public final class Symbol implements Comparable<Symbol> {
return (flags & KINDMASK) == IS_PARAM;
}
/**
* Check if this symbol is a function parameter of known
* narrowest type
* @return true if parameter
*/
public boolean isSpecializedParam() {
return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM;
}
/**
* Check whether this symbol ever has primitive assignments. Conservative
* @return true if primitive assignments exist
@ -404,7 +439,10 @@ public final class Symbol implements Comparable<Symbol> {
*/
public void setCanBeUndefined() {
assert type.isObject() : type;
flags |= CAN_BE_UNDEFINED;
if(!canBeUndefined()) {
assert !isShared();
flags |= CAN_BE_UNDEFINED;
}
}
/**
@ -412,7 +450,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param type the primitive type it occurs with, currently unused but can be used for width guesses
*/
public void setCanBePrimitive(final Type type) {
flags |= CAN_BE_PRIMITIVE;
if(!canBePrimitive()) {
assert !isShared();
flags |= CAN_BE_PRIMITIVE;
}
}
/**
@ -452,7 +493,10 @@ public final class Symbol implements Comparable<Symbol> {
* Flag this symbol as a let
*/
public void setIsLet() {
flags |= IS_LET;
if(!isLet()) {
assert !isShared();
flags |= IS_LET;
}
}
/**
@ -481,7 +525,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param fieldIndex field index - a positive integer
*/
public void setFieldIndex(final int fieldIndex) {
this.fieldIndex = fieldIndex;
if(this.fieldIndex != fieldIndex) {
assert !isShared();
this.fieldIndex = fieldIndex;
}
}
/**
@ -497,7 +544,10 @@ public final class Symbol implements Comparable<Symbol> {
* @param flags flags
*/
public void setFlags(final int flags) {
this.flags = flags;
if(this.flags != flags) {
assert !isShared();
this.flags = flags;
}
}
/**
@ -537,6 +587,7 @@ public final class Symbol implements Comparable<Symbol> {
*/
public void setSlot(final int slot) {
if (slot != this.slot) {
assert !isShared();
trace("SET SLOT " + slot);
this.slot = slot;
}
@ -561,6 +612,15 @@ public final class Symbol implements Comparable<Symbol> {
setTypeOverride(Type.widest(this.type, type));
}
/**
* Returns true if calling {@link #setType(Type)} on this symbol would effectively change its type.
* @param newType the new type to test for
* @return true if setting this symbols type to a new value would effectively change its type.
*/
public boolean wouldChangeType(final Type newType) {
return Type.widest(this.type, newType) != this.type;
}
/**
* Only use this if you know about an existing type
* constraint - otherwise a type can only be
@ -571,11 +631,32 @@ public final class Symbol implements Comparable<Symbol> {
public void setTypeOverride(final Type type) {
final Type old = this.type;
if (old != type) {
assert !isShared();
trace("TYPE CHANGE: " + old + "=>" + type + " == " + type);
this.type = type;
}
}
/**
* Sets the type of the symbol to the specified type. If the type would be changed, but this symbol is a shared
* temporary, it will instead return a different temporary symbol of the requested type from the passed temporary
* symbols. That way, it never mutates the type of a shared temporary.
* @param type the new type for the symbol
* @param ts a holder of temporary symbols
* @return either this symbol, or a different symbol if this symbol is a shared temporary and it type would have to
* be changed.
*/
public Symbol setTypeOverrideShared(final Type type, final TemporarySymbols ts) {
if(getSymbolType() != type) {
if(isShared()) {
assert !hasSlot();
return ts.getTypedTemporarySymbol(type);
}
setTypeOverride(type);
}
return this;
}
/**
* From a lexical context, set this symbol as needing scope, which
* will set flags for the defining block that will be written when

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

View File

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

View File

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

View File

@ -43,10 +43,12 @@ public interface TypeOverride<T extends Node> {
/**
* Set the override type
*
* @param type the type
* @param ts temporary symbols
* @param lc the current lexical context
* @param type the type
* @return a node equivalent to this one except for the requested change.
*/
public T setType(final Type type);
public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type);
/**
* Returns true if this node can have a callsite override, e.g. all scope ident nodes

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@ -453,26 +452,6 @@ public abstract class NodeVisitor {
return leaveDefault(labelNode);
}
/**
* Callback for entering a LineNumberNode
*
* @param lineNumberNode the node
* @return true if traversal should continue and node children be traversed, false otherwise
*/
public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
return enterDefault(lineNumberNode);
}
/**
* Callback for leaving a LineNumberNode
*
* @param lineNumberNode the node
* @return processed node, which will replace the original one, or the original node
*/
public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
return leaveDefault(lineNumberNode);
}
/**
* Callback for entering a LiteralNode
*

View File

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

View File

@ -86,66 +86,6 @@ public final class NativeDebug extends ScriptObject {
return UNDEFINED;
}
/**
* Nashorn extension: get embed0 from {@link ScriptObject}
*
* @param self self reference
* @param obj script object
* @return the embed0 property value for the given ScriptObject
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object embed0(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).embed0;
}
return UNDEFINED;
}
/**
* Nashorn extension: get embed1 from {@link ScriptObject}
*
* @param self self reference
* @param obj script object
* @return the embed1 property value for the given ScriptObject
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object embed1(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).embed1;
}
return UNDEFINED;
}
/**
* Nashorn extension: get embed2 from {@link ScriptObject}
*
* @param self self reference
* @param obj script object
* @return the embed2 property value for the given ScriptObject
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object embed2(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).embed2;
}
return UNDEFINED;
}
/**
* Nashorn extension: get embed3 from {@link ScriptObject}
*
* @param self self reference
* @param obj script object
* @return the embed3 property value for the given ScriptObject
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object embed3(final Object self, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).embed3;
}
return UNDEFINED;
}
/**
* Nashorn extension: get spill vector from {@link ScriptObject}
*

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -88,7 +88,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
int weight = Type.typeFor(type.returnType()).getWeight();
for (final Class<?> paramType : type.parameterArray()) {
final int pweight = Type.typeFor(paramType).getWeight();
final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized
weight += pweight;
}
return weight;

View File

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

View File

@ -201,9 +201,6 @@ public final class Context {
/** Current error manager. */
private final ErrorManager errors;
/** Empty map used for seed map for JO objects */
final PropertyMap emptyMap = PropertyMap.newEmptyMap(this);
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
@ -414,7 +411,7 @@ public final class Context {
return ScriptRuntime.apply(func, evalThis);
}
private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
if (srcStr.startsWith(prefix)) {
final String resource = resourcePath + srcStr.substring(prefix.length());
// NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
@ -513,7 +510,7 @@ public final class Context {
/**
* Lookup a Java class. This is used for JSR-223 stuff linking in from
* {@link jdk.nashorn.internal.objects.NativeJava} and {@link jdk.nashorn.internal.runtime.NativeJavaPackage}
* {@code jdk.nashorn.internal.objects.NativeJava} and {@code jdk.nashorn.internal.runtime.NativeJavaPackage}
*
* @param fullName full name of class to load
*
@ -762,10 +759,10 @@ public final class Context {
final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
final Compiler compiler = new Compiler(installer, functionNode, strict);
final Compiler compiler = new Compiler(installer, strict);
compiler.compile();
script = compiler.install();
final FunctionNode newFunctionNode = compiler.compile(functionNode);
script = compiler.install(newFunctionNode);
if (global != null) {
global.cacheClass(source, script);

View File

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

View File

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

View File

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

View File

@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_MAP;
import static jdk.nashorn.internal.runtime.PropertyHashMap.EMPTY_HASHMAP;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
@ -49,29 +49,27 @@ import java.util.WeakHashMap;
* will return a new map.
*/
public final class PropertyMap implements Iterable<Object>, PropertyListener {
/** Is this a prototype PropertyMap? */
public static final int IS_PROTOTYPE = 0b0000_0001;
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
public static final int NOT_EXTENSIBLE = 0b0000_0010;
public static final int NOT_EXTENSIBLE = 0b0000_0001;
/** This mask is used to preserve certain flags when cloning the PropertyMap. Others should not be copied */
private static final int CLONEABLE_FLAGS_MASK = 0b0000_1111;
/** Has a listener been added to this property map. This flag is not copied when cloning a map. See {@link PropertyListener} */
public static final int IS_LISTENER_ADDED = 0b0001_0000;
/** Empty map used for seed map for JO$ objects */
private static final PropertyMap EMPTY_MAP = new PropertyMap(EMPTY_HASHMAP);
/** Map status flags. */
private int flags;
/** Class of object referenced.*/
private final Class<?> structure;
/** Context associated with this {@link PropertyMap}. */
private final Context context;
/** Map of properties. */
private final PropertyHashMap properties;
/** objects proto. */
private ScriptObject proto;
/** Number of fields in use. */
private int fieldCount;
/** Number of fields available. */
private int fieldMaximum;
/** Length of spill in use. */
private int spillLength;
@ -91,21 +89,30 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
/**
* Constructor.
*
* @param structure Class the map's {@link AccessorProperty}s apply to.
* @param context Context associated with this {@link PropertyMap}.
* @param properties A {@link PropertyHashMap} with initial contents.
* @param properties A {@link PropertyHashMap} with initial contents.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
*/
PropertyMap(final Class<?> structure, final Context context, final PropertyHashMap properties) {
this.structure = structure;
this.context = context;
this.properties = properties;
this.hashCode = computeHashCode();
private PropertyMap(final PropertyHashMap properties, final int fieldCount, final int fieldMaximum) {
this.properties = properties;
this.hashCode = computeHashCode();
this.fieldCount = fieldCount;
this.fieldMaximum = fieldMaximum;
if (Context.DEBUG) {
count++;
}
}
/**
* Constructor.
*
* @param properties A {@link PropertyHashMap} with initial contents.
*/
private PropertyMap(final PropertyHashMap properties) {
this(properties, 0, 0);
}
/**
* Cloning constructor.
*
@ -113,13 +120,12 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @param properties A {@link PropertyHashMap} with a new set of properties.
*/
private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
this.structure = propertyMap.structure;
this.context = propertyMap.context;
this.properties = properties;
this.flags = propertyMap.getClonedFlags();
this.proto = propertyMap.proto;
this.spillLength = propertyMap.spillLength;
this.hashCode = computeHashCode();
this.properties = properties;
this.flags = propertyMap.getClonedFlags();
this.spillLength = propertyMap.spillLength;
this.fieldCount = propertyMap.fieldCount;
this.fieldMaximum = propertyMap.fieldMaximum;
this.hashCode = computeHashCode();
if (Context.DEBUG) {
count++;
@ -127,6 +133,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
}
/**
* Cloning constructor.
*
* @param propertyMap Existing property map.
*/
private PropertyMap(final PropertyMap propertyMap) {
this(propertyMap, propertyMap.properties);
}
/**
* Duplicates this PropertyMap instance. This is used by nasgen generated
* prototype and constructor classes. {@link PropertyMap} used for singletons
@ -138,7 +153,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return Duplicated {@link PropertyMap}.
*/
public PropertyMap duplicate() {
return new PropertyMap(this.structure, this.context, this.properties);
return new PropertyMap(this.properties);
}
/**
@ -146,20 +161,20 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
*
* @param structure Class the map's {@link AccessorProperty}s apply to.
* @param properties Collection of initial properties.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
*
* @return New {@link PropertyMap}.
*/
public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties) {
final Context context = Context.fromClass(structure);
public static PropertyMap newMap(final Class<?> structure, final Collection<Property> properties, final int fieldCount, final int fieldMaximum) {
// Reduce the number of empty maps in the context.
if (structure == jdk.nashorn.internal.scripts.JO.class) {
return context.emptyMap;
return EMPTY_MAP;
}
PropertyHashMap newProperties = EMPTY_MAP.immutableAdd(properties);
PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
return new PropertyMap(structure, context, newProperties);
return new PropertyMap(newProperties, fieldCount, fieldMaximum);
}
/**
@ -170,7 +185,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New {@link PropertyMap}.
*/
public static PropertyMap newMap(final Class<?> structure) {
return newMap(structure, null);
return newMap(structure, null, 0, 0);
}
/**
@ -180,7 +195,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New empty {@link PropertyMap}.
*/
public static PropertyMap newEmptyMap(final Context context) {
return new PropertyMap(jdk.nashorn.internal.scripts.JO.class, context, EMPTY_MAP);
return new PropertyMap(EMPTY_HASHMAP);
}
/**
@ -195,11 +210,12 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
/**
* Return a SwitchPoint used to track changes of a property in a prototype.
*
* @param key {@link Property} key.
* @param proto Object prototype.
* @param key {@link Property} key.
*
* @return A shared {@link SwitchPoint} for the property.
*/
public SwitchPoint getProtoGetSwitchPoint(final String key) {
public SwitchPoint getProtoGetSwitchPoint(final ScriptObject proto, final String key) {
if (proto == null) {
return null;
}
@ -295,6 +311,11 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyHashMap newProperties = properties.immutableAdd(property);
newMap = new PropertyMap(this, newProperties);
addToHistory(property, newMap);
if(!property.isSpill()) {
newMap.fieldCount = Math.max(newMap.fieldCount, property.getSlot() + 1);
}
newMap.spillLength += property.getSpillCount();
}
@ -355,7 +376,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
newProperty instanceof UserAccessorProperty) : "arbitrary replaceProperty attempted";
newMap.flags = getClonedFlags();
newMap.proto = proto;
/*
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
@ -411,7 +431,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return New map with {@link #NOT_EXTENSIBLE} flag set.
*/
PropertyMap preventExtensions() {
final PropertyMap newMap = new PropertyMap(this, this.properties);
final PropertyMap newMap = new PropertyMap(this);
newMap.flags |= NOT_EXTENSIBLE;
return newMap;
}
@ -423,7 +443,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* {@link Property#NOT_CONFIGURABLE} set.
*/
PropertyMap seal() {
PropertyHashMap newProperties = EMPTY_MAP;
PropertyHashMap newProperties = EMPTY_HASHMAP;
for (final Property oldProperty : properties.getProperties()) {
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
@ -442,7 +462,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* {@link Property#NOT_CONFIGURABLE} and {@link Property#NOT_WRITABLE} set.
*/
PropertyMap freeze() {
PropertyHashMap newProperties = EMPTY_MAP;
PropertyHashMap newProperties = EMPTY_HASHMAP;
for (Property oldProperty : properties.getProperties()) {
int propertyFlags = Property.NOT_CONFIGURABLE;
@ -578,11 +598,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
* @return Computed hash code.
*/
private int computeHashCode() {
int hash = structure.hashCode();
if (proto != null) {
hash ^= proto.hashCode();
}
int hash = 0;
for (final Property property : getProperties()) {
hash = hash << 7 ^ hash >> 7;
@ -605,9 +621,7 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
final PropertyMap otherMap = (PropertyMap)other;
if (structure != otherMap.structure ||
proto != otherMap.proto ||
properties.size() != otherMap.properties.size()) {
if (properties.size() != otherMap.properties.size()) {
return false;
}
@ -658,31 +672,6 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
return new PropertyMapIterator(this);
}
/**
* Return map's {@link Context}.
*
* @return The {@link Context} where the map originated.
*/
Context getContext() {
return context;
}
/**
* Check if this map is a prototype
*
* @return {@code true} if is prototype
*/
public boolean isPrototype() {
return (flags & IS_PROTOTYPE) != 0;
}
/**
* Flag this map as having a prototype.
*/
private void setIsPrototype() {
flags |= IS_PROTOTYPE;
}
/**
* Check whether a {@link PropertyListener} has been added to this map.
*
@ -720,6 +709,22 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
boolean isFrozen() {
return !isExtensible() && allFrozen();
}
/**
* Get the number of fields allocated for this {@link PropertyMap}.
*
* @return Number of fields allocated.
*/
int getFieldCount() {
return fieldCount;
}
/**
* Get maximum number of fields available for this {@link PropertyMap}.
*
* @return Number of fields available.
*/
int getFieldMaximum() {
return fieldMaximum;
}
/**
* Get length of spill area associated with this {@link PropertyMap}.
@ -731,24 +736,14 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
}
/**
* Return the prototype of objects associated with this {@link PropertyMap}.
* Change the prototype of objects associated with this {@link PropertyMap}.
*
* @return Prototype object.
*/
ScriptObject getProto() {
return proto;
}
/**
* Set the prototype of objects associated with this {@link PropertyMap}.
*
* @param newProto Prototype object to use.
* @param oldProto Current prototype object.
* @param newProto New prototype object to replace oldProto.
*
* @return New {@link PropertyMap} with prototype changed.
*/
PropertyMap setProto(final ScriptObject newProto) {
final ScriptObject oldProto = this.proto;
PropertyMap changeProto(final ScriptObject oldProto, final ScriptObject newProto) {
if (oldProto == newProto) {
return this;
}
@ -761,19 +756,10 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
if (Context.DEBUG) {
incrementSetProtoNewMapCount();
}
final PropertyMap newMap = new PropertyMap(this, this.properties);
final PropertyMap newMap = new PropertyMap(this);
addToProtoHistory(newProto, newMap);
newMap.proto = newProto;
if (oldProto != null && newMap.isListenerAdded()) {
oldProto.removePropertyListener(newMap);
}
if (newProto != null) {
newProto.getMap().setIsPrototype();
}
return newMap;
}
@ -927,4 +913,3 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
setProtoNewMapCount++;
}
}

View File

@ -30,9 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.LinkedList;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.FunctionSignature;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.parser.Token;
@ -148,10 +151,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
if (functionNode.isLazy()) {
Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
final Compiler compiler = new Compiler(installer, functionNode);
functionNode = compiler.compile();
final Compiler compiler = new Compiler(installer);
functionNode = compiler.compile(functionNode);
assert !functionNode.isLazy();
compiler.install();
compiler.install(functionNode);
// we don't need to update any flags - varArgs and needsCallee are instrincic
// in the function world we need to get a destination node from the compile instead
@ -164,23 +167,118 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
// code exists - look it up and add it into the automatically sorted invoker list
code.add(
new CompiledFunction(
MH.findStatic(
LOOKUP,
functionNode.getCompileUnit().getCode(),
functionNode.getName(),
new FunctionSignature(functionNode).
getMethodType())));
addCode(functionNode, null, null);
}
private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) {
final MethodHandle target =
MH.findStatic(
LOOKUP,
fn.getCompileUnit().getCode(),
fn.getName(),
new FunctionSignature(fn).
getMethodType());
MethodHandle mh = target;
if (guard != null) {
try {
mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback);
} catch (Throwable e) {
e.printStackTrace();
}
}
final CompiledFunction cf = new CompiledFunction(mh);
code.add(cf);
return cf.getInvoker();
}
private static Type runtimeType(final Object arg) {
if (arg == null) {
return Type.OBJECT;
}
final Class<?> clazz = arg.getClass();
assert !clazz.isPrimitive() : "always boxed";
if (clazz == Double.class) {
return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER;
} else if (clazz == Integer.class) {
return Type.INT;
} else if (clazz == Long.class) {
return Type.LONG;
} else if (clazz == String.class) {
return Type.STRING;
}
return Type.OBJECT;
}
@SuppressWarnings("unused")
private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) {
//System.err.println("Param type guard " + Arrays.asList(args));
return false;
}
private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class);
@Override
MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
final MethodHandle mh = super.getBestInvoker(callSiteType, args);
if (code.isLessSpecificThan(callSiteType)) {
// opportunity for code specialization - we can regenerate a better version of this method
if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) {
return mh;
}
return mh;
final FunctionNode snapshot = functionNode.getSnapshot();
if (snapshot == null) {
return mh;
}
int i;
//classes known at runtime
final LinkedList<Type> runtimeArgs = new LinkedList<>();
for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
runtimeArgs.addLast(runtimeType(args[i]));
}
//classes known at compile time
final LinkedList<Type> compileTimeArgs = new LinkedList<>();
for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
}
//the classes known at compile time are a safe to generate as primitives without parameter guards
//the classes known at runtime are safe to generate as primitives IFF there are parameter guards
MethodHandle guard = null;
for (i = 0; i < compileTimeArgs.size(); i++) {
final Type runtimeType = runtimeArgs.get(i);
final Type compileType = compileTimeArgs.get(i);
if (compileType.isObject() && !runtimeType.isObject()) {
if (guard == null) {
guard = PARAM_TYPE_GUARD;
guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
}
}
}
//System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
assert snapshot != null;
assert snapshot != functionNode;
final Compiler compiler = new Compiler(installer);
final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
compiler.install(compiledSnapshot);
final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
return nmh;
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
}
}

View File

@ -26,9 +26,13 @@
package jdk.nashorn.internal.runtime;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.options.KeyValueOption;
@ -136,6 +140,9 @@ public final class ScriptEnvironment {
/** Print resulting bytecode for script */
public final boolean _print_code;
/** Print memory usage for IR after each phase */
public final boolean _print_mem_usage;
/** Print function will no print newline characters */
public final boolean _print_no_newline;
@ -151,6 +158,9 @@ public final class ScriptEnvironment {
/** is this environment in scripting mode? */
public final boolean _scripting;
/** is the JIT allowed to specializ calls based on callsite types? */
public final Set<String> _specialize_calls;
/** is this environment in strict mode? */
public final boolean _strict;
@ -204,6 +214,7 @@ public final class ScriptEnvironment {
_print_ast = options.getBoolean("print.ast");
_print_lower_ast = options.getBoolean("print.lower.ast");
_print_code = options.getBoolean("print.code");
_print_mem_usage = options.getBoolean("print.mem.usage");
_print_no_newline = options.getBoolean("print.no.newline");
_print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse");
@ -213,6 +224,17 @@ public final class ScriptEnvironment {
_version = options.getBoolean("version");
_verify_code = options.getBoolean("verify.code");
final String specialize = options.getString("specialize.calls");
if (specialize == null) {
_specialize_calls = null;
} else {
_specialize_calls = new HashSet<>();
final StringTokenizer st = new StringTokenizer(specialize, ",");
while (st.hasMoreElements()) {
_specialize_calls.add(st.nextToken());
}
}
int callSiteFlags = 0;
if (options.getBoolean("profile.callsites")) {
callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE;
@ -246,6 +268,18 @@ public final class ScriptEnvironment {
this._locale = Locale.getDefault();
}
/**
* Can we specialize a particular method name?
* @param functionName method name
* @return true if we are allowed to generate versions of this method
*/
public boolean canSpecialize(final String functionName) {
if (_specialize_calls == null) {
return false;
}
return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName);
}
/**
* Get the output stream for this environment
* @return output print writer

View File

@ -104,34 +104,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Per ScriptObject flag - is this an arguments object? */
public static final int IS_ARGUMENTS = 0b0000_0100;
/** Is this a prototype PropertyMap? */
public static final int IS_PROTOTYPE = 0b0000_1000;
/** Spill growth rate - by how many elements does {@link ScriptObject#spill} when full */
public static final int SPILL_RATE = 8;
/** Map to property information and accessor functions. Ordered by insertion. */
private PropertyMap map;
/** objects proto. */
private ScriptObject proto;
/** Context of the object, lazily cached. */
private Context context;
/** Object flags. */
private int flags;
/** Area for properties added to object after instantiation, see {@link SpillProperty} */
/** Area for properties added to object after instantiation, see {@link AccessorProperty} */
public Object[] spill;
/** Local embed area position 0 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
public Object embed0;
/** Local embed area position 1 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
public Object embed1;
/** Local embed area position 2 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
public Object embed2;
/** Local embed area position 3 - used for {@link SpillProperty} before {@link ScriptObject#spill} */
public Object embed3;
/** Indexed array data. */
private ArrayData arrayData;
static final MethodHandle SETEMBED = findOwnMH("setEmbed", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, int.class, Object.class, Object.class);
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
static final MethodHandle SETSPILLWITHNEW = findOwnMH("setSpillWithNew", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
static final MethodHandle SETSPILLWITHGROW = findOwnMH("setSpillWithGrow", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, int.class, Object.class, Object.class);
@ -665,9 +662,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
if (deep) {
final ScriptObject proto = getProto();
if(proto != null) {
return proto.findProperty(key, deep, stopOnNonScope, start);
final ScriptObject myProto = getProto();
if (myProto != null) {
return myProto.findProperty(key, deep, stopOnNonScope, start);
}
}
@ -783,8 +780,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
// delete getter and setter function references so that we don't leak
if (property instanceof UserAccessorProperty) {
final UserAccessorProperty uc = (UserAccessorProperty) property;
setEmbedOrSpill(uc.getGetterSlot(), null);
setEmbedOrSpill(uc.getSetterSlot(), null);
setSpill(uc.getGetterSlot(), null);
setSpill(uc.getSetterSlot(), null);
}
return true;
}
@ -809,7 +806,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int getterSlot = uc.getGetterSlot();
// clear the old getter and set the new getter
setEmbedOrSpill(getterSlot, getter);
setSpill(getterSlot, getter);
// if getter function is null, flag the slot to be negative (less by 1)
if (getter == null) {
getterSlot = -getterSlot - 1;
@ -817,7 +814,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
int setterSlot = uc.getSetterSlot();
// clear the old setter and set the new setter
setEmbedOrSpill(setterSlot, setter);
setSpill(setterSlot, setter);
// if setter function is null, flag the slot to be negative (less by 1)
if (setter == null) {
setterSlot = -setterSlot - 1;
@ -973,9 +970,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @param bindName null or name to bind to second argument (property not found method.)
*
* @return value of property as a MethodHandle or null.
*
*/
@SuppressWarnings("static-method")
protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
return getCallMethodHandle(getObjectValue(find), type, bindName);
}
@ -1056,8 +1051,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* Return the current context from the object's map.
* @return Current context.
*/
final Context getContext() {
return getMap().getContext();
protected final Context getContext() {
if (context == null) {
context = Context.fromClass(getClass());
}
return context;
}
/**
@ -1097,44 +1095,30 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return __proto__ object.
*/
public final ScriptObject getProto() {
return getMap().getProto();
}
/**
* Check if this is a prototype
* @return true if {@link PropertyMap#isPrototype()} is true for this ScriptObject
*/
public final boolean isPrototype() {
return getMap().isPrototype();
return proto;
}
/**
* Set the __proto__ of an object.
* @param newProto new __proto__ to set.
*/
public final void setProto(final ScriptObject newProto) {
PropertyMap oldMap = getMap();
ScriptObject oldProto = getProto();
public synchronized final void setProto(final ScriptObject newProto) {
final ScriptObject oldProto = proto;
map = map.changeProto(oldProto, newProto);
while (oldProto != newProto) {
final PropertyMap newMap = oldMap.setProto(newProto);
if (newProto != null) {
newProto.setIsPrototype();
}
if (!compareAndSetMap(oldMap, newMap)) {
oldMap = getMap();
oldProto = getProto();
} else {
if (isPrototype()) {
proto = newProto;
if (oldProto != null) {
oldProto.removePropertyListener(this);
}
if (isPrototype()) {
if (oldProto != null) {
oldProto.removePropertyListener(this);
}
if (newProto != null) {
newProto.addPropertyListener(this);
}
}
return;
if (newProto != null) {
newProto.addPropertyListener(this);
}
}
}
@ -1326,6 +1310,25 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
flags |= IS_ARGUMENTS;
}
/**
* Check if this object is a prototype
*
* @return {@code true} if is prototype
*/
public boolean isPrototype() {
return (flags & IS_PROTOTYPE) != 0;
}
/**
* Flag this object as having a prototype.
*/
public void setIsPrototype() {
if (proto != null && !isPrototype()) {
proto.addPropertyListener(this);
}
flags |= IS_PROTOTYPE;
}
/**
* Get the {@link ArrayData} for this ScriptObject if it is an array
* @return array data
@ -1719,11 +1722,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (!property.hasGetterFunction()) {
methodHandle = bindTo(methodHandle, prototype);
}
return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(name), guard);
return new GuardedInvocation(methodHandle, getMap().getProtoGetSwitchPoint(proto, name), guard);
}
assert !NashornCallSiteDescriptor.isFastScope(desc);
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(name), guard);
return new GuardedInvocation(Lookup.emptyGetter(returnType), getMap().getProtoGetSwitchPoint(proto, name), guard);
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
@ -1822,27 +1825,31 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
final PropertyMap myMap = getMap();
return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(myMap));
return new GuardedInvocation(Lookup.EMPTY_SETTER, myMap.getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(myMap));
}
@SuppressWarnings("unused")
private static void setEmbed(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final int i, final Object self, final Object value) throws Throwable {
private static void setField(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final MethodHandle setter, final Object self, final Object value) throws Throwable {
final ScriptObject obj = (ScriptObject)self;
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
obj.useEmbed(i);
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
if (!obj.isExtensible()) {
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj));
} else if (obj.compareAndSetMap(oldMap, newMap)) {
setter.invokeExact(self, value);
} else {
obj.set(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND), value, isStrict);
}
}
@SuppressWarnings("unused")
private static void setSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) {
final ScriptObject obj = (ScriptObject)self;
if (obj.trySetEmbedOrSpill(desc, oldMap, newMap, value)) {
if (obj.trySetSpill(desc, oldMap, newMap, value)) {
obj.spill[index] = value;
}
}
private boolean trySetEmbedOrSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
private boolean trySetSpill(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final Object value) {
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
if (!isExtensible() && isStrict) {
throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(this));
@ -1964,7 +1971,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
methodHandle = bindTo(methodHandle, UNDEFINED);
}
return new GuardedInvocation(methodHandle,
find.isInherited()? getMap().getProtoGetSwitchPoint(NO_SUCH_PROPERTY_NAME) : null,
find.isInherited()? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null,
getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class), find.getOwner(), func));
}
}
@ -1995,7 +2002,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
}
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap()));
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(proto, name), NashornGuards.getMapGuard(getMap()));
}
private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> {
@ -2070,36 +2077,39 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
* @return Added property.
*/
private Property addSpillProperty(final String key, final int propertyFlags) {
int i = findEmbed();
Property spillProperty;
int fieldCount = getMap().getFieldCount();
int fieldMaximum = getMap().getFieldMaximum();
Property property;
if (i >= EMBED_SIZE) {
i = getMap().getSpillLength();
if (fieldCount < fieldMaximum) {
property = new AccessorProperty(key, propertyFlags & ~Property.IS_SPILL, getClass(), fieldCount);
notifyPropertyAdded(this, property);
property = addOwnProperty(property);
} else {
int i = getMap().getSpillLength();
MethodHandle getter = MH.arrayElementGetter(Object[].class);
MethodHandle setter = MH.arrayElementSetter(Object[].class);
getter = MH.asType(MH.insertArguments(getter, 1, i), Lookup.GET_OBJECT_TYPE);
setter = MH.asType(MH.insertArguments(setter, 1, i), Lookup.SET_OBJECT_TYPE);
spillProperty = new SpillProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
notifyPropertyAdded(this, spillProperty);
spillProperty = addOwnProperty(spillProperty);
i = spillProperty.getSlot();
property = new AccessorProperty(key, propertyFlags | Property.IS_SPILL, i, getter, setter);
notifyPropertyAdded(this, property);
property = addOwnProperty(property);
i = property.getSlot();
final int newLength = (i + SPILL_RATE) / SPILL_RATE * SPILL_RATE;
final Object[] newSpill = new Object[newLength];
if (spill != null) {
System.arraycopy(spill, 0, newSpill, 0, spill.length);
if (spill == null || newLength > spill.length) {
final Object[] newSpill = new Object[newLength];
if (spill != null) {
System.arraycopy(spill, 0, newSpill, 0, spill.length);
}
spill = newSpill;
}
spill = newSpill;
} else {
useEmbed(i);
spillProperty = new SpillProperty(key, propertyFlags, i, GET_EMBED[i], SET_EMBED[i]);
notifyPropertyAdded(this, spillProperty);
spillProperty = addOwnProperty(spillProperty);
}
return spillProperty;
return property;
}
@ -3158,41 +3168,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return true;
}
/*
* Embed management
*/
/** Number of embed slots */
public static final int EMBED_SIZE = 4;
/** Embed offset */
public static final int EMBED_OFFSET = 32 - EMBED_SIZE;
static final MethodHandle[] GET_EMBED;
static final MethodHandle[] SET_EMBED;
static {
GET_EMBED = new MethodHandle[EMBED_SIZE];
SET_EMBED = new MethodHandle[EMBED_SIZE];
for (int i = 0; i < EMBED_SIZE; i++) {
final String name = "embed" + i;
GET_EMBED[i] = MH.asType(MH.getter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.GET_OBJECT_TYPE);
SET_EMBED[i] = MH.asType(MH.setter(MethodHandles.lookup(), ScriptObject.class, name, Object.class), Lookup.SET_OBJECT_TYPE);
}
}
void useEmbed(final int i) {
flags |= 1 << (EMBED_OFFSET + i);
}
int findEmbed() {
final int bits = ~(flags >>> EMBED_OFFSET);
final int least = bits ^ -bits;
final int index = Integer.numberOfTrailingZeros(least) - 1;
return index;
}
/*
* Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object.
@ -3200,26 +3175,16 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
private UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
int oldSpillLength = getMap().getSpillLength();
int getterSlot = findEmbed();
if (getterSlot >= EMBED_SIZE) {
getterSlot = oldSpillLength + EMBED_SIZE;
++oldSpillLength;
} else {
useEmbed(getterSlot);
}
setEmbedOrSpill(getterSlot, getter);
int getterSlot = oldSpillLength++;
setSpill(getterSlot, getter);
// if getter function is null, flag the slot to be negative (less by 1)
if (getter == null) {
getterSlot = -getterSlot - 1;
}
int setterSlot = findEmbed();
if (setterSlot >= EMBED_SIZE) {
setterSlot = oldSpillLength + EMBED_SIZE;
} else {
useEmbed(setterSlot);
}
setEmbedOrSpill(setterSlot, setter);
int setterSlot = oldSpillLength++;
setSpill(setterSlot, setter);
// if setter function is null, flag the slot to be negative (less by 1)
if (setter == null) {
setterSlot = -setterSlot - 1;
@ -3228,56 +3193,28 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return new UserAccessorProperty(key, propertyFlags, getterSlot, setterSlot);
}
private void setEmbedOrSpill(final int slot, final Object value) {
switch (slot) {
case 0:
embed0 = value;
break;
case 1:
embed1 = value;
break;
case 2:
embed2 = value;
break;
case 3:
embed3 = value;
break;
default:
if (slot >= 0) {
final int index = (slot - EMBED_SIZE);
if (spill == null) {
// create new spill.
spill = new Object[Math.max(index + 1, SPILL_RATE)];
} else if (index >= spill.length) {
// grow spill as needed
final Object[] newSpill = new Object[index + 1];
System.arraycopy(spill, 0, newSpill, 0, spill.length);
spill = newSpill;
}
spill[index] = value;
private void setSpill(final int slot, final Object value) {
if (slot >= 0) {
final int index = slot;
if (spill == null) {
// create new spill.
spill = new Object[Math.max(index + 1, SPILL_RATE)];
} else if (index >= spill.length) {
// grow spill as needed
final Object[] newSpill = new Object[index + 1];
System.arraycopy(spill, 0, newSpill, 0, spill.length);
spill = newSpill;
}
break;
spill[index] = value;
}
}
// user accessors are either stored in embed fields or spill array slots
// get the accessor value using slot number. Note that slot is either embed
// field number or (spill array index + embedSize).
Object getEmbedOrSpill(final int slot) {
switch (slot) {
case 0:
return embed0;
case 1:
return embed1;
case 2:
return embed2;
case 3:
return embed3;
default:
final int index = (slot - EMBED_SIZE);
return (index < 0 || (index >= spill.length)) ? null : spill[index];
}
// user accessors are either stored in spill array slots
// get the accessor value using slot number. Note that slot is spill array index.
Object getSpill(final int slot) {
final int index = slot;
return (index < 0 || (index >= spill.length)) ? null : spill[index];
}
// User defined getter and setter are always called by "dyn:call". Note that the user
@ -3287,7 +3224,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@SuppressWarnings("unused")
private static Object userAccessorGetter(final ScriptObject proto, final int slot, final Object self) {
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
final Object func = container.getEmbedOrSpill(slot);
final Object func = container.getSpill(slot);
if (func instanceof ScriptFunction) {
try {
@ -3305,7 +3242,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
@SuppressWarnings("unused")
private static void userAccessorSetter(final ScriptObject proto, final int slot, final String name, final Object self, final Object value) {
final ScriptObject container = (proto != null) ? proto : (ScriptObject)self;
final Object func = container.getEmbedOrSpill(slot);
final Object func = container.getSpill(slot);
if (func instanceof ScriptFunction) {
try {

View File

@ -166,18 +166,20 @@ final class SetMethodCreator {
}
private SetMethod createNewPropertySetter() {
final int nextEmbed = sobj.findEmbed();
final SetMethod sm;
if (nextEmbed >= ScriptObject.EMBED_SIZE) {
sm = createNewSpillPropertySetter();
} else {
sm = createNewEmbedPropertySetter(nextEmbed);
}
final SetMethod sm = map.getFieldCount() < map.getFieldMaximum() ? createNewFieldSetter() : createNewSpillPropertySetter();
sobj.notifyPropertyAdded(sobj, sm.property);
return sm;
}
private SetMethod createNewFieldSetter() {
final PropertyMap oldMap = getMap();
final Property property = new AccessorProperty(getName(), 0, sobj.getClass(), oldMap.getFieldCount());
final PropertyMap newMap = oldMap.addProperty(property);
MethodHandle setter = MH.insertArguments(ScriptObject.SETFIELD, 0, desc, oldMap, newMap, property.getSetter(Object.class, newMap));
return new SetMethod(MH.asType(setter, Lookup.SET_OBJECT_TYPE), property);
}
private SetMethod createNewSpillPropertySetter() {
final int nextSpill = getMap().getSpillLength();
@ -189,7 +191,7 @@ final class SetMethodCreator {
final MethodHandle getter = MH.asType(MH.insertArguments(MH.arrayElementGetter(Object[].class), 1, nextSpill), Lookup.GET_OBJECT_TYPE);
final MethodHandle setter = MH.asType(MH.insertArguments(MH.arrayElementSetter(Object[].class), 1, nextSpill), Lookup.SET_OBJECT_TYPE);
return new SpillProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
return new AccessorProperty(getName(), Property.IS_SPILL, nextSpill, getter, setter);
}
private MethodHandle createSpillMethodHandle(final int nextSpill, Property property) {
@ -207,14 +209,6 @@ final class SetMethodCreator {
}
}
private SetMethod createNewEmbedPropertySetter(final int nextEmbed) {
sobj.useEmbed(nextEmbed);
final Property property = new SpillProperty(getName(), 0, nextEmbed, ScriptObject.GET_EMBED[nextEmbed], ScriptObject.SET_EMBED[nextEmbed]);
//TODO specfields
final MethodHandle methodHandle = MH.insertArguments(ScriptObject.SETEMBED, 0, desc, getMap(), getNewMap(property), property.getSetter(Object.class, getMap()), nextEmbed);
return new SetMethod(methodHandle, property);
}
private PropertyMap getNewMap(Property property) {
return getMap().addProperty(property);
}

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
protected Class<?> findClass(final String name) throws ClassNotFoundException {
if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length();
return generateClass(name, name.substring(start, name.length()));
return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
}
return super.findClass(name);
}

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@ -65,7 +65,7 @@ final class RegExpScanner extends Scanner {
/** Are we currently inside a negated character class? */
private boolean inNegativeClass = false;
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?";
private static final String NON_IDENT_ESCAPES = "$^*+(){}[]|\\.?-";
private static class Capture {
/**
@ -934,7 +934,7 @@ final class RegExpScanner extends Scanner {
return true;
}
private void unicode(final int value, final StringBuilder buffer) {
private static void unicode(final int value, final StringBuilder buffer) {
final String hex = Integer.toHexString(value);
buffer.append('u');
for (int i = 0; i < 4 - hex.length(); i++) {
@ -944,7 +944,7 @@ final class RegExpScanner extends Scanner {
}
// Convert what would have been a backreference into a unicode escape, or a number literal, or both.
private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) {
final int length = numberLiteral.length();
int octalValue = 0;
int pos = 0;

View File

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

View File

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

View File

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

View File

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

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