提交 e333949d 编写于 作者: L lagergren

8033334: Make sure that scope depth information is maintained in the...

8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation
Summary: Compute RecompiledScriptFunctionDatas eagerly, annotate them with scope depth information and use them in recompilations.
Reviewed-by: attila, hannesw, jlaskey
上级 79120cfb
......@@ -52,10 +52,13 @@ import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
......@@ -139,6 +142,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
private final Set<Long> optimistic = new HashSet<>();
private final Set<Long> neverOptimistic = new HashSet<>();
private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
private int catchNestingLevel;
......@@ -454,7 +458,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
// Create and add to appropriate block.
symbol = new Symbol(name, flags);
symbol = createSymbol(name, flags);
symbolBlock.putSymbol(lc, symbol);
if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
......@@ -467,6 +471,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return symbol;
}
private Symbol createSymbol(final String name, final int flags) {
if ((flags & Symbol.KINDMASK) == IS_GLOBAL) {
//reuse global symbols so they can be hashed
Symbol global = globalSymbols.get(name);
if (global == null) {
global = new Symbol(name, flags);
globalSymbols.put(name, global);
}
return global;
}
return new Symbol(name, flags);
}
@Override
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
final Expression expr = expressionStatement.getExpression();
......@@ -555,10 +572,16 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
final int optimisticFlag = lc.hasOptimisticAssumptions() ? FunctionNode.IS_OPTIMISTIC : 0;
newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR).setFlag(lc, optimisticFlag);
popLocals();
if (!env.isOnDemandCompilation() && newFunctionNode.isProgram()) {
newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE));
assert newFunctionNode.getId() == 1;
}
return end(newFunctionNode, false);
}
......@@ -576,7 +599,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final IdentNode init = compilerConstant(initConstant);
assert init.getSymbol() != null && init.getSymbol().hasSlot();
VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init);
final VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init);
final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName());
assert nameSymbol != null;
......@@ -631,7 +654,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
maybeForceScope(symbol);
} else {
LOG.info("No symbol exists. Declare undefined: ", symbol);
symbol = defineSymbol(block, name, IS_GLOBAL);
symbol = defineGlobalSymbol(block, name);
// we have never seen this before, it can be undefined
newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
symbol.setCanBeUndefined();
......@@ -652,6 +675,10 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(node);
}
private Symbol defineGlobalSymbol(final Block block, final String name) {
return defineSymbol(block, name, IS_GLOBAL);
}
private boolean inCatch() {
return catchNestingLevel > 0;
}
......@@ -908,7 +935,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public boolean enterNOT(UnaryNode unaryNode) {
public boolean enterNOT(final UnaryNode unaryNode) {
tagNeverOptimistic(unaryNode.getExpression());
return true;
}
......@@ -1021,7 +1048,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(coerce(unaryNode, Type.BOOLEAN));
}
private IdentNode compilerConstant(CompilerConstants cc) {
private IdentNode compilerConstant(final CompilerConstants cc) {
return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc, lc.getCurrentFunction().compilerConstant(cc));
}
......@@ -1040,7 +1067,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
public Node leaveTYPEOF(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.getExpression();
List<Expression> args = new ArrayList<>();
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
args.add(compilerConstant(SCOPE));
args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
......@@ -1099,7 +1126,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
//which will be corrected in the post pass if unknown at this stage
Type argumentsType = Type.widest(lhs.getType(), rhs.getType());
if(argumentsType.getTypeClass() == String.class) {
if (argumentsType.getTypeClass() == String.class) {
assert binaryNode.isTokenType(TokenType.ADD);
argumentsType = Type.OBJECT;
}
......@@ -1151,7 +1178,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final Symbol symbol = findSymbol(block, name);
if (symbol == null) {
defineSymbol(block, name, IS_GLOBAL);
defineGlobalSymbol(block, name);
} else {
maybeForceScope(symbol);
}
......@@ -1169,7 +1196,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(ensureSymbol(binaryNode, type));
}
private boolean isLocal(FunctionNode function, Symbol symbol) {
private boolean isLocal(final FunctionNode function, final Symbol symbol) {
final FunctionNode definingFn = lc.getDefiningFunction(symbol);
// Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
return definingFn == null || definingFn == function;
......@@ -1372,7 +1399,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final Type type = Type.narrowest(lhs.getType(), rhs.getType(), Type.INT);
inferParameter(lhs, type);
inferParameter(rhs, type);
Type widest = Type.widest(lhs.getType(), rhs.getType());
final Type widest = Type.widest(lhs.getType(), rhs.getType());
ensureSymbol(lhs, widest);
ensureSymbol(rhs, widest);
return end(ensureSymbol(binaryNode, Type.BOOLEAN));
......@@ -1390,7 +1417,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public boolean enterEQ(BinaryNode binaryNode) {
public boolean enterEQ(final BinaryNode binaryNode) {
return enterBinaryArithmetic(binaryNode);
}
......@@ -1549,7 +1576,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public boolean enterForNode(ForNode forNode) {
public boolean enterForNode(final ForNode forNode) {
tagNeverOptimistic(forNode.getTest());
return true;
}
......@@ -1570,7 +1597,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public boolean enterTernaryNode(TernaryNode ternaryNode) {
public boolean enterTernaryNode(final TernaryNode ternaryNode) {
tagNeverOptimistic(ternaryNode.getTest());
return true;
}
......@@ -1675,7 +1702,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
newParams.add((IdentNode)param.setSymbol(lc, paramSymbol));
assert paramSymbol != null;
Type type = paramSymbol.getSymbolType();
final Type type = paramSymbol.getSymbolType();
// all param types are initialized to unknown
// first we check if we do have a type (inferred during generation)
......@@ -1705,7 +1732,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
}
FunctionNode newFunctionNode = functionNode;
final FunctionNode newFunctionNode = functionNode;
return newFunctionNode.setParameters(lc, newParams);
}
......@@ -1721,7 +1748,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
for (final Property property : map.getProperties()) {
final String key = property.getKey();
final Symbol symbol = defineSymbol(block, key, IS_GLOBAL);
final Symbol symbol = defineGlobalSymbol(block, key);
newType(symbol, Type.OBJECT);
LOG.info("Added global symbol from property map ", symbol);
}
......@@ -1761,9 +1788,11 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
if (node instanceof LiteralNode) {
return node;
}
Type from = node.getType();
final Type from = node.getType();
if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
if (LOG.isEnabled()) {
LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to);
}
Symbol symbol = node.getSymbol();
if (symbol.isShared() && symbol.wouldChangeType(to)) {
symbol = temporarySymbols.getTypedTemporarySymbol(to);
......@@ -1875,7 +1904,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public Node leaveTernaryNode(TernaryNode ternaryNode) {
public Node leaveTernaryNode(final TernaryNode ternaryNode) {
return widen(ternaryNode, Type.widest(ternaryNode.getTrueExpression().getType(), ternaryNode.getFalseExpression().getType()));
}
......@@ -1938,19 +1967,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
@Override
public boolean enterReturnNode(ReturnNode returnNode) {
public boolean enterReturnNode(final ReturnNode returnNode) {
tagOptimistic(returnNode.getExpression());
return true;
}
@Override
public boolean enterIfNode(IfNode ifNode) {
public boolean enterIfNode(final IfNode ifNode) {
tagNeverOptimistic(ifNode.getTest());
return true;
}
@Override
public boolean enterWhileNode(WhileNode whileNode) {
public boolean enterWhileNode(final WhileNode whileNode) {
tagNeverOptimistic(whileNode.getTest());
return true;
}
......@@ -1966,7 +1995,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
* @param expr an expression that is to be tagged as optimistic.
*/
private long tag(final Optimistic expr) {
return ((long)lc.getCurrentFunction().getId() << 32) | expr.getProgramPoint();
return (long)lc.getCurrentFunction().getId() << 32 | expr.getProgramPoint();
}
/**
......@@ -2000,7 +2029,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return optimistic.contains(tag(expr));
}
private Type getOptimisticType(Optimistic expr) {
private Type getOptimisticType(final Optimistic expr) {
return useOptimisticTypes() ? env.getOptimisticType(expr) : expr.getMostPessimisticType();
}
......@@ -2138,7 +2167,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
}
private BinaryNode coerce(final BinaryNode binaryNode, final Type pessimisticType, final Type argumentsType) {
BinaryNode newNode = ensureSymbolTypeOverride(binaryNode, pessimisticType, argumentsType);
final BinaryNode newNode = ensureSymbolTypeOverride(binaryNode, pessimisticType, argumentsType);
inferParameter(binaryNode.lhs(), newNode.getType());
inferParameter(binaryNode.rhs(), newNode.getType());
return newNode;
......@@ -2161,7 +2190,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
private static String name(final Node node) {
final String cn = node.getClass().getName();
int lastDot = cn.lastIndexOf('.');
final int lastDot = cn.lastIndexOf('.');
if (lastDot == -1) {
return cn;
}
......
......@@ -277,51 +277,52 @@ public class ClassEmitter implements Emitter {
}
// $getXXXX$array - get the ith entry from the constants table and cast to XXXX[].
for (final Class<?> cls : constantMethodNeeded) {
if (cls.isArray()) {
defineGetArrayMethod(cls);
for (final Class<?> clazz : constantMethodNeeded) {
if (clazz.isArray()) {
defineGetArrayMethod(clazz);
}
}
}
/**
* Constructs a primitive specific method for getting the ith entry from the constants table and cast.
* @param cls Array class.
* @param clazz Array class.
*/
private void defineGetArrayMethod(final Class<?> cls) {
private void defineGetArrayMethod(final Class<?> clazz) {
assert unitClassName != null;
final String methodName = getArrayMethodName(cls);
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class);
final String methodName = getArrayMethodName(clazz);
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class);
getArrayMethod.begin();
getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor())
.load(Type.INT, 0)
.arrayload()
.checkcast(cls)
.checkcast(clazz)
.dup()
.arraylength()
.invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class))
.invoke(staticCallNoLookup(Arrays.class, "copyOf", clazz, clazz, int.class))
._return();
getArrayMethod.end();
}
/**
* Generate the name of a get array from constant pool method.
* @param cls Name of array class.
* @param clazz Name of array class.
* @return Method name.
*/
static String getArrayMethodName(final Class<?> cls) {
assert cls.isArray();
return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
static String getArrayMethodName(final Class<?> clazz) {
assert clazz.isArray();
return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
}
/**
* Ensure a get constant method is issued for the class.
* @param cls Class of constant.
* @param clazz Class of constant.
*/
void needGetConstantMethod(final Class<?> cls) {
constantMethodNeeded.add(cls);
void needGetConstantMethod(final Class<?> clazz) {
constantMethodNeeded.add(clazz);
}
/**
......@@ -672,7 +673,7 @@ public class ClassEmitter implements Emitter {
}
}
private MethodVisitor methodVisitor(EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
private MethodVisitor methodVisitor(final EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null);
}
......
......@@ -50,10 +50,12 @@ public final class CompilationEnvironment {
private final ParamTypeMap paramTypes;
private final RecompilableScriptFunctionData compiledFunction;
private RecompilableScriptFunctionData compiledFunction;
private boolean strict;
private final boolean onDemand;
/**
* If this is a recompilation, this is how we pass in the invalidations, e.g. programPoint=17, Type == int means
* that using whatever was at program point 17 as an int failed.
......@@ -88,12 +90,13 @@ public final class CompilationEnvironment {
CompilationPhase.ATTRIBUTION_PHASE,
CompilationPhase.RANGE_ANALYSIS_PHASE,
CompilationPhase.TYPE_FINALIZATION_PHASE,
CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
CompilationPhase.BYTECODE_GENERATION_PHASE
};
private final static List<CompilationPhase> SEQUENCE_EAGER;
static {
LinkedList<CompilationPhase> eager = new LinkedList<>();
final LinkedList<CompilationPhase> eager = new LinkedList<>();
for (final CompilationPhase phase : SEQUENCE_EAGER_ARRAY) {
eager.add(phase);
}
......@@ -121,7 +124,7 @@ public final class CompilationEnvironment {
private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
final LinkedList<CompilationPhase> list = new LinkedList<>();
for (CompilationPhase p : phases) {
for (final CompilationPhase p : phases) {
list.add(p);
if (p == phase) {
list.add(newPhase);
......@@ -166,80 +169,90 @@ public final class CompilationEnvironment {
public CompilationEnvironment(
final CompilationPhases phases,
final boolean strict) {
this(phases, null, null, null, null, strict);
this(phases, null, null, null, null, strict, false);
}
/**
* Constructor for compilation environment of the rest-of method
* @param phases compilation phases
* @param strict strict mode
* @param recompiledFunction recompiled function
* @param continuationEntryPoint program points used as the continuation entry points in the current rest-of sequence
* @param invalidatedProgramPoints map of invalidated program points to their type
* @param compiledFunction recompiled function
* @param paramTypeMap known parameter types if any exist
* @param invalidatedProgramPoints map of invalidated program points to their type
* @param continuationEntryPoint program points used as the continuation entry points in the current rest-of sequence
* @param onDemand is this an on demand compilation
*/
public CompilationEnvironment(
final CompilationPhases phases,
final boolean strict,
final RecompilableScriptFunctionData recompiledFunction,
final RecompilableScriptFunctionData compiledFunction,
final ParamTypeMap paramTypeMap,
final Map<Integer, Type> invalidatedProgramPoints,
final int[] continuationEntryPoint) {
this(phases, paramTypeMap, invalidatedProgramPoints, recompiledFunction, continuationEntryPoint, strict);
final int[] continuationEntryPoint,
final boolean onDemand) {
this(phases, paramTypeMap, invalidatedProgramPoints, compiledFunction, continuationEntryPoint, strict, onDemand);
}
/**
* Constructor
* @param phases compilation phases
* @param strict strict mode
* @param recompiledFunction recompiled function
* @param compiledFunction recompiled function
* @param paramTypeMap known parameter types
* @param invalidatedProgramPoints map of invalidated program points to their type
* @param onDemand is this an on demand compilation
*/
public CompilationEnvironment(
final CompilationPhases phases,
final boolean strict,
final RecompilableScriptFunctionData recompiledFunction,
final RecompilableScriptFunctionData compiledFunction,
final ParamTypeMap paramTypeMap,
final Map<Integer, Type> invalidatedProgramPoints) {
this(phases, paramTypeMap, invalidatedProgramPoints, recompiledFunction, null, strict);
final Map<Integer, Type> invalidatedProgramPoints,
final boolean onDemand) {
this(phases, paramTypeMap, invalidatedProgramPoints, compiledFunction, null, strict, onDemand);
}
@SuppressWarnings("null")
private CompilationEnvironment(
final CompilationPhases phases,
final ParamTypeMap paramTypes,
final Map<Integer, Type> invalidatedProgramPoints,
final RecompilableScriptFunctionData compiledFunction,
final int[] continuationEntryPoints,
final boolean strict) {
final boolean strict,
final boolean onDemand) {
this.phases = phases;
this.paramTypes = paramTypes;
this.continuationEntryPoints = continuationEntryPoints;
this.continuationEntryPoints = continuationEntryPoints;
this.invalidatedProgramPoints =
invalidatedProgramPoints == null ?
Collections.unmodifiableMap(new HashMap<Integer, Type>()) :
invalidatedProgramPoints;
this.compiledFunction = compiledFunction;
this.compiledFunction = compiledFunction;
this.strict = strict;
this.optimistic = phases.contains(CompilationPhase.PROGRAM_POINT_PHASE);
this.onDemand = onDemand;
// If entry point array is passed, it must have at least one element
assert continuationEntryPoints == null || continuationEntryPoints.length > 0;
assert !isCompileRestOf() || isOnDemandCompilation(); // isCompileRestOf => isRecompilation
// continuation entry points must be among the invalidated program points
assert !isCompileRestOf() || (invalidatedProgramPoints != null && containsAll(invalidatedProgramPoints.keySet(), continuationEntryPoints));
assert !isCompileRestOf() || invalidatedProgramPoints != null && containsAll(invalidatedProgramPoints.keySet(), continuationEntryPoints);
}
private static boolean containsAll(Set<Integer> set, final int[] array) {
for(int i = 0; i < array.length; ++i) {
if(!set.contains(array[i])) {
private static boolean containsAll(final Set<Integer> set, final int[] array) {
for (int i = 0; i < array.length; ++i) {
if (!set.contains(array[i])) {
return false;
}
}
return true;
}
void setData(final RecompilableScriptFunctionData data) {
assert this.compiledFunction == null : data;
this.compiledFunction = data;
}
boolean isStrict() {
return strict;
}
......@@ -291,7 +304,7 @@ public final class CompilationEnvironment {
* @return true if this is an on-demand compilation, false if this is an eager compilation.
*/
boolean isOnDemandCompilation() {
return compiledFunction != null;
return onDemand; //data != null;
}
/**
......@@ -300,9 +313,9 @@ public final class CompilationEnvironment {
* @return true if it is a continuation entry point
*/
boolean isContinuationEntryPoint(final int programPoint) {
if(continuationEntryPoints != null) {
for(int i = 0; i < continuationEntryPoints.length; ++i) {
if(continuationEntryPoints[i] == programPoint) {
if (continuationEntryPoints != null) {
for (final int continuationEntryPoint : continuationEntryPoints) {
if (continuationEntryPoint == programPoint) {
return true;
}
}
......@@ -338,7 +351,6 @@ public final class CompilationEnvironment {
* @return most optimistic type in current environment
*/
Type getOptimisticType(final Optimistic node) {
assert useOptimisticTypes();
final Type invalidType = invalidatedProgramPoints.get(node.getProgramPoint());
if (invalidType != null) {
......
......@@ -6,6 +6,7 @@ import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SCOPE_DEPTHS_COMPUTED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
import java.util.ArrayDeque;
......@@ -13,6 +14,7 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.EnumSet;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Expression;
......@@ -120,10 +122,14 @@ enum CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final TemporarySymbols ts = compiler.getTemporarySymbols();
final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(compiler.getCompilationEnvironment(), ts));
final FunctionNode newFunctionNode =
(FunctionNode)enterAttr(fn, ts).
accept(new Attr(compiler.getCompilationEnvironment(), ts));
if (compiler.getEnv()._print_mem_usage) {
Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
}
return newFunctionNode;
}
......@@ -271,12 +277,24 @@ enum CompilationPhase {
}
},
SCOPE_DEPTH_COMPUTATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
return (FunctionNode)fn.accept(new FindScopeDepths(compiler));
}
@Override
public String toString() {
return "[Scope Depth Computation]";
}
},
/**
* Bytecode generation:
*
* Generate the byte code class(es) resulting from the compiled FunctionNode
*/
BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) {
BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED, SCOPE_DEPTHS_COMPUTED)) {
@Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv();
......
......@@ -170,6 +170,16 @@ public enum CompilerConstants {
/** get array suffix */
GET_ARRAY_SUFFIX("$array");
/** To save memory - intern the compiler constant symbol names, as they are frequently reused */
static {
for (final CompilerConstants c : values()) {
final String symbolName = c.symbolName();
if (symbolName != null) {
symbolName.intern();
}
}
}
/**
* Prefix used for internal methods generated in script clases.
*/
......
/*
* 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. 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 static jdk.nashorn.internal.codegen.ObjectClassGenerator.getClassName;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
/**
* Establishes depth of scope for non local symbols at the start of method.
* If this is a recompilation, the previous data from eager compilation is
* stored in the RecompilableScriptFunctionData and is transferred to the
* FunctionNode being compiled
*/
final class FindScopeDepths extends NodeVisitor<LexicalContext> {
private final Compiler compiler;
private final CompilationEnvironment env;
private final Map<Integer, Map<Integer, RecompilableScriptFunctionData>> fnIdToNestedFunctions = new HashMap<>();
private final Map<Integer, Map<String, Integer>> externalSymbolDepths = new HashMap<>();
FindScopeDepths(final Compiler compiler) {
super(new LexicalContext());
this.compiler = compiler;
this.env = compiler.getCompilationEnvironment();
}
static int findScopesToStart(final LexicalContext lc, final FunctionNode fn, final Block block) {
final Block bodyBlock = findBodyBlock(lc, fn, block);
final Iterator<Block> iter = lc.getBlocks(block);
Block b = iter.next();
int scopesToStart = 0;
while (true) {
if (b.needsScope()) {
scopesToStart++;
}
if (b == bodyBlock) {
break;
}
b = iter.next();
}
return scopesToStart;
}
static int findInternalDepth(final LexicalContext lc, final FunctionNode fn, final Block block, final Symbol symbol) {
final Block bodyBlock = findBodyBlock(lc, fn, block);
final Iterator<Block> iter = lc.getBlocks(block);
Block b = iter.next();
int scopesToStart = 0;
while (true) {
if (definedInBlock(b, symbol)) {
return scopesToStart;
}
if (b.needsScope()) {
scopesToStart++;
}
if (b == bodyBlock) {
break; //don't go past body block, but process it
}
b = iter.next();
}
return -1;
}
private static boolean definedInBlock(final Block block, final Symbol symbol) {
if (symbol.isGlobal()) {
if (block.isGlobalScope()) {
return true;
}
//globals cannot be defined anywhere else
return false;
}
return block.getExistingSymbol(symbol.getName()) == symbol;
}
static Block findBodyBlock(final LexicalContext lc, final FunctionNode fn, final Block block) {
final Iterator<Block> iter = lc.getBlocks(block);
while (iter.hasNext()) {
final Block next = iter.next();
if (fn.getBody() == next) {
return next;
}
}
return null;
}
private static Block findGlobalBlock(final LexicalContext lc, final FunctionNode fn, final Block block) {
final Iterator<Block> iter = lc.getBlocks(block);
Block globalBlock = null;
while (iter.hasNext()) {
globalBlock = iter.next();
}
return globalBlock;
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if (env.isOnDemandCompilation()) {
return true;
}
final int fnId = functionNode.getId();
Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
if (nestedFunctions == null) {
nestedFunctions = new HashMap<>();
fnIdToNestedFunctions.put(fnId, nestedFunctions);
}
return true;
}
//external symbols hold the scope depth of sc11 from global at the start of the method
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.SCOPE_DEPTHS_COMPUTED);
if (env.isOnDemandCompilation()) {
final RecompilableScriptFunctionData data = env.getScriptFunctionData(newFunctionNode.getId());
assert data != null : newFunctionNode.getName() + " lacks data";
return newFunctionNode;
}
//create recompilable scriptfunctiondata
final int fnId = newFunctionNode.getId();
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
assert nestedFunctions != null;
// Generate the object class and property map in case this function is ever used as constructor
final int fieldCount = getPaddedFieldCount(newFunctionNode.countThisProperties());
final String allocatorClassName = Compiler.binaryName(getClassName(fieldCount));
final PropertyMap allocatorMap = PropertyMap.newMap(null, 0, fieldCount, 0);
final RecompilableScriptFunctionData data = new RecompilableScriptFunctionData(
newFunctionNode,
compiler.getCodeInstaller(),
allocatorClassName,
allocatorMap,
nestedFunctions,
compiler.getSourceURL(),
externalSymbolDepths.get(fnId)
);
if (lc.getOutermostFunction() != newFunctionNode) {
final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
if (parentFn != null) {
fnIdToNestedFunctions.get(parentFn.getId()).put(fnId, data);
}
} else {
env.setData(data);
}
return newFunctionNode;
}
@Override
public boolean enterBlock(final Block block) {
if (env.isOnDemandCompilation()) {
return true;
}
if (!lc.isFunctionBody()) {
return true;
}
//the below part only happens on eager compilation when we have the entire hierarchy
//block is a function body
final FunctionNode fn = lc.getCurrentFunction();
//get all symbols that are referenced inside this function body
final Set<Symbol> symbols = new HashSet<>();
block.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public final boolean enterDefault(final Node node) {
if (!env.isOnDemandCompilation()) {
if (node instanceof Expression) {
final Symbol symbol = ((Expression)node).getSymbol();
if (symbol != null && symbol.isScope()) {
//if this is an internal symbol, skip it.
symbols.add(symbol);
}
}
}
return true;
}
});
final Map<String, Integer> internals = new HashMap<>();
for (final Symbol symbol : symbols) {
Iterator<Block> iter;
final Block globalBlock = findGlobalBlock(lc, fn, block);
final Block bodyBlock = findBodyBlock(lc, fn, block);
assert globalBlock != null;
assert bodyBlock != null;
final int internalDepth = findInternalDepth(lc, fn, block, symbol);
final boolean internal = internalDepth >= 0;
if (internal) {
internals.put(symbol.getName(), internalDepth);
}
// if not internal, we have to continue walking until we reach the top. We
// start outside the body and each new scope adds a depth count. When we
// find the symbol, we store its depth count
if (!internal) {
int depthAtStart = 0;
//not internal - keep looking.
iter = lc.getAncestorBlocks(bodyBlock);
while (iter.hasNext()) {
final Block b2 = iter.next();
if (definedInBlock(b2, symbol)) {
addExternalSymbol(fn, symbol, depthAtStart);
break;
}
if (b2.needsScope()) {
depthAtStart++;
}
}
}
}
return true;
}
private void addExternalSymbol(final FunctionNode functionNode, final Symbol symbol, final int depthAtStart) {
final int fnId = functionNode.getId();
Map<String, Integer> depths = externalSymbolDepths.get(fnId);
if (depths == null) {
depths = new HashMap<>();
externalSymbolDepths.put(fnId, depths);
}
//System.err.println("PUT " + functionNode.getName() + " " + symbol + " " +depthAtStart);
depths.put(symbol.getName(), depthAtStart);
}
}
......@@ -44,6 +44,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPEQ;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ACMPNE;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPNE;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGT;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLE;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPLT;
import static jdk.internal.org.objectweb.asm.Opcodes.INSTANCEOF;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
......@@ -1570,6 +1574,16 @@ public class MethodEmitter implements Emitter {
jump(IFLT, label, 1);
}
/**
* Generate an if_icmplt
*
* @param label label to true case
*/
void if_icmplt(final Label label) {
debug("if_icmplt", label);
jump(IF_ICMPLT, label, 2);
}
/**
* Generate an ifle
*
......@@ -1580,6 +1594,16 @@ public class MethodEmitter implements Emitter {
jump(IFLE, label, 1);
}
/**
* Generate an if_icmple
*
* @param label label to true case
*/
void if_icmple(final Label label) {
debug("if_icmple", label);
jump(IF_ICMPLE, label, 2);
}
/**
* Generate an ifgt
*
......@@ -1590,6 +1614,16 @@ public class MethodEmitter implements Emitter {
jump(IFGT, label, 1);
}
/**
* Generate an if_icmpgt
*
* @param label label to true case
*/
void if_icmpgt(final Label label) {
debug("if_icmpgt", label);
jump(IF_ICMPGT, label, 2);
}
/**
* Generate an ifge
*
......@@ -1600,6 +1634,16 @@ public class MethodEmitter implements Emitter {
jump(IFGE, label, 1);
}
/**
* Generate an if_icmpge
*
* @param label label to true case
*/
void if_icmpge(final Label label) {
debug("if_icmpge", label);
jump(IF_ICMPGE, label, 2);
}
/**
* Unconditional jump to a label
*
......@@ -1995,7 +2039,7 @@ public class MethodEmitter implements Emitter {
}
private static String getProgramPoint(int flags) {
private static String getProgramPoint(final int flags) {
if((flags & CALLSITE_OPTIMISTIC) == 0) {
return "";
}
......
......@@ -165,12 +165,10 @@ class SharedScopeCall {
method.loadNull();
int slot = 2;
for (final Type type : paramTypes) {
method.load(type, slot++);
if (type == Type.NUMBER || type == Type.LONG) {
slot++;
}
method.load(type, slot);
slot += type.getSlots();
}
// Shared scope calls disabled in optimistic world.
// Shared scope calls disabled in optimistic world. TODO is this right?
method.dynamicCall(returnType, 2 + paramTypes.length, flags);
}
......
......@@ -58,6 +58,7 @@ import java.util.concurrent.ConcurrentMap;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
......@@ -224,7 +225,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
case jdk.internal.org.objectweb.asm.Type.OBJECT:
try {
return Type.typeFor(Class.forName(itype.getClassName()));
} catch(ClassNotFoundException e) {
} catch(final ClassNotFoundException e) {
throw new AssertionError(e);
}
case jdk.internal.org.objectweb.asm.Type.VOID:
......@@ -424,7 +425,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
* @return true if types are equivalent, false otherwise
*/
public boolean isEquivalentTo(final Type type) {
return this.weight() == type.weight() || (isObject() && type.isObject());
return this.weight() == type.weight() || isObject() && type.isObject();
}
/**
......@@ -778,6 +779,11 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
*/
public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class));
/**
* This is the singleton for ScriptObjects
*/
public static final Type SCRIPT_OBJECT = putInCache(new ObjectType(ScriptObject.class));
/**
* This is the singleton for integer arrays
*/
......
......@@ -76,6 +76,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
*/
public static final int IS_TERMINAL = 1 << 2;
/**
* Is this block the eager global scope - i.e. the original program. This isn't true for the
* outermost level of recompiles
*/
public static final int IS_GLOBAL_SCOPE = 1 << 3;
/**
* Constructor
*
......@@ -91,7 +97,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
this.entryLabel = new Label("block_entry");
this.breakLabel = new Label("block_break");
final int len = statements.length;
this.flags = (len > 0 && statements[len - 1].hasTerminalFlags()) ? IS_TERMINAL : 0;
this.flags = len > 0 && statements[len - 1].hasTerminalFlags() ? IS_TERMINAL : 0;
}
/**
......@@ -115,6 +121,15 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
this.finish = finish;
}
/**
* Is this block the outermost eager global scope - i.e. the primordial program?
* Used for global anchor point for scope depth computation for recompilation code
* @return true if outermost eager global scope
*/
public boolean isGlobalScope() {
return getFlag(IS_GLOBAL_SCOPE);
}
/**
* Clear the symbols in a block
* TODO: make this immutable
......@@ -292,7 +307,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
}
@Override
public Block setFlags(final LexicalContext lc, int flags) {
public Block setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) {
return this;
}
......@@ -300,12 +315,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
}
@Override
public Block clearFlag(final LexicalContext lc, int flag) {
public Block clearFlag(final LexicalContext lc, final int flag) {
return setFlags(lc, flags & ~flag);
}
@Override
public Block setFlag(final LexicalContext lc, int flag) {
public Block setFlag(final LexicalContext lc, final int flag) {
return setFlags(lc, flags | flag);
}
......@@ -354,7 +369,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
}
@Override
public Node accept(NodeVisitor<? extends LexicalContext> visitor) {
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
return Acceptor.accept(this, visitor);
}
}
......@@ -32,6 +32,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
......@@ -84,6 +85,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
SPLIT,
/** method has had its types finalized */
FINALIZED,
/** computed scope depths for symbols */
SCOPE_DEPTHS_COMPUTED,
/** method has been emitted to bytecode */
EMITTED
}
......@@ -139,6 +142,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
/** //@ sourceURL or //# sourceURL for program function nodes */
private final String sourceURL;
/** Line number of function start */
private final int lineNumber;
/** Is anonymous function flag. */
......@@ -214,8 +218,11 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
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 = 1;
public static final int FIRST_FUNCTION_ID = NO_FUNCTION_ID + 1;
/** What is the return type of this function? */
private Type returnType = Type.UNKNOWN;
......@@ -275,7 +282,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final FunctionNode functionNode,
final long lastToken,
final int flags,
String sourceURL,
final String sourceURL,
final String name,
final Type returnType,
final CompileUnit compileUnit,
......@@ -335,7 +342,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @return name for the script source
*/
public String getSourceName() {
return (sourceURL != null)? sourceURL : source.getName();
return sourceURL != null? sourceURL : source.getName();
}
/**
......@@ -472,7 +479,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
}
@Override
public FunctionNode setFlags(final LexicalContext lc, int flags) {
public FunctionNode setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) {
return this;
}
......@@ -700,7 +707,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return name;
}
/**
* Set the internal name for this function
* @param lc lexical context
......@@ -823,7 +829,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
type,
compileUnit,
compilationState,
body.setReturnType(type), parameters));
body.setReturnType(type),
parameters
));
}
/**
......
......@@ -235,7 +235,7 @@ public class LexicalContext {
public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) {
for (int i = sp - 1; i >= 0; i--) {
if (stack[i] == oldNode) {
assert i == (sp - 1) : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it";
assert i == sp - 1 : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it";
stack[i] = newNode;
break;
}
......@@ -269,6 +269,17 @@ public class LexicalContext {
return iter.hasNext() ? iter.next() : null;
}
/*
public FunctionNode getProgram() {
final Iterator<FunctionNode> iter = getFunctions();
FunctionNode last = null;
while (iter.hasNext()) {
last = iter.next();
}
assert last != null;
return last;
}*/
/**
* Returns an iterator over all ancestors block of the given block, with its parent block first.
* @param block the block whose ancestors are returned
......@@ -381,7 +392,7 @@ public class LexicalContext {
* @param symbol symbol
* @return function node in which this symbol is defined, assert if no such symbol exists in context
*/
public FunctionNode getDefiningFunction(Symbol symbol) {
public FunctionNode getDefiningFunction(final Symbol symbol) {
if (symbol.isTemp()) {
return null;
}
......@@ -392,7 +403,7 @@ public class LexicalContext {
while (iter.hasNext()) {
final LexicalContextNode next2 = iter.next();
if (next2 instanceof FunctionNode) {
return ((FunctionNode)next2);
return (FunctionNode)next2;
}
}
throw new AssertionError("Defining block for symbol " + name + " has no function in the context");
......@@ -437,11 +448,11 @@ public class LexicalContext {
int n = 0;
for (final Iterator<LexicalContextNode> iter = getAllNodes(); iter.hasNext();) {
final LexicalContextNode node = iter.next();
if(node == until) {
if (node == until) {
break;
}
assert !(node instanceof FunctionNode); // Can't go outside current function
if(node instanceof WithNode || (node instanceof Block && ((Block)node).needsScope())) {
if (node instanceof WithNode || node instanceof Block && ((Block)node).needsScope()) {
n++;
}
}
......@@ -618,7 +629,7 @@ public class LexicalContext {
if (next == null) {
throw new NoSuchElementException();
}
T lnext = next;
final T lnext = next;
next = findNext();
return lnext;
}
......
......@@ -31,6 +31,7 @@ import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context;
......@@ -109,7 +110,7 @@ public final class Symbol implements Comparable<Symbol> {
if (stacktrace != null) {
trace = stacktrace; //stacktrace always implies trace as well
TRACE_SYMBOLS_STACKTRACE = new HashSet<>();
for (StringTokenizer st = new StringTokenizer(stacktrace, ","); st.hasMoreTokens(); ) {
for (final StringTokenizer st = new StringTokenizer(stacktrace, ","); st.hasMoreTokens(); ) {
TRACE_SYMBOLS_STACKTRACE.add(st.nextToken());
}
} else {
......@@ -119,7 +120,7 @@ public final class Symbol implements Comparable<Symbol> {
if (trace != null) {
TRACE_SYMBOLS = new HashSet<>();
for (StringTokenizer st = new StringTokenizer(trace, ","); st.hasMoreTokens(); ) {
for (final StringTokenizer st = new StringTokenizer(trace, ","); st.hasMoreTokens(); ) {
TRACE_SYMBOLS.add(st.nextToken());
}
} else {
......@@ -351,7 +352,7 @@ public final class Symbol implements Comparable<Symbol> {
* @return true if this is scoped
*/
public boolean isScope() {
assert ((flags & KINDMASK) != IS_GLOBAL) || ((flags & IS_SCOPE) == IS_SCOPE) : "global without scope flag";
assert (flags & KINDMASK) != IS_GLOBAL || (flags & IS_SCOPE) == IS_SCOPE : "global without scope flag";
return (flags & IS_SCOPE) == IS_SCOPE;
}
......
......@@ -39,6 +39,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
......@@ -48,6 +49,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader;
import jdk.internal.org.objectweb.asm.util.Printer;
import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Pretty printer for --print-code.
......@@ -160,8 +162,8 @@ public final class NashornTextifier extends Printer {
}
if (interfaces != null && interfaces.length > 0) {
sb.append(" implements ");
for (int i = 0; i < interfaces.length; ++i) {
appendDescriptor(sb, INTERNAL_NAME, interfaces[i]);
for (final String interface1 : interfaces) {
appendDescriptor(sb, INTERNAL_NAME, interface1);
sb.append(' ');
}
}
......@@ -222,8 +224,8 @@ public final class NashornTextifier extends Printer {
sb.append(tab);
appendDescriptor(sb, FIELD_SIGNATURE, signature);
TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature);
final TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
final SignatureReader r = new SignatureReader(signature);
r.acceptType(sv);
sb.append(tab).
append("// declaration: ").
......@@ -249,7 +251,7 @@ public final class NashornTextifier extends Printer {
sb.append(";\n");
addText(sb);
NashornTextifier t = createNashornTextifier();
final NashornTextifier t = createNashornTextifier();
addText(t.getText());
return t;
......@@ -280,12 +282,12 @@ public final class NashornTextifier extends Printer {
sb.append(tab);
appendDescriptor(sb, METHOD_SIGNATURE, signature);
TraceSignatureVisitor v = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature);
final TraceSignatureVisitor v = new TraceSignatureVisitor(0);
final SignatureReader r = new SignatureReader(signature);
r.accept(v);
String genericDecl = v.getDeclaration();
String genericReturn = v.getReturnType();
String genericExceptions = v.getExceptions();
final String genericDecl = v.getDeclaration();
final String genericReturn = v.getReturnType();
final String genericExceptions = v.getExceptions();
sb.append(tab).
append("// declaration: ").
......@@ -316,8 +318,8 @@ public final class NashornTextifier extends Printer {
appendDescriptor(sb, METHOD_DESCRIPTOR, desc);
if (exceptions != null && exceptions.length > 0) {
sb.append(" throws ");
for (int i = 0; i < exceptions.length; ++i) {
appendDescriptor(sb, INTERNAL_NAME, exceptions[i]);
for (final String exception : exceptions) {
appendDescriptor(sb, INTERNAL_NAME, exception);
sb.append(' ');
}
}
......@@ -325,7 +327,7 @@ public final class NashornTextifier extends Printer {
sb.append('\n');
addText(sb);
NashornTextifier t = createNashornTextifier();
final NashornTextifier t = createNashornTextifier();
addText(t.getText());
return t;
}
......@@ -345,7 +347,7 @@ public final class NashornTextifier extends Printer {
final StringBuilder sb = new StringBuilder();
sb.append(tab2).append("// parameter ");
appendAccess(sb, access);
sb.append(' ').append((name == null) ? "<no name>" : name)
sb.append(' ').append(name == null ? "<no name>" : name)
.append('\n');
addText(sb);
}
......@@ -393,11 +395,11 @@ public final class NashornTextifier extends Printer {
}
private StringBuilder appendOpcode(final StringBuilder sb, final int opcode) {
Label next = labelIter == null ? null : labelIter.next();
final Label next = labelIter == null ? null : labelIter.next();
if (next instanceof NashornLabel) {
final int bci = next.getOffset();
if (bci != -1) {
String bcis = "" + bci;
final String bcis = "" + bci;
for (int i = 0; i < 5 - bcis.length(); i++) {
sb.append(' ');
}
......@@ -480,7 +482,6 @@ public final class NashornTextifier extends Printer {
}
sb.append(" [");
appendHandle(sb, bsm);
sb.append(" args=");
if (bsmArgs.length == 0) {
sb.append("none");
} else {
......@@ -492,12 +493,12 @@ public final class NashornTextifier extends Printer {
} else if (cst instanceof Handle) {
appendHandle(sb, (Handle)cst);
} else if (cst instanceof Integer) {
int c = (Integer)cst;
int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT;
final int c = (Integer)cst;
final int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT;
if (pp != 0) {
sb.append("pp=").append(pp).append(' ');
sb.append(" pp=").append(pp);
}
sb.append("0x").append(Integer.toHexString(c & FLAGS_MASK));
sb.append(NashornCallSiteDescriptor.toString(c & FLAGS_MASK));
} else {
sb.append(cst);
}
......@@ -539,7 +540,7 @@ public final class NashornTextifier extends Printer {
public void visitJumpInsn(final int opcode, final Label label) {
final StringBuilder sb = new StringBuilder();
appendOpcode(sb, opcode).append(' ');
String to = appendLabel(sb, label);
final String to = appendLabel(sb, label);
sb.append('\n');
addText(sb);
checkNoFallThru(opcode, to);
......@@ -556,7 +557,7 @@ public final class NashornTextifier extends Printer {
public void visitLabel(final Label label) {
final StringBuilder sb = new StringBuilder();
sb.append("\n");
String name = appendLabel(sb, label);
final String name = appendLabel(sb, label);
sb.append(" [bci=");
sb.append(label.info);
sb.append("]");
......@@ -689,8 +690,8 @@ public final class NashornTextifier extends Printer {
sb.append(tab2);
appendDescriptor(sb, FIELD_SIGNATURE, signature);
TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature);
final TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
final SignatureReader r = new SignatureReader(signature);
r.acceptType(sv);
sb.append(tab2).append("// declaration: ")
.append(sv.getDeclaration()).append('\n');
......@@ -718,7 +719,7 @@ public final class NashornTextifier extends Printer {
private void printToDir(final Graph g) {
if (env._print_code_dir != null) {
File dir = new File(env._print_code_dir);
final File dir = new File(env._print_code_dir);
if (!dir.exists() && !dir.mkdirs()) {
throw new RuntimeException(dir.toString());
}
......@@ -726,14 +727,14 @@ public final class NashornTextifier extends Printer {
File file;
int uniqueId = 0;
do {
String fileName = g.getName() + (uniqueId == 0 ? "" : "_" + uniqueId) + ".dot";
final String fileName = g.getName() + (uniqueId == 0 ? "" : "_" + uniqueId) + ".dot";
file = new File(dir, fileName);
uniqueId++;
} while (file.exists());
try (PrintWriter pw = new PrintWriter(new FileOutputStream(file))) {
pw.println(g);
} catch (FileNotFoundException e) {
} catch (final FileNotFoundException e) {
throw new RuntimeException(e);
}
}
......@@ -869,7 +870,7 @@ public final class NashornTextifier extends Printer {
sb.append(' ');
}
if (o[i] instanceof String) {
String desc = (String) o[i];
final String desc = (String) o[i];
if (desc.startsWith("[")) {
appendDescriptor(sb, FIELD_DESCRIPTOR, desc);
} else {
......@@ -926,7 +927,7 @@ public final class NashornTextifier extends Printer {
}
}
} else {
int lastSlash = desc.lastIndexOf('/');
final int lastSlash = desc.lastIndexOf('/');
sb.append(lastSlash == -1 ? desc : desc.substring(lastSlash + 1));
}
}
......@@ -934,7 +935,7 @@ public final class NashornTextifier extends Printer {
private static void appendStr(final StringBuilder sb, final String s) {
sb.append('\"');
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
final char c = s.charAt(i);
if (c == '\n') {
sb.append("\\n");
} else if (c == '\r') {
......@@ -1056,7 +1057,7 @@ public final class NashornTextifier extends Printer {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
final StringBuilder sb = new StringBuilder();
sb.append("digraph " + name + " {");
sb.append("\n");
sb.append("\tgraph [fontname=courier]\n");
......@@ -1083,7 +1084,7 @@ public final class NashornTextifier extends Printer {
}
for (final String from : edges.keySet()) {
for (String to : edges.get(from)) {
for (final String to : edges.get(from)) {
sb.append("\t");
sb.append(from);
sb.append(" -> ");
......
......@@ -61,6 +61,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace;
......@@ -270,7 +271,7 @@ public class Parser extends AbstractParser {
final String end = this + " end '" + scriptName + "'";
if (Timing.isEnabled()) {
Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms");
LOG.info(end, "' in ", System.currentTimeMillis() - t0, " ms");
} else {
LOG.info(end);
}
......@@ -314,7 +315,7 @@ public class Parser extends AbstractParser {
try {
stream = new TokenStream();
lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
int functionLine = line;
final int functionLine = line;
// Set up first token (skips opening EOL.)
k = -1;
......@@ -1076,7 +1077,7 @@ loop:
// If is a statement then handle end of line.
if (isStatement) {
boolean semicolon = type == SEMICOLON;
final boolean semicolon = type == SEMICOLON;
endOfLine();
if (semicolon) {
lc.getCurrentBlock().setFinish(finish);
......@@ -2663,7 +2664,7 @@ loop:
private String getDefaultValidFunctionName(final int functionLine) {
final String defaultFunctionName = getDefaultFunctionName();
return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : (ANON_FUNCTION_PREFIX.symbolName() + functionLine);
return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine;
}
private static boolean isValidIdentifier(String name) {
......
......@@ -264,7 +264,7 @@ final class CompiledFunction {
return betterThanFinal(type(), other.type(), callSiteMethodType);
}
static boolean betterThanFinal(final MethodType thisMethodType, MethodType otherMethodType, final MethodType callSiteMethodType) {
static boolean betterThanFinal(final MethodType thisMethodType, final MethodType otherMethodType, final MethodType callSiteMethodType) {
final int thisParamCount = getParamCount(thisMethodType);
final int otherParamCount = getParamCount(otherMethodType);
final int callSiteRawParamCount = getParamCount(callSiteMethodType);
......@@ -389,7 +389,7 @@ final class CompiledFunction {
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical
}
private static Type[] toTypeWithoutCallee(final MethodType type, int thisIndex) {
private static Type[] toTypeWithoutCallee(final MethodType type, final int thisIndex) {
final int paramCount = type.parameterCount();
final Type[] t = new Type[paramCount - thisIndex];
for(int i = thisIndex; i < paramCount; ++i) {
......@@ -398,7 +398,7 @@ final class CompiledFunction {
return t;
}
private static Type getParamType(int i, Type[] paramTypes, boolean isVarArg) {
private static Type getParamType(final int i, final Type[] paramTypes, final boolean isVarArg) {
final int fixParamCount = paramTypes.length - (isVarArg ? 1 : 0);
if(i < fixParamCount) {
return paramTypes[i];
......@@ -424,8 +424,8 @@ final class CompiledFunction {
final boolean csIsVarArg = csParamCount == Integer.MAX_VALUE;
final int thisThisIndex = needsCallee() ? 1 : 0; // Index of "this" parameter in this function's type
int fnParamCountNoCallee = fnParamCount - thisThisIndex;
int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1
final int fnParamCountNoCallee = fnParamCount - thisThisIndex;
final int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1
// We must match all incoming parameters, except "this". Starting from 1 to skip "this".
for(int i = 1; i < minParams; ++i) {
final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
......@@ -464,7 +464,7 @@ final class CompiledFunction {
return optimismInfo != null;
}
private MethodHandle createComposableInvoker(boolean isConstructor) {
private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them
......@@ -498,7 +498,7 @@ final class CompiledFunction {
cs.setTarget(target);
}
private MethodHandle getInvokerOrConstructor(boolean selectCtor) {
private MethodHandle getInvokerOrConstructor(final boolean selectCtor) {
return selectCtor ? getConstructor() : createInvokerForPessimisticCaller();
}
......@@ -535,7 +535,7 @@ final class CompiledFunction {
return MH.foldArguments(RESTOF_INVOKER, MH.insertArguments(HANDLE_REWRITE_EXCEPTION, 0, this, optimismInfo));
}
private static MethodHandle changeReturnType(MethodHandle mh, Class<?> newReturnType) {
private static MethodHandle changeReturnType(final MethodHandle mh, final Class<?> newReturnType) {
return Bootstrap.getLinkerServices().asType(mh, mh.type().changeReturnType(newReturnType));
}
......@@ -571,7 +571,9 @@ final class CompiledFunction {
//is recompiled
assert optimismInfo == oldOptimismInfo;
isOptimistic = fn.isOptimistic();
LOG.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ")", isOptimistic ? " remains optimistic." : " is no longer optimistic.");
if (LOG.isEnabled()) {
LOG.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ")", isOptimistic ? " remains optimistic." : " is no longer optimistic.");
}
final MethodHandle newInvoker = oldOptimismInfo.data.lookup(fn);
invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType()));
constructor = null; // Will be regenerated when needed
......
......@@ -197,7 +197,7 @@ public final class Context {
*/
public static PrintWriter getCurrentErr() {
final ScriptObject global = getGlobalTrusted();
return (global != null)? global.getContext().getErr() : new PrintWriter(System.err);
return global != null ? global.getContext().getErr() : new PrintWriter(System.err);
}
/**
......@@ -423,7 +423,7 @@ public final class Context {
* @return the return value of the {@code eval}
*/
public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) {
final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString();
final String file = location == UNDEFINED || location == null ? "<eval>" : location.toString();
final Source source = new Source(file, string);
final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
final ScriptObject global = Context.getGlobalTrusted();
......@@ -468,10 +468,10 @@ public final class Context {
scope = strictEvalScope;
}
ScriptFunction func = getProgramFunction(clazz, scope);
final ScriptFunction func = getProgramFunction(clazz, scope);
Object evalThis;
if (directEval) {
evalThis = (callThis instanceof ScriptObject || strictFlag) ? callThis : global;
evalThis = callThis instanceof ScriptObject || strictFlag ? callThis : global;
} else {
evalThis = global;
}
......@@ -490,7 +490,7 @@ public final class Context {
public Source run() {
try {
final URL resURL = Context.class.getResource(resource);
return (resURL != null)? new Source(srcStr, resURL) : null;
return resURL != null ? new Source(srcStr, resURL) : null;
} catch (final IOException exp) {
return null;
}
......@@ -513,7 +513,7 @@ public final class Context {
* @throws IOException if source cannot be found or loaded
*/
public Object load(final ScriptObject scope, final Object from) throws IOException {
final Object src = (from instanceof ConsString)? from.toString() : from;
final Object src = from instanceof ConsString ? from.toString() : from;
Source source = null;
// load accepts a String (which could be a URL or a file name), a File, a URL
......@@ -521,8 +521,8 @@ public final class Context {
if (src instanceof String) {
final String srcStr = (String)src;
if (srcStr.startsWith(LOAD_CLASSPATH)) {
URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
source = (url != null)? new Source(url.toString(), url) : null;
final URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
source = url != null ? new Source(url.toString(), url) : null;
} else {
final File file = new File(srcStr);
if (srcStr.indexOf(':') != -1) {
......@@ -837,7 +837,7 @@ public final class Context {
/**
* Set the current global scope
*/
static void setGlobalTrusted(ScriptObject global) {
static void setGlobalTrusted(final ScriptObject global) {
currentGlobal.set(global);
}
......
......@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.parser.TokenType.EOF;
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenStream;
......@@ -71,7 +70,7 @@ public final class Debug {
* @return system identity hashcode as string
*/
public static String id(final Object x) {
return "0x" + Integer.toHexString(System.identityHashCode(x));
return String.format("0x%08x", System.identityHashCode(x));
}
/**
......
......@@ -563,24 +563,33 @@ public abstract class Property {
return sb.toString();
}
private static String indent(final String str, final int indent) {
final StringBuilder sb = new StringBuilder();
sb.append(str);
for (int i = 0; i < indent - str.length(); i++) {
sb.append(' ');
}
return sb.toString();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
final Class<?> type = getCurrentType();
sb.append(getKey()).
sb.append(indent(getKey(), 20)).
append(" id=").
append(Debug.id(this)).
append(" (0x").
append(Integer.toHexString(flags)).
append(indent(Integer.toHexString(flags), 4)).
append(") ").
append(getClass().getSimpleName()).
append(" {").
append(type(type)).
append(indent(type(type), 5)).
append('}');
if (slot != -1) {
sb.append('[').
sb.append(" [").
append("slot=").
append(slot).
append(']');
......
......@@ -154,8 +154,8 @@ public interface PropertyDescriptor {
/**
* Check existence and compare attributes of descriptors.
*
* @return true if every field of this desc exists in otherDesc and has the same value.
* @param otherDesc other descriptor to compare to
* @return true if every field of this descriptor exists in otherDesc and has the same value.
*/
public boolean hasAndEquals(PropertyDescriptor otherDesc);
}
......
......@@ -31,11 +31,15 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import java.lang.invoke.SwitchPoint;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.WeakHashMap;
......@@ -698,19 +702,16 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(" [");
boolean isFirst = true;
sb.append(Debug.id(this));
sb.append(" = {\n");
for (final Property property : properties.values()) {
if (!isFirst) {
sb.append(", ");
}
isFirst = false;
for (final Property property : plist) {
sb.append('\t');
sb.append(property);
sb.append('\n');
}
sb.append(']');
sb.append('}');
return sb.toString();
}
......
......@@ -36,6 +36,7 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.CompilationEnvironment;
import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases;
......@@ -96,7 +97,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/** lazily generated allocator */
private MethodHandle allocator;
private Map<Integer, RecompilableScriptFunctionData> nestedFunctions;
private final Map<Integer, RecompilableScriptFunctionData> nestedFunctions;
/** Id to parent function if one exists */
private RecompilableScriptFunctionData parent;
private final boolean isDeclared;
private final boolean isAnonymous;
......@@ -109,16 +113,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
private static final DebugLogger LOG = new DebugLogger("recompile");
private final Map<String, Integer> externalScopeDepths;
private static final int GET_SET_PREFIX_LENGTH = "*et ".length();
/**
* Constructor - public as scripts use it
*
* @param functionNode functionNode that represents this function code
* @param installer installer for code regeneration versions of this function
* @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
* @param allocatorMap allocator map to seed instances with, when constructing
* @param nestedFunctions nested function map
* @param sourceURL source URL
* @param functionNode functionNode that represents this function code
* @param installer installer for code regeneration versions of this function
* @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
* @param allocatorMap allocator map to seed instances with, when constructing
* @param nestedFunctions nested function map
* @param sourceURL source URL
* @param externalScopeDepths external scope depths
*/
public RecompilableScriptFunctionData(
final FunctionNode functionNode,
......@@ -126,7 +134,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final String allocatorClassName,
final PropertyMap allocatorMap,
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
final String sourceURL) {
final String sourceURL,
final Map<String, Integer> externalScopeDepths) {
super(functionName(functionNode),
Math.min(functionNode.getParameters().size(), MAX_ARITY),
functionNode.isStrict(),
......@@ -134,19 +144,57 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
true,
functionNode.isVarArg());
this.functionName = functionNode.getName();
this.lineNumber = functionNode.getLineNumber();
this.isDeclared = functionNode.isDeclared();
this.needsCallee = functionNode.needsCallee();
this.isAnonymous = functionNode.isAnonymous();
this.functionNodeId = functionNode.getId();
this.source = functionNode.getSource();
this.token = tokenFor(functionNode);
this.installer = installer;
this.sourceURL = sourceURL;
this.allocatorClassName = allocatorClassName;
this.allocatorMap = allocatorMap;
this.nestedFunctions = nestedFunctions;
this.functionName = functionNode.getName();
this.lineNumber = functionNode.getLineNumber();
this.isDeclared = functionNode.isDeclared();
this.needsCallee = functionNode.needsCallee();
this.isAnonymous = functionNode.isAnonymous();
this.functionNodeId = functionNode.getId();
this.source = functionNode.getSource();
this.token = tokenFor(functionNode);
this.installer = installer;
this.sourceURL = sourceURL;
this.allocatorClassName = allocatorClassName;
this.allocatorMap = allocatorMap;
this.nestedFunctions = nestedFunctions;//deepTraverse(nestedFunctions);
this.externalScopeDepths = externalScopeDepths;
for (final RecompilableScriptFunctionData nfn : nestedFunctions.values()) {
assert nfn.getParent() == null;
nfn.setParent(this);
}
}
/**
* Return the external symbol table
* @param symbolName symbol name
* @return the external symbol table with proto depths
*/
public int getExternalSymbolDepth(final String symbolName) {
final Map<String, Integer> map = externalScopeDepths;
if (map == null) {
return -1;
}
final Integer depth = map.get(symbolName);
if (depth == null) {
return -1;
}
return depth;
}
/**
* 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
* only be used for conservative assumptions.
* @return parent data, or null if non exists and also null IF UNKNOWN.
*/
public RecompilableScriptFunctionData getParent() {
return parent;
}
void setParent(final RecompilableScriptFunctionData parent) {
this.parent = parent;
}
@Override
......@@ -162,6 +210,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("fid=").append(functionNodeId).append(' ');
if (source != null) {
sb.append(source.getName())
.append(':')
......@@ -179,7 +229,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final FunctionNode.Kind kind = fn.getKind();
if (kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) {
final String name = NameCodec.decode(fn.getIdent().getName());
return name.substring(4); // 4 is "get " or "set "
return name.substring(GET_SET_PREFIX_LENGTH);
}
return fn.getIdent().getName();
}
......@@ -265,7 +315,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
this,
isVariableArity() ? null : new ParamTypeMap(functionNodeId, explicitParams(fnCallSiteType)),
invalidatedProgramPoints,
continuationEntryPoints
continuationEntryPoints,
true
),
installer);
......@@ -276,7 +327,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class));
}
private FunctionNode compileTypeSpecialization(MethodType actualCallSiteType) {
private FunctionNode compileTypeSpecialization(final MethodType actualCallSiteType) {
return compile(actualCallSiteType, null, "Type specialized compilation");
}
......@@ -297,7 +348,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
new ParamTypeMap(
functionNodeId,
explicitParams(fnCallSiteType)),
invalidatedProgramPoints),
invalidatedProgramPoints,
true),
installer);
fn = compiler.compile(scriptName, fn);
......@@ -377,7 +429,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
public void initializeCode(final FunctionNode functionNode) {
// Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit.
if(!(code.isEmpty() && functionNode.getCompileUnit().isInitializing(this, functionNode))) {
throw new IllegalStateException();
throw new IllegalStateException(functionNode.getName() + " id=" + functionNode.getId());
}
addCode(functionNode);
}
......@@ -409,7 +461,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final MethodHandle handle = lookup(fn);
final MethodType fromType = handle.type();
MethodType toType = (needsCallee(fromType) ? callSiteType.changeParameterType(0, ScriptFunction.class) : callSiteType.dropParameterTypes(0, 1));
MethodType toType = needsCallee(fromType) ? callSiteType.changeParameterType(0, ScriptFunction.class) : callSiteType.dropParameterTypes(0, 1);
toType = toType.changeReturnType(fromType.returnType());
final int toCount = toType.parameterCount();
......@@ -436,7 +488,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
}
@Override
CompiledFunction getBest(MethodType callSiteType) {
CompiledFunction getBest(final MethodType callSiteType) {
synchronized(code) {
final CompiledFunction existingBest = super.getBest(callSiteType);
// TODO: what if callSiteType is vararg?
......@@ -465,17 +517,28 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/**
* Return a script function data based on a function id, either this function if
* the id matches or a nested function based on functionId.
* the id matches or a nested function based on functionId. This goes down into
* nested functions until all leaves are exhausted.
*
* @param functionId function id
* @return script function data or null if invalid id
*/
public RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
if(functionId == functionNodeId) {
if (functionId == functionNodeId) {
return this;
}
if(nestedFunctions == null) {
return null;
RecompilableScriptFunctionData data;
data = nestedFunctions == null ? null : nestedFunctions.get(functionId);
if (data != null) {
return data;
}
for (final RecompilableScriptFunctionData ndata : nestedFunctions.values()) {
data = ndata.getScriptFunctionData(functionId);
if (data != null) {
return data;
}
}
return nestedFunctions.get(functionId);
return null;
}
}
......@@ -198,7 +198,7 @@ public abstract class ScriptFunction extends ScriptObject {
return data.needsWrappedThis();
}
private static boolean needsWrappedThis(Object fn) {
private static boolean needsWrappedThis(final Object fn) {
return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false;
}
......
......@@ -163,6 +163,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Method handle for getting the array data */
public static final Call GET_ARRAY = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArray", ArrayData.class);
/** Method handle for getting the property map - debugging purposes */
public static final Call GET_MAP = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getMap", PropertyMap.class);
/** Method handle for setting the array data */
public static final Call SET_ARRAY = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArray", void.class, ArrayData.class);
......@@ -175,6 +178,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Method handle for getting the proto of a ScriptObject */
public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class);
/** Method handle for getting the proto of a ScriptObject */
public static final Call GET_PROTO_DEPTH = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class, int.class);
/** Method handle for setting the proto of a ScriptObject */
public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setProto", void.class, ScriptObject.class);
......@@ -1212,6 +1218,20 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return proto;
}
/**
* Get the proto of a specific depth
* @param n depth
* @return proto at given depth
*/
public final ScriptObject getProto(final int n) {
assert n > 0;
ScriptObject p = getProto();
for (int i = n; i-- > 0;) {
p = p.getProto();
}
return p;
}
/**
* Set the __proto__ of an object.
* @param newProto new __proto__ to set.
......@@ -1901,9 +1921,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
mh = find.getGetter(returnType, programPoint);
//we never need a guard if noGuard is set
final boolean noGuard =/* OBJECT_FIELDS_ONLY &&*/ NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
// getMap() is fine as we have the prototype switchpoint depending on where the property was found
final boolean noGuard = OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
MethodHandle guard;
final Class<? extends Throwable> exception;
if (noGuard) {
......@@ -1919,7 +1939,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (mh == null) {
mh = Lookup.emptyGetter(returnType);
} else {
assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
if (find.isSelf()) {
return new GuardedInvocation(mh, guard, null, exception);
}
......
......@@ -269,7 +269,7 @@ public final class ScriptRuntime {
private final int length;
private int index;
RangeIterator(int length) {
RangeIterator(final int length) {
this.length = length;
}
......@@ -427,7 +427,7 @@ public final class ScriptRuntime {
}
// checking for xVal == -0.0 and yVal == +0.0 or vice versa
if (xVal == 0.0 && (Double.doubleToLongBits(xVal) != Double.doubleToLongBits(yVal))) {
if (xVal == 0.0 && Double.doubleToLongBits(xVal) != Double.doubleToLongBits(yVal)) {
return false;
}
......@@ -438,7 +438,7 @@ public final class ScriptRuntime {
return x.equals(y);
}
return (x == y);
return x == y;
}
/**
......@@ -510,7 +510,7 @@ public final class ScriptRuntime {
final boolean xIsUndefined = x == UNDEFINED;
final boolean yIsUndefined = y == UNDEFINED;
if ((xIsNumber && yIsUndefined) || (xIsUndefined && yIsNumber) || (xIsUndefined && yIsUndefined)) {
if (xIsNumber && yIsUndefined || xIsUndefined && yIsNumber || xIsUndefined && yIsUndefined) {
return Double.NaN;
}
......@@ -713,8 +713,8 @@ public final class ScriptRuntime {
return x == y;
}
if ((xType == JSType.UNDEFINED && yType == JSType.NULL) ||
(xType == JSType.NULL && yType == JSType.UNDEFINED)) {
if (xType == JSType.UNDEFINED && yType == JSType.NULL ||
xType == JSType.NULL && yType == JSType.UNDEFINED) {
return true;
}
......@@ -735,11 +735,11 @@ public final class ScriptRuntime {
}
if ((xType == JSType.STRING || xType == JSType.NUMBER) &&
(y instanceof ScriptObject)) {
y instanceof ScriptObject) {
return EQ(x, JSType.toPrimitive(y));
}
if ((x instanceof ScriptObject) &&
if (x instanceof ScriptObject &&
(yType == JSType.STRING || yType == JSType.NUMBER)) {
return EQ(JSType.toPrimitive(x), y);
}
......@@ -876,7 +876,7 @@ public final class ScriptRuntime {
*/
public static boolean LT(final Object x, final Object y) {
final Object value = lessThan(x, y, true);
return (value == UNDEFINED) ? false : (Boolean)value;
return value == UNDEFINED ? false : (Boolean)value;
}
/**
......@@ -889,7 +889,7 @@ public final class ScriptRuntime {
*/
public static boolean GT(final Object x, final Object y) {
final Object value = lessThan(y, x, false);
return (value == UNDEFINED) ? false : (Boolean)value;
return value == UNDEFINED ? false : (Boolean)value;
}
/**
......@@ -902,7 +902,7 @@ public final class ScriptRuntime {
*/
public static boolean LE(final Object x, final Object y) {
final Object value = lessThan(y, x, false);
return (!(Boolean.TRUE.equals(value) || value == UNDEFINED));
return !(Boolean.TRUE.equals(value) || value == UNDEFINED);
}
/**
......@@ -915,7 +915,7 @@ public final class ScriptRuntime {
*/
public static boolean GE(final Object x, final Object y) {
final Object value = lessThan(x, y, true);
return (!(Boolean.TRUE.equals(value) || value == UNDEFINED));
return !(Boolean.TRUE.equals(value) || value == UNDEFINED);
}
/** ECMA 11.8.5 The Abstract Relational Comparison Algorithm */
......@@ -933,7 +933,7 @@ public final class ScriptRuntime {
if (JSType.of(px) == JSType.STRING && JSType.of(py) == JSType.STRING) {
// May be String or ConsString
return (px.toString()).compareTo(py.toString()) < 0;
return px.toString().compareTo(py.toString()) < 0;
}
final double nx = JSType.toNumber(px);
......
......@@ -60,6 +60,7 @@ final class ByteBufferArrayData extends ArrayData {
*
* @return property descriptor for element
*/
@Override
public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
// make the index properties not configurable
return global.newDataDescriptor(getObject(index), false, true, true);
......@@ -197,7 +198,7 @@ final class ByteBufferArrayData extends ArrayData {
throw unsupported("convert");
}
private UnsupportedOperationException unsupported(final String method) {
private static UnsupportedOperationException unsupported(final String method) {
return new UnsupportedOperationException(method);
}
}
......@@ -86,7 +86,7 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
/**
* Maximum program point value. 22 bits should be enough for anyone
*/
public static final int MAX_PROGRAM_POINT_VALUE = (1 << (32 - CALLSITE_PROGRAM_POINT_SHIFT)) - 1;
public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
/**
* Flag mask to get the program point flags
......@@ -107,6 +107,22 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
private final MethodType methodType;
private final int flags;
public static String toString(final int flags) {
final StringBuilder sb = new StringBuilder();
if ((flags & CALLSITE_SCOPE) != 0) {
if ((flags & CALLSITE_FAST_SCOPE) != 0) {
sb.append("fastscope ");
} else {
assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
sb.append("scope ");
}
}
if ((flags & CALLSITE_STRICT) != 0) {
sb.append("strict ");
}
return sb.length() == 0 ? "" : " " + sb.toString().trim();
}
/**
* Retrieves a Nashorn call site descriptor with the specified values. Since call site descriptors are immutable
* this method is at liberty to retrieve canonicalized instances (although it is not guaranteed it will do so).
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册