--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java Wed Sep 10 19:37:52 2014 -0700
@@ -194,12 +194,12 @@
*/
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
// This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers.
- //
body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
- public boolean enterFunctionNode(final FunctionNode nestedFn) {
- // Don't descend into nested functions
- return false;
+ protected boolean enterDefault(final Node node) {
+ // Don't bother visiting expressions; var is a statement, it can't be inside an expression.
+ // This will also prevent visiting nested functions (as FunctionNode is an expression).
+ return !(node instanceof Expression);
}
@Override
@@ -443,12 +443,27 @@
if (lc.isFunctionBody()) {
block.clearSymbols();
+ final FunctionNode fn = lc.getCurrentFunction();
+ if (isUnparsedFunction(fn)) {
+ // It's a skipped nested function. Just mark the symbols being used by it as being in use.
+ for(final String name: compiler.getScriptFunctionData(fn.getId()).getExternalSymbolNames()) {
+ nameIsUsed(name, null);
+ }
+ // Don't bother descending into it, it must be empty anyway.
+ assert block.getStatements().isEmpty();
+ return false;
+ }
+
enterFunctionBody();
}
return true;
}
+ private boolean isUnparsedFunction(final FunctionNode fn) {
+ return compiler.isOnDemandCompilation() && fn != lc.getOutermostFunction();
+ }
+
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
@@ -492,18 +507,13 @@
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
- // TODO: once we have information on symbols used by nested functions, we can stop descending into nested
- // functions with on-demand compilation, e.g. add
- // if(!thisProperties.isEmpty() && env.isOnDemandCompilation()) {
- // return false;
- // }
start(functionNode, false);
thisProperties.push(new HashSet<String>());
- //an outermost function in our lexical context that is not a program
- //is possible - it is a function being compiled lazily
if (functionNode.isDeclared()) {
+ // Can't use lc.getCurrentBlock() as we can have an outermost function in our lexical context that
+ // is not a program - it is a function being compiled on-demand.
final Iterator<Block> blocks = lc.getBlocks();
if (blocks.hasNext()) {
final IdentNode ident = functionNode.getIdent();
@@ -511,6 +521,11 @@
}
}
+ // Every function has a body, even the ones skipped on reparse (they have an empty one). We're
+ // asserting this as even for those, enterBlock() must be invoked to correctly process symbols that
+ // are used in them.
+ assert functionNode.getBody() != null;
+
return true;
}
@@ -533,7 +548,7 @@
/**
* This has to run before fix assignment types, store any type specializations for
- * paramters, then turn then to objects for the generic version of this method
+ * parameters, then turn them into objects for the generic version of this method.
*
* @param functionNode functionNode
*/
@@ -733,14 +748,20 @@
@Override
public Node leaveBlock(final Block block) {
- // It's not necessary to guard the marking of symbols as locals with this "if"condition for correctness, it's
- // just an optimization -- runtime type calculation is not used when the compilation is not an on-demand
- // optimistic compilation, so we can skip locals marking then.
+ // It's not necessary to guard the marking of symbols as locals with this "if" condition for
+ // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
+ // is not an on-demand optimistic compilation, so we can skip locals marking then.
if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
- for (final Symbol symbol: block.getSymbols()) {
- if (!symbol.isScope()) {
- assert symbol.isVar() || symbol.isParam();
- compiler.declareLocalSymbol(symbol.getName());
+ // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
+ // compilation, and we're skipping parsing the function bodies for nested functions, this
+ // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
+ // symbol in the outer function named the same as one of the parameters, though.
+ if (lc.getFunction(block) == lc.getOutermostFunction()) {
+ for (final Symbol symbol: block.getSymbols()) {
+ if (!symbol.isScope()) {
+ assert symbol.isVar() || symbol.isParam();
+ compiler.declareLocalSymbol(symbol.getName());
+ }
}
}
}
@@ -811,24 +832,45 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
-
- return markProgramBlock(
+ final FunctionNode finalizedFunction;
+ if (isUnparsedFunction(functionNode)) {
+ finalizedFunction = functionNode;
+ } else {
+ finalizedFunction =
+ markProgramBlock(
removeUnusedSlots(
createSyntheticInitializers(
finalizeParameters(
lc.applyTopFlags(functionNode))))
- .setThisProperties(lc, thisProperties.pop().size())
- .setState(lc, CompilationState.SYMBOLS_ASSIGNED));
+ .setThisProperties(lc, thisProperties.pop().size()));
+ }
+ return finalizedFunction.setState(lc, CompilationState.SYMBOLS_ASSIGNED);
}
@Override
public Node leaveIdentNode(final IdentNode identNode) {
- final String name = identNode.getName();
-
if (identNode.isPropertyName()) {
return identNode;
}
+ final Symbol symbol = nameIsUsed(identNode.getName(), identNode);
+
+ if (!identNode.isInitializedHere()) {
+ symbol.increaseUseCount();
+ }
+
+ IdentNode newIdentNode = identNode.setSymbol(symbol);
+
+ // If a block-scoped var is used before its declaration mark it as dead.
+ // We can only statically detect this for local vars, cross-function symbols require runtime checks.
+ if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
+ newIdentNode = newIdentNode.markDead();
+ }
+
+ return end(newIdentNode);
+ }
+
+ private Symbol nameIsUsed(final String name, final IdentNode origin) {
final Block block = lc.getCurrentBlock();
Symbol symbol = findSymbol(block, name);
@@ -847,24 +889,11 @@
maybeForceScope(symbol);
} else {
log.info("No symbol exists. Declare as global: ", name);
- symbol = defineSymbol(block, name, identNode, IS_GLOBAL | IS_SCOPE);
+ symbol = defineSymbol(block, name, origin, IS_GLOBAL | IS_SCOPE);
}
functionUsesSymbol(symbol);
-
- if (!identNode.isInitializedHere()) {
- symbol.increaseUseCount();
- }
-
- IdentNode newIdentNode = identNode.setSymbol(symbol);
-
- // If a block-scoped var is used before its declaration mark it as dead.
- // We can only statically detect this for local vars, cross-function symbols require runtime checks.
- if (symbol.isBlockScoped() && !symbol.hasBeenDeclared() && !identNode.isDeclaredHere() && isLocal(lc.getCurrentFunction(), symbol)) {
- newIdentNode = newIdentNode.markDead();
- }
-
- return end(newIdentNode);
+ return symbol;
}
@Override
@@ -912,7 +941,6 @@
return functionNode;
}
- assert functionNode.getId() == 1;
return functionNode.setBody(lc, functionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java Wed Sep 10 19:37:52 2014 -0700
@@ -59,6 +59,7 @@
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
+
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
@@ -135,6 +136,16 @@
/** Set of constants access methods required. */
private Set<Class<?>> constantMethodNeeded;
+ private int methodCount;
+
+ private int initCount;
+
+ private int clinitCount;
+
+ private int fieldCount;
+
+ private final Set<String> methodNames;
+
/**
* Constructor - only used internally in this class as it breaks
* abstraction towards ASM or other code generator below
@@ -146,6 +157,11 @@
this.context = context;
this.cw = cw;
this.methodsStarted = new HashSet<>();
+ this.methodNames = new HashSet<>();
+ }
+
+ public Set<String> getMethodNames() {
+ return methodNames;
}
/**
@@ -209,6 +225,38 @@
}
/**
+ * Get the method count, including init and clinit methods
+ * @return method count
+ */
+ public int getMethodCount() {
+ return methodCount;
+ }
+
+ /**
+ * Get the clinit count
+ * @return clinit count
+ */
+ public int getClinitCount() {
+ return clinitCount;
+ }
+
+ /**
+ * Get the init count
+ * @return init count
+ */
+ public int getInitCount() {
+ return initCount;
+ }
+
+ /**
+ * Get the field count
+ * @return field count
+ */
+ public int getFieldCount() {
+ return fieldCount;
+ }
+
+ /**
* Convert a binary name to a package/class name.
*
* @param name Binary name.
@@ -359,9 +407,16 @@
*/
@Override
public void end() {
- assert classStarted;
+ assert classStarted : "class not started for " + unitClassName;
if (unitClassName != null) {
+ final MethodEmitter initMethod = init(EnumSet.of(Flag.PRIVATE));
+ initMethod.begin();
+ initMethod.load(Type.OBJECT, 0);
+ initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
+ initMethod.returnVoid();
+ initMethod.end();
+
defineCommonUtilities();
}
@@ -419,6 +474,8 @@
}
SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
+ methodCount++;
+ methodNames.add(methodName);
return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
}
@@ -446,6 +503,8 @@
* @return method emitter to use for weaving this method
*/
MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
+ methodCount++;
+ methodNames.add(methodName);
return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes));
}
@@ -471,6 +530,8 @@
* @return method emitter to use for weaving this method
*/
MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final String descriptor) {
+ methodCount++;
+ methodNames.add(methodName);
return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, descriptor, null, null));
}
@@ -481,6 +542,8 @@
* @return method emitter to use for weaving this method
*/
MethodEmitter method(final FunctionNode functionNode) {
+ methodCount++;
+ methodNames.add(functionNode.getName());
final FunctionSignature signature = new FunctionSignature(functionNode);
final MethodVisitor mv = cw.visitMethod(
ACC_PUBLIC | ACC_STATIC | (functionNode.isVarArg() ? ACC_VARARGS : 0),
@@ -499,6 +562,8 @@
* @return method emitter to use for weaving this method
*/
MethodEmitter restOfMethod(final FunctionNode functionNode) {
+ methodCount++;
+ methodNames.add(functionNode.getName());
final MethodVisitor mv = cw.visitMethod(
ACC_PUBLIC | ACC_STATIC,
functionNode.getName(),
@@ -516,6 +581,7 @@
* @return method emitter to use for weaving <clinit>
*/
MethodEmitter clinit() {
+ clinitCount++;
return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class);
}
@@ -525,6 +591,7 @@
* @return method emitter to use for weaving <init>()V
*/
MethodEmitter init() {
+ initCount++;
return method(INIT.symbolName(), void.class);
}
@@ -535,6 +602,7 @@
* @return method emitter to use for weaving <init>()V
*/
MethodEmitter init(final Class<?>... ptypes) {
+ initCount++;
return method(INIT.symbolName(), void.class, ptypes);
}
@@ -547,6 +615,7 @@
* @return method emitter to use for weaving <init>(...)V
*/
MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) {
+ initCount++;
return method(flags, INIT.symbolName(), void.class, ptypes);
}
@@ -561,6 +630,7 @@
* @see ClassEmitter.Flag
*/
final void field(final EnumSet<Flag> fieldFlags, final String fieldName, final Class<?> fieldType, final Object value) {
+ fieldCount++;
cw.visitField(Flag.getValue(fieldFlags), fieldName, typeDescriptor(fieldType), null, value).visitEnd();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Sep 10 19:37:52 2014 -0700
@@ -1622,9 +1622,18 @@
@Override
protected void evaluate() {
- method.load(ITERATOR_TYPE, iterSlot);
- // TODO: optimistic for-in iteration
- method.invoke(interfaceCallNoLookup(ITERATOR_CLASS, "next", Object.class));
+ new OptimisticOperation((Optimistic)forNode.getInit(), TypeBounds.UNBOUNDED) {
+ @Override
+ void loadStack() {
+ method.load(ITERATOR_TYPE, iterSlot);
+ }
+
+ @Override
+ void consumeStack() {
+ method.invoke(interfaceCallNoLookup(ITERATOR_CLASS, "next", Object.class));
+ convertOptimisticReturnValue();
+ }
+ }.emit();
}
}.store();
body.accept(this);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed Sep 10 19:37:52 2014 -0700
@@ -31,6 +31,7 @@
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
+
import jdk.nashorn.internal.IntDeque;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Block;
@@ -158,7 +159,9 @@
CompileUnit popCompileUnit(final CompileUnit oldUnit) {
assert compileUnits.peek() == oldUnit;
- compileUnits.pop();
+ final CompileUnit unit = compileUnits.pop();
+ assert unit.hasCode() : "compile unit popped without code";
+ unit.setUsed();
return compileUnits.isEmpty() ? null : compileUnits.peek();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java Wed Sep 10 19:37:52 2014 -0700
@@ -48,6 +48,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+
import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
import jdk.nashorn.internal.ir.FunctionNode;
@@ -300,6 +301,7 @@
}
},
+
/**
* Reuse compile units, if they are already present. We are using the same compiler
* to recompile stuff
@@ -334,6 +336,8 @@
if (phases.isRestOfCompilation()) {
sb.append("$restOf");
}
+ //it's ok to not copy the initCount, methodCount and clinitCount here, as codegen is what
+ //fills those out anyway. Thus no need for a copy constructor
final CompileUnit newUnit = compiler.createCompileUnit(sb.toString(), oldUnit.getWeight());
log.fine("Creating new compile unit ", oldUnit, " => ", newUnit);
map.put(oldUnit, newUnit);
@@ -430,8 +434,14 @@
FunctionNode newFunctionNode = fn;
+ //root class is special, as it is bootstrapped from createProgramFunction, thus it's skipped
+ //in CodeGeneration - the rest can be used as a working "is compile unit used" metric
+ fn.getCompileUnit().setUsed();
+
compiler.getLogger().fine("Starting bytecode generation for ", quote(fn.getName()), " - restOf=", phases.isRestOfCompilation());
+
final CodeGenerator codegen = new CodeGenerator(compiler, phases.isRestOfCompilation() ? compiler.getContinuationEntryPoints() : null);
+
try {
// Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
// in the lazy + optimistic world. See CodeGenerator.skipFunction().
@@ -455,12 +465,18 @@
final ClassEmitter classEmitter = compileUnit.getClassEmitter();
classEmitter.end();
+ if (!compileUnit.isUsed()) {
+ compiler.getLogger().fine("Skipping unused compile unit ", compileUnit);
+ continue;
+ }
+
final byte[] bytecode = classEmitter.toByteArray();
assert bytecode != null;
final String className = compileUnit.getUnitClassName();
+ compiler.addClass(className, bytecode); //classes are only added to the bytecode map if compile unit is used
- compiler.addClass(className, bytecode);
+ CompileUnit.increaseEmitCount();
// should we verify the generated code?
if (senv._verify_code) {
@@ -536,6 +552,9 @@
// initialize function in the compile units
for (final CompileUnit unit : compiler.getCompileUnits()) {
+ if (!unit.isUsed()) {
+ continue;
+ }
unit.setCode(installedClasses.get(unit.getUnitClassName()));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java Wed Sep 10 19:37:52 2014 -0700
@@ -42,6 +42,10 @@
private Class<?> clazz;
+ private boolean isUsed;
+
+ private static int emittedUnitCount;
+
CompileUnit(final String className, final ClassEmitter classEmitter, final long initialWeight) {
this.className = className;
this.weight = initialWeight;
@@ -52,6 +56,33 @@
return new TreeSet<>();
}
+ static void increaseEmitCount() {
+ emittedUnitCount++;
+ }
+
+ public static int getEmittedUnitCount() {
+ return emittedUnitCount;
+ }
+
+ /**
+ * Check if this compile unit is used
+ * @return true if tagged as in use - i.e active code that needs to be generated
+ */
+ public boolean isUsed() {
+ return isUsed;
+ }
+
+ public boolean hasCode() {
+ return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
+ }
+
+ /**
+ * Tag this compile unit as used
+ */
+ public void setUsed() {
+ this.isUsed = true;
+ }
+
/**
* Return the class that contains the code for this unit, null if not
* generated yet
@@ -121,7 +152,8 @@
@Override
public String toString() {
- return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']';
+ final String methods = classEmitter != null ? classEmitter.getMethodNames().toString() : "<anon>";
+ return "[CompileUnit className=" + shortName(className) + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + " hasCode=" + methods + ']';
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java Wed Sep 10 19:37:52 2014 -0700
@@ -38,7 +38,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -51,8 +50,8 @@
import java.util.function.Consumer;
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.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.Optimistic;
import jdk.nashorn.internal.ir.debug.ClassHistogramElement;
@@ -65,6 +64,7 @@
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -248,6 +248,15 @@
return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
}
+ @SuppressWarnings("unused") //TODO I'll use this soon
+ private CompilationPhases replace(final CompilationPhase phase, final CompilationPhase newPhase) {
+ final LinkedList<CompilationPhase> list = new LinkedList<>();
+ for (final CompilationPhase p : phases) {
+ list.add(p == phase ? newPhase : p);
+ }
+ return new CompilationPhases(desc, list.toArray(new CompilationPhase[list.size()]));
+ }
+
private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
final LinkedList<CompilationPhase> list = new LinkedList<>();
for (final CompilationPhase p : phases) {
@@ -473,6 +482,19 @@
return typeEvaluator.getOptimisticType(node);
}
+ /**
+ * Returns true if the expression can be safely evaluated, and its value is an object known to always use
+ * String as the type of its property names retrieved through
+ * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its
+ * property name types.
+ * @param expr the expression to test
+ * @return true if the expression can be safely evaluated, and its value is an object known to always use
+ * String as the type of its property iterators.
+ */
+ boolean hasStringPropertyIterator(final Expression expr) {
+ return typeEvaluator.hasStringPropertyIterator(expr);
+ }
+
void addInvalidatedProgramPoint(final int programPoint, final Type type) {
invalidatedProgramPoints.put(programPoint, type);
}
@@ -675,16 +697,8 @@
CompileUnit createCompileUnit(final String unitClassName, final long initialWeight) {
final ClassEmitter classEmitter = new ClassEmitter(context, sourceName, unitClassName, isStrict());
final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
-
classEmitter.begin();
- final MethodEmitter initMethod = classEmitter.init(EnumSet.of(Flag.PRIVATE));
- initMethod.begin();
- initMethod.load(Type.OBJECT, 0);
- initMethod.newInstance(jdk.nashorn.internal.scripts.JS.class);
- initMethod.returnVoid();
- initMethod.end();
-
return compileUnit;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Sep 10 19:37:52 2014 -0700
@@ -551,13 +551,19 @@
final Expression init = forNode.getInit();
if(forNode.isForIn()) {
- forNode.getModify().accept(this);
- enterTestFirstLoop(forNode, null, init);
+ final JoinPredecessorExpression iterable = forNode.getModify();
+ iterable.accept(this);
+ enterTestFirstLoop(forNode, null, init,
+ // If we're iterating over property names, and we can discern from the runtime environment
+ // of the compilation that the object being iterated over must use strings for property
+ // names (e.g., it is a native JS object or array), then we'll not bother trying to treat
+ // the property names optimistically.
+ !forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression()));
} else {
if(init != null) {
init.accept(this);
}
- enterTestFirstLoop(forNode, forNode.getModify(), null);
+ enterTestFirstLoop(forNode, forNode.getModify(), null, false);
}
return false;
}
@@ -792,7 +798,8 @@
return false;
}
- private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify, final Expression iteratorValues) {
+ private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
+ final Expression iteratorValues, final boolean iteratorValuesAreObject) {
final JoinPredecessorExpression test = loopNode.getTest();
if(isAlwaysFalse(test)) {
test.accept(this);
@@ -814,8 +821,12 @@
jumpToLabel(test, breakLabel);
}
if(iteratorValues instanceof IdentNode) {
- // Receives iterator values; they're currently all objects (JDK-8034954).
- onAssignment((IdentNode)iteratorValues, LvarType.OBJECT);
+ final IdentNode ident = (IdentNode)iteratorValues;
+ // Receives iterator values; the optimistic type of the iterator values is tracked on the
+ // identifier, but we override optimism if it's known that the object being iterated over will
+ // never have primitive property names.
+ onAssignment(ident, iteratorValuesAreObject ? LvarType.OBJECT :
+ toLvarType(compiler.getOptimisticType(ident)));
}
final Block body = loopNode.getBody();
body.accept(this);
@@ -955,7 +966,7 @@
if(whileNode.isDoWhile()) {
enterDoWhileLoop(whileNode);
} else {
- enterTestFirstLoop(whileNode, null, null);
+ enterTestFirstLoop(whileNode, null, null, false);
}
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java Wed Sep 10 19:37:52 2014 -0700
@@ -71,7 +71,6 @@
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
-import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Source;
@@ -93,9 +92,6 @@
private final DebugLogger log;
- // needed only to get unique eval id
- private final CodeInstaller<?> installer;
-
/**
* Constructor.
*/
@@ -143,7 +139,6 @@
}
});
- this.installer = compiler.getCodeInstaller();
this.log = initLogger(compiler.getContext());
}
@@ -566,16 +561,13 @@
private String evalLocation(final IdentNode node) {
final Source source = lc.getCurrentFunction().getSource();
final int pos = node.position();
- // Code installer is null when running with --compile-only, use 0 as id in that case
- final long id = installer == null ? 0 : installer.getUniqueEvalId();
return new StringBuilder().
append(source.getName()).
append('#').
append(source.getLine(pos)).
append(':').
append(source.getColumn(pos)).
- append("<eval>@").
- append(id).
+ append("<eval>").
toString();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Sep 10 19:37:52 2014 -0700
@@ -53,6 +53,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.AccessorProperty;
@@ -308,7 +309,7 @@
newEmptyInit(className, classEmitter);
newAllocate(className, classEmitter);
- return toByteArray(classEmitter);
+ return toByteArray(className, classEmitter);
}
/**
@@ -341,7 +342,7 @@
initWithArguments.returnVoid();
initWithArguments.end();
- return toByteArray(classEmitter);
+ return toByteArray(className, classEmitter);
}
/**
@@ -484,15 +485,13 @@
* @param classEmitter Open class emitter.
* @return Byte codes for the class.
*/
- private byte[] toByteArray(final ClassEmitter classEmitter) {
+ private byte[] toByteArray(final String className, final ClassEmitter classEmitter) {
classEmitter.end();
final byte[] code = classEmitter.toByteArray();
final ScriptEnvironment env = context.getEnv();
- if (env._print_code && env._print_code_dir == null) {
- env.getErr().println(ClassEmitter.disassemble(code));
- }
+ DumpBytecode.dumpBytecode(env, log, code, className);
if (env._verify_code) {
context.verify(code);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeEvaluator.java Wed Sep 10 19:37:52 2014 -0700
@@ -55,6 +55,19 @@
this.runtimeScope = runtimeScope;
}
+ /**
+ * Returns true if the expression can be safely evaluated, and its value is an object known to always use
+ * String as the type of its property names retrieved through
+ * {@link ScriptRuntime#toPropertyIterator(Object)}. It is used to avoid optimistic assumptions about its
+ * property name types.
+ * @param expr the expression to test
+ * @return true if the expression can be safely evaluated, and its value is an object known to always use
+ * String as the type of its property iterators.
+ */
+ boolean hasStringPropertyIterator(final Expression expr) {
+ return evaluateSafely(expr) instanceof ScriptObject;
+ }
+
Type getOptimisticType(final Optimistic node) {
assert compiler.useOptimisticTypes();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java Wed Sep 10 19:37:52 2014 -0700
@@ -277,6 +277,14 @@
}
/**
+ * Returns the number of statements in the block.
+ * @return the number of statements in the block.
+ */
+ public int getStatementCount() {
+ return statements.size();
+ }
+
+ /**
* Returns the line number of the first statement in the block.
* @return the line number of the first statement in the block, or -1 if the block has no statements.
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CompileUnitHolder.java Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import jdk.nashorn.internal.codegen.CompileUnit;
+
+/**
+ * Marker interface for things in the IR that can hold compile units.
+ * {@link CompileUnit}
+ */
+public interface CompileUnitHolder {
+ /**
+ * Return the compile unit held by this instance
+ * @return compile unit
+ */
+ public CompileUnit getCompileUnit();
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Wed Sep 10 19:37:52 2014 -0700
@@ -34,10 +34,8 @@
import java.util.Collections;
import java.util.EnumSet;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Set;
import java.util.function.Function;
import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.CompileUnit;
@@ -48,6 +46,7 @@
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.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
@@ -57,7 +56,7 @@
* IR representation for function (or script.)
*/
@Immutable
-public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode> {
+public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode>, CompileUnitHolder {
/** Type used for all FunctionNodes */
public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
@@ -110,8 +109,11 @@
/** Source of entity. */
private final Source source;
- /** Unique ID used for recompilation among other things */
- private final int id;
+ /**
+ * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
+ * to skip parsing inner functions.
+ */
+ private final Object endParserState;
/** External function identifier. */
@Ignore
@@ -256,6 +258,14 @@
/** trace callsite values in this function? */
public static final int IS_TRACE_VALUES = 1 << 26;
+ /**
+ * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
+ * parameter on invocation. Note that we aren't, in fact using this flag in function nodes.
+ * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
+ * will, however, cache the value of this flag.
+ */
+ public static final int NEEDS_CALLEE = 1 << 27;
+
/** extension callsite flags mask */
public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
@@ -271,16 +281,9 @@
/** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
- /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval.
- * We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
+ /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval. */
private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
- /** Used to signify "null", e.g. if someone asks for the parent of the program node */
- public static final int NO_FUNCTION_ID = 0;
-
- /** Where to start assigning global and unique function node ids */
- public static final int FIRST_FUNCTION_ID = NO_FUNCTION_ID + 1;
-
/** What is the return type of this function? */
private Type returnType = Type.UNKNOWN;
@@ -288,11 +291,10 @@
* Constructor
*
* @param source the source
- * @param id unique id
* @param lineNumber line number
* @param token token
* @param finish finish
- * @param firstToken first token of the funtion node (including the function declaration)
+ * @param firstToken first token of the function node (including the function declaration)
* @param namespace the namespace
* @param ident the identifier
* @param name the name of the function
@@ -302,7 +304,6 @@
*/
public FunctionNode(
final Source source,
- final int id,
final int lineNumber,
final long token,
final int finish,
@@ -316,7 +317,6 @@
super(token, finish);
this.source = source;
- this.id = id;
this.lineNumber = lineNumber;
this.ident = ident;
this.name = name;
@@ -331,11 +331,13 @@
this.body = null;
this.thisProperties = 0;
this.rootClass = null;
+ this.endParserState = null;
}
private FunctionNode(
final FunctionNode functionNode,
final long lastToken,
+ Object endParserState,
final int flags,
final String name,
final Type returnType,
@@ -347,6 +349,7 @@
final Class<?> rootClass) {
super(functionNode);
+ this.endParserState = endParserState;
this.lineNumber = functionNode.lineNumber;
this.flags = flags;
this.name = name;
@@ -361,7 +364,6 @@
// the fields below never change - they are final and assigned in constructor
this.source = functionNode.source;
- this.id = functionNode.id;
this.ident = functionNode.ident;
this.namespace = functionNode.namespace;
this.kind = functionNode.kind;
@@ -429,11 +431,11 @@
}
/**
- * Get the unique ID for this function
+ * Get the unique ID for this function within the script file.
* @return the id
*/
public int getId() {
- return id;
+ return position();
}
/**
@@ -535,6 +537,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -606,6 +609,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -644,15 +648,24 @@
}
/**
- * Check if the {@code eval} keyword is used in this function
+ * Check if this function has a call expression for the identifier "eval" (that is, {@code eval(...)}).
*
- * @return true if {@code eval} is used
+ * @return true if {@code eval} is called.
*/
public boolean hasEval() {
return getFlag(HAS_EVAL);
}
/**
+ * Returns true if a function nested (directly or transitively) within this function {@link #hasEval()}.
+ *
+ * @return true if a nested function calls {@code eval}.
+ */
+ public boolean hasNestedEval() {
+ return getFlag(HAS_NESTED_EVAL);
+ }
+
+ /**
* Get the first token for this function
* @return the first token
*/
@@ -741,6 +754,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags |
(body.needsScope() ?
FunctionNode.HAS_SCOPE_BLOCK :
@@ -839,6 +853,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -899,6 +914,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -911,6 +927,41 @@
}
/**
+ * Returns the end parser state for this function.
+ * @return the end parser state for this function.
+ */
+ public Object getEndParserState() {
+ return endParserState;
+ }
+
+ /**
+ * Set the end parser state for this function.
+ * @param lc lexical context
+ * @param endParserState the parser state to set
+ * @return function node or a new one if state was changed
+ */
+ public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
+ if (this.endParserState == endParserState) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(
+ lc,
+ this,
+ new FunctionNode(
+ this,
+ lastToken,
+ endParserState,
+ flags,
+ name,
+ returnType,
+ compileUnit,
+ compilationState,
+ body,
+ parameters,
+ thisProperties, rootClass));
+ }
+
+ /**
* Get the name of this function
* @return the name
*/
@@ -934,6 +985,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -999,6 +1051,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -1077,6 +1130,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
type,
@@ -1102,6 +1156,7 @@
* @see Compiler
* @return the compile unit
*/
+ @Override
public CompileUnit getCompileUnit() {
return compileUnit;
}
@@ -1123,6 +1178,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
@@ -1178,6 +1234,7 @@
new FunctionNode(
this,
lastToken,
+ endParserState,
flags,
name,
returnType,
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LexicalContext.java Wed Sep 10 19:37:52 2014 -0700
@@ -351,8 +351,7 @@
}
/**
- * Get the function for this block. If the block is itself a function
- * this returns identity
+ * Get the function for this block.
* @param block block for which to get function
* @return function for block
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Wed Sep 10 19:37:52 2014 -0700
@@ -603,7 +603,7 @@
* An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
* be split if they are too large, for bytecode generation reasons
*/
- public static final class ArrayUnit {
+ public static final class ArrayUnit implements CompileUnitHolder {
/** Compile unit associated with the postsets range. */
private final CompileUnit compileUnit;
@@ -642,6 +642,7 @@
* The array compile unit
* @return array compile unit
*/
+ @Override
public CompileUnit getCompileUnit() {
return compileUnit;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitNode.java Wed Sep 10 19:37:52 2014 -0700
@@ -39,7 +39,7 @@
* Node indicating code is split across classes.
*/
@Immutable
-public class SplitNode extends LexicalContextStatement implements Labels {
+public class SplitNode extends LexicalContextStatement implements Labels, CompileUnitHolder {
/** Split node method name. */
private final String name;
@@ -116,6 +116,7 @@
* Get the compile unit for this split node
* @return compile unit
*/
+ @Override
public CompileUnit getCompileUnit() {
return compileUnit;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Sep 10 19:37:52 2014 -0700
@@ -631,6 +631,24 @@
}
/**
+ * Returns a method handle that creates a wrapper object for a JS primitive value.
+ *
+ * @param self receiver object
+ * @return method handle to create wrapper objects for primitive receiver
+ */
+ public static MethodHandle getPrimitiveWrapFilter(final Object self) {
+ if (self instanceof String || self instanceof ConsString) {
+ return NativeString.WRAPFILTER;
+ } else if (self instanceof Number) {
+ return NativeNumber.WRAPFILTER;
+ } else if (self instanceof Boolean) {
+ return NativeBoolean.WRAPFILTER;
+ }
+ throw new IllegalArgumentException("Unsupported primitive: " + self);
+ }
+
+
+ /**
* Create a new empty script object
*
* @return the new ScriptObject
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java Wed Sep 10 19:37:52 2014 -0700
@@ -51,9 +51,9 @@
public final class NativeBoolean extends ScriptObject {
private final boolean value;
- // Method handle to create an object wrapper for a primitive boolean
- private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
- // Method handle to retrieve the Boolean prototype object
+ /** Method handle to create an object wrapper for a primitive boolean. */
+ static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
+ /** Method handle to retrieve the Boolean prototype object. */
private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
// initialized by nasgen
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Wed Sep 10 19:37:52 2014 -0700
@@ -28,6 +28,7 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -697,7 +698,7 @@
if (methodHandle != null) {
return new GuardedInvocation(
methodHandle,
- testJSAdaptor(adaptee, findData.getGetter(Object.class, UnwarrantedOptimismException.INVALID_PROGRAM_POINT), findData.getOwner(), func),
+ testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Wed Sep 10 19:37:52 2014 -0700
@@ -57,9 +57,9 @@
@ScriptClass("Number")
public final class NativeNumber extends ScriptObject {
- // Method handle to create an object wrapper for a primitive number
- private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
- // Method handle to retrieve the Number prototype object
+ /** Method handle to create an object wrapper for a primitive number. */
+ static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
+ /** Method handle to retrieve the Number prototype object. */
private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
/** ECMA 15.7.3.2 largest positive finite value */
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Sep 10 19:37:52 2014 -0700
@@ -71,9 +71,9 @@
private final CharSequence value;
- // Method handle to create an object wrapper for a primitive string
- private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
- // Method handle to retrieve the String prototype object
+ /** Method handle to create an object wrapper for a primitive string */
+ static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
+ /** Method handle to retrieve the String prototype object */
private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
// initialized by nasgen
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/AbstractParser.java Wed Sep 10 19:37:52 2014 -0700
@@ -326,18 +326,28 @@
}
/**
- * Check next token and advance.
+ * Check current token and advance to the next token.
*
* @param expected Expected tokenType.
*
* @throws ParserException on unexpected token type
*/
protected final void expect(final TokenType expected) throws ParserException {
+ expectDontAdvance(expected);
+ next();
+ }
+
+ /**
+ * Check current token, but don't advance to the next token.
+ *
+ * @param expected Expected tokenType.
+ *
+ * @throws ParserException on unexpected token type
+ */
+ protected final void expectDontAdvance(final TokenType expected) throws ParserException {
if (type != expected) {
throw error(expectMessage(expected));
}
-
- next();
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java Wed Sep 10 19:37:52 2014 -0700
@@ -35,6 +35,7 @@
import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
import static jdk.nashorn.internal.parser.TokenType.EXECSTRING;
import static jdk.nashorn.internal.parser.TokenType.FLOATING;
+import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
import static jdk.nashorn.internal.parser.TokenType.HEXADECIMAL;
import static jdk.nashorn.internal.parser.TokenType.LBRACE;
import static jdk.nashorn.internal.parser.TokenType.LPAREN;
@@ -85,6 +86,9 @@
/** Type of last token added. */
private TokenType last;
+ private final boolean pauseOnFunctionBody;
+ private boolean pauseOnNextLeftBrace;
+
private static final String SPACETAB = " \t"; // ASCII space and tab
private static final String LFCR = "\n\r"; // line feed and carriage return (ctrl-m)
@@ -182,20 +186,23 @@
* @param scripting are we in scripting mode
*/
public Lexer(final Source source, final TokenStream stream, final boolean scripting) {
- this(source, 0, source.getLength(), stream, scripting);
+ this(source, 0, source.getLength(), stream, scripting, false);
}
/**
- * Contructor
+ * Constructor
*
* @param source the source
* @param start start position in source from which to start lexing
* @param len length of source segment to lex
* @param stream token stream to lex
* @param scripting are we in scripting mode
+ * @param pauseOnFunctionBody if true, lexer will return from {@link #lexify()} when it encounters a
+ * function body. This is used with the feature where the parser is skipping nested function bodies to
+ * avoid reading ahead unnecessarily when we skip the function bodies.
*/
- public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting) {
+ public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean pauseOnFunctionBody) {
super(source.getContent(), 1, start, len);
this.source = source;
this.stream = stream;
@@ -203,6 +210,8 @@
this.nested = false;
this.pendingLine = 1;
this.last = EOL;
+
+ this.pauseOnFunctionBody = pauseOnFunctionBody;
}
private Lexer(final Lexer lexer, final State state) {
@@ -216,6 +225,7 @@
pendingLine = state.pendingLine;
linePosition = state.linePosition;
last = EOL;
+ pauseOnFunctionBody = false;
}
static class State extends Scanner.State {
@@ -810,6 +820,9 @@
final int length = scanIdentifier();
// Check to see if it is a keyword.
final TokenType type = TokenLookup.lookupKeyword(content, start, length);
+ if (type == FUNCTION && pauseOnFunctionBody) {
+ pauseOnNextLeftBrace = true;
+ }
// Add keyword or identifier token.
add(type, start);
}
@@ -1597,6 +1610,9 @@
// We break to let the parser decide what it is.
if (canStartLiteral(type)) {
break;
+ } else if (type == LBRACE && pauseOnNextLeftBrace) {
+ pauseOnNextLeftBrace = false;
+ break;
}
} else if (Character.isJavaIdentifierStart(ch0) || ch0 == '\\' && ch1 == 'u') {
// Scan and add identifier or keyword.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java Wed Sep 10 19:37:52 2014 -0700
@@ -148,7 +148,7 @@
/** to receive line information from Lexer when scanning multine literals. */
protected final Lexer.LineInfoReceiver lineInfoReceiver;
- private int nextFunctionId;
+ private RecompilableScriptFunctionData reparsedFunction;
/**
* Constructor
@@ -171,7 +171,7 @@
* @param log debug logger if one is needed
*/
public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) {
- this(env, source, errors, strict, FunctionNode.FIRST_FUNCTION_ID, 0, log);
+ this(env, source, errors, strict, 0, log);
}
/**
@@ -181,15 +181,13 @@
* @param source source to parse
* @param errors error manager
* @param strict parser created with strict mode enabled.
- * @param nextFunctionId starting value for assigning new unique ids to function nodes
* @param lineOffset line offset to start counting lines from
* @param log debug logger if one is needed
*/
- public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int nextFunctionId, final int lineOffset, final DebugLogger log) {
+ public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
super(source, errors, strict, lineOffset);
this.env = env;
this.namespace = new Namespace(env.getNamespace());
- this.nextFunctionId = nextFunctionId;
this.scripting = env._scripting;
if (this.scripting) {
this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
@@ -228,6 +226,16 @@
}
/**
+ * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this
+ * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation).
+ * This will trigger various special behaviors, such as skipping nested function bodies.
+ * @param reparsedFunction the function being reparsed.
+ */
+ public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) {
+ this.reparsedFunction = reparsedFunction;
+ }
+
+ /**
* Execute parse and return the resulting function node.
* Errors will be thrown and the error manager will contain information
* if parsing should fail
@@ -264,7 +272,7 @@
try {
stream = new TokenStream();
- lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions);
+ lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
lexer.line = lexer.pendingLine = lineOffset + 1;
line = lineOffset;
@@ -472,7 +480,6 @@
final FunctionNode functionNode =
new FunctionNode(
source,
- nextFunctionId++,
functionLine,
token,
Token.descPosition(token),
@@ -2828,10 +2835,14 @@
FunctionNode functionNode = null;
long lastToken = 0L;
+ final boolean parseBody;
+ Object endParserState = null;
try {
// Create a new function block.
functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
-
+ assert functionNode != null;
+ final int functionId = functionNode.getId();
+ parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
// Nashorn extension: expression closures
if (!env._no_syntax_extensions && type != LBRACE) {
/*
@@ -2847,34 +2858,143 @@
assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
// EOL uses length field to store the line number
final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
- final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
- appendStatement(returnNode);
+ // Only create the return node if we aren't skipping nested functions. Note that we aren't
+ // skipping parsing of these extended functions; they're considered to be small anyway. Also,
+ // they don't end with a single well known token, so it'd be very hard to get correctly (see
+ // the note below for reasoning on skipping happening before instead of after RBRACE for
+ // details).
+ if (parseBody) {
+ final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
+ appendStatement(returnNode);
+ }
functionNode.setFinish(lastFinish);
-
} else {
- expect(LBRACE);
-
- // Gather the function elements.
- final List<Statement> prevFunctionDecls = functionDeclarations;
- functionDeclarations = new ArrayList<>();
- try {
- sourceElements(false);
- addFunctionDeclarations(functionNode);
- } finally {
- functionDeclarations = prevFunctionDecls;
+ expectDontAdvance(LBRACE);
+ if (parseBody || !skipFunctionBody(functionNode)) {
+ next();
+ // Gather the function elements.
+ final List<Statement> prevFunctionDecls = functionDeclarations;
+ functionDeclarations = new ArrayList<>();
+ try {
+ sourceElements(false);
+ addFunctionDeclarations(functionNode);
+ } finally {
+ functionDeclarations = prevFunctionDecls;
+ }
+
+ lastToken = token;
+ if (parseBody) {
+ // Since the lexer can read ahead and lexify some number of tokens in advance and have
+ // them buffered in the TokenStream, we need to produce a lexer state as it was just
+ // before it lexified RBRACE, and not whatever is its current (quite possibly well read
+ // ahead) state.
+ endParserState = new ParserState(Token.descPosition(token), line, linePosition);
+
+ // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of
+ // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the
+ // state after it. The reason is that RBRACE is a well-known token that we can expect and
+ // will never involve us getting into a weird lexer state, and as such is a great reparse
+ // point. Typical example of a weird lexer state after RBRACE would be:
+ // function this_is_skipped() { ... } "use strict";
+ // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead
+ // of compensating for the possibility of a string literal (or similar) after RBRACE,
+ // we'll rather just restart parsing from this well-known, friendly token instead.
+ }
}
-
- lastToken = token;
expect(RBRACE);
functionNode.setFinish(finish);
}
} finally {
functionNode = restoreFunctionNode(functionNode, lastToken);
}
+
+ // NOTE: we can only do alterations to the function node after restoreFunctionNode.
+
+ if (parseBody) {
+ functionNode = functionNode.setEndParserState(lc, endParserState);
+ } else if (functionNode.getBody().getStatementCount() > 0){
+ // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
+ // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
+ // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
+ // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
+ // nested bodies early if we were supposed to skip 'em.
+ functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null,
+ Collections.<Statement>emptyList()));
+ }
+
+ if (reparsedFunction != null) {
+ // We restore the flags stored in the function's ScriptFunctionData that we got when we first
+ // eagerly parsed the code. We're doing it because some flags would be set based on the
+ // content of the function, or even content of its nested functions, most of which are normally
+ // skipped during an on-demand compilation.
+ final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
+ if (data != null) {
+ // Data can be null if when we originally parsed the file, we removed the function declaration
+ // as it was dead code.
+ functionNode = functionNode.setFlags(lc, data.getFunctionFlags());
+ // This compensates for missing markEval() in case the function contains an inner function
+ // that contains eval(), that now we didn't discover since we skipped the inner function.
+ if (functionNode.hasNestedEval()) {
+ assert functionNode.hasScopeBlock();
+ functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null));
+ }
+ }
+ }
printAST(functionNode);
return functionNode;
}
+ private boolean skipFunctionBody(final FunctionNode functionNode) {
+ if (reparsedFunction == null) {
+ // Not reparsing, so don't skip any function body.
+ return false;
+ }
+ // Skip to the RBRACE of this function, and continue parsing from there.
+ final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
+ if (data == null) {
+ // Nested function is not known to the reparsed function. This can happen if the FunctionNode was
+ // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the
+ // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it.
+ return false;
+ }
+ final ParserState parserState = (ParserState)data.getEndParserState();
+ assert parserState != null;
+
+ stream.reset();
+ lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions);
+ line = parserState.line;
+ linePosition = parserState.linePosition;
+ // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
+ // the RBRACE.
+ type = SEMICOLON;
+ k = -1;
+ next();
+
+ return true;
+ }
+
+ /**
+ * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer
+ * for resuming parsing after skipping a function body.
+ */
+ private static class ParserState {
+ private final int position;
+ private final int line;
+ private final int linePosition;
+
+ ParserState(final int position, final int line, final int linePosition) {
+ this.position = position;
+ this.line = line;
+ this.linePosition = linePosition;
+ }
+
+ Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) {
+ final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true);
+ newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
+ return newLexer;
+ }
+ }
+
private void printAST(final FunctionNode functionNode) {
if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
env.getErr().println(new ASTWriter(functionNode));
@@ -3247,6 +3367,9 @@
} else {
lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
}
+ // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
+ // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
+ // this method when the parser skips a nested function.
lc.setBlockNeedsScope(lc.getFunctionBody(fn));
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenStream.java Wed Sep 10 19:37:52 2014 -0700
@@ -209,4 +209,8 @@
in = count;
buffer = newBuffer;
}
+
+ void reset() {
+ in = out = count = base = 0;
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Wed Sep 10 19:37:52 2014 -0700
@@ -80,12 +80,6 @@
public long getUniqueScriptId();
/**
- * Get next unique eval id
- * @return unique eval id
- */
- public long getUniqueEvalId();
-
- /**
* Store a compiled script for later reuse
* @param source the script source
* @param mainClassName the main class name
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Wed Sep 10 19:37:52 2014 -0700
@@ -27,7 +27,6 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -39,6 +38,7 @@
import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.logging.Level;
+
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Wed Sep 10 19:37:52 2014 -0700
@@ -196,16 +196,11 @@
}
@Override
- public long getUniqueEvalId() {
- return context.getUniqueEvalId();
- }
-
- @Override
- public void storeScript(final String classInfoFile, final Source source, final String mainClassName,
+ public void storeScript(final String cacheKey, final Source source, final String mainClassName,
final Map<String,byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers,
final Object[] constants, final int compilationId) {
if (context.codeStore != null) {
- context.codeStore.storeScript(classInfoFile, source, mainClassName, classBytes, initializers, constants, compilationId);
+ context.codeStore.storeScript(cacheKey, source, mainClassName, classBytes, initializers, constants, compilationId);
}
}
@@ -334,9 +329,6 @@
/** Unique id for script. Used only when --loader-per-compile=false */
private final AtomicLong uniqueScriptId;
- /** Unique id for 'eval' */
- private final AtomicLong uniqueEvalId;
-
/** Optional class filter to use for Java classes. Can be null. */
private final ClassFilter classFilter;
@@ -450,7 +442,6 @@
this.uniqueScriptId = new AtomicLong();
}
this.errors = errors;
- this.uniqueEvalId = new AtomicLong();
// if user passed -classpath option, make a class loader with that and set it as
// thread context class loader so that script can access classes from that path.
@@ -1190,10 +1181,6 @@
}, CREATE_LOADER_ACC_CTXT);
}
- private long getUniqueEvalId() {
- return uniqueEvalId.getAndIncrement();
- }
-
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Sep 10 19:37:52 2014 -0700
@@ -29,7 +29,9 @@
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import java.lang.invoke.MethodHandle;
+import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
+import jdk.nashorn.internal.objects.Global;
/**
* This class represents the result from a find property search.
@@ -79,25 +81,17 @@
* @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
* @return method handle for the getter
*/
- public MethodHandle getGetter(final Class<?> type, final int programPoint) {
+ public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
final MethodHandle getter;
if (isValid(programPoint)) {
getter = property.getOptimisticGetter(type, programPoint);
} else {
getter = property.getGetter(type);
}
- return getGetterInner(getter);
- }
-
- private MethodHandle getGetterInner(final MethodHandle getter) {
if (property instanceof UserAccessorProperty) {
- final UserAccessorProperty uc = (UserAccessorProperty)property;
- final ScriptObject owner = getOwner();
- final ScriptObject container = (owner != null) ? owner : self;
- return MH.insertArguments(getter, 0, uc.getAccessors(container));
+ return insertAccessorsGetter((UserAccessorProperty) property, request, getter);
}
return getter;
-
}
/**
@@ -111,18 +105,31 @@
*
* @return method handle for the getter
*/
- public MethodHandle getSetter(final Class<?> type, final boolean strict) {
- final MethodHandle setter = property.getSetter(type, getOwner().getMap());
+ public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) {
+ MethodHandle setter = property.getSetter(type, getOwner().getMap());
if (property instanceof UserAccessorProperty) {
- final UserAccessorProperty uc = (UserAccessorProperty)property;
- final ScriptObject owner = getOwner();
- final ScriptObject container = (owner != null) ? owner : self;
- return MH.insertArguments(setter, 0, uc.getAccessors(container), strict ? property.getKey() : null);
+ setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null);
+ return insertAccessorsGetter((UserAccessorProperty) property, request, setter);
}
return setter;
}
+ // Fold an accessor getter into the method handle of a user accessor property.
+ private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
+ MethodHandle superGetter = uap.getAccessorsGetter();
+ if (isInherited()) {
+ superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
+ }
+ if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
+ final MethodHandle wrapFilter = Global.getPrimitiveWrapFilter(request.getReceiver());
+ superGetter = MH.filterArguments(superGetter, 0, wrapFilter.asType(wrapFilter.type().changeReturnType(superGetter.type().parameterType(0))));
+ }
+ superGetter = MH.asType(superGetter, superGetter.type().changeParameterType(0, Object.class));
+
+ return MH.foldArguments(mh, superGetter);
+ }
+
/**
* Return the {@code ScriptObject} owning of the property: this means the prototype.
* @return owner of property
@@ -136,7 +143,7 @@
* @return appropriate receiver
*/
public ScriptObject getGetterReceiver() {
- return property != null && property.hasGetterFunction(prototype) ? self : prototype;
+ return property != null && property instanceof UserAccessorProperty ? self : prototype;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Sep 10 19:37:52 2014 -0700
@@ -84,6 +84,12 @@
/** Allocator map from makeMap() */
private final PropertyMap allocatorMap;
+ /**
+ * Opaque object representing parser state at the end of the function. Used when reparsing outer function
+ * to help with skipping parsing inner functions.
+ */
+ private final Object endParserState;
+
/** Code installer used for all further recompilation/specialization of this ScriptFunction */
private transient CodeInstaller<ScriptEnvironment> installer;
@@ -98,9 +104,8 @@
/** Id to parent function if one exists */
private RecompilableScriptFunctionData parent;
- private final boolean isDeclared;
- private final boolean isAnonymous;
- private final boolean needsCallee;
+ /** Copy of the {@link FunctionNode} flags. */
+ private final int functionFlags;
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
@@ -136,15 +141,14 @@
super(functionName(functionNode),
Math.min(functionNode.getParameters().size(), MAX_ARITY),
- getFlags(functionNode));
+ getDataFlags(functionNode));
this.functionName = functionNode.getName();
this.lineNumber = functionNode.getLineNumber();
- this.isDeclared = functionNode.isDeclared();
- this.needsCallee = functionNode.needsCallee();
- this.isAnonymous = functionNode.isAnonymous();
+ this.functionFlags = functionNode.getFlags() | (functionNode.needsCallee() ? FunctionNode.NEEDS_CALLEE : 0);
this.functionNodeId = functionNode.getId();
this.source = functionNode.getSource();
+ this.endParserState = functionNode.getEndParserState();
this.token = tokenFor(functionNode);
this.installer = installer;
this.allocatorClassName = allocatorClassName;
@@ -202,6 +206,24 @@
}
/**
+ * Returns the names of all external symbols this function uses.
+ * @return the names of all external symbols this function uses.
+ */
+ public Set<String> getExternalSymbolNames() {
+ return externalScopeDepths == null ? Collections.<String>emptySet() :
+ Collections.unmodifiableSet(externalScopeDepths.keySet());
+ }
+
+ /**
+ * Returns the opaque object representing the parser state at the end of this function's body, used to
+ * skip parsing this function when reparsing its containing outer function.
+ * @return the object representing the end parser state
+ */
+ public Object getEndParserState() {
+ return endParserState;
+ }
+
+ /**
* Get the parent of this RecompilableScriptFunctionData. If we are
* a nested function, we have a parent. Note that "null" return value
* can also mean that we have a parent but it is unknown, so this can
@@ -269,7 +291,7 @@
@Override
public boolean inDynamicContext() {
- return (flags & IN_DYNAMIC_CONTEXT) != 0;
+ return getFunctionFlag(FunctionNode.IN_DYNAMIC_CONTEXT);
}
private static String functionName(final FunctionNode fn) {
@@ -293,7 +315,7 @@
return Token.toDesc(TokenType.FUNCTION, position, length);
}
- private static int getFlags(final FunctionNode functionNode) {
+ private static int getDataFlags(final FunctionNode functionNode) {
int flags = IS_CONSTRUCTOR;
if (functionNode.isStrict()) {
flags |= IS_STRICT;
@@ -307,9 +329,6 @@
if (functionNode.isVarArg()) {
flags |= IS_VARIABLE_ARITY;
}
- if (functionNode.inDynamicContext()) {
- flags |= IN_DYNAMIC_CONTEXT;
- }
return flags;
}
@@ -337,7 +356,6 @@
}
FunctionNode reparse() {
- final boolean isProgram = functionNodeId == FunctionNode.FIRST_FUNCTION_ID;
// NOTE: If we aren't recompiling the top-level program, we decrease functionNodeId 'cause we'll have a synthetic program node
final int descPosition = Token.descPosition(token);
final Context context = Context.getContextTrusted();
@@ -346,18 +364,27 @@
source,
new Context.ThrowErrorManager(),
isStrict(),
- functionNodeId - (isProgram ? 0 : 1),
lineNumber - 1,
context.getLogger(Parser.class)); // source starts at line 0, so even though lineNumber is the correct declaration line, back off one to make it exclusive
- if (isAnonymous) {
+ if (getFunctionFlag(FunctionNode.IS_ANONYMOUS)) {
parser.setFunctionName(functionName);
}
+ parser.setReparsedFunction(this);
- final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition, Token.descLength(token), true);
- // Parser generates a program AST even if we're recompiling a single function, so when we are only recompiling a
- // single function, extract it from the program.
- return (isProgram ? program : extractFunctionFromScript(program)).setName(null, functionName);
+ final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition,
+ Token.descLength(token), true);
+ // Parser generates a program AST even if we're recompiling a single function, so when we are only
+ // recompiling a single function, extract it from the program.
+ return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
+ }
+
+ private boolean getFunctionFlag(final int flag) {
+ return (functionFlags & flag) != 0;
+ }
+
+ private boolean isProgram() {
+ return getFunctionFlag(FunctionNode.IS_PROGRAM);
}
TypeMap typeMap(final MethodType fnCallSiteType) {
@@ -546,7 +573,7 @@
assert fns.size() == 1 : "got back more than one method in recompilation";
final FunctionNode f = fns.iterator().next();
assert f.getId() == functionNodeId;
- if (!isDeclared && f.isDeclared()) {
+ if (!getFunctionFlag(FunctionNode.IS_DECLARED) && f.isDeclared()) {
return f.clearFlag(null, FunctionNode.IS_DECLARED);
}
return f;
@@ -669,7 +696,15 @@
@Override
public boolean needsCallee() {
- return needsCallee;
+ return getFunctionFlag(FunctionNode.NEEDS_CALLEE);
+ }
+
+ /**
+ * Returns the {@link FunctionNode} flags associated with this function data.
+ * @return the {@link FunctionNode} flags associated with this function data.
+ */
+ public int getFunctionFlags() {
+ return functionFlags;
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Sep 10 19:37:52 2014 -0700
@@ -90,8 +90,6 @@
public static final int USES_THIS = 1 << 4;
/** Is this a variable arity function? */
public static final int IS_VARIABLE_ARITY = 1 << 5;
- /** Is this declared in a dynamic context */
- public static final int IN_DYNAMIC_CONTEXT = 1 << 6;
/** Flag for strict or built-in functions */
public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Sep 10 19:37:52 2014 -0700
@@ -1050,7 +1050,7 @@
}
private static int getIntValue(final FindProperty find, final int programPoint) {
- final MethodHandle getter = find.getGetter(int.class, programPoint);
+ final MethodHandle getter = find.getGetter(int.class, programPoint, null);
if (getter != null) {
try {
return (int)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1065,7 +1065,7 @@
}
private static long getLongValue(final FindProperty find, final int programPoint) {
- final MethodHandle getter = find.getGetter(long.class, programPoint);
+ final MethodHandle getter = find.getGetter(long.class, programPoint, null);
if (getter != null) {
try {
return (long)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1080,7 +1080,7 @@
}
private static double getDoubleValue(final FindProperty find, final int programPoint) {
- final MethodHandle getter = find.getGetter(double.class, programPoint);
+ final MethodHandle getter = find.getGetter(double.class, programPoint, null);
if (getter != null) {
try {
return (double)getter.invokeExact((Object)find.getGetterReceiver());
@@ -1983,7 +1983,7 @@
NashornCallSiteDescriptor.getProgramPoint(desc) :
UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
- mh = find.getGetter(returnType, programPoint);
+ mh = find.getGetter(returnType, programPoint, request);
// Get the appropriate guard for this callsite and property.
final MethodHandle guard = NashornGuards.getGuard(this, property, desc, explicitInstanceOfCheck);
final ScriptObject owner = find.getOwner();
@@ -1995,8 +1995,9 @@
mh = Lookup.emptyGetter(returnType);
protoSwitchPoint = getProtoSwitchPoint(name, owner);
} else if (!find.isSelf()) {
- assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
- if (!property.hasGetterFunction(owner)) {
+ assert mh.type().returnType().equals(returnType) :
+ "return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
+ if (!(property instanceof UserAccessorProperty)) {
// Add a filter that replaces the self object with the prototype owning the property.
mh = addProtoFilter(mh, find.getProtoChainLength());
}
@@ -2167,7 +2168,7 @@
}
}
- final GuardedInvocation inv = new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
+ final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
if (cinv != null) {
@@ -2320,13 +2321,13 @@
find.isSelf()?
getKnownFunctionPropertyGuardSelf(
getMap(),
- find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+ find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
func)
:
//TODO this always does a scriptobject check
getKnownFunctionPropertyGuardProto(
getMap(),
- find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+ find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
find.getProtoChainLength(),
func),
getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Sep 10 19:37:52 2014 -0700
@@ -33,6 +33,7 @@
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -48,7 +49,7 @@
private final FindProperty find;
private final CallSiteDescriptor desc;
private final Class<?> type;
- private final boolean explicitInstanceOfCheck;
+ private final LinkRequest request;
/**
* Creates a new property setter method creator.
@@ -56,14 +57,15 @@
* @param find a result of a {@link ScriptObject#findProperty(String, boolean)} on the object for the property we
* want to create a setter for. Can be null if the property does not yet exist on the object.
* @param desc the descriptor of the call site that triggered the property setter lookup
+ * @param request the link request
*/
- SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) {
- this.sobj = sobj;
- this.map = sobj.getMap();
- this.find = find;
- this.desc = desc;
- this.type = desc.getMethodType().parameterType(1);
- this.explicitInstanceOfCheck = explicitInstanceOfCheck;
+ SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final LinkRequest request) {
+ this.sobj = sobj;
+ this.map = sobj.getMap();
+ this.find = find;
+ this.desc = desc;
+ this.type = desc.getMethodType().parameterType(1);
+ this.request = request;
}
@@ -111,6 +113,7 @@
// getGuard() and getException() either both return null, or neither does. The reason for that is that now
// getGuard returns a map guard that casts its argument to ScriptObject, and if that fails, we need to
// relink on ClassCastException.
+ final boolean explicitInstanceOfCheck = NashornGuards.explicitInstanceOfCheck(desc, request);
return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc, explicitInstanceOfCheck),
(SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
}
@@ -140,6 +143,7 @@
private SetMethod createExistingPropertySetter() {
final Property property = find.getProperty();
+ final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
final MethodHandle methodHandle;
if (NashornCallSiteDescriptor.isDeclaration(desc)) {
@@ -152,7 +156,7 @@
final PropertyMap oldMap = getMap();
final Property newProperty = property.removeFlags(Property.NEEDS_DECLARATION);
final PropertyMap newMap = oldMap.replaceProperty(property, newProperty);
- final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+ final MethodHandle fastSetter = find.replaceProperty(newProperty).getSetter(type, isStrict, request);
final MethodHandle slowSetter = MH.insertArguments(ScriptObject.DECLARE_AND_SET, 1, getName()).asType(fastSetter.type());
// cas map used as guard, if true that means we can do the set fast
@@ -161,14 +165,14 @@
casMap = MH.asType(casMap, casMap.type().changeParameterType(0, Object.class));
methodHandle = MH.guardWithTest(casMap, fastSetter, slowSetter);
} else {
- methodHandle = find.getSetter(type, NashornCallSiteDescriptor.isStrict(desc));
+ methodHandle = find.getSetter(type, isStrict, request);
}
assert methodHandle != null;
assert property != null;
final MethodHandle boundHandle;
- if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
+ if (!(property instanceof UserAccessorProperty) && find.isInherited()) {
boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
} else {
boundHandle = methodHandle;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Timing.java Wed Sep 10 19:37:52 2014 -0700
@@ -33,6 +33,8 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
+
+import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
@@ -189,7 +191,7 @@
maxKeyLength++;
final StringBuilder sb = new StringBuilder();
- sb.append("Accumulated complation phase Timings:\n\n");
+ sb.append("Accumulated compilation phase timings:\n\n");
for (final Map.Entry<String, Long> entry : timings.entrySet()) {
int len;
@@ -224,6 +226,9 @@
append((int)(knownTime * 100.0 / total)).
append("%])");
+ sb.append("\n\nEmitted compile units: ").
+ append(CompileUnit.getEmittedUnitCount());
+
return sb.toString();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Wed Sep 10 19:37:52 2014 -0700
@@ -34,8 +34,8 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.util.concurrent.Callable;
-import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -48,7 +48,7 @@
private static final long serialVersionUID = -5928687246526840321L;
- static class Accessors {
+ static final class Accessors {
Object getter;
Object setter;
@@ -67,20 +67,20 @@
}
}
+ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
/** Getter method handle */
- private final static CompilerConstants.Call USER_ACCESSOR_GETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
- "userAccessorGetter", Object.class, Accessors.class, Object.class);
+ private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class);
/** Setter method handle */
- private final static CompilerConstants.Call USER_ACCESSOR_SETTER = staticCall(MethodHandles.lookup(), UserAccessorProperty.class,
- "userAccessorSetter", void.class, Accessors.class, String.class, Object.class, Object.class);
+ private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class);
/** Dynamic invoker for getter */
- private static final Object INVOKE_UA_GETTER = new Object();
+ private static final Object GETTER_INVOKER_KEY = new Object();
private static MethodHandle getINVOKE_UA_GETTER() {
- return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
+ return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY,
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
@@ -91,10 +91,10 @@
}
/** Dynamic invoker for setter */
- private static Object INVOKE_UA_SETTER = new Object();
+ private static Object SETTER_INVOKER_KEY = new Object();
private static MethodHandle getINVOKE_UA_SETTER() {
- return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
+ return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY,
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
@@ -190,7 +190,7 @@
@Override
public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
- return userAccessorGetter(getAccessors((owner != null) ? owner : self), self);
+ return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self);
}
@Override
@@ -210,13 +210,13 @@
@Override
public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
- userAccessorSetter(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
+ invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
}
@Override
public MethodHandle getGetter(final Class<?> type) {
//this returns a getter on the format (Accessors, Object receiver)
- return Lookup.filterReturnType(USER_ACCESSOR_GETTER.methodHandle(), type);
+ return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type);
}
@Override
@@ -260,7 +260,7 @@
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- return USER_ACCESSOR_SETTER.methodHandle();
+ return INVOKE_SETTER_ACCESSOR;
}
@Override
@@ -269,11 +269,21 @@
return (value instanceof ScriptFunction) ? (ScriptFunction)value : null;
}
+ /**
+ * Get the getter for the {@code Accessors} object.
+ * This is the the super {@code Object} type getter with {@code Accessors} return type.
+ *
+ * @return The getter handle for the Accessors
+ */
+ MethodHandle getAccessorsGetter() {
+ return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
+ }
+
// User defined getter and setter are always called by "dyn:call". Note that the user
// getter/setter may be inherited. If so, proto is bound during lookup. In either
// inherited or self case, slot is also bound during lookup. Actual ScriptFunction
// to be called is retrieved everytime and applied.
- static Object userAccessorGetter(final Accessors gs, final Object self) {
+ private static Object invokeGetterAccessor(final Accessors gs, final Object self) {
final Object func = gs.getter;
if (func instanceof ScriptFunction) {
try {
@@ -288,7 +298,7 @@
return UNDEFINED;
}
- static void userAccessorSetter(final Accessors gs, final String name, final Object self, final Object value) {
+ private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) {
final Object func = gs.setter;
if (func instanceof ScriptFunction) {
try {
@@ -303,4 +313,8 @@
}
}
+ private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
+ return MH.findStatic(LOOKUP, UserAccessorProperty.class, name, MH.type(rtype, types));
+ }
+
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed Sep 10 19:37:52 2014 -0700
@@ -32,11 +32,10 @@
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
-import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.UserAccessorProperty;
/**
* Implements lookup of methods to link for dynamic operations on JavaScript primitive values (booleans, strings, and
@@ -86,15 +85,6 @@
final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
- final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
- if ("setProp".equals(operator) || "setElem".equals(operator)) {
- final MethodType type = desc.getMethodType();
- MethodHandle method = MH.asType(Lookup.EMPTY_SETTER, MH.type(void.class, Object.class, type.parameterType(1)));
- if (type.parameterCount() == 3) {
- method = MH.dropArguments(method, 2, type.parameterType(2));
- }
- return new GuardedInvocation(method, guard);
- }
if(desc.getNameTokenCount() > 2) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
@@ -102,7 +92,7 @@
if(find == null) {
// Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
return null;
- } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
+ } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java Wed Sep 10 19:37:52 2014 -0700
@@ -246,7 +246,7 @@
// For each file on the command line.
for (final String fileName : files) {
- final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors, env._strict, FunctionNode.FIRST_FUNCTION_ID, 0, context.getLogger(Parser.class)).parse();
+ final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors, env._strict, 0, context.getLogger(Parser.class)).parse();
if (errors.getNumberOfErrors() != 0) {
return COMPILATION_ERROR;
--- a/nashorn/test/script/basic/JDK-8030182_2.js Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/JDK-8030182_2.js Wed Sep 10 19:37:52 2014 -0700
@@ -41,6 +41,6 @@
try {
eval(str);
} catch (e) {
- print(e.stack.replace(/\\/g, '/').replace(/<eval>@[0-9]+/, '<eval>@<id>'));
+ print(e.stack.replace(/\\/g, '/'));
}
--- a/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/JDK-8030182_2.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -1,3 +1,3 @@
ReferenceError: "g" is not defined
- at <program> (test/script/basic/JDK-8030182_2.js#42:4<eval>@<id>:-1)
+ at <program> (test/script/basic/JDK-8030182_2.js#42:4<eval>:-1)
at <program> (test/script/basic/JDK-8030182_2.js:42)
--- a/nashorn/test/script/basic/JDK-8048079_1.js Wed Jul 05 20:00:07 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * JDK-8048079: Persistent code store is broken after optimistic types merge
- *
- * @test
- * @run
- * @option -pcc
- * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
- * @fork
- */
-
-load(__DIR__ + 'prototype.js');
-load(__DIR__ + 'yui.js');
--- a/nashorn/test/script/basic/JDK-8048079_1.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-parsed and compiled ok prototype.js
-parsed and compiled ok yui-min.js
-parsed and compiled ok yui.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_1a.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8048079: Persistent code store is broken after optimistic types merge
+ *
+ * @test
+ * @runif external.prototype
+ * @option -pcc
+ * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_1a.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_1b.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8048079: Persistent code store is broken after optimistic types merge
+ *
+ * @test
+ * @runif external.yui
+ * @option -pcc
+ * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_1b.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/nashorn/test/script/basic/JDK-8048079_2.js Wed Jul 05 20:00:07 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * JDK-8048079: Persistent code store is broken after optimistic types merge
- *
- * @test
- * @run
- * @option -pcc
- * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
- * @fork
- */
-
-load(__DIR__ + 'prototype.js');
-load(__DIR__ + 'yui.js');
--- a/nashorn/test/script/basic/JDK-8048079_2.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-parsed and compiled ok prototype.js
-parsed and compiled ok yui-min.js
-parsed and compiled ok yui.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_2a.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8048079: Persistent code store is broken after optimistic types merge.
+ * Same script as JDK-8048079_1a.js to exercise code cache.
+ * @test
+ * @runif external.prototype
+ * @option -pcc
+ * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_2a.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_2b.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8048079: Persistent code store is broken after optimistic types merge
+ * Same script as JDK-8048079_1b.js to exercise code cache again.
+ * @test
+ * @runif external.yui
+ * @option -pcc
+ * @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8048079_2b.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/nashorn/test/script/basic/es6/const-empty.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/es6/const-empty.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/es6/const-empty.js#33:4<eval>@1:2:7 Missing assignment to constant "x"
+SyntaxError: test/script/basic/es6/const-empty.js#33:4<eval>:2:7 Missing assignment to constant "x"
const x;
^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare-extra.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+tryIt(<<CODE
+ "use strict";
+ const x = 2;
+ var x = {};
+CODE)
+
+tryIt(<<CODE
+ "use strict";
+ var x = 2;
+ const x = {};
+CODE)
+
+tryIt(<<CODE
+ "use strict";
+ function x () {}
+ const x = 5;
+CODE)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/const-redeclare-extra.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,9 @@
+SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:3:8 Variable "x" has already been declared
+ var x = {};
+ ^
+SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:2:8 Variable "x" has already been declared
+ var x = 2;
+ ^
+SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8<eval>:2:13 Variable "x" has already been declared
+ function x () {}
+ ^
--- a/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/es6/const-redeclare.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/es6/const-redeclare.js#33:4<eval>@1:2:6 Variable "x" has already been declared
+SyntaxError: test/script/basic/es6/const-redeclare.js#33:4<eval>:2:6 Variable "x" has already been declared
const x = 2;
^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare-extra.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+tryIt(<<CODE
+ "use strict";
+ let x = 2;
+ const x = function (a,b,c) {};
+CODE)
+
+tryIt(<<CODE
+ "use strict";
+ let x = {};
+ var x = 2;
+CODE)
+
+tryIt(<<CODE
+ "use strict";
+ var x = 2;
+ let x = undefined;
+CODE)
+
+tryIt(<<CODE
+ "use strict";
+ const x = function (){};
+ let x = {};
+CODE)
+
+
+tryIt(<<CODE
+ "use strict";
+ let a = 2;
+ function a () {};
+CODE)
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let-redeclare-extra.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,15 @@
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:8 Variable "x" has already been declared
+ let x = 2;
+ ^
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:3:8 Variable "x" has already been declared
+ var x = 2;
+ ^
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:8 Variable "x" has already been declared
+ var x = 2;
+ ^
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:2:10 Variable "x" has already been declared
+ const x = function (){};
+ ^
+SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8<eval>:3:13 Variable "a" has already been declared
+ function a () {};
+ ^
--- a/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/es6/let-redeclare.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -1,3 +1,3 @@
-SyntaxError: test/script/basic/es6/let-redeclare.js#33:4<eval>@1:2:4 Variable "x" has already been declared
+SyntaxError: test/script/basic/es6/let-redeclare.js#33:4<eval>:2:4 Variable "x" has already been declared
let x = 2;
^
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_const_closure.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+function tryIt(code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+
+tryIt(<<CODE
+ function a () {
+ this.val = 41
+ let self = this
+ this.b = function () {
+ return self.val;
+ }
+ }
+ c = new a()
+ print(c.b.call(null))
+CODE)
+
+
+tryIt(<<CODE
+ function a () {
+ this.val = 42
+ let self = this
+ this.b = function () {
+ return this.val;
+ }.bind(self)
+ }
+ c = new a()
+ print(c.b.call(null))
+CODE)
+
+tryIt(<<CODE
+ function a () {
+ this.val = 43
+ const self = this
+ this.b = function () {
+ return self.val;
+ }
+ }
+ c = new a()
+ print(c.b.call(null))
+CODE)
+
+tryIt(<<CODE
+ function a () {
+ this.val = 44
+ const self = this
+ this.b = function () {
+ return this.val;
+ }.bind(self)
+ }
+ c = new a()
+ print(c.b.call(null))
+CODE)
+
+tryIt(<<CODE
+ let a = {name : 'test'}
+ let f = function () {
+ print(this.name)
+ }
+ let nf = f.bind(a)
+ nf()
+ if (true) {
+ let a = null
+ nf()
+ }
+ nf()
+CODE)
+
+
+tryIt(<<CODE
+ let arr = []
+ for (let i = 0; i < 3; i++) {
+ arr[i] = function(){return i;}
+ }
+ for (let i in arr) {
+ print(arr[i]())
+ }
+ arr = []
+ for (var i = 0; i < 3; i++) {
+ (function(i){
+ arr[i] = function(){return i;}
+ })(i)
+ }
+ for (let i in arr) {
+ print(arr[i]())
+ }
+CODE)
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_const_closure.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,13 @@
+41
+42
+43
+44
+test
+test
+test
+3
+3
+3
+0
+1
+2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_const_reuse.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+tryIt(<<CODE
+ let a = 23
+ if (true) {
+ a--
+ let a = 43;
+ }
+CODE)
+
+tryIt(<<CODE
+ const a = 23
+ if (true) {
+ a--
+ const a = 43;
+ }
+CODE)
+
+tryIt(<<CODE
+ let a = 23
+ if (true) {
+ a--
+ const a = 43;
+ }
+CODE)
+
+tryIt(<<CODE
+ const a = 23
+ if (true) {
+ a--
+ let a = 43;
+ }
+CODE)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_const_reuse.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,8 @@
+ReferenceError: "a" is not defined
+SyntaxError: test/script/basic/es6/let_const_reuse.js#35:9<eval>:3:8 Assignment to constant "a"
+ a--
+ ^
+SyntaxError: test/script/basic/es6/let_const_reuse.js#35:9<eval>:3:8 Assignment to constant "a"
+ a--
+ ^
+ReferenceError: "a" is not defined
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_different_types.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+tryIt(<<CODE
+ let a = function () { var a = "Hello World!"; return a; }
+ print(typeof a)
+ {
+ let a = 34;
+ print(typeof a)
+ if (true) {
+ let c = 54.7
+ var d = c
+ print(typeof c)
+ print(typeof d)
+ }
+ }
+ print(typeof a)
+ print(typeof a())
+ print(typeof c)
+ print(typeof d)
+ print(d)
+CODE)
+
+tryIt(<<CODE
+ let a = {}
+ if (true) {
+ function a () {
+ print (typeof a)
+ return 'Hello World!'
+ }
+ print(typeof a)
+ print(a())
+ }
+ print(typeof a)
+CODE)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_different_types.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,13 @@
+function
+number
+number
+number
+function
+string
+undefined
+number
+54.7
+function
+function
+Hello World!
+object
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_loops.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8057678: Tests for let&const keywords in Nashorn
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ * @option -scripting
+ */
+
+
+function tryIt (code) {
+ try {
+ eval(code)
+ } catch (e) {
+ print(e)
+ }
+}
+
+tryIt(<<CODE
+ let a = 2;
+ do {
+ a--;
+ let b = a;
+ } while (a > 0);
+ print(a)
+ print(b)
+CODE)
+
+tryIt(<<CODE
+ let a = 2
+ while(a > 0) {
+ a--
+ let b = a
+ }
+ print(a)
+ print(b)
+CODE)
+
+tryIt(<<CODE
+ let a = 2
+ while(a > 0) {
+ a--
+ const b = a
+ }
+ print(a)
+ print(b)
+CODE)
+
+tryIt(<<CODE
+ let a = 2;
+ do {
+ a--;
+ const b = a;
+ } while (a > 0);
+ print(a)
+ print(b)
+CODE)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/let_loops.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,8 @@
+0
+ReferenceError: "b" is not defined
+0
+ReferenceError: "b" is not defined
+0
+ReferenceError: "b" is not defined
+0
+ReferenceError: "b" is not defined
--- a/nashorn/test/script/basic/optimistic_check_type.js Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/optimistic_check_type.js Wed Sep 10 19:37:52 2014 -0700
@@ -36,13 +36,18 @@
// Testing conditional operator
print(inspect("" ? b : x.a, "ternary operator"))
-print(inspect(x.b ? b : x.a, "ternary operator"))
-print(inspect(c ? b : a, "ternary operator"))
-print(inspect(!c ? b : a, "ternary operator"))
-print(inspect(d ? b : x.c, "ternary operator"))
+var b1 = b;
+print(inspect(x.b ? b1 : x.a, "ternary operator"))
+var b2 = b;
+print(inspect(c ? b2 : a, "ternary operator"))
+var b3 = b;
+print(inspect(!c ? b3 : a, "ternary operator"))
+var b4 = b;
+print(inspect(d ? b4 : x.c, "ternary operator"))
print(inspect(x.c ? a : c, "ternary operator"))
print(inspect(c ? d : a, "ternary operator"))
-print(inspect(c ? +a : b, "ternary operator"))
+var b5 = b;
+print(inspect(c ? +a : b5, "ternary operator"))
// Testing format methods
print(inspect(b.toFixed(2), "global double toFixed()"))
@@ -53,11 +58,14 @@
print(inspect(trees[1], "member object"))
trees[1] = undefined;
print(inspect(trees[1], "member undefined"))
-print(inspect(1 in trees ? b : a, "conditional on array member"))
+var b6=b;
+print(inspect(1 in trees ? b6 : a, "conditional on array member"))
delete trees[2]
-print(inspect(2 in trees ? b : a, "conditional on array member"))
+var b7=b;
+print(inspect(2 in trees ? b7 : a, "conditional on array member"))
print(inspect(3 in trees ? trees[2]="bay" : a, "conditional on array member"))
-print(inspect("oak" in trees ? b : a, "conditional on array member"))
+var b8=b;
+print(inspect("oak" in trees ? b8 : a, "conditional on array member"))
// Testing nested functions and return value
function f1() {
--- a/nashorn/test/script/basic/splitter.js Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/splitter.js Wed Sep 10 19:37:52 2014 -0700
@@ -30,7 +30,5 @@
* @fork
*/
-load(__DIR__ + 'prototype.js');
-load(__DIR__ + 'yui.js');
load(__DIR__ + 'NASHORN-689.js');
load(__DIR__ + 'NASHORN-58.js');
--- a/nashorn/test/script/basic/splitter.js.EXPECTED Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/script/basic/splitter.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -1,6 +1,3 @@
-parsed and compiled ok prototype.js
-parsed and compiled ok yui-min.js
-parsed and compiled ok yui.js
a=10
a=9
a=8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/splitter_prototype.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test various scripts with low splitter threshold
+ *
+ * @test
+ * @option -Dnashorn.compiler.splitter.threshold=200
+ * @runif external.prototype
+ * @fork
+ */
+
+load(__DIR__ + 'prototype.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/splitter_prototype.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,1 @@
+parsed and compiled ok prototype.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/splitter_yui.js Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test various scripts with low splitter threshold
+ *
+ * @test
+ * @option -Dnashorn.compiler.splitter.threshold=200
+ * @runif external.yui
+ * @fork
+ */
+
+load(__DIR__ + 'yui.js');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/splitter_yui.js.EXPECTED Wed Sep 10 19:37:52 2014 -0700
@@ -0,0 +1,2 @@
+parsed and compiled ok yui-min.js
+parsed and compiled ok yui.js
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java Wed Sep 10 19:37:52 2014 -0700
@@ -407,6 +407,75 @@
Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
}
+
+ /**
+ * Test multi-threaded access to prototype user accessor properties for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedAccessorTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'original context' })", origContext);
+ e.eval("Object.defineProperty(Object.prototype, 'foo', { get: function() 'new context', configurable: true })", newCtxt);
+ final String sharedScript = "({}).foo";
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ final Object obj3 = e.eval("delete Object.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+ assertEquals(obj3, "newer context");
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+ }
+
+ /**
+ * Test multi-threaded access to primitive prototype user accessor properties for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedPrimitiveAccessorTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'original context' })", origContext);
+ e.eval("Object.defineProperty(String.prototype, 'foo', { get: function() 'new context' })", newCtxt);
+ final String sharedScript = "''.foo";
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ final Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+ assertEquals(obj3, "newer context");
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+ }
+
/**
* Test multi-threaded scope function invocation for shared script classes with multiple globals.
*/
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java Wed Jul 05 20:00:07 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java Wed Sep 10 19:37:52 2014 -0700
@@ -261,14 +261,17 @@
isTest = false;
isNotTest = true;
break;
- case "@runif":
- if (System.getProperty(scanner.next()) != null) {
+ case "@runif": {
+ final String prop = scanner.next();
+ if (System.getProperty(prop) != null) {
shouldRun = true;
} else {
+ factory.log("WARNING: (" + prop + ") skipping " + testFile);
isTest = false;
isNotTest = true;
}
break;
+ }
case "@run":
shouldRun = true;
break;