diff --git a/nashorn/bin/jjsdebug.sh b/nashorn/bin/jjsdebug.sh
new file mode 100644
index 00000000000..509700c39bf
--- /dev/null
+++ b/nashorn/bin/jjsdebug.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# 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.
+#
+
+$JAVA_HOME/bin/jjs -J-Djava.ext.dirs=`dirname $0`/../dist -J-agentlib:jdwp=transport=dt_socket,address=localhost:9009,server=y,suspend=y $*
diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml
index 1b28e9bdcbe..a872f358e6d 100644
--- a/nashorn/make/build.xml
+++ b/nashorn/make/build.xml
@@ -125,8 +125,7 @@
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
-
-
+
diff --git a/nashorn/make/nbproject/ide-targets.xml b/nashorn/make/nbproject/ide-targets.xml
index a592cff6a07..d1e8135f101 100644
--- a/nashorn/make/nbproject/ide-targets.xml
+++ b/nashorn/make/nbproject/ide-targets.xml
@@ -34,7 +34,7 @@
-
+
diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties
index eb708a41320..77f8ed73bf7 100644
--- a/nashorn/make/project.properties
+++ b/nashorn/make/project.properties
@@ -279,6 +279,7 @@ run.test.jvmargs.common=\
-Dfile.encoding=UTF-8 \
-Duser.language=${run.test.user.language} \
-Duser.country=${run.test.user.country} \
+ -Dnashorn.typeInfo.cacheDir=${build.dir}${file.separator}test${file.separator}type_info_cache \
${jfr.args} \
-XX:+HeapDumpOnOutOfMemoryError
diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java
index 75332859f17..70ec495a7ac 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java
@@ -152,7 +152,7 @@ class OverloadedMethod {
@SuppressWarnings("unused")
private MethodHandle selectMethod(final Object[] args) throws NoSuchMethodException {
- final Class>[] argTypes = new Class[args.length];
+ final Class>[] argTypes = new Class>[args.length];
for(int i = 0; i < argTypes.length; ++i) {
final Object arg = args[i];
argTypes[i] = arg == null ? ClassString.NULL_CLASS : arg.getClass();
diff --git a/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java
index 814fc6936bf..91946969370 100644
--- a/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java
+++ b/nashorn/src/jdk/internal/dynalink/support/CompositeTypeBasedGuardingDynamicLinker.java
@@ -111,7 +111,7 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
private final TypeBasedGuardingDynamicLinker[] linkers;
private final List[] singletonLinkers;
- @SuppressWarnings("unchecked")
+ @SuppressWarnings(value={"unchecked", "rawtypes"})
ClassToLinker(final TypeBasedGuardingDynamicLinker[] linkers) {
this.linkers = linkers;
singletonLinkers = new List[linkers.length];
@@ -120,6 +120,7 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
}
}
+ @SuppressWarnings("fallthrough")
@Override
protected List computeValue(final Class> clazz) {
List list = NO_LINKER;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
index 4a817fae3db..0659e3f5c3e 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -209,7 +209,7 @@ final class AssignSymbols extends NodeOperatorVisitor implements
if (varNode.isFunctionDeclaration()) {
symbol.setIsFunctionDeclaration();
}
- return varNode.setName((IdentNode)ident.setSymbol(symbol));
+ return varNode.setName(ident.setSymbol(symbol));
}
return varNode;
}
@@ -217,7 +217,7 @@ final class AssignSymbols extends NodeOperatorVisitor implements
}
private IdentNode compilerConstantIdentifier(final CompilerConstants cc) {
- return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc.getCurrentFunction().compilerConstant(cc));
+ return createImplicitIdentifier(cc.symbolName()).setSymbol(lc.getCurrentFunction().compilerConstant(cc));
}
/**
@@ -263,7 +263,7 @@ final class AssignSymbols extends NodeOperatorVisitor implements
final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName());
assert nameSymbol != null;
- return (VarNode)synthVar.setName((IdentNode)name.setSymbol(nameSymbol)).accept(this);
+ return (VarNode)synthVar.setName(name.setSymbol(nameSymbol)).accept(this);
}
private FunctionNode createSyntheticInitializers(final FunctionNode functionNode) {
@@ -522,7 +522,7 @@ final class AssignSymbols extends NodeOperatorVisitor implements
final Symbol paramSymbol = body.getExistingSymbol(param.getName());
assert paramSymbol != null;
assert paramSymbol.isParam() : paramSymbol + " " + paramSymbol.getFlags();
- newParams.add((IdentNode)param.setSymbol(paramSymbol));
+ newParams.add(param.setSymbol(paramSymbol));
// parameters should not be slots for a function that uses variable arity signature
if (isVarArg) {
@@ -702,7 +702,7 @@ final class AssignSymbols extends NodeOperatorVisitor implements
// If this is a declared variable or a function parameter, delete always fails (except for globals).
final String name = ident.getName();
final Symbol symbol = ident.getSymbol();
- final boolean failDelete = strictMode || symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel());
+ final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
if (failDelete && symbol.isThis()) {
return LiteralNode.newInstance(unaryNode, true).accept(this);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 21b51b334c3..bfb9851c0f3 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -145,6 +145,7 @@ import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.RewriteException;
import jdk.nashorn.internal.runtime.Scope;
+import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -210,6 +211,9 @@ final class CodeGenerator extends NodeOperatorVisitor(new LexicalContext()) {
+ @Override
+ public LiteralNode> leaveLiteralNode(final LiteralNode> literalNode) {
+ return literalNode.initialize(lc);
+ }
+ });
+
+ newFunctionNode = new Splitter(compiler, newFunctionNode, outermostCompileUnit).split(newFunctionNode, true);
assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn=" + fn.getName() + ", fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
assert newFunctionNode.isStrict() == compiler.isStrict() : "functionNode.isStrict() != compiler.isStrict() for " + quote(newFunctionNode.getName());
@@ -374,7 +385,7 @@ enum CompilationPhase {
assert newUnit != null;
newArrayUnits.add(new ArrayUnit(newUnit, au.getLo(), au.getHi()));
}
- aln.setUnits(newArrayUnits);
+ return aln.setUnits(lc, newArrayUnits);
}
return node;
}
@@ -421,7 +432,9 @@ enum CompilationPhase {
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 {
- newFunctionNode = (FunctionNode)newFunctionNode.accept(codegen);
+ // 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().
+ newFunctionNode = ((FunctionNode)newFunctionNode.accept(codegen)).setState(null, BYTECODE_GENERATED);
codegen.generateScopeCalls();
} catch (final VerifyError e) {
if (senv._verify_code || senv._print_code) {
@@ -489,7 +502,7 @@ enum CompilationPhase {
Class> rootClass = null;
long length = 0L;
- final CodeInstaller> codeInstaller = compiler.getCodeInstaller();
+ final CodeInstaller codeInstaller = compiler.getCodeInstaller();
final Map bytecode = compiler.getBytecode();
@@ -514,12 +527,10 @@ enum CompilationPhase {
final Object[] constants = compiler.getConstantData().toArray();
codeInstaller.initialize(installedClasses.values(), compiler.getSource(), constants);
- // index recompilable script function datas in the constant pool
- final Map rfns = new IdentityHashMap<>();
+ // initialize transient fields on recompilable script function data
for (final Object constant: constants) {
if (constant instanceof RecompilableScriptFunctionData) {
- final RecompilableScriptFunctionData rfn = (RecompilableScriptFunctionData)constant;
- rfns.put(rfn, rfn);
+ ((RecompilableScriptFunctionData)constant).initTransients(compiler.getSource(), codeInstaller);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
index 5c7757a1fa7..f5281ba9d56 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -46,10 +46,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
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;
@@ -122,6 +122,11 @@ public final class Compiler implements Loggable {
*/
private final Map invalidatedProgramPoints;
+ /**
+ * Descriptor of the location where we write the type information after compilation.
+ */
+ private final Object typeInformationFile;
+
/**
* Compile unit name of first compile unit - this prefix will be used for all
* classes that a compilation generates.
@@ -317,7 +322,7 @@ public final class Compiler implements Loggable {
final Source source,
final String sourceURL,
final boolean isStrict) {
- this(context, env, installer, source, sourceURL, isStrict, false, null, null, null, null, null);
+ this(context, env, installer, source, sourceURL, isStrict, false, null, null, null, null, null, null);
}
/**
@@ -333,6 +338,7 @@ public final class Compiler implements Loggable {
* @param compiledFunction compiled function, if any
* @param types parameter and return value type information, if any is known
* @param invalidatedProgramPoints invalidated program points for recompilation
+ * @param typeInformationFile descriptor of the location where type information is persisted
* @param continuationEntryPoints continuation entry points for restof method
* @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator}
*/
@@ -347,6 +353,7 @@ public final class Compiler implements Loggable {
final RecompilableScriptFunctionData compiledFunction,
final TypeMap types,
final Map invalidatedProgramPoints,
+ final Object typeInformationFile,
final int[] continuationEntryPoints,
final ScriptObject runtimeScope) {
this.context = context;
@@ -363,6 +370,7 @@ public final class Compiler implements Loggable {
this.compiledFunction = compiledFunction;
this.types = types;
this.invalidatedProgramPoints = invalidatedProgramPoints == null ? new HashMap() : invalidatedProgramPoints;
+ this.typeInformationFile = typeInformationFile;
this.continuationEntryPoints = continuationEntryPoints == null ? null: continuationEntryPoints.clone();
this.typeEvaluator = new TypeEvaluator(this, runtimeScope);
this.firstCompileUnitName = firstCompileUnitName();
@@ -457,6 +465,16 @@ public final class Compiler implements Loggable {
invalidatedProgramPoints.put(programPoint, type);
}
+
+ /**
+ * Returns a copy of this compiler's current mapping of invalidated optimistic program points to their types. The
+ * copy is not live with regard to changes in state in this compiler instance, and is mutable.
+ * @return a copy of this compiler's current mapping of invalidated optimistic program points to their types.
+ */
+ public Map getInvalidatedProgramPoints() {
+ return invalidatedProgramPoints == null ? null : new TreeMap<>(invalidatedProgramPoints);
+ }
+
TypeMap getTypeMap() {
return types;
}
@@ -513,6 +531,10 @@ public final class Compiler implements Loggable {
time += (env.isTimingEnabled() ? phase.getEndTime() - phase.getStartTime() : 0L);
}
+ if(typeInformationFile != null && !phases.isRestOfCompilation()) {
+ OptimisticTypesPersistence.store(typeInformationFile, invalidatedProgramPoints);
+ }
+
log.unindent();
if (info) {
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
index 7e461088747..86dcd772db3 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
@@ -62,6 +62,8 @@ public abstract class FieldObjectCreator extends ObjectCreator {
/** call site flags to be used for invocations */
private final int callSiteFlags;
+ /** are we creating this field object from 'eval' code? */
+ private final boolean evalCode;
/**
* Constructor
@@ -88,7 +90,7 @@ public abstract class FieldObjectCreator extends ObjectCreator {
FieldObjectCreator(final CodeGenerator codegen, final List> tuples, final boolean isScope, final boolean hasArguments) {
super(codegen, tuples, isScope, hasArguments);
this.callSiteFlags = codegen.getCallSiteFlags();
-
+ this.evalCode = codegen.isEvalCode();
countFields();
findClass();
}
@@ -153,7 +155,7 @@ public abstract class FieldObjectCreator extends ObjectCreator {
@Override
protected PropertyMap makeMap() {
assert propertyMap == null : "property map already initialized";
- propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), fieldCount, paddedFieldCount);
+ propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), fieldCount, paddedFieldCount, evalCode);
return propertyMap;
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
index 627623b378e..5e06794609c 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
@@ -141,7 +141,7 @@ public final class FunctionSignature {
paramTypeList.add(paramType.getTypeClass());
}
- this.methodType = MH.type(returnType.getTypeClass(), paramTypeList.toArray(new Class[paramTypes.length]));
+ this.methodType = MH.type(returnType.getTypeClass(), paramTypeList.toArray(new Class>[paramTypes.length]));
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index 5a1f09ae1ec..df763c1ba4f 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -25,10 +25,12 @@
package jdk.nashorn.internal.codegen;
+import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse;
import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
@@ -63,7 +65,6 @@ import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
@@ -72,6 +73,7 @@ import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TernaryNode;
@@ -356,6 +358,8 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
private boolean reachable = true;
// Return type of the function
private Type returnType = Type.UNKNOWN;
+ // Synthetic return node that we must insert at the end of the function if it's end is reachable.
+ private ReturnNode syntheticReturn;
// Topmost current split node (if any)
private SplitNode topSplit;
@@ -583,7 +587,11 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
}
}
setCompilerConstantAsObject(functionNode, CompilerConstants.THIS);
- if(functionNode.needsParentScope()) {
+
+ // TODO: coarse-grained. If we wanted to solve it completely precisely,
+ // we'd also need to push/pop its type when handling WithNode (so that
+ // it can go back to undefined after a 'with' block.
+ if(functionNode.hasScopeBlock() || functionNode.needsParentScope()) {
setCompilerConstantAsObject(functionNode, CompilerConstants.SCOPE);
}
if(functionNode.needsCallee()) {
@@ -841,6 +849,10 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
@Override
public boolean enterThrowNode(final ThrowNode throwNode) {
+ if(!reachable) {
+ return false;
+ }
+
throwNode.getExpression().accept(this);
jumpToCatchBlock(throwNode);
doesNotContinueSequentially();
@@ -1027,6 +1039,15 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
@Override
public Node leaveBlock(final Block block) {
if(lc.isFunctionBody()) {
+ if(reachable) {
+ // reachable==true means we can reach the end of the function without an explicit return statement. We
+ // need to insert a synthetic one then. This logic used to be in Lower.leaveBlock(), but Lower's
+ // reachability analysis (through Terminal.isTerminal() flags) is not precise enough so
+ // Lower$BlockLexicalContext.afterSetStatements will sometimes think the control flow terminates even
+ // when it didn't. Example: function() { switch((z)) { default: {break; } throw x; } }.
+ createSyntheticReturn(block);
+ assert !reachable;
+ }
// We must calculate the return type here (and not in leaveFunctionNode) as it can affect the liveness of
// the :return symbol and thus affect conversion type liveness calculations for it.
calculateReturnType();
@@ -1085,6 +1106,23 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
retSymbol.setNeedsSlot(true);
}
}
+
+ private void createSyntheticReturn(final Block body) {
+ final FunctionNode functionNode = lc.getCurrentFunction();
+ final long token = functionNode.getToken();
+ final int finish = functionNode.getFinish();
+ final List statements = body.getStatements();
+ final int lineNumber = statements.isEmpty() ? functionNode.getLineNumber() : statements.get(statements.size() - 1).getLineNumber();
+ final IdentNode returnExpr;
+ if(functionNode.isProgram()) {
+ returnExpr = new IdentNode(token, finish, RETURN.symbolName()).setSymbol(getCompilerConstantSymbol(functionNode, RETURN));
+ } else {
+ returnExpr = null;
+ }
+ syntheticReturn = new ReturnNode(lineNumber, token, finish, returnExpr);
+ syntheticReturn.accept(this);
+ }
+
/**
* Leave a breakable node. If there's a join point associated with its break label (meaning there was at least one
* break statement to the end of the node), insert the join point into the flow.
@@ -1158,7 +1196,9 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
} else if(binaryNode.isOptimisticUndecidedType()) {
// At this point, we can assign a static type to the optimistic binary ADD operator as now we know
// the types of its operands.
- return binaryNode.setType(Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()));
+ final Type type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
+ // Use Type.CHARSEQUENCE instead of Type.STRING to avoid conversion of ConsStrings to Strings.
+ return binaryNode.setType(type.equals(Type.STRING) ? Type.CHARSEQUENCE : type);
}
return binaryNode;
}
@@ -1173,6 +1213,16 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
return node;
}
+ @Override
+ public Node leaveBlock(final Block block) {
+ if(inOuterFunction && syntheticReturn != null && lc.isFunctionBody()) {
+ final ArrayList stmts = new ArrayList<>(block.getStatements());
+ stmts.add((ReturnNode)syntheticReturn.accept(this));
+ return block.setStatements(lc, stmts);
+ }
+ return super.leaveBlock(block);
+ }
+
@Override
public Node leaveFunctionNode(final FunctionNode nestedFunctionNode) {
inOuterFunction = true;
@@ -1207,10 +1257,10 @@ final class LocalVariableTypesCalculator extends NodeVisitor{
@Override
public Node leaveLiteralNode(final LiteralNode> literalNode) {
- if(literalNode instanceof ArrayLiteralNode) {
- ((ArrayLiteralNode)literalNode).analyze();
- }
- return literalNode;
+ //for e.g. ArrayLiteralNodes the initial types may have been narrowed due to the
+ //introduction of optimistic behavior - hence ensure that all literal nodes are
+ //reinitialized
+ return literalNode.initialize(lc);
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
index 3da0f778712..352270d05dd 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
@@ -75,7 +75,6 @@ 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.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -159,30 +158,6 @@ final class Lower extends NodeOperatorVisitor implements Lo
return context.getLogger(this.getClass());
}
- @Override
- public Node leaveBlock(final Block block) {
- //now we have committed the entire statement list to the block, but we need to truncate
- //whatever is after the last terminal. block append won't append past it
-
-
- if (lc.isFunctionBody()) {
- final FunctionNode currentFunction = lc.getCurrentFunction();
- final boolean isProgram = currentFunction.isProgram();
- final Statement last = lc.getLastStatement();
- final ReturnNode returnNode = new ReturnNode(
- last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO?
- currentFunction.getToken(),
- currentFunction.getFinish(),
- isProgram ?
- compilerConstant(RETURN) :
- LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
-
- returnNode.accept(this);
- }
-
- return block;
- }
-
@Override
public boolean enterBreakNode(final BreakNode breakNode) {
addStatement(breakNode);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java
index 8e7cfa3fd78..d4800f8a892 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java
@@ -63,13 +63,13 @@ public class MapCreator {
/**
* Constructs a property map based on a set of fields.
*
- * @param hasArguments does the created object have an "arguments" property
+ * @param hasArguments does the created object have an "arguments" property
* @param fieldCount Number of fields in use.
- * @param fieldMaximum Number of fields available.
- *
+ * @param fieldMaximum Number of fields available.
+ * @param evalCode is this property map created for 'eval' code?
* @return New map populated with accessor properties.
*/
- PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
+ PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum, final boolean evalCode) {
final List properties = new ArrayList<>();
assert tuples != null;
@@ -79,7 +79,7 @@ public class MapCreator {
final Class> initialType = tuple.getValueType();
if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
- final int flags = getPropertyFlags(symbol, hasArguments);
+ final int flags = getPropertyFlags(symbol, hasArguments, evalCode);
final Property property = new AccessorProperty(
key,
flags,
@@ -104,7 +104,7 @@ public class MapCreator {
//TODO initial type is object here no matter what. Is that right?
if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
- final int flags = getPropertyFlags(symbol, hasArguments);
+ final int flags = getPropertyFlags(symbol, hasArguments, false);
properties.add(
new SpillProperty(
key,
@@ -124,7 +124,7 @@ public class MapCreator {
*
* @return flags to use for fields
*/
- static int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
+ static int getPropertyFlags(final Symbol symbol, final boolean hasArguments, final boolean evalCode) {
int flags = 0;
if (symbol.isParam()) {
@@ -135,7 +135,13 @@ public class MapCreator {
flags |= Property.HAS_ARGUMENTS;
}
- if (symbol.isScope()) {
+ // See ECMA 5.1 10.5 Declaration Binding Instantiation.
+ // Step 2 If code is eval code, then let configurableBindings
+ // be true else let configurableBindings be false.
+ // We have to make vars, functions declared in 'eval' code
+ // configurable. But vars, functions from any other code is
+ // not configurable.
+ if (symbol.isScope() && !evalCode) {
flags |= Property.NOT_CONFIGURABLE;
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java b/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java
new file mode 100644
index 00000000000..b90fa026ddb
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java
@@ -0,0 +1,345 @@
+/*
+ * 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. 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.codegen;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.MessageDigest;
+import java.security.PrivilegedAction;
+import java.sql.Date;
+import java.text.SimpleDateFormat;
+import java.util.Base64;
+import java.util.Map;
+import java.util.TreeMap;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+import jdk.nashorn.internal.runtime.Source;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
+import jdk.nashorn.internal.runtime.options.Options;
+
+/**
+ * Static utility that encapsulates persistence of decompilation information for functions. Normally, the type info
+ * persistence feature is enabled and operates in an operating-system specific per-user cache directory. You can
+ * override the directory by specifying it in the {@code nashorn.typeInfo.cacheDir} directory. Also, you can disable the
+ * type info persistence altogether by specifying the {@code nashorn.typeInfo.disabled} system property.
+ */
+public final class OptimisticTypesPersistence {
+ private static final File cacheDir = createCacheDir();
+ // In-process locks to make sure we don't have a cross-thread race condition manipulating any file.
+ private static final Object[] locks = cacheDir == null ? null : createLockArray();
+
+ // Only report one read/write error every minute
+ private static final long ERROR_REPORT_THRESHOLD = 60000L;
+
+ private static volatile long lastReportedError;
+
+ /**
+ * Retrieves an opaque descriptor for the persistence location for a given function. It should be passed to
+ * {@link #load(Object)} and {@link #store(Object, Map)} methods.
+ * @param source the source where the function comes from
+ * @param functionId the unique ID number of the function within the source
+ * @param paramTypes the types of the function parameters (as persistence is per parameter type specialization).
+ * @return an opaque descriptor for the persistence location. Can be null if persistence is disabled.
+ */
+ public static Object getLocationDescriptor(final Source source, final int functionId, final Type[] paramTypes) {
+ if(cacheDir == null) {
+ return null;
+ }
+ final StringBuilder b = new StringBuilder(48);
+ // Base64-encode the digest of the source, and append the function id.
+ b.append(Base64.getUrlEncoder().encodeToString(source.getDigest())).append('-').append(functionId);
+ // Finally, if this is a parameter-type specialized version of the function, add the parameter types to the file
+ // name.
+ if(paramTypes != null && paramTypes.length > 0) {
+ b.append('-');
+ for(final Type t: paramTypes) {
+ b.append(t.getBytecodeStackType());
+ }
+ }
+ return new LocationDescriptor(new File(cacheDir, b.toString()));
+ }
+
+ private static final class LocationDescriptor {
+ private final File file;
+
+ LocationDescriptor(final File file) {
+ this.file = file;
+ }
+ }
+
+
+ /**
+ * Stores the map of optimistic types for a given function.
+ * @param locationDescriptor the opaque persistence location descriptor, retrieved by calling
+ * {@link #getLocationDescriptor(Source, int, Type[])}.
+ * @param optimisticTypes the map of optimistic types.
+ */
+ @SuppressWarnings("resource")
+ public static void store(final Object locationDescriptor, final Map optimisticTypes) {
+ if(locationDescriptor == null) {
+ return;
+ }
+ final File file = ((LocationDescriptor)locationDescriptor).file;
+ AccessController.doPrivileged(new PrivilegedAction() {
+ @Override
+ public Void run() {
+ synchronized(getFileLock(file)) {
+ try (final FileOutputStream out = new FileOutputStream(file);) {
+ out.getChannel().lock(); // lock exclusive
+ final DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(out));
+ dout.writeInt(optimisticTypes.size());
+ for(Map.Entry e: optimisticTypes.entrySet()) {
+ dout.writeInt(e.getKey());
+ final byte typeChar;
+ final Type type = e.getValue();
+ if(type == Type.OBJECT) {
+ typeChar = 'L';
+ } else if(type == Type.NUMBER) {
+ typeChar = 'D';
+ } else if(type == Type.LONG) {
+ typeChar = 'J';
+ } else {
+ throw new AssertionError();
+ }
+ dout.write(typeChar);
+ }
+ dout.flush();
+ } catch(final Exception e) {
+ reportError("write", file, e);
+ }
+ }
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Loads the map of optimistic types for a given function.
+ * @param locationDescriptor the opaque persistence location descriptor, retrieved by calling
+ * {@link #getLocationDescriptor(Source, int, Type[])}.
+ * @return the map of optimistic types, or null if persisted type information could not be retrieved.
+ */
+ @SuppressWarnings("resource")
+ public static Map load(final Object locationDescriptor) {
+ if (locationDescriptor == null) {
+ return null;
+ }
+ final File file = ((LocationDescriptor)locationDescriptor).file;
+
+ return AccessController.doPrivileged(new PrivilegedAction