8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
cd9c2c1bb2
commit
6f6ec2d9d1
@ -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 $*
|
||||
|
@ -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
@ -568,8 +568,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());
|
||||
}
|
||||
@ -937,11 +936,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 +1000,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 +1071,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
|
||||
@ -2364,7 +2354,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 +2362,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
|
||||
method.pop();
|
||||
discard.pop();
|
||||
}
|
||||
// System.err.println("**** Leave discard " + unaryNode);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,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 +58,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 +171,26 @@ 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());
|
||||
return (FunctionNode)enterAttr(fn).accept(new Attr());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
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 Attr.ensureSymbol(lc, lc.getCurrentBlock(), 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 +212,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 +222,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;
|
||||
}
|
||||
|
||||
|
@ -77,6 +77,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,12 +89,10 @@ 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;
|
||||
|
||||
/** logger for compiler, trampolines, splits and related code generation events
|
||||
@ -167,6 +167,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 +242,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 +265,43 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 +310,7 @@ public final class Compiler {
|
||||
long time = 0L;
|
||||
|
||||
for (final CompilationPhase phase : sequence) {
|
||||
this.functionNode = phase.apply(this, functionNode);
|
||||
newFunctionNode = phase.apply(this, newFunctionNode);
|
||||
|
||||
final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
|
||||
time += duration;
|
||||
@ -293,7 +320,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 +336,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,16 +348,15 @@ public final class Compiler {
|
||||
LOG.info(sb);
|
||||
}
|
||||
|
||||
return functionNode;
|
||||
return newFunctionNode;
|
||||
}
|
||||
|
||||
private Class<?> install(final String className, final byte[] code) {
|
||||
private Class<?> install(final FunctionNode functionNode, final String className, final byte[] code) {
|
||||
LOG.fine("Installing class ", className);
|
||||
|
||||
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 +381,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";
|
||||
@ -366,7 +393,7 @@ public final class Compiler {
|
||||
|
||||
final String rootClassName = firstCompileUnitName();
|
||||
final byte[] rootByteCode = bytecode.get(rootClassName);
|
||||
final Class<?> rootClass = install(rootClassName, rootByteCode);
|
||||
final Class<?> rootClass = install(functionNode, rootClassName, rootByteCode);
|
||||
|
||||
int length = rootByteCode.length;
|
||||
|
||||
@ -380,7 +407,7 @@ public final class Compiler {
|
||||
final byte[] code = entry.getValue();
|
||||
length += code.length;
|
||||
|
||||
installedClasses.put(className, install(className, code));
|
||||
installedClasses.put(className, install(functionNode, className, code));
|
||||
}
|
||||
|
||||
for (final CompileUnit unit : compileUnits) {
|
||||
@ -430,10 +457,6 @@ public final class Compiler {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
FunctionNode getFunctionNode() {
|
||||
return functionNode;
|
||||
}
|
||||
|
||||
ConstantData getConstantData() {
|
||||
return constantData;
|
||||
}
|
||||
@ -442,10 +465,6 @@ public final class Compiler {
|
||||
return installer;
|
||||
}
|
||||
|
||||
Source getSource() {
|
||||
return functionNode.getSource();
|
||||
}
|
||||
|
||||
void addClass(final String name, final byte[] code) {
|
||||
bytecode.put(name, code);
|
||||
}
|
||||
@ -496,7 +515,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();
|
||||
|
@ -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;
|
||||
@ -354,13 +353,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();
|
||||
@ -551,8 +543,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;
|
||||
}
|
||||
@ -812,14 +803,12 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
|
||||
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 Attr.ensureSymbol(lc, lc.getCurrentBlock(), to, resultNode);
|
||||
}
|
||||
|
||||
private static Node discard(final Node node) {
|
||||
@ -905,7 +894,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
|
||||
|
||||
if (literalNode != null) {
|
||||
//inherit literal symbol for attr.
|
||||
literalNode.setSymbol(parent.getSymbol());
|
||||
literalNode = (LiteralNode<?>)literalNode.setSymbol(null, parent.getSymbol());
|
||||
}
|
||||
|
||||
return literalNode;
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.codegen;
|
||||
|
||||
import java.util.List;
|
||||
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
|
||||
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING;
|
||||
import jdk.nashorn.internal.ir.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
|
@ -75,7 +75,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 +95,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);
|
||||
@ -273,7 +273,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;
|
||||
|
@ -30,7 +30,6 @@ 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;
|
||||
@ -104,18 +103,26 @@ public class Block extends BreakableNode implements Flags<Block> {
|
||||
this(source, token, finish, statements.toArray(new Node[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<Node> 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));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,15 +144,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);
|
||||
@ -241,17 +248,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 +275,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 +303,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 +313,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;
|
||||
}
|
||||
|
@ -138,7 +138,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;
|
||||
}
|
||||
|
@ -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;
|
||||
@ -95,6 +91,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
@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 +127,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 +179,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;
|
||||
|
||||
@ -219,37 +225,52 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
final int flags) {
|
||||
super(source, 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.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.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 +281,36 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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 +358,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 +391,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 +432,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 +541,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 +609,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 +657,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 +736,10 @@ public final class FunctionNode extends LexicalContextNode implements Flags<Func
|
||||
returnType),
|
||||
compileUnit,
|
||||
compilationState,
|
||||
body));
|
||||
body,
|
||||
parameters,
|
||||
snapshot,
|
||||
hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -705,7 +770,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 +782,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)
|
||||
|
@ -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
|
||||
|
@ -70,4 +70,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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -659,9 +659,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 +753,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 +815,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 +852,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('[');
|
||||
|
@ -252,10 +252,17 @@ public abstract class Node extends Location {
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +281,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;
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ 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;
|
||||
|
||||
/** Null or name identifying symbol. */
|
||||
private final String name;
|
||||
@ -383,6 +385,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
|
||||
|
@ -794,15 +794,15 @@ public final class NativeRegExp extends ScriptObject {
|
||||
|
||||
RegExpResult match;
|
||||
final int inputLength = string.length();
|
||||
int lastLength = -1;
|
||||
int lastIndex = 0;
|
||||
int lastLastIndex = 0;
|
||||
int splitLastLength = -1;
|
||||
int splitLastIndex = 0;
|
||||
int splitLastLastIndex = 0;
|
||||
|
||||
while ((match = execSplit(string, lastIndex)) != null) {
|
||||
lastIndex = match.getIndex() + match.length();
|
||||
while ((match = execSplit(string, splitLastIndex)) != null) {
|
||||
splitLastIndex = match.getIndex() + match.length();
|
||||
|
||||
if (lastIndex > lastLastIndex) {
|
||||
matches.add(string.substring(lastLastIndex, match.getIndex()));
|
||||
if (splitLastIndex > splitLastLastIndex) {
|
||||
matches.add(string.substring(splitLastLastIndex, match.getIndex()));
|
||||
final Object[] groups = match.getGroups();
|
||||
if (groups.length > 1 && match.getIndex() < inputLength) {
|
||||
for (int index = 1; index < groups.length && matches.size() < limit; index++) {
|
||||
@ -810,7 +810,7 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
lastLength = match.length();
|
||||
splitLastLength = match.length();
|
||||
|
||||
if (matches.size() >= limit) {
|
||||
break;
|
||||
@ -818,10 +818,10 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
|
||||
// bump the index to avoid infinite loop
|
||||
if (lastIndex == lastLastIndex) {
|
||||
lastIndex++;
|
||||
if (splitLastIndex == splitLastLastIndex) {
|
||||
splitLastIndex++;
|
||||
} else {
|
||||
lastLastIndex = lastIndex;
|
||||
splitLastLastIndex = splitLastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,12 +829,12 @@ public final class NativeRegExp extends ScriptObject {
|
||||
// check special case if we need to append an empty string at the
|
||||
// end of the match
|
||||
// if the lastIndex was the entire string
|
||||
if (lastLastIndex == string.length()) {
|
||||
if (lastLength > 0 || execSplit("", 0) == null) {
|
||||
if (splitLastLastIndex == string.length()) {
|
||||
if (splitLastLength > 0 || execSplit("", 0) == null) {
|
||||
matches.add("");
|
||||
}
|
||||
} else {
|
||||
matches.add(string.substring(lastLastIndex, inputLength));
|
||||
matches.add(string.substring(splitLastLastIndex, inputLength));
|
||||
}
|
||||
}
|
||||
|
||||
@ -899,10 +899,6 @@ public final class NativeRegExp extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
private void setGlobal(final boolean global) {
|
||||
regexp.setGlobal(global);
|
||||
}
|
||||
|
||||
boolean getGlobal() {
|
||||
return regexp.isGlobal();
|
||||
}
|
||||
|
@ -249,6 +249,7 @@ public abstract class AbstractParser {
|
||||
*
|
||||
* @param errorType The error type of the warning
|
||||
* @param message Warning message.
|
||||
* @param errorToken error token
|
||||
*/
|
||||
protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
|
||||
errors.warning(error(errorType, message, errorToken));
|
||||
|
@ -305,6 +305,11 @@ 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 =
|
||||
@ -320,11 +325,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 +337,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.
|
||||
@ -529,6 +539,7 @@ loop:
|
||||
|
||||
script = restoreFunctionNode(script, token); //commit code
|
||||
script = script.setBody(lc, script.getBody().setNeedsScope(lc));
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -800,7 +811,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()) {
|
||||
|
@ -88,7 +88,7 @@ final class CompiledFunction implements Comparable<CompiledFunction> {
|
||||
|
||||
int weight = Type.typeFor(type.returnType()).getWeight();
|
||||
for (final Class<?> paramType : type.parameterArray()) {
|
||||
final int pweight = Type.typeFor(paramType).getWeight();
|
||||
final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized
|
||||
weight += pweight;
|
||||
}
|
||||
return weight;
|
||||
|
@ -69,5 +69,4 @@ final class CompiledFunctions extends TreeSet<CompiledFunction> {
|
||||
return best(type).moreGenericThan(type);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -411,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
|
||||
@ -759,10 +759,10 @@ public final class Context {
|
||||
final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
|
||||
final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
|
||||
|
||||
final Compiler compiler = new Compiler(installer, functionNode, strict);
|
||||
final Compiler compiler = new Compiler(installer, strict);
|
||||
|
||||
compiler.compile();
|
||||
script = compiler.install();
|
||||
final FunctionNode newFunctionNode = compiler.compile(functionNode);
|
||||
script = compiler.install(newFunctionNode);
|
||||
|
||||
if (global != null) {
|
||||
global.cacheClass(source, script);
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import static jdk.nashorn.internal.runtime.ScriptObject.isArray;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -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,114 @@ 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();
|
||||
int i;
|
||||
|
||||
//classes known at runtime
|
||||
final LinkedList<Type> runtimeArgs = new LinkedList<>();
|
||||
for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) {
|
||||
runtimeArgs.addLast(runtimeType(args[i]));
|
||||
}
|
||||
|
||||
//classes known at compile time
|
||||
final LinkedList<Type> compileTimeArgs = new LinkedList<>();
|
||||
for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) {
|
||||
compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i)));
|
||||
}
|
||||
|
||||
//the classes known at compile time are a safe to generate as primitives without parameter guards
|
||||
//the classes known at runtime are safe to generate as primitives IFF there are parameter guards
|
||||
MethodHandle guard = null;
|
||||
for (i = 0; i < compileTimeArgs.size(); i++) {
|
||||
final Type runtimeType = runtimeArgs.get(i);
|
||||
final Type compileType = compileTimeArgs.get(i);
|
||||
|
||||
if (compileType.isObject() && !runtimeType.isObject()) {
|
||||
if (guard == null) {
|
||||
guard = PARAM_TYPE_GUARD;
|
||||
guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs);
|
||||
|
||||
assert snapshot != null;
|
||||
assert snapshot != functionNode;
|
||||
|
||||
final Compiler compiler = new Compiler(installer);
|
||||
final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()]))));
|
||||
|
||||
compiler.install(compiledSnapshot);
|
||||
|
||||
final MethodHandle nmh = addCode(compiledSnapshot, guard, mh);
|
||||
|
||||
return nmh;
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
|
||||
return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,9 +26,13 @@
|
||||
package jdk.nashorn.internal.runtime;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import jdk.nashorn.internal.codegen.Namespace;
|
||||
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
|
||||
import jdk.nashorn.internal.runtime.options.KeyValueOption;
|
||||
@ -151,6 +155,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;
|
||||
|
||||
@ -213,6 +220,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 +264,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
|
||||
|
@ -662,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,16 +107,16 @@ public class DefaultRegExp extends RegExp {
|
||||
|
||||
class DefaultMatcher implements RegExpMatcher {
|
||||
final String input;
|
||||
final Matcher matcher;
|
||||
final Matcher defaultMatcher;
|
||||
|
||||
DefaultMatcher(final String input) {
|
||||
this.input = input;
|
||||
this.matcher = pattern.matcher(input);
|
||||
this.defaultMatcher = pattern.matcher(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean search(final int start) {
|
||||
return matcher.find(start);
|
||||
return defaultMatcher.find(start);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,37 +126,37 @@ public class DefaultRegExp extends RegExp {
|
||||
|
||||
@Override
|
||||
public int start() {
|
||||
return matcher.start();
|
||||
return defaultMatcher.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(final int group) {
|
||||
return matcher.start(group);
|
||||
return defaultMatcher.start(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end() {
|
||||
return matcher.end();
|
||||
return defaultMatcher.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end(final int group) {
|
||||
return matcher.end(group);
|
||||
return defaultMatcher.end(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group() {
|
||||
return matcher.group();
|
||||
return defaultMatcher.group();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group(final int group) {
|
||||
return matcher.group(group);
|
||||
return defaultMatcher.group(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int groupCount() {
|
||||
return matcher.groupCount();
|
||||
return defaultMatcher.groupCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,16 +121,16 @@ public class JoniRegExp extends RegExp {
|
||||
|
||||
class JoniMatcher implements RegExpMatcher {
|
||||
final String input;
|
||||
final Matcher matcher;
|
||||
final Matcher joniMatcher;
|
||||
|
||||
JoniMatcher(final String input) {
|
||||
this.input = input;
|
||||
this.matcher = regex.matcher(input.toCharArray());
|
||||
this.joniMatcher = regex.matcher(input.toCharArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean search(final int start) {
|
||||
return matcher.search(start, input.length(), Option.NONE) > -1;
|
||||
return joniMatcher.search(start, input.length(), Option.NONE) > -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -140,27 +140,27 @@ public class JoniRegExp extends RegExp {
|
||||
|
||||
@Override
|
||||
public int start() {
|
||||
return matcher.getBegin();
|
||||
return joniMatcher.getBegin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int start(final int group) {
|
||||
return group == 0 ? start() : matcher.getRegion().beg[group];
|
||||
return group == 0 ? start() : joniMatcher.getRegion().beg[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end() {
|
||||
return matcher.getEnd();
|
||||
return joniMatcher.getEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int end(final int group) {
|
||||
return group == 0 ? end() : matcher.getRegion().end[group];
|
||||
return group == 0 ? end() : joniMatcher.getRegion().end[group];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String group() {
|
||||
return input.substring(matcher.getBegin(), matcher.getEnd());
|
||||
return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,13 +168,13 @@ public class JoniRegExp extends RegExp {
|
||||
if (group == 0) {
|
||||
return group();
|
||||
}
|
||||
final Region region = matcher.getRegion();
|
||||
final Region region = joniMatcher.getRegion();
|
||||
return input.substring(region.beg[group], region.end[group]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int groupCount() {
|
||||
final Region region = matcher.getRegion();
|
||||
final Region region = joniMatcher.getRegion();
|
||||
return region == null ? 0 : region.numRegs - 1;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -288,12 +288,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 +312,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", \
|
||||
|
@ -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();
|
||||
|
38
nashorn/test/script/basic/paramspec.js
Normal file
38
nashorn/test/script/basic/paramspec.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* paramspec - test that Attr doesn't break parameters when specializing
|
||||
*
|
||||
* @run
|
||||
* @test
|
||||
*/
|
||||
|
||||
function f(a) {
|
||||
var b = ~a;
|
||||
return b == ~17;
|
||||
}
|
||||
|
||||
print(f("17"));
|
||||
print(f(17));
|
||||
|
2
nashorn/test/script/basic/paramspec.js.EXPECTED
Normal file
2
nashorn/test/script/basic/paramspec.js.EXPECTED
Normal file
@ -0,0 +1,2 @@
|
||||
true
|
||||
true
|
@ -86,7 +86,7 @@ function runsuite(tests) {
|
||||
changed = true;
|
||||
}
|
||||
} catch (e) {
|
||||
print("error: " + e);
|
||||
print("error: " + e.printStackTrace());
|
||||
if (e.toString().indexOf(tests) == 1) {
|
||||
throw e;
|
||||
}
|
||||
|
@ -90,16 +90,17 @@ var methodsCalled = [
|
||||
|
||||
function check(str, strs) {
|
||||
for each (s in strs) {
|
||||
if (s.indexOf(str) !== -1) {
|
||||
if (str.indexOf(s) !== -1) {
|
||||
continue;
|
||||
}
|
||||
print(method + "not found");
|
||||
print(s + " not found");
|
||||
return;
|
||||
}
|
||||
print("check ok!");
|
||||
}
|
||||
|
||||
str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
|
||||
str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js");
|
||||
|
||||
check(str, methodsCalled);
|
||||
check(str, ['return', 'get', 'set', '[fields]']);
|
Loading…
Reference in New Issue
Block a user