提交 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; ...@@ -52,10 +52,13 @@ import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode; import jdk.nashorn.internal.ir.BinaryNode;
...@@ -139,6 +142,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -139,6 +142,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
private final Set<Long> optimistic = new HashSet<>(); private final Set<Long> optimistic = new HashSet<>();
private final Set<Long> neverOptimistic = 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; private int catchNestingLevel;
...@@ -454,7 +458,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -454,7 +458,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
// Create and add to appropriate block. // Create and add to appropriate block.
symbol = new Symbol(name, flags); symbol = createSymbol(name, flags);
symbolBlock.putSymbol(lc, symbol); symbolBlock.putSymbol(lc, symbol);
if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
...@@ -467,6 +471,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -467,6 +471,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return symbol; 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 @Override
public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
final Expression expr = expressionStatement.getExpression(); final Expression expr = expressionStatement.getExpression();
...@@ -555,10 +572,16 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -555,10 +572,16 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
final int optimisticFlag = lc.hasOptimisticAssumptions() ? FunctionNode.IS_OPTIMISTIC : 0; final int optimisticFlag = lc.hasOptimisticAssumptions() ? FunctionNode.IS_OPTIMISTIC : 0;
newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR).setFlag(lc, optimisticFlag); newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR).setFlag(lc, optimisticFlag);
popLocals(); 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); return end(newFunctionNode, false);
} }
...@@ -576,7 +599,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -576,7 +599,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final IdentNode init = compilerConstant(initConstant); final IdentNode init = compilerConstant(initConstant);
assert init.getSymbol() != null && init.getSymbol().hasSlot(); 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()); final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName());
assert nameSymbol != null; assert nameSymbol != null;
...@@ -631,7 +654,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -631,7 +654,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
maybeForceScope(symbol); maybeForceScope(symbol);
} else { } else {
LOG.info("No symbol exists. Declare undefined: ", symbol); 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 // we have never seen this before, it can be undefined
newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
symbol.setCanBeUndefined(); symbol.setCanBeUndefined();
...@@ -652,6 +675,10 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -652,6 +675,10 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(node); return end(node);
} }
private Symbol defineGlobalSymbol(final Block block, final String name) {
return defineSymbol(block, name, IS_GLOBAL);
}
private boolean inCatch() { private boolean inCatch() {
return catchNestingLevel > 0; return catchNestingLevel > 0;
} }
...@@ -908,7 +935,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -908,7 +935,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public boolean enterNOT(UnaryNode unaryNode) { public boolean enterNOT(final UnaryNode unaryNode) {
tagNeverOptimistic(unaryNode.getExpression()); tagNeverOptimistic(unaryNode.getExpression());
return true; return true;
} }
...@@ -1021,7 +1048,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1021,7 +1048,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(coerce(unaryNode, Type.BOOLEAN)); 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)); return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc, lc.getCurrentFunction().compilerConstant(cc));
} }
...@@ -1040,7 +1067,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1040,7 +1067,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
public Node leaveTYPEOF(final UnaryNode unaryNode) { public Node leaveTYPEOF(final UnaryNode unaryNode) {
final Expression rhs = unaryNode.getExpression(); 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()) { if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
args.add(compilerConstant(SCOPE)); args.add(compilerConstant(SCOPE));
args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
...@@ -1099,7 +1126,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1099,7 +1126,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
//which will be corrected in the post pass if unknown at this stage //which will be corrected in the post pass if unknown at this stage
Type argumentsType = Type.widest(lhs.getType(), rhs.getType()); Type argumentsType = Type.widest(lhs.getType(), rhs.getType());
if(argumentsType.getTypeClass() == String.class) { if (argumentsType.getTypeClass() == String.class) {
assert binaryNode.isTokenType(TokenType.ADD); assert binaryNode.isTokenType(TokenType.ADD);
argumentsType = Type.OBJECT; argumentsType = Type.OBJECT;
} }
...@@ -1151,7 +1178,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1151,7 +1178,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final Symbol symbol = findSymbol(block, name); final Symbol symbol = findSymbol(block, name);
if (symbol == null) { if (symbol == null) {
defineSymbol(block, name, IS_GLOBAL); defineGlobalSymbol(block, name);
} else { } else {
maybeForceScope(symbol); maybeForceScope(symbol);
} }
...@@ -1169,7 +1196,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1169,7 +1196,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return end(ensureSymbol(binaryNode, type)); 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); 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 // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
return definingFn == null || definingFn == function; return definingFn == null || definingFn == function;
...@@ -1372,7 +1399,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1372,7 +1399,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
final Type type = Type.narrowest(lhs.getType(), rhs.getType(), Type.INT); final Type type = Type.narrowest(lhs.getType(), rhs.getType(), Type.INT);
inferParameter(lhs, type); inferParameter(lhs, type);
inferParameter(rhs, 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(lhs, widest);
ensureSymbol(rhs, widest); ensureSymbol(rhs, widest);
return end(ensureSymbol(binaryNode, Type.BOOLEAN)); return end(ensureSymbol(binaryNode, Type.BOOLEAN));
...@@ -1390,7 +1417,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1390,7 +1417,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public boolean enterEQ(BinaryNode binaryNode) { public boolean enterEQ(final BinaryNode binaryNode) {
return enterBinaryArithmetic(binaryNode); return enterBinaryArithmetic(binaryNode);
} }
...@@ -1549,7 +1576,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1549,7 +1576,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public boolean enterForNode(ForNode forNode) { public boolean enterForNode(final ForNode forNode) {
tagNeverOptimistic(forNode.getTest()); tagNeverOptimistic(forNode.getTest());
return true; return true;
} }
...@@ -1570,7 +1597,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1570,7 +1597,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public boolean enterTernaryNode(TernaryNode ternaryNode) { public boolean enterTernaryNode(final TernaryNode ternaryNode) {
tagNeverOptimistic(ternaryNode.getTest()); tagNeverOptimistic(ternaryNode.getTest());
return true; return true;
} }
...@@ -1675,7 +1702,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1675,7 +1702,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
newParams.add((IdentNode)param.setSymbol(lc, paramSymbol)); newParams.add((IdentNode)param.setSymbol(lc, paramSymbol));
assert paramSymbol != null; assert paramSymbol != null;
Type type = paramSymbol.getSymbolType(); final Type type = paramSymbol.getSymbolType();
// all param types are initialized to unknown // all param types are initialized to unknown
// first we check if we do have a type (inferred during generation) // first we check if we do have a type (inferred during generation)
...@@ -1705,7 +1732,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1705,7 +1732,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
} }
FunctionNode newFunctionNode = functionNode; final FunctionNode newFunctionNode = functionNode;
return newFunctionNode.setParameters(lc, newParams); return newFunctionNode.setParameters(lc, newParams);
} }
...@@ -1721,7 +1748,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1721,7 +1748,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
for (final Property property : map.getProperties()) { for (final Property property : map.getProperties()) {
final String key = property.getKey(); final String key = property.getKey();
final Symbol symbol = defineSymbol(block, key, IS_GLOBAL); final Symbol symbol = defineGlobalSymbol(block, key);
newType(symbol, Type.OBJECT); newType(symbol, Type.OBJECT);
LOG.info("Added global symbol from property map ", symbol); LOG.info("Added global symbol from property map ", symbol);
} }
...@@ -1761,9 +1788,11 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1761,9 +1788,11 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
if (node instanceof LiteralNode) { if (node instanceof LiteralNode) {
return node; return node;
} }
Type from = node.getType(); final Type from = node.getType();
if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { 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(); Symbol symbol = node.getSymbol();
if (symbol.isShared() && symbol.wouldChangeType(to)) { if (symbol.isShared() && symbol.wouldChangeType(to)) {
symbol = temporarySymbols.getTypedTemporarySymbol(to); symbol = temporarySymbols.getTypedTemporarySymbol(to);
...@@ -1875,7 +1904,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1875,7 +1904,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public Node leaveTernaryNode(TernaryNode ternaryNode) { public Node leaveTernaryNode(final TernaryNode ternaryNode) {
return widen(ternaryNode, Type.widest(ternaryNode.getTrueExpression().getType(), ternaryNode.getFalseExpression().getType())); return widen(ternaryNode, Type.widest(ternaryNode.getTrueExpression().getType(), ternaryNode.getFalseExpression().getType()));
} }
...@@ -1938,19 +1967,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1938,19 +1967,19 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
@Override @Override
public boolean enterReturnNode(ReturnNode returnNode) { public boolean enterReturnNode(final ReturnNode returnNode) {
tagOptimistic(returnNode.getExpression()); tagOptimistic(returnNode.getExpression());
return true; return true;
} }
@Override @Override
public boolean enterIfNode(IfNode ifNode) { public boolean enterIfNode(final IfNode ifNode) {
tagNeverOptimistic(ifNode.getTest()); tagNeverOptimistic(ifNode.getTest());
return true; return true;
} }
@Override @Override
public boolean enterWhileNode(WhileNode whileNode) { public boolean enterWhileNode(final WhileNode whileNode) {
tagNeverOptimistic(whileNode.getTest()); tagNeverOptimistic(whileNode.getTest());
return true; return true;
} }
...@@ -1966,7 +1995,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -1966,7 +1995,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
* @param expr an expression that is to be tagged as optimistic. * @param expr an expression that is to be tagged as optimistic.
*/ */
private long tag(final Optimistic expr) { 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> { ...@@ -2000,7 +2029,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
return optimistic.contains(tag(expr)); return optimistic.contains(tag(expr));
} }
private Type getOptimisticType(Optimistic expr) { private Type getOptimisticType(final Optimistic expr) {
return useOptimisticTypes() ? env.getOptimisticType(expr) : expr.getMostPessimisticType(); return useOptimisticTypes() ? env.getOptimisticType(expr) : expr.getMostPessimisticType();
} }
...@@ -2138,7 +2167,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -2138,7 +2167,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
} }
private BinaryNode coerce(final BinaryNode binaryNode, final Type pessimisticType, final Type argumentsType) { 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.lhs(), newNode.getType());
inferParameter(binaryNode.rhs(), newNode.getType()); inferParameter(binaryNode.rhs(), newNode.getType());
return newNode; return newNode;
...@@ -2161,7 +2190,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> { ...@@ -2161,7 +2190,7 @@ final class Attr extends NodeOperatorVisitor<OptimisticLexicalContext> {
private static String name(final Node node) { private static String name(final Node node) {
final String cn = node.getClass().getName(); final String cn = node.getClass().getName();
int lastDot = cn.lastIndexOf('.'); final int lastDot = cn.lastIndexOf('.');
if (lastDot == -1) { if (lastDot == -1) {
return cn; return cn;
} }
......
...@@ -277,51 +277,52 @@ public class ClassEmitter implements Emitter { ...@@ -277,51 +277,52 @@ public class ClassEmitter implements Emitter {
} }
// $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[].
for (final Class<?> cls : constantMethodNeeded) { for (final Class<?> clazz : constantMethodNeeded) {
if (cls.isArray()) { if (clazz.isArray()) {
defineGetArrayMethod(cls); defineGetArrayMethod(clazz);
} }
} }
} }
/** /**
* Constructs a primitive specific method for getting the ith entry from the constants table and cast. * 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; assert unitClassName != null;
final String methodName = getArrayMethodName(cls); final String methodName = getArrayMethodName(clazz);
final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class);
getArrayMethod.begin(); getArrayMethod.begin();
getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor())
.load(Type.INT, 0) .load(Type.INT, 0)
.arrayload() .arrayload()
.checkcast(cls) .checkcast(clazz)
.dup() .dup()
.arraylength() .arraylength()
.invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class)) .invoke(staticCallNoLookup(Arrays.class, "copyOf", clazz, clazz, int.class))
._return(); ._return();
getArrayMethod.end(); getArrayMethod.end();
} }
/** /**
* Generate the name of a get array from constant pool method. * 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. * @return Method name.
*/ */
static String getArrayMethodName(final Class<?> cls) { static String getArrayMethodName(final Class<?> clazz) {
assert cls.isArray(); assert clazz.isArray();
return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
} }
/** /**
* Ensure a get constant method is issued for the class. * 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) { void needGetConstantMethod(final Class<?> clazz) {
constantMethodNeeded.add(cls); constantMethodNeeded.add(clazz);
} }
/** /**
...@@ -672,7 +673,7 @@ public class ClassEmitter implements Emitter { ...@@ -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); return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null);
} }
......
...@@ -47,8 +47,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; ...@@ -47,8 +47,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY; import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getClassName;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
...@@ -76,6 +74,7 @@ import java.util.Map; ...@@ -76,6 +74,7 @@ import java.util.Map;
import java.util.RandomAccess; import java.util.RandomAccess;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode;
...@@ -224,11 +223,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -224,11 +223,10 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// Function Id -> ContinuationInfo. Used by compilation of rest-of function only. // Function Id -> ContinuationInfo. Used by compilation of rest-of function only.
private final Map<Integer, ContinuationInfo> fnIdToContinuationInfo = new HashMap<>(); private final Map<Integer, ContinuationInfo> fnIdToContinuationInfo = new HashMap<>();
// Function Id -> (Function Id -> Function Data)). Used by compilation of most-optimistic function only.
private final Map<Integer, Map<Integer, RecompilableScriptFunctionData>> fnIdToNestedFunctions = new HashMap<>();
private final Deque<Label> scopeEntryLabels = new ArrayDeque<>(); private final Deque<Label> scopeEntryLabels = new ArrayDeque<>();
private final Set<Integer> initializedFunctionIds = new HashSet<>();
/** /**
* Constructor. * Constructor.
* *
...@@ -299,6 +297,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -299,6 +297,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
loadFastScopeVar(identNode, type, flags, isCompileTimePropertyName); loadFastScopeVar(identNode, type, flags, isCompileTimePropertyName);
} }
} else { } else {
//slow scope load, we have no proto depth
new OptimisticOperation() { new OptimisticOperation() {
@Override @Override
void loadStack() { void loadStack() {
...@@ -409,9 +408,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -409,9 +408,13 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
method.load(isFastScope(symbol) ? getScopeProtoDepth(lc.getCurrentBlock(), symbol) : -1); assert !isOptimisticOrRestOf();
final SharedScopeCall scopeCall = lc.getScopeGet(unit, symbol, valueType, flags | CALLSITE_FAST_SCOPE); if (isFastScope(symbol)) {
return scopeCall.generateInvoke(method); method.load(getScopeProtoDepth(lc.getCurrentBlock(), symbol));
} else {
method.load(-1);
}
return lc.getScopeGet(unit, symbol, valueType, flags | CALLSITE_FAST_SCOPE).generateInvoke(method);
} }
private MethodEmitter loadFastScopeVar(final IdentNode identNode, final Type type, final int flags, final boolean isCompileTimePropertyName) { private MethodEmitter loadFastScopeVar(final IdentNode identNode, final Type type, final int flags, final boolean isCompileTimePropertyName) {
...@@ -424,7 +427,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -424,7 +427,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override @Override
void consumeStack() { void consumeStack() {
dynamicGet(method, identNode, isCompileTimePropertyName ? Type.OBJECT : type, identNode.getSymbol().getName(), flags | CALLSITE_FAST_SCOPE, identNode.isFunction()); dynamicGet(method, identNode, isCompileTimePropertyName ? Type.OBJECT : type, identNode.getSymbol().getName(), flags | CALLSITE_FAST_SCOPE, identNode.isFunction());
if(isCompileTimePropertyName) { if (isCompileTimePropertyName) {
replaceCompileTimeProperty(identNode, type); replaceCompileTimeProperty(identNode, type);
} }
} }
...@@ -438,23 +441,30 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -438,23 +441,30 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
//walk up the chain from startingblock and when we bump into the current function boundary, add the external
//information.
final FunctionNode fn = lc.getCurrentFunction();
final int fnId = fn.getId();
final int externalDepth = compiler.getCompilationEnvironment().getScriptFunctionData(fnId).getExternalSymbolDepth(symbol.getName());
//count the number of scopes from this place to the start of the function
final int internalDepth = FindScopeDepths.findInternalDepth(lc, fn, startingBlock, symbol);
final int scopesToStart = FindScopeDepths.findScopesToStart(lc, fn, startingBlock);
int depth = 0; int depth = 0;
final String name = symbol.getName(); if (internalDepth == -1) {
for(final Iterator<Block> blocks = lc.getBlocks(startingBlock); blocks.hasNext();) { depth = scopesToStart + externalDepth;
final Block currentBlock = blocks.next(); } else {
if (currentBlock.getExistingSymbol(name) == symbol) { assert internalDepth <= scopesToStart;
return depth; depth = internalDepth;
}
if (currentBlock.needsScope()) {
++depth;
}
} }
return -1;
return depth;
} }
private void loadFastScopeProto(final Symbol symbol, final boolean swap) { private void loadFastScopeProto(final Symbol symbol, final boolean swap) {
final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol); final int depth = getScopeProtoDepth(lc.getCurrentBlock(), symbol);
assert depth != -1 : "Couldn't find scope depth for symbol " + symbol.getName(); assert depth != -1 : "Couldn't find scope depth for symbol " + symbol.getName() + " in " + lc.getCurrentFunction();
if (depth > 0) { if (depth > 0) {
if (swap) { if (swap) {
method.swap(); method.swap();
...@@ -588,7 +598,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -588,7 +598,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
@Override @Override
public boolean enterFunctionNode(FunctionNode functionNode) { public boolean enterFunctionNode(final FunctionNode functionNode) {
// function nodes will always leave a constructed function object on stack, no need to load the symbol // function nodes will always leave a constructed function object on stack, no need to load the symbol
// separately as in enterDefault() // separately as in enterDefault()
lc.pop(functionNode); lc.pop(functionNode);
...@@ -603,12 +613,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -603,12 +613,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
@Override @Override
public boolean enterCallNode(CallNode callNode) { public boolean enterCallNode(final CallNode callNode) {
return codegen.enterCallNode(callNode, type); return codegen.enterCallNode(callNode, type);
} }
@Override @Override
public boolean enterLiteralNode(LiteralNode<?> literalNode) { public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
return codegen.enterLiteralNode(literalNode, type); return codegen.enterLiteralNode(literalNode, type);
} }
...@@ -658,7 +668,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -658,7 +668,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
if (symbol.hasSlot()) { if (symbol.hasSlot()) {
final Type type = symbol.getSymbolType(); final Type type = symbol.getSymbolType();
if(symbol.canBeUndefined() && !isInternal) { if (symbol.canBeUndefined() && !isInternal) {
if (type.isNumber()) { if (type.isNumber()) {
numbers.add(symbol); numbers.add(symbol);
} else if (type.isObject()) { } else if (type.isObject()) {
...@@ -1122,7 +1132,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1122,7 +1132,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param isMethod whether we're preferrably retrieving a function * @param isMethod whether we're preferrably retrieving a function
* @return the passed in method emitter * @return the passed in method emitter
*/ */
private static MethodEmitter dynamicGet(MethodEmitter method, Expression expr, Type desiredType, final String name, final int flags, boolean isMethod) { private static MethodEmitter dynamicGet(final MethodEmitter method, final Expression expr, final Type desiredType, final String name, final int flags, final boolean isMethod) {
final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags); final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags);
if(isOptimistic(finalFlags)) { if(isOptimistic(finalFlags)) {
return method.dynamicGet(getOptimisticCoercedType(desiredType, expr), name, finalFlags, isMethod).convert(desiredType); return method.dynamicGet(getOptimisticCoercedType(desiredType, expr), name, finalFlags, isMethod).convert(desiredType);
...@@ -1130,7 +1140,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1130,7 +1140,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method.dynamicGet(desiredType, name, finalFlags, isMethod); return method.dynamicGet(desiredType, name, finalFlags, isMethod);
} }
private static MethodEmitter dynamicGetIndex(MethodEmitter method, Expression expr, Type desiredType, int flags, boolean isMethod) { private static MethodEmitter dynamicGetIndex(final MethodEmitter method, final Expression expr, final Type desiredType, final int flags, final boolean isMethod) {
final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags); final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags);
if(isOptimistic(finalFlags)) { if(isOptimistic(finalFlags)) {
return method.dynamicGetIndex(getOptimisticCoercedType(desiredType, expr), finalFlags, isMethod).convert(desiredType); return method.dynamicGetIndex(getOptimisticCoercedType(desiredType, expr), finalFlags, isMethod).convert(desiredType);
...@@ -1138,7 +1148,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1138,7 +1148,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return method.dynamicGetIndex(desiredType, finalFlags, isMethod); return method.dynamicGetIndex(desiredType, finalFlags, isMethod);
} }
private static MethodEmitter dynamicCall(MethodEmitter method, Expression expr, Type desiredType, int argCount, int flags) { private static MethodEmitter dynamicCall(final MethodEmitter method, final Expression expr, final Type desiredType, final int argCount, final int flags) {
final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags); final int finalFlags = maybeRemoveOptimisticFlags(desiredType, flags);
if(isOptimistic(finalFlags)) { if(isOptimistic(finalFlags)) {
return method.dynamicCall(getOptimisticCoercedType(desiredType, expr), argCount, finalFlags).convert(desiredType); return method.dynamicCall(getOptimisticCoercedType(desiredType, expr), argCount, finalFlags).convert(desiredType);
...@@ -1176,7 +1186,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1176,7 +1186,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param flags original flags * @param flags original flags
* @return either the original flags, or flags with optimism stripped, if the return value type is object * @return either the original flags, or flags with optimism stripped, if the return value type is object
*/ */
private static int maybeRemoveOptimisticFlags(Type type, int flags) { private static int maybeRemoveOptimisticFlags(final Type type, final int flags) {
return type.isObject() ? nonOptimisticFlags(flags) : flags; return type.isObject() ? nonOptimisticFlags(flags) : flags;
} }
...@@ -1185,8 +1195,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1185,8 +1195,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param flags the flags that need optimism stripped from them. * @param flags the flags that need optimism stripped from them.
* @return flags without optimism * @return flags without optimism
*/ */
static int nonOptimisticFlags(int flags) { static int nonOptimisticFlags(final int flags) {
return flags & ~(CALLSITE_OPTIMISTIC | -1 << CALLSITE_PROGRAM_POINT_SHIFT); return flags & ~(CALLSITE_OPTIMISTIC | (-1 << CALLSITE_PROGRAM_POINT_SHIFT));
} }
@Override @Override
...@@ -1423,7 +1433,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1423,7 +1433,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
method.storeCompilerConstant(SCOPE); method.storeCompilerConstant(SCOPE);
if(!isFunctionBody) { if (!isFunctionBody) {
// Function body doesn't need a try/catch to restore scope, as it'd be a dead store anyway. Allowing it // Function body doesn't need a try/catch to restore scope, as it'd be a dead store anyway. Allowing it
// actually causes issues with UnwarrantedOptimismException handlers as ASM will sort this handler to // actually causes issues with UnwarrantedOptimismException handlers as ASM will sort this handler to
// the top of the exception handler table, so it'll be triggered instead of the UOE handlers. // the top of the exception handler table, so it'll be triggered instead of the UOE handlers.
...@@ -1474,13 +1484,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1474,13 +1484,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
@Override @Override
public boolean enterFunctionNode(final FunctionNode functionNode) { public boolean enterFunctionNode(final FunctionNode functionNode) {
final int fnId = functionNode.getId(); final int fnId = functionNode.getId();
Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId);
if (nestedFunctions == null) {
nestedFunctions = new HashMap<>();
fnIdToNestedFunctions.put(fnId, nestedFunctions);
}
// Nested functions are not visited when we either recompile or lazily compile, only the outermost function is.
if (compileOutermostOnly() && lc.getOutermostFunction() != functionNode) { if (compileOutermostOnly() && lc.getOutermostFunction() != functionNode) {
// In case we are not generating code for the function, we must create or retrieve the function object and // In case we are not generating code for the function, we must create or retrieve the function object and
// load it on the stack here. // load it on the stack here.
...@@ -1544,11 +1548,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1544,11 +1548,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED); FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
if(markOptimistic) { if (markOptimistic) {
newFunctionNode = newFunctionNode.setFlag(lc, FunctionNode.IS_OPTIMISTIC); newFunctionNode = newFunctionNode.setFlag(lc, FunctionNode.IS_OPTIMISTIC);
} }
newFunctionObject(newFunctionNode, true); newFunctionObject(newFunctionNode, true);
return newFunctionNode; return newFunctionNode;
} catch (final Throwable t) { } catch (final Throwable t) {
Context.printStackTrace(t); Context.printStackTrace(t);
...@@ -1614,7 +1619,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -1614,7 +1619,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
lineNumber(statement.getLineNumber()); lineNumber(statement.getLineNumber());
} }
private void lineNumber(int lineNumber) { private void lineNumber(final int lineNumber) {
if (lineNumber != lastLineNumber) { if (lineNumber != lastLineNumber) {
method.lineNumber(lineNumber); method.lineNumber(lineNumber);
} }
...@@ -3696,7 +3701,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -3696,7 +3701,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
*/ */
target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override @Override
protected boolean enterDefault(Node node) { protected boolean enterDefault(final Node node) {
throw new AssertionError("Unexpected node " + node + " in store epilogue"); throw new AssertionError("Unexpected node " + node + " in store epilogue");
} }
...@@ -3754,42 +3759,28 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -3754,42 +3759,28 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
final int fnId = functionNode.getId(); final int fnId = functionNode.getId();
final CompilationEnvironment env = compiler.getCompilationEnvironment(); final CompilationEnvironment env = compiler.getCompilationEnvironment();
RecompilableScriptFunctionData data = env.getScriptFunctionData(fnId); final RecompilableScriptFunctionData data = env.getScriptFunctionData(fnId);
// data != null => compileOutermostOnly()
assert data == null || compileOutermostOnly() : functionNode.getName() + " isRecompile=" + env.isOnDemandCompilation() + " data=" + data; assert data != null : functionNode.getName() + " has no data";
if(data == null) {
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions = fnIdToNestedFunctions.get(fnId); final FunctionNode parentFn = lc.getParentFunction(functionNode);
assert nestedFunctions != null; if (parentFn == null && functionNode.isProgram()) {
// Generate the object class and property map in case this function is ever used as constructor final CompileUnit fnUnit = functionNode.getCompileUnit();
final int fieldCount = getPaddedFieldCount(functionNode.countThisProperties()); final MethodEmitter createFunction = fnUnit.getClassEmitter().method(
final String allocatorClassName = Compiler.binaryName(getClassName(fieldCount)); EnumSet.of(Flag.PUBLIC, Flag.STATIC), CREATE_PROGRAM_FUNCTION.symbolName(),
final PropertyMap allocatorMap = PropertyMap.newMap(null, 0, fieldCount, 0); ScriptFunction.class, ScriptObject.class);
createFunction.begin();
data = new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), allocatorClassName, allocatorMap, nestedFunctions, compiler.getSourceURL()); createFunction._new(SCRIPTFUNCTION_IMPL_NAME, SCRIPTFUNCTION_IMPL_TYPE).dup();
loadConstant(data, fnUnit, createFunction);
final FunctionNode parentFn = lc.getParentFunction(functionNode); createFunction.load(SCOPE_TYPE, 0);
if(parentFn == null) { createFunction.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class));
if(functionNode.isProgram()) { createFunction._return();
// Emit the "public static ScriptFunction createScriptFunction(ScriptObject scope)" method createFunction.end();
final CompileUnit fnUnit = functionNode.getCompileUnit(); }
final MethodEmitter createFunction = fnUnit.getClassEmitter().method(
EnumSet.of(Flag.PUBLIC, Flag.STATIC), CREATE_PROGRAM_FUNCTION.symbolName(), if (addInitializer && !initializedFunctionIds.contains(fnId) && !env.isOnDemandCompilation()) {
ScriptFunction.class, ScriptObject.class);
createFunction.begin();
createFunction._new(SCRIPTFUNCTION_IMPL_NAME, SCRIPTFUNCTION_IMPL_TYPE).dup();
loadConstant(data, fnUnit, createFunction);
createFunction.load(SCOPE_TYPE, 0);
createFunction.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class));
createFunction._return();
createFunction.end();
}
} else {
fnIdToNestedFunctions.get(parentFn.getId()).put(fnId, data);
}
}
if(addInitializer && !env.isOnDemandCompilation()) {
functionNode.getCompileUnit().addFunctionInitializer(data, functionNode); functionNode.getCompileUnit().addFunctionInitializer(data, functionNode);
initializedFunctionIds.add(fnId);
} }
// We don't emit a ScriptFunction on stack for the outermost compiled function (as there's no code being // We don't emit a ScriptFunction on stack for the outermost compiled function (as there's no code being
...@@ -3806,6 +3797,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -3806,6 +3797,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} else { } else {
method.loadNull(); method.loadNull();
} }
method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class)); method.invoke(constructorNoLookup(SCRIPTFUNCTION_IMPL_NAME, RecompilableScriptFunctionData.class, ScriptObject.class));
} }
...@@ -3954,7 +3946,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -3954,7 +3946,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* a label for a catch block for the {@code UnwarantedOptimizationException}, suitable for capturing the * a label for a catch block for the {@code UnwarantedOptimizationException}, suitable for capturing the
* currently live local variables, tailored to their types. * currently live local variables, tailored to their types.
*/ */
private int storeStack(final int ignoreArgCount, final boolean optimisticOrContinuation) { private final int storeStack(final int ignoreArgCount, final boolean optimisticOrContinuation) {
if(!optimisticOrContinuation) { if(!optimisticOrContinuation) {
return -1; // NOTE: correct value to return is lc.getUsedSlotCount(), but it wouldn't be used anyway return -1; // NOTE: correct value to return is lc.getUsedSlotCount(), but it wouldn't be used anyway
} }
...@@ -4059,7 +4051,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -4059,7 +4051,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
* @param localLoadsOnStack the current local variable loads on the stack * @param localLoadsOnStack the current local variable loads on the stack
* @return the number of used local variable slots, including all live stack-store temporaries. * @return the number of used local variable slots, including all live stack-store temporaries.
*/ */
private int getUsedSlotsWithLiveTemporaries(List<Type> localVariableTypes, int[] localLoadsOnStack) { private final int getUsedSlotsWithLiveTemporaries(final List<Type> localVariableTypes, final int[] localLoadsOnStack) {
// There are at least as many as are declared by the current blocks. // There are at least as many as are declared by the current blocks.
int usedSlots = lc.getUsedSlotCount(); int usedSlots = lc.getUsedSlotCount();
// Look at every load on the stack, and bump the number of used slots up by the temporaries seen there. // Look at every load on the stack, and bump the number of used slots up by the temporaries seen there.
...@@ -4082,7 +4074,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -4082,7 +4074,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
abstract void consumeStack(); abstract void consumeStack();
} }
private static boolean everyLocalLoadIsValid(final int[] loads, int localCount) { private static boolean everyLocalLoadIsValid(final int[] loads, final int localCount) {
for (final int load : loads) { for (final int load : loads) {
if(load < 0 || load >= localCount) { if(load < 0 || load >= localCount) {
return false; return false;
...@@ -4297,7 +4289,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -4297,7 +4289,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
return true; return true;
} }
private static String commonPrefix(String s1, String s2) { private static String commonPrefix(final String s1, final String s2) {
final int l1 = s1.length(); final int l1 = s1.length();
final int l = Math.min(l1, s2.length()); final int l = Math.min(l1, s2.length());
for(int i = 0; i < l; ++i) { for(int i = 0; i < l; ++i) {
...@@ -4313,7 +4305,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -4313,7 +4305,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private final boolean catchTarget; private final boolean catchTarget;
private boolean delegationTarget; private boolean delegationTarget;
OptimismExceptionHandlerSpec(final String lvarSpec, boolean catchTarget) { OptimismExceptionHandlerSpec(final String lvarSpec, final boolean catchTarget) {
this.lvarSpec = lvarSpec; this.lvarSpec = lvarSpec;
this.catchTarget = catchTarget; this.catchTarget = catchTarget;
if(!catchTarget) { if(!catchTarget) {
...@@ -4322,7 +4314,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex ...@@ -4322,7 +4314,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
} }
@Override @Override
public int compareTo(OptimismExceptionHandlerSpec o) { public int compareTo(final OptimismExceptionHandlerSpec o) {
return lvarSpec.compareTo(o.lvarSpec); return lvarSpec.compareTo(o.lvarSpec);
} }
......
...@@ -50,10 +50,12 @@ public final class CompilationEnvironment { ...@@ -50,10 +50,12 @@ public final class CompilationEnvironment {
private final ParamTypeMap paramTypes; private final ParamTypeMap paramTypes;
private final RecompilableScriptFunctionData compiledFunction; private RecompilableScriptFunctionData compiledFunction;
private boolean strict; 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 * 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. * that using whatever was at program point 17 as an int failed.
...@@ -88,12 +90,13 @@ public final class CompilationEnvironment { ...@@ -88,12 +90,13 @@ public final class CompilationEnvironment {
CompilationPhase.ATTRIBUTION_PHASE, CompilationPhase.ATTRIBUTION_PHASE,
CompilationPhase.RANGE_ANALYSIS_PHASE, CompilationPhase.RANGE_ANALYSIS_PHASE,
CompilationPhase.TYPE_FINALIZATION_PHASE, CompilationPhase.TYPE_FINALIZATION_PHASE,
CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
CompilationPhase.BYTECODE_GENERATION_PHASE CompilationPhase.BYTECODE_GENERATION_PHASE
}; };
private final static List<CompilationPhase> SEQUENCE_EAGER; private final static List<CompilationPhase> SEQUENCE_EAGER;
static { static {
LinkedList<CompilationPhase> eager = new LinkedList<>(); final LinkedList<CompilationPhase> eager = new LinkedList<>();
for (final CompilationPhase phase : SEQUENCE_EAGER_ARRAY) { for (final CompilationPhase phase : SEQUENCE_EAGER_ARRAY) {
eager.add(phase); eager.add(phase);
} }
...@@ -121,7 +124,7 @@ public final class CompilationEnvironment { ...@@ -121,7 +124,7 @@ public final class CompilationEnvironment {
private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) { private CompilationPhases addAfter(final CompilationPhase phase, final CompilationPhase newPhase) {
final LinkedList<CompilationPhase> list = new LinkedList<>(); final LinkedList<CompilationPhase> list = new LinkedList<>();
for (CompilationPhase p : phases) { for (final CompilationPhase p : phases) {
list.add(p); list.add(p);
if (p == phase) { if (p == phase) {
list.add(newPhase); list.add(newPhase);
...@@ -166,80 +169,90 @@ public final class CompilationEnvironment { ...@@ -166,80 +169,90 @@ public final class CompilationEnvironment {
public CompilationEnvironment( public CompilationEnvironment(
final CompilationPhases phases, final CompilationPhases phases,
final boolean strict) { 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 * Constructor for compilation environment of the rest-of method
* @param phases compilation phases * @param phases compilation phases
* @param strict strict mode * @param strict strict mode
* @param recompiledFunction recompiled function * @param compiledFunction 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 paramTypeMap known parameter types if any exist * @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( public CompilationEnvironment(
final CompilationPhases phases, final CompilationPhases phases,
final boolean strict, final boolean strict,
final RecompilableScriptFunctionData recompiledFunction, final RecompilableScriptFunctionData compiledFunction,
final ParamTypeMap paramTypeMap, final ParamTypeMap paramTypeMap,
final Map<Integer, Type> invalidatedProgramPoints, final Map<Integer, Type> invalidatedProgramPoints,
final int[] continuationEntryPoint) { final int[] continuationEntryPoint,
this(phases, paramTypeMap, invalidatedProgramPoints, recompiledFunction, continuationEntryPoint, strict); final boolean onDemand) {
this(phases, paramTypeMap, invalidatedProgramPoints, compiledFunction, continuationEntryPoint, strict, onDemand);
} }
/** /**
* Constructor * Constructor
* @param phases compilation phases * @param phases compilation phases
* @param strict strict mode * @param strict strict mode
* @param recompiledFunction recompiled function * @param compiledFunction recompiled function
* @param paramTypeMap known parameter types * @param paramTypeMap known parameter types
* @param invalidatedProgramPoints map of invalidated program points to their type * @param invalidatedProgramPoints map of invalidated program points to their type
* @param onDemand is this an on demand compilation
*/ */
public CompilationEnvironment( public CompilationEnvironment(
final CompilationPhases phases, final CompilationPhases phases,
final boolean strict, final boolean strict,
final RecompilableScriptFunctionData recompiledFunction, final RecompilableScriptFunctionData compiledFunction,
final ParamTypeMap paramTypeMap, final ParamTypeMap paramTypeMap,
final Map<Integer, Type> invalidatedProgramPoints) { final Map<Integer, Type> invalidatedProgramPoints,
this(phases, paramTypeMap, invalidatedProgramPoints, recompiledFunction, null, strict); final boolean onDemand) {
this(phases, paramTypeMap, invalidatedProgramPoints, compiledFunction, null, strict, onDemand);
} }
@SuppressWarnings("null")
private CompilationEnvironment( private CompilationEnvironment(
final CompilationPhases phases, final CompilationPhases phases,
final ParamTypeMap paramTypes, final ParamTypeMap paramTypes,
final Map<Integer, Type> invalidatedProgramPoints, final Map<Integer, Type> invalidatedProgramPoints,
final RecompilableScriptFunctionData compiledFunction, final RecompilableScriptFunctionData compiledFunction,
final int[] continuationEntryPoints, final int[] continuationEntryPoints,
final boolean strict) { final boolean strict,
final boolean onDemand) {
this.phases = phases; this.phases = phases;
this.paramTypes = paramTypes; this.paramTypes = paramTypes;
this.continuationEntryPoints = continuationEntryPoints; this.continuationEntryPoints = continuationEntryPoints;
this.invalidatedProgramPoints = this.invalidatedProgramPoints =
invalidatedProgramPoints == null ? invalidatedProgramPoints == null ?
Collections.unmodifiableMap(new HashMap<Integer, Type>()) : Collections.unmodifiableMap(new HashMap<Integer, Type>()) :
invalidatedProgramPoints; invalidatedProgramPoints;
this.compiledFunction = compiledFunction; this.compiledFunction = compiledFunction;
this.strict = strict; this.strict = strict;
this.optimistic = phases.contains(CompilationPhase.PROGRAM_POINT_PHASE); this.optimistic = phases.contains(CompilationPhase.PROGRAM_POINT_PHASE);
this.onDemand = onDemand;
// If entry point array is passed, it must have at least one element // If entry point array is passed, it must have at least one element
assert continuationEntryPoints == null || continuationEntryPoints.length > 0; assert continuationEntryPoints == null || continuationEntryPoints.length > 0;
assert !isCompileRestOf() || isOnDemandCompilation(); // isCompileRestOf => isRecompilation assert !isCompileRestOf() || isOnDemandCompilation(); // isCompileRestOf => isRecompilation
// continuation entry points must be among the invalidated program points // 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) { private static boolean containsAll(final Set<Integer> set, final int[] array) {
for(int i = 0; i < array.length; ++i) { for (int i = 0; i < array.length; ++i) {
if(!set.contains(array[i])) { if (!set.contains(array[i])) {
return false; return false;
} }
} }
return true; return true;
} }
void setData(final RecompilableScriptFunctionData data) {
assert this.compiledFunction == null : data;
this.compiledFunction = data;
}
boolean isStrict() { boolean isStrict() {
return strict; return strict;
} }
...@@ -291,7 +304,7 @@ public final class CompilationEnvironment { ...@@ -291,7 +304,7 @@ public final class CompilationEnvironment {
* @return true if this is an on-demand compilation, false if this is an eager compilation. * @return true if this is an on-demand compilation, false if this is an eager compilation.
*/ */
boolean isOnDemandCompilation() { boolean isOnDemandCompilation() {
return compiledFunction != null; return onDemand; //data != null;
} }
/** /**
...@@ -300,9 +313,9 @@ public final class CompilationEnvironment { ...@@ -300,9 +313,9 @@ public final class CompilationEnvironment {
* @return true if it is a continuation entry point * @return true if it is a continuation entry point
*/ */
boolean isContinuationEntryPoint(final int programPoint) { boolean isContinuationEntryPoint(final int programPoint) {
if(continuationEntryPoints != null) { if (continuationEntryPoints != null) {
for(int i = 0; i < continuationEntryPoints.length; ++i) { for (final int continuationEntryPoint : continuationEntryPoints) {
if(continuationEntryPoints[i] == programPoint) { if (continuationEntryPoint == programPoint) {
return true; return true;
} }
} }
...@@ -338,7 +351,6 @@ public final class CompilationEnvironment { ...@@ -338,7 +351,6 @@ public final class CompilationEnvironment {
* @return most optimistic type in current environment * @return most optimistic type in current environment
*/ */
Type getOptimisticType(final Optimistic node) { Type getOptimisticType(final Optimistic node) {
assert useOptimisticTypes(); assert useOptimisticTypes();
final Type invalidType = invalidatedProgramPoints.get(node.getProgramPoint()); final Type invalidType = invalidatedProgramPoints.get(node.getProgramPoint());
if (invalidType != null) { if (invalidType != null) {
......
...@@ -6,6 +6,7 @@ import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.FINALIZED; ...@@ -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.INITIALIZED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED; 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.PARSED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SCOPE_DEPTHS_COMPUTED;
import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
import java.util.ArrayDeque; import java.util.ArrayDeque;
...@@ -13,6 +14,7 @@ import java.util.ArrayList; ...@@ -13,6 +14,7 @@ import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import jdk.nashorn.internal.codegen.types.Range; import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Expression; import jdk.nashorn.internal.ir.Expression;
...@@ -120,10 +122,14 @@ enum CompilationPhase { ...@@ -120,10 +122,14 @@ enum CompilationPhase {
@Override @Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) { FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final TemporarySymbols ts = compiler.getTemporarySymbols(); 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) { if (compiler.getEnv()._print_mem_usage) {
Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount());
} }
return newFunctionNode; return newFunctionNode;
} }
...@@ -271,12 +277,24 @@ enum CompilationPhase { ...@@ -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: * Bytecode generation:
* *
* Generate the byte code class(es) resulting from the compiled FunctionNode * 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 @Override
FunctionNode transform(final Compiler compiler, final FunctionNode fn) { FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
final ScriptEnvironment env = compiler.getEnv(); final ScriptEnvironment env = compiler.getEnv();
......
...@@ -170,6 +170,16 @@ public enum CompilerConstants { ...@@ -170,6 +170,16 @@ public enum CompilerConstants {
/** get array suffix */ /** get array suffix */
GET_ARRAY_SUFFIX("$array"); 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. * 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; ...@@ -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_ACMPNE;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPEQ; 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_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.INSTANCEOF;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
...@@ -1570,6 +1574,16 @@ public class MethodEmitter implements Emitter { ...@@ -1570,6 +1574,16 @@ public class MethodEmitter implements Emitter {
jump(IFLT, label, 1); 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 * Generate an ifle
* *
...@@ -1580,6 +1594,16 @@ public class MethodEmitter implements Emitter { ...@@ -1580,6 +1594,16 @@ public class MethodEmitter implements Emitter {
jump(IFLE, label, 1); 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 * Generate an ifgt
* *
...@@ -1590,6 +1614,16 @@ public class MethodEmitter implements Emitter { ...@@ -1590,6 +1614,16 @@ public class MethodEmitter implements Emitter {
jump(IFGT, label, 1); 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 * Generate an ifge
* *
...@@ -1600,6 +1634,16 @@ public class MethodEmitter implements Emitter { ...@@ -1600,6 +1634,16 @@ public class MethodEmitter implements Emitter {
jump(IFGE, label, 1); 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 * Unconditional jump to a label
* *
...@@ -1995,7 +2039,7 @@ public class MethodEmitter implements Emitter { ...@@ -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) { if((flags & CALLSITE_OPTIMISTIC) == 0) {
return ""; return "";
} }
......
...@@ -165,12 +165,10 @@ class SharedScopeCall { ...@@ -165,12 +165,10 @@ class SharedScopeCall {
method.loadNull(); method.loadNull();
int slot = 2; int slot = 2;
for (final Type type : paramTypes) { for (final Type type : paramTypes) {
method.load(type, slot++); method.load(type, slot);
if (type == Type.NUMBER || type == Type.LONG) { slot += type.getSlots();
slot++;
}
} }
// 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); method.dynamicCall(returnType, 2 + paramTypes.length, flags);
} }
......
...@@ -58,6 +58,7 @@ import java.util.concurrent.ConcurrentMap; ...@@ -58,6 +58,7 @@ import java.util.concurrent.ConcurrentMap;
import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Undefined; import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.Bootstrap;
...@@ -224,7 +225,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps { ...@@ -224,7 +225,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
case jdk.internal.org.objectweb.asm.Type.OBJECT: case jdk.internal.org.objectweb.asm.Type.OBJECT:
try { try {
return Type.typeFor(Class.forName(itype.getClassName())); return Type.typeFor(Class.forName(itype.getClassName()));
} catch(ClassNotFoundException e) { } catch(final ClassNotFoundException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
case jdk.internal.org.objectweb.asm.Type.VOID: case jdk.internal.org.objectweb.asm.Type.VOID:
...@@ -424,7 +425,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps { ...@@ -424,7 +425,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
* @return true if types are equivalent, false otherwise * @return true if types are equivalent, false otherwise
*/ */
public boolean isEquivalentTo(final Type type) { 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 { ...@@ -778,6 +779,11 @@ public abstract class Type implements Comparable<Type>, BytecodeOps {
*/ */
public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class)); 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 * This is the singleton for integer arrays
*/ */
......
...@@ -76,6 +76,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> { ...@@ -76,6 +76,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
*/ */
public static final int IS_TERMINAL = 1 << 2; 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 * Constructor
* *
...@@ -91,7 +97,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> { ...@@ -91,7 +97,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
this.entryLabel = new Label("block_entry"); this.entryLabel = new Label("block_entry");
this.breakLabel = new Label("block_break"); this.breakLabel = new Label("block_break");
final int len = statements.length; 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> { ...@@ -115,6 +121,15 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
this.finish = finish; 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 * Clear the symbols in a block
* TODO: make this immutable * TODO: make this immutable
...@@ -292,7 +307,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> { ...@@ -292,7 +307,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
} }
@Override @Override
public Block setFlags(final LexicalContext lc, int flags) { public Block setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) { if (this.flags == flags) {
return this; return this;
} }
...@@ -300,12 +315,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> { ...@@ -300,12 +315,12 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
} }
@Override @Override
public Block clearFlag(final LexicalContext lc, int flag) { public Block clearFlag(final LexicalContext lc, final int flag) {
return setFlags(lc, flags & ~flag); return setFlags(lc, flags & ~flag);
} }
@Override @Override
public Block setFlag(final LexicalContext lc, int flag) { public Block setFlag(final LexicalContext lc, final int flag) {
return setFlags(lc, flags | flag); return setFlags(lc, flags | flag);
} }
...@@ -354,7 +369,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> { ...@@ -354,7 +369,7 @@ public class Block extends Node implements BreakableNode, Flags<Block> {
} }
@Override @Override
public Node accept(NodeVisitor<? extends LexicalContext> visitor) { public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
return Acceptor.accept(this, visitor); return Acceptor.accept(this, visitor);
} }
} }
...@@ -32,6 +32,7 @@ import java.util.Iterator; ...@@ -32,6 +32,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
...@@ -84,6 +85,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -84,6 +85,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
SPLIT, SPLIT,
/** method has had its types finalized */ /** method has had its types finalized */
FINALIZED, FINALIZED,
/** computed scope depths for symbols */
SCOPE_DEPTHS_COMPUTED,
/** method has been emitted to bytecode */ /** method has been emitted to bytecode */
EMITTED EMITTED
} }
...@@ -139,6 +142,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -139,6 +142,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
/** //@ sourceURL or //# sourceURL for program function nodes */ /** //@ sourceURL or //# sourceURL for program function nodes */
private final String sourceURL; private final String sourceURL;
/** Line number of function start */
private final int lineNumber; private final int lineNumber;
/** Is anonymous function flag. */ /** Is anonymous function flag. */
...@@ -214,8 +218,11 @@ public final class FunctionNode extends LexicalContextExpression implements 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 */ * 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; 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 */ /** 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? */ /** What is the return type of this function? */
private Type returnType = Type.UNKNOWN; private Type returnType = Type.UNKNOWN;
...@@ -275,7 +282,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -275,7 +282,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final FunctionNode functionNode, final FunctionNode functionNode,
final long lastToken, final long lastToken,
final int flags, final int flags,
String sourceURL, final String sourceURL,
final String name, final String name,
final Type returnType, final Type returnType,
final CompileUnit compileUnit, final CompileUnit compileUnit,
...@@ -335,7 +342,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -335,7 +342,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @return name for the script source * @return name for the script source
*/ */
public String getSourceName() { 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 ...@@ -472,7 +479,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
} }
@Override @Override
public FunctionNode setFlags(final LexicalContext lc, int flags) { public FunctionNode setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) { if (this.flags == flags) {
return this; return this;
} }
...@@ -700,7 +707,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -700,7 +707,6 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return name; return name;
} }
/** /**
* Set the internal name for this function * Set the internal name for this function
* @param lc lexical context * @param lc lexical context
...@@ -823,7 +829,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -823,7 +829,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
type, type,
compileUnit, compileUnit,
compilationState, compilationState,
body.setReturnType(type), parameters)); body.setReturnType(type),
parameters
));
} }
/** /**
......
...@@ -235,7 +235,7 @@ public class LexicalContext { ...@@ -235,7 +235,7 @@ public class LexicalContext {
public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) { public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) {
for (int i = sp - 1; i >= 0; i--) { for (int i = sp - 1; i >= 0; i--) {
if (stack[i] == oldNode) { 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; stack[i] = newNode;
break; break;
} }
...@@ -269,6 +269,17 @@ public class LexicalContext { ...@@ -269,6 +269,17 @@ public class LexicalContext {
return iter.hasNext() ? iter.next() : null; 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. * Returns an iterator over all ancestors block of the given block, with its parent block first.
* @param block the block whose ancestors are returned * @param block the block whose ancestors are returned
...@@ -381,7 +392,7 @@ public class LexicalContext { ...@@ -381,7 +392,7 @@ public class LexicalContext {
* @param symbol symbol * @param symbol symbol
* @return function node in which this symbol is defined, assert if no such symbol exists in context * @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()) { if (symbol.isTemp()) {
return null; return null;
} }
...@@ -392,7 +403,7 @@ public class LexicalContext { ...@@ -392,7 +403,7 @@ public class LexicalContext {
while (iter.hasNext()) { while (iter.hasNext()) {
final LexicalContextNode next2 = iter.next(); final LexicalContextNode next2 = iter.next();
if (next2 instanceof FunctionNode) { if (next2 instanceof FunctionNode) {
return ((FunctionNode)next2); return (FunctionNode)next2;
} }
} }
throw new AssertionError("Defining block for symbol " + name + " has no function in the context"); throw new AssertionError("Defining block for symbol " + name + " has no function in the context");
...@@ -437,11 +448,11 @@ public class LexicalContext { ...@@ -437,11 +448,11 @@ public class LexicalContext {
int n = 0; int n = 0;
for (final Iterator<LexicalContextNode> iter = getAllNodes(); iter.hasNext();) { for (final Iterator<LexicalContextNode> iter = getAllNodes(); iter.hasNext();) {
final LexicalContextNode node = iter.next(); final LexicalContextNode node = iter.next();
if(node == until) { if (node == until) {
break; break;
} }
assert !(node instanceof FunctionNode); // Can't go outside current function 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++; n++;
} }
} }
...@@ -618,7 +629,7 @@ public class LexicalContext { ...@@ -618,7 +629,7 @@ public class LexicalContext {
if (next == null) { if (next == null) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
T lnext = next; final T lnext = next;
next = findNext(); next = findNext();
return lnext; return lnext;
} }
......
...@@ -31,6 +31,7 @@ import java.io.PrintWriter; ...@@ -31,6 +31,7 @@ import java.io.PrintWriter;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import jdk.nashorn.internal.codegen.types.Range; import jdk.nashorn.internal.codegen.types.Range;
import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
...@@ -109,7 +110,7 @@ public final class Symbol implements Comparable<Symbol> { ...@@ -109,7 +110,7 @@ public final class Symbol implements Comparable<Symbol> {
if (stacktrace != null) { if (stacktrace != null) {
trace = stacktrace; //stacktrace always implies trace as well trace = stacktrace; //stacktrace always implies trace as well
TRACE_SYMBOLS_STACKTRACE = new HashSet<>(); 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()); TRACE_SYMBOLS_STACKTRACE.add(st.nextToken());
} }
} else { } else {
...@@ -119,7 +120,7 @@ public final class Symbol implements Comparable<Symbol> { ...@@ -119,7 +120,7 @@ public final class Symbol implements Comparable<Symbol> {
if (trace != null) { if (trace != null) {
TRACE_SYMBOLS = new HashSet<>(); 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()); TRACE_SYMBOLS.add(st.nextToken());
} }
} else { } else {
...@@ -351,7 +352,7 @@ public final class Symbol implements Comparable<Symbol> { ...@@ -351,7 +352,7 @@ public final class Symbol implements Comparable<Symbol> {
* @return true if this is scoped * @return true if this is scoped
*/ */
public boolean isScope() { 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; return (flags & IS_SCOPE) == IS_SCOPE;
} }
......
...@@ -39,6 +39,7 @@ import java.util.LinkedHashSet; ...@@ -39,6 +39,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
...@@ -48,6 +49,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader; ...@@ -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.Printer;
import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor; import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor;
import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/** /**
* Pretty printer for --print-code. * Pretty printer for --print-code.
...@@ -160,8 +162,8 @@ public final class NashornTextifier extends Printer { ...@@ -160,8 +162,8 @@ public final class NashornTextifier extends Printer {
} }
if (interfaces != null && interfaces.length > 0) { if (interfaces != null && interfaces.length > 0) {
sb.append(" implements "); sb.append(" implements ");
for (int i = 0; i < interfaces.length; ++i) { for (final String interface1 : interfaces) {
appendDescriptor(sb, INTERNAL_NAME, interfaces[i]); appendDescriptor(sb, INTERNAL_NAME, interface1);
sb.append(' '); sb.append(' ');
} }
} }
...@@ -222,8 +224,8 @@ public final class NashornTextifier extends Printer { ...@@ -222,8 +224,8 @@ public final class NashornTextifier extends Printer {
sb.append(tab); sb.append(tab);
appendDescriptor(sb, FIELD_SIGNATURE, signature); appendDescriptor(sb, FIELD_SIGNATURE, signature);
TraceSignatureVisitor sv = new TraceSignatureVisitor(0); final TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature); final SignatureReader r = new SignatureReader(signature);
r.acceptType(sv); r.acceptType(sv);
sb.append(tab). sb.append(tab).
append("// declaration: "). append("// declaration: ").
...@@ -249,7 +251,7 @@ public final class NashornTextifier extends Printer { ...@@ -249,7 +251,7 @@ public final class NashornTextifier extends Printer {
sb.append(";\n"); sb.append(";\n");
addText(sb); addText(sb);
NashornTextifier t = createNashornTextifier(); final NashornTextifier t = createNashornTextifier();
addText(t.getText()); addText(t.getText());
return t; return t;
...@@ -280,12 +282,12 @@ public final class NashornTextifier extends Printer { ...@@ -280,12 +282,12 @@ public final class NashornTextifier extends Printer {
sb.append(tab); sb.append(tab);
appendDescriptor(sb, METHOD_SIGNATURE, signature); appendDescriptor(sb, METHOD_SIGNATURE, signature);
TraceSignatureVisitor v = new TraceSignatureVisitor(0); final TraceSignatureVisitor v = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature); final SignatureReader r = new SignatureReader(signature);
r.accept(v); r.accept(v);
String genericDecl = v.getDeclaration(); final String genericDecl = v.getDeclaration();
String genericReturn = v.getReturnType(); final String genericReturn = v.getReturnType();
String genericExceptions = v.getExceptions(); final String genericExceptions = v.getExceptions();
sb.append(tab). sb.append(tab).
append("// declaration: "). append("// declaration: ").
...@@ -316,8 +318,8 @@ public final class NashornTextifier extends Printer { ...@@ -316,8 +318,8 @@ public final class NashornTextifier extends Printer {
appendDescriptor(sb, METHOD_DESCRIPTOR, desc); appendDescriptor(sb, METHOD_DESCRIPTOR, desc);
if (exceptions != null && exceptions.length > 0) { if (exceptions != null && exceptions.length > 0) {
sb.append(" throws "); sb.append(" throws ");
for (int i = 0; i < exceptions.length; ++i) { for (final String exception : exceptions) {
appendDescriptor(sb, INTERNAL_NAME, exceptions[i]); appendDescriptor(sb, INTERNAL_NAME, exception);
sb.append(' '); sb.append(' ');
} }
} }
...@@ -325,7 +327,7 @@ public final class NashornTextifier extends Printer { ...@@ -325,7 +327,7 @@ public final class NashornTextifier extends Printer {
sb.append('\n'); sb.append('\n');
addText(sb); addText(sb);
NashornTextifier t = createNashornTextifier(); final NashornTextifier t = createNashornTextifier();
addText(t.getText()); addText(t.getText());
return t; return t;
} }
...@@ -345,7 +347,7 @@ public final class NashornTextifier extends Printer { ...@@ -345,7 +347,7 @@ public final class NashornTextifier extends Printer {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append(tab2).append("// parameter "); sb.append(tab2).append("// parameter ");
appendAccess(sb, access); appendAccess(sb, access);
sb.append(' ').append((name == null) ? "<no name>" : name) sb.append(' ').append(name == null ? "<no name>" : name)
.append('\n'); .append('\n');
addText(sb); addText(sb);
} }
...@@ -393,11 +395,11 @@ public final class NashornTextifier extends Printer { ...@@ -393,11 +395,11 @@ public final class NashornTextifier extends Printer {
} }
private StringBuilder appendOpcode(final StringBuilder sb, final int opcode) { 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) { if (next instanceof NashornLabel) {
final int bci = next.getOffset(); final int bci = next.getOffset();
if (bci != -1) { if (bci != -1) {
String bcis = "" + bci; final String bcis = "" + bci;
for (int i = 0; i < 5 - bcis.length(); i++) { for (int i = 0; i < 5 - bcis.length(); i++) {
sb.append(' '); sb.append(' ');
} }
...@@ -480,7 +482,6 @@ public final class NashornTextifier extends Printer { ...@@ -480,7 +482,6 @@ public final class NashornTextifier extends Printer {
} }
sb.append(" ["); sb.append(" [");
appendHandle(sb, bsm); appendHandle(sb, bsm);
sb.append(" args=");
if (bsmArgs.length == 0) { if (bsmArgs.length == 0) {
sb.append("none"); sb.append("none");
} else { } else {
...@@ -492,12 +493,12 @@ public final class NashornTextifier extends Printer { ...@@ -492,12 +493,12 @@ public final class NashornTextifier extends Printer {
} else if (cst instanceof Handle) { } else if (cst instanceof Handle) {
appendHandle(sb, (Handle)cst); appendHandle(sb, (Handle)cst);
} else if (cst instanceof Integer) { } else if (cst instanceof Integer) {
int c = (Integer)cst; final int c = (Integer)cst;
int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT; final int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT;
if (pp != 0) { 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 { } else {
sb.append(cst); sb.append(cst);
} }
...@@ -539,7 +540,7 @@ public final class NashornTextifier extends Printer { ...@@ -539,7 +540,7 @@ public final class NashornTextifier extends Printer {
public void visitJumpInsn(final int opcode, final Label label) { public void visitJumpInsn(final int opcode, final Label label) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
appendOpcode(sb, opcode).append(' '); appendOpcode(sb, opcode).append(' ');
String to = appendLabel(sb, label); final String to = appendLabel(sb, label);
sb.append('\n'); sb.append('\n');
addText(sb); addText(sb);
checkNoFallThru(opcode, to); checkNoFallThru(opcode, to);
...@@ -556,7 +557,7 @@ public final class NashornTextifier extends Printer { ...@@ -556,7 +557,7 @@ public final class NashornTextifier extends Printer {
public void visitLabel(final Label label) { public void visitLabel(final Label label) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("\n"); sb.append("\n");
String name = appendLabel(sb, label); final String name = appendLabel(sb, label);
sb.append(" [bci="); sb.append(" [bci=");
sb.append(label.info); sb.append(label.info);
sb.append("]"); sb.append("]");
...@@ -689,8 +690,8 @@ public final class NashornTextifier extends Printer { ...@@ -689,8 +690,8 @@ public final class NashornTextifier extends Printer {
sb.append(tab2); sb.append(tab2);
appendDescriptor(sb, FIELD_SIGNATURE, signature); appendDescriptor(sb, FIELD_SIGNATURE, signature);
TraceSignatureVisitor sv = new TraceSignatureVisitor(0); final TraceSignatureVisitor sv = new TraceSignatureVisitor(0);
SignatureReader r = new SignatureReader(signature); final SignatureReader r = new SignatureReader(signature);
r.acceptType(sv); r.acceptType(sv);
sb.append(tab2).append("// declaration: ") sb.append(tab2).append("// declaration: ")
.append(sv.getDeclaration()).append('\n'); .append(sv.getDeclaration()).append('\n');
...@@ -718,7 +719,7 @@ public final class NashornTextifier extends Printer { ...@@ -718,7 +719,7 @@ public final class NashornTextifier extends Printer {
private void printToDir(final Graph g) { private void printToDir(final Graph g) {
if (env._print_code_dir != null) { 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()) { if (!dir.exists() && !dir.mkdirs()) {
throw new RuntimeException(dir.toString()); throw new RuntimeException(dir.toString());
} }
...@@ -726,14 +727,14 @@ public final class NashornTextifier extends Printer { ...@@ -726,14 +727,14 @@ public final class NashornTextifier extends Printer {
File file; File file;
int uniqueId = 0; int uniqueId = 0;
do { do {
String fileName = g.getName() + (uniqueId == 0 ? "" : "_" + uniqueId) + ".dot"; final String fileName = g.getName() + (uniqueId == 0 ? "" : "_" + uniqueId) + ".dot";
file = new File(dir, fileName); file = new File(dir, fileName);
uniqueId++; uniqueId++;
} while (file.exists()); } while (file.exists());
try (PrintWriter pw = new PrintWriter(new FileOutputStream(file))) { try (PrintWriter pw = new PrintWriter(new FileOutputStream(file))) {
pw.println(g); pw.println(g);
} catch (FileNotFoundException e) { } catch (final FileNotFoundException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
...@@ -869,7 +870,7 @@ public final class NashornTextifier extends Printer { ...@@ -869,7 +870,7 @@ public final class NashornTextifier extends Printer {
sb.append(' '); sb.append(' ');
} }
if (o[i] instanceof String) { if (o[i] instanceof String) {
String desc = (String) o[i]; final String desc = (String) o[i];
if (desc.startsWith("[")) { if (desc.startsWith("[")) {
appendDescriptor(sb, FIELD_DESCRIPTOR, desc); appendDescriptor(sb, FIELD_DESCRIPTOR, desc);
} else { } else {
...@@ -926,7 +927,7 @@ public final class NashornTextifier extends Printer { ...@@ -926,7 +927,7 @@ public final class NashornTextifier extends Printer {
} }
} }
} else { } else {
int lastSlash = desc.lastIndexOf('/'); final int lastSlash = desc.lastIndexOf('/');
sb.append(lastSlash == -1 ? desc : desc.substring(lastSlash + 1)); sb.append(lastSlash == -1 ? desc : desc.substring(lastSlash + 1));
} }
} }
...@@ -934,7 +935,7 @@ public final class NashornTextifier extends Printer { ...@@ -934,7 +935,7 @@ public final class NashornTextifier extends Printer {
private static void appendStr(final StringBuilder sb, final String s) { private static void appendStr(final StringBuilder sb, final String s) {
sb.append('\"'); sb.append('\"');
for (int i = 0; i < s.length(); ++i) { for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i); final char c = s.charAt(i);
if (c == '\n') { if (c == '\n') {
sb.append("\\n"); sb.append("\\n");
} else if (c == '\r') { } else if (c == '\r') {
...@@ -1056,7 +1057,7 @@ public final class NashornTextifier extends Printer { ...@@ -1056,7 +1057,7 @@ public final class NashornTextifier extends Printer {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("digraph " + name + " {"); sb.append("digraph " + name + " {");
sb.append("\n"); sb.append("\n");
sb.append("\tgraph [fontname=courier]\n"); sb.append("\tgraph [fontname=courier]\n");
...@@ -1083,7 +1084,7 @@ public final class NashornTextifier extends Printer { ...@@ -1083,7 +1084,7 @@ public final class NashornTextifier extends Printer {
} }
for (final String from : edges.keySet()) { for (final String from : edges.keySet()) {
for (String to : edges.get(from)) { for (final String to : edges.get(from)) {
sb.append("\t"); sb.append("\t");
sb.append(from); sb.append(from);
sb.append(" -> "); sb.append(" -> ");
......
...@@ -61,6 +61,7 @@ import java.util.HashSet; ...@@ -61,6 +61,7 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.internal.dynalink.support.NameCodec; import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace; import jdk.nashorn.internal.codegen.Namespace;
...@@ -270,7 +271,7 @@ public class Parser extends AbstractParser { ...@@ -270,7 +271,7 @@ public class Parser extends AbstractParser {
final String end = this + " end '" + scriptName + "'"; final String end = this + " end '" + scriptName + "'";
if (Timing.isEnabled()) { if (Timing.isEnabled()) {
Timing.accumulateTime(toString(), System.currentTimeMillis() - t0); Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms"); LOG.info(end, "' in ", System.currentTimeMillis() - t0, " ms");
} else { } else {
LOG.info(end); LOG.info(end);
} }
...@@ -314,7 +315,7 @@ public class Parser extends AbstractParser { ...@@ -314,7 +315,7 @@ public class Parser extends AbstractParser {
try { try {
stream = new TokenStream(); stream = new TokenStream();
lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions); lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
int functionLine = line; final int functionLine = line;
// Set up first token (skips opening EOL.) // Set up first token (skips opening EOL.)
k = -1; k = -1;
...@@ -1076,7 +1077,7 @@ loop: ...@@ -1076,7 +1077,7 @@ loop:
// If is a statement then handle end of line. // If is a statement then handle end of line.
if (isStatement) { if (isStatement) {
boolean semicolon = type == SEMICOLON; final boolean semicolon = type == SEMICOLON;
endOfLine(); endOfLine();
if (semicolon) { if (semicolon) {
lc.getCurrentBlock().setFinish(finish); lc.getCurrentBlock().setFinish(finish);
...@@ -2663,7 +2664,7 @@ loop: ...@@ -2663,7 +2664,7 @@ loop:
private String getDefaultValidFunctionName(final int functionLine) { private String getDefaultValidFunctionName(final int functionLine) {
final String defaultFunctionName = getDefaultFunctionName(); 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) { private static boolean isValidIdentifier(String name) {
......
...@@ -264,7 +264,7 @@ final class CompiledFunction { ...@@ -264,7 +264,7 @@ final class CompiledFunction {
return betterThanFinal(type(), other.type(), callSiteMethodType); 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 thisParamCount = getParamCount(thisMethodType);
final int otherParamCount = getParamCount(otherMethodType); final int otherParamCount = getParamCount(otherMethodType);
final int callSiteRawParamCount = getParamCount(callSiteMethodType); final int callSiteRawParamCount = getParamCount(callSiteMethodType);
...@@ -389,7 +389,7 @@ final class CompiledFunction { ...@@ -389,7 +389,7 @@ final class CompiledFunction {
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical 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 int paramCount = type.parameterCount();
final Type[] t = new Type[paramCount - thisIndex]; final Type[] t = new Type[paramCount - thisIndex];
for(int i = thisIndex; i < paramCount; ++i) { for(int i = thisIndex; i < paramCount; ++i) {
...@@ -398,7 +398,7 @@ final class CompiledFunction { ...@@ -398,7 +398,7 @@ final class CompiledFunction {
return t; 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); final int fixParamCount = paramTypes.length - (isVarArg ? 1 : 0);
if(i < fixParamCount) { if(i < fixParamCount) {
return paramTypes[i]; return paramTypes[i];
...@@ -424,8 +424,8 @@ final class CompiledFunction { ...@@ -424,8 +424,8 @@ final class CompiledFunction {
final boolean csIsVarArg = csParamCount == Integer.MAX_VALUE; final boolean csIsVarArg = csParamCount == Integer.MAX_VALUE;
final int thisThisIndex = needsCallee() ? 1 : 0; // Index of "this" parameter in this function's type final int thisThisIndex = needsCallee() ? 1 : 0; // Index of "this" parameter in this function's type
int fnParamCountNoCallee = fnParamCount - thisThisIndex; final int fnParamCountNoCallee = fnParamCount - thisThisIndex;
int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1 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". // We must match all incoming parameters, except "this". Starting from 1 to skip "this".
for(int i = 1; i < minParams; ++i) { for(int i = 1; i < minParams; ++i) {
final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex)); final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
...@@ -464,7 +464,7 @@ final class CompiledFunction { ...@@ -464,7 +464,7 @@ final class CompiledFunction {
return optimismInfo != null; return optimismInfo != null;
} }
private MethodHandle createComposableInvoker(boolean isConstructor) { private MethodHandle createComposableInvoker(final boolean isConstructor) {
final MethodHandle handle = getInvokerOrConstructor(isConstructor); final MethodHandle handle = getInvokerOrConstructor(isConstructor);
// If compiled function is not optimistic, it can't ever change its invoker/constructor, so just return them // 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 { ...@@ -498,7 +498,7 @@ final class CompiledFunction {
cs.setTarget(target); cs.setTarget(target);
} }
private MethodHandle getInvokerOrConstructor(boolean selectCtor) { private MethodHandle getInvokerOrConstructor(final boolean selectCtor) {
return selectCtor ? getConstructor() : createInvokerForPessimisticCaller(); return selectCtor ? getConstructor() : createInvokerForPessimisticCaller();
} }
...@@ -535,7 +535,7 @@ final class CompiledFunction { ...@@ -535,7 +535,7 @@ final class CompiledFunction {
return MH.foldArguments(RESTOF_INVOKER, MH.insertArguments(HANDLE_REWRITE_EXCEPTION, 0, this, optimismInfo)); 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)); return Bootstrap.getLinkerServices().asType(mh, mh.type().changeReturnType(newReturnType));
} }
...@@ -571,7 +571,9 @@ final class CompiledFunction { ...@@ -571,7 +571,9 @@ final class CompiledFunction {
//is recompiled //is recompiled
assert optimismInfo == oldOptimismInfo; assert optimismInfo == oldOptimismInfo;
isOptimistic = fn.isOptimistic(); 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); final MethodHandle newInvoker = oldOptimismInfo.data.lookup(fn);
invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType())); invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType()));
constructor = null; // Will be regenerated when needed constructor = null; // Will be regenerated when needed
......
...@@ -197,7 +197,7 @@ public final class Context { ...@@ -197,7 +197,7 @@ public final class Context {
*/ */
public static PrintWriter getCurrentErr() { public static PrintWriter getCurrentErr() {
final ScriptObject global = getGlobalTrusted(); 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 { ...@@ -423,7 +423,7 @@ public final class Context {
* @return the return value of the {@code eval} * @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) { 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 Source source = new Source(file, string);
final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
final ScriptObject global = Context.getGlobalTrusted(); final ScriptObject global = Context.getGlobalTrusted();
...@@ -468,10 +468,10 @@ public final class Context { ...@@ -468,10 +468,10 @@ public final class Context {
scope = strictEvalScope; scope = strictEvalScope;
} }
ScriptFunction func = getProgramFunction(clazz, scope); final ScriptFunction func = getProgramFunction(clazz, scope);
Object evalThis; Object evalThis;
if (directEval) { if (directEval) {
evalThis = (callThis instanceof ScriptObject || strictFlag) ? callThis : global; evalThis = callThis instanceof ScriptObject || strictFlag ? callThis : global;
} else { } else {
evalThis = global; evalThis = global;
} }
...@@ -490,7 +490,7 @@ public final class Context { ...@@ -490,7 +490,7 @@ public final class Context {
public Source run() { public Source run() {
try { try {
final URL resURL = Context.class.getResource(resource); 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) { } catch (final IOException exp) {
return null; return null;
} }
...@@ -513,7 +513,7 @@ public final class Context { ...@@ -513,7 +513,7 @@ public final class Context {
* @throws IOException if source cannot be found or loaded * @throws IOException if source cannot be found or loaded
*/ */
public Object load(final ScriptObject scope, final Object from) throws IOException { 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; Source source = null;
// load accepts a String (which could be a URL or a file name), a File, a URL // 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 { ...@@ -521,8 +521,8 @@ public final class Context {
if (src instanceof String) { if (src instanceof String) {
final String srcStr = (String)src; final String srcStr = (String)src;
if (srcStr.startsWith(LOAD_CLASSPATH)) { if (srcStr.startsWith(LOAD_CLASSPATH)) {
URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length())); final URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
source = (url != null)? new Source(url.toString(), url) : null; source = url != null ? new Source(url.toString(), url) : null;
} else { } else {
final File file = new File(srcStr); final File file = new File(srcStr);
if (srcStr.indexOf(':') != -1) { if (srcStr.indexOf(':') != -1) {
...@@ -837,7 +837,7 @@ public final class Context { ...@@ -837,7 +837,7 @@ public final class Context {
/** /**
* Set the current global scope * Set the current global scope
*/ */
static void setGlobalTrusted(ScriptObject global) { static void setGlobalTrusted(final ScriptObject global) {
currentGlobal.set(global); currentGlobal.set(global);
} }
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime; package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.parser.TokenType.EOF; import static jdk.nashorn.internal.parser.TokenType.EOF;
import jdk.nashorn.internal.parser.Lexer; import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenStream; import jdk.nashorn.internal.parser.TokenStream;
...@@ -71,7 +70,7 @@ public final class Debug { ...@@ -71,7 +70,7 @@ public final class Debug {
* @return system identity hashcode as string * @return system identity hashcode as string
*/ */
public static String id(final Object x) { 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 { ...@@ -563,24 +563,33 @@ public abstract class Property {
return sb.toString(); 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 @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final Class<?> type = getCurrentType(); final Class<?> type = getCurrentType();
sb.append(getKey()). sb.append(indent(getKey(), 20)).
append(" id="). append(" id=").
append(Debug.id(this)). append(Debug.id(this)).
append(" (0x"). append(" (0x").
append(Integer.toHexString(flags)). append(indent(Integer.toHexString(flags), 4)).
append(") "). append(") ").
append(getClass().getSimpleName()). append(getClass().getSimpleName()).
append(" {"). append(" {").
append(type(type)). append(indent(type(type), 5)).
append('}'); append('}');
if (slot != -1) { if (slot != -1) {
sb.append('['). sb.append(" [").
append("slot="). append("slot=").
append(slot). append(slot).
append(']'); append(']');
......
...@@ -154,8 +154,8 @@ public interface PropertyDescriptor { ...@@ -154,8 +154,8 @@ public interface PropertyDescriptor {
/** /**
* Check existence and compare attributes of descriptors. * Check existence and compare attributes of descriptors.
* * @param otherDesc other descriptor to compare to
* @return true if every field of this desc exists in otherDesc and has the same value. * @return true if every field of this descriptor exists in otherDesc and has the same value.
*/ */
public boolean hasAndEquals(PropertyDescriptor otherDesc); public boolean hasAndEquals(PropertyDescriptor otherDesc);
} }
......
...@@ -31,11 +31,15 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; ...@@ -31,11 +31,15 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import java.lang.invoke.SwitchPoint; import java.lang.invoke.SwitchPoint;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.WeakHashMap; import java.util.WeakHashMap;
...@@ -698,19 +702,16 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener { ...@@ -698,19 +702,16 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append(" ["); sb.append(Debug.id(this));
boolean isFirst = true; sb.append(" = {\n");
for (final Property property : properties.values()) { for (final Property property : plist) {
if (!isFirst) { sb.append('\t');
sb.append(", ");
}
isFirst = false;
sb.append(property); sb.append(property);
sb.append('\n');
} }
sb.append(']'); sb.append('}');
return sb.toString(); return sb.toString();
} }
......
...@@ -36,6 +36,7 @@ import java.util.Iterator; ...@@ -36,6 +36,7 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import jdk.internal.dynalink.support.NameCodec; import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.CompilationEnvironment; import jdk.nashorn.internal.codegen.CompilationEnvironment;
import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases; import jdk.nashorn.internal.codegen.CompilationEnvironment.CompilationPhases;
...@@ -96,7 +97,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -96,7 +97,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/** lazily generated allocator */ /** lazily generated allocator */
private MethodHandle 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 isDeclared;
private final boolean isAnonymous; private final boolean isAnonymous;
...@@ -109,16 +113,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -109,16 +113,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
private static final DebugLogger LOG = new DebugLogger("recompile"); 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 * Constructor - public as scripts use it
* *
* @param functionNode functionNode that represents this function code * @param functionNode functionNode that represents this function code
* @param installer installer for code regeneration versions of this function * @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 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 allocatorMap allocator map to seed instances with, when constructing
* @param nestedFunctions nested function map * @param nestedFunctions nested function map
* @param sourceURL source URL * @param sourceURL source URL
* @param externalScopeDepths external scope depths
*/ */
public RecompilableScriptFunctionData( public RecompilableScriptFunctionData(
final FunctionNode functionNode, final FunctionNode functionNode,
...@@ -126,7 +134,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -126,7 +134,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final String allocatorClassName, final String allocatorClassName,
final PropertyMap allocatorMap, final PropertyMap allocatorMap,
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions, final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
final String sourceURL) { final String sourceURL,
final Map<String, Integer> externalScopeDepths) {
super(functionName(functionNode), super(functionName(functionNode),
Math.min(functionNode.getParameters().size(), MAX_ARITY), Math.min(functionNode.getParameters().size(), MAX_ARITY),
functionNode.isStrict(), functionNode.isStrict(),
...@@ -134,19 +144,57 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -134,19 +144,57 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
true, true,
functionNode.isVarArg()); functionNode.isVarArg());
this.functionName = functionNode.getName(); this.functionName = functionNode.getName();
this.lineNumber = functionNode.getLineNumber(); this.lineNumber = functionNode.getLineNumber();
this.isDeclared = functionNode.isDeclared(); this.isDeclared = functionNode.isDeclared();
this.needsCallee = functionNode.needsCallee(); this.needsCallee = functionNode.needsCallee();
this.isAnonymous = functionNode.isAnonymous(); this.isAnonymous = functionNode.isAnonymous();
this.functionNodeId = functionNode.getId(); this.functionNodeId = functionNode.getId();
this.source = functionNode.getSource(); this.source = functionNode.getSource();
this.token = tokenFor(functionNode); this.token = tokenFor(functionNode);
this.installer = installer; this.installer = installer;
this.sourceURL = sourceURL; this.sourceURL = sourceURL;
this.allocatorClassName = allocatorClassName; this.allocatorClassName = allocatorClassName;
this.allocatorMap = allocatorMap; this.allocatorMap = allocatorMap;
this.nestedFunctions = nestedFunctions; 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 @Override
...@@ -162,6 +210,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -162,6 +210,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append("fid=").append(functionNodeId).append(' ');
if (source != null) { if (source != null) {
sb.append(source.getName()) sb.append(source.getName())
.append(':') .append(':')
...@@ -179,7 +229,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -179,7 +229,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final FunctionNode.Kind kind = fn.getKind(); final FunctionNode.Kind kind = fn.getKind();
if (kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) { if (kind == FunctionNode.Kind.GETTER || kind == FunctionNode.Kind.SETTER) {
final String name = NameCodec.decode(fn.getIdent().getName()); 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(); return fn.getIdent().getName();
} }
...@@ -265,7 +315,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -265,7 +315,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
this, this,
isVariableArity() ? null : new ParamTypeMap(functionNodeId, explicitParams(fnCallSiteType)), isVariableArity() ? null : new ParamTypeMap(functionNodeId, explicitParams(fnCallSiteType)),
invalidatedProgramPoints, invalidatedProgramPoints,
continuationEntryPoints continuationEntryPoints,
true
), ),
installer); installer);
...@@ -276,7 +327,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -276,7 +327,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return lookupWithExplicitType(fn, MethodType.methodType(fn.getReturnType().getTypeClass(), RewriteException.class)); 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"); return compile(actualCallSiteType, null, "Type specialized compilation");
} }
...@@ -297,7 +348,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -297,7 +348,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
new ParamTypeMap( new ParamTypeMap(
functionNodeId, functionNodeId,
explicitParams(fnCallSiteType)), explicitParams(fnCallSiteType)),
invalidatedProgramPoints), invalidatedProgramPoints,
true),
installer); installer);
fn = compiler.compile(scriptName, fn); fn = compiler.compile(scriptName, fn);
...@@ -377,7 +429,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -377,7 +429,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
public void initializeCode(final FunctionNode functionNode) { public void initializeCode(final FunctionNode functionNode) {
// Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit. // 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))) { if(!(code.isEmpty() && functionNode.getCompileUnit().isInitializing(this, functionNode))) {
throw new IllegalStateException(); throw new IllegalStateException(functionNode.getName() + " id=" + functionNode.getId());
} }
addCode(functionNode); addCode(functionNode);
} }
...@@ -409,7 +461,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -409,7 +461,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final MethodHandle handle = lookup(fn); final MethodHandle handle = lookup(fn);
final MethodType fromType = handle.type(); 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()); toType = toType.changeReturnType(fromType.returnType());
final int toCount = toType.parameterCount(); final int toCount = toType.parameterCount();
...@@ -436,7 +488,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -436,7 +488,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
} }
@Override @Override
CompiledFunction getBest(MethodType callSiteType) { CompiledFunction getBest(final MethodType callSiteType) {
synchronized(code) { synchronized(code) {
final CompiledFunction existingBest = super.getBest(callSiteType); final CompiledFunction existingBest = super.getBest(callSiteType);
// TODO: what if callSiteType is vararg? // TODO: what if callSiteType is vararg?
...@@ -465,17 +517,28 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { ...@@ -465,17 +517,28 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
/** /**
* Return a script function data based on a function id, either this function if * 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 * @param functionId function id
* @return script function data or null if invalid id * @return script function data or null if invalid id
*/ */
public RecompilableScriptFunctionData getScriptFunctionData(final int functionId) { public RecompilableScriptFunctionData getScriptFunctionData(final int functionId) {
if(functionId == functionNodeId) { if (functionId == functionNodeId) {
return this; return this;
} }
if(nestedFunctions == null) { RecompilableScriptFunctionData data;
return null;
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 { ...@@ -198,7 +198,7 @@ public abstract class ScriptFunction extends ScriptObject {
return data.needsWrappedThis(); return data.needsWrappedThis();
} }
private static boolean needsWrappedThis(Object fn) { private static boolean needsWrappedThis(final Object fn) {
return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false; return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false;
} }
......
...@@ -163,6 +163,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr ...@@ -163,6 +163,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Method handle for getting the array data */ /** Method handle for getting the array data */
public static final Call GET_ARRAY = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArray", ArrayData.class); 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 */ /** Method handle for setting the array data */
public static final Call SET_ARRAY = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArray", void.class, ArrayData.class); 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 ...@@ -175,6 +178,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
/** Method handle for getting the proto of a ScriptObject */ /** Method handle for getting the proto of a ScriptObject */
public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class); 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 */ /** Method handle for setting the proto of a ScriptObject */
public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setProto", void.class, ScriptObject.class); 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 ...@@ -1212,6 +1218,20 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return proto; 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. * Set the __proto__ of an object.
* @param newProto new __proto__ to set. * @param newProto new __proto__ to set.
...@@ -1901,9 +1921,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr ...@@ -1901,9 +1921,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
UnwarrantedOptimismException.INVALID_PROGRAM_POINT; UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
mh = find.getGetter(returnType, programPoint); mh = find.getGetter(returnType, programPoint);
//we never need a guard if noGuard is set //we never need a guard if noGuard is set
final boolean noGuard =/* OBJECT_FIELDS_ONLY &&*/ NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType(); 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
MethodHandle guard; MethodHandle guard;
final Class<? extends Throwable> exception; final Class<? extends Throwable> exception;
if (noGuard) { if (noGuard) {
...@@ -1919,7 +1939,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr ...@@ -1919,7 +1939,8 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
if (mh == null) { if (mh == null) {
mh = Lookup.emptyGetter(returnType); mh = Lookup.emptyGetter(returnType);
} else { } 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()) { if (find.isSelf()) {
return new GuardedInvocation(mh, guard, null, exception); return new GuardedInvocation(mh, guard, null, exception);
} }
......
...@@ -269,7 +269,7 @@ public final class ScriptRuntime { ...@@ -269,7 +269,7 @@ public final class ScriptRuntime {
private final int length; private final int length;
private int index; private int index;
RangeIterator(int length) { RangeIterator(final int length) {
this.length = length; this.length = length;
} }
...@@ -427,7 +427,7 @@ public final class ScriptRuntime { ...@@ -427,7 +427,7 @@ public final class ScriptRuntime {
} }
// checking for xVal == -0.0 and yVal == +0.0 or vice versa // 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; return false;
} }
...@@ -438,7 +438,7 @@ public final class ScriptRuntime { ...@@ -438,7 +438,7 @@ public final class ScriptRuntime {
return x.equals(y); return x.equals(y);
} }
return (x == y); return x == y;
} }
/** /**
...@@ -510,7 +510,7 @@ public final class ScriptRuntime { ...@@ -510,7 +510,7 @@ public final class ScriptRuntime {
final boolean xIsUndefined = x == UNDEFINED; final boolean xIsUndefined = x == UNDEFINED;
final boolean yIsUndefined = y == UNDEFINED; final boolean yIsUndefined = y == UNDEFINED;
if ((xIsNumber && yIsUndefined) || (xIsUndefined && yIsNumber) || (xIsUndefined && yIsUndefined)) { if (xIsNumber && yIsUndefined || xIsUndefined && yIsNumber || xIsUndefined && yIsUndefined) {
return Double.NaN; return Double.NaN;
} }
...@@ -713,8 +713,8 @@ public final class ScriptRuntime { ...@@ -713,8 +713,8 @@ public final class ScriptRuntime {
return x == y; return x == y;
} }
if ((xType == JSType.UNDEFINED && yType == JSType.NULL) || if (xType == JSType.UNDEFINED && yType == JSType.NULL ||
(xType == JSType.NULL && yType == JSType.UNDEFINED)) { xType == JSType.NULL && yType == JSType.UNDEFINED) {
return true; return true;
} }
...@@ -735,11 +735,11 @@ public final class ScriptRuntime { ...@@ -735,11 +735,11 @@ public final class ScriptRuntime {
} }
if ((xType == JSType.STRING || xType == JSType.NUMBER) && if ((xType == JSType.STRING || xType == JSType.NUMBER) &&
(y instanceof ScriptObject)) { y instanceof ScriptObject) {
return EQ(x, JSType.toPrimitive(y)); return EQ(x, JSType.toPrimitive(y));
} }
if ((x instanceof ScriptObject) && if (x instanceof ScriptObject &&
(yType == JSType.STRING || yType == JSType.NUMBER)) { (yType == JSType.STRING || yType == JSType.NUMBER)) {
return EQ(JSType.toPrimitive(x), y); return EQ(JSType.toPrimitive(x), y);
} }
...@@ -876,7 +876,7 @@ public final class ScriptRuntime { ...@@ -876,7 +876,7 @@ public final class ScriptRuntime {
*/ */
public static boolean LT(final Object x, final Object y) { public static boolean LT(final Object x, final Object y) {
final Object value = lessThan(x, y, true); 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 { ...@@ -889,7 +889,7 @@ public final class ScriptRuntime {
*/ */
public static boolean GT(final Object x, final Object y) { public static boolean GT(final Object x, final Object y) {
final Object value = lessThan(y, x, false); 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 { ...@@ -902,7 +902,7 @@ public final class ScriptRuntime {
*/ */
public static boolean LE(final Object x, final Object y) { public static boolean LE(final Object x, final Object y) {
final Object value = lessThan(y, x, false); 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 { ...@@ -915,7 +915,7 @@ public final class ScriptRuntime {
*/ */
public static boolean GE(final Object x, final Object y) { public static boolean GE(final Object x, final Object y) {
final Object value = lessThan(x, y, true); 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 */ /** ECMA 11.8.5 The Abstract Relational Comparison Algorithm */
...@@ -933,7 +933,7 @@ public final class ScriptRuntime { ...@@ -933,7 +933,7 @@ public final class ScriptRuntime {
if (JSType.of(px) == JSType.STRING && JSType.of(py) == JSType.STRING) { if (JSType.of(px) == JSType.STRING && JSType.of(py) == JSType.STRING) {
// May be String or ConsString // 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); final double nx = JSType.toNumber(px);
......
...@@ -60,6 +60,7 @@ final class ByteBufferArrayData extends ArrayData { ...@@ -60,6 +60,7 @@ final class ByteBufferArrayData extends ArrayData {
* *
* @return property descriptor for element * @return property descriptor for element
*/ */
@Override
public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) { public PropertyDescriptor getDescriptor(final GlobalObject global, final int index) {
// make the index properties not configurable // make the index properties not configurable
return global.newDataDescriptor(getObject(index), false, true, true); return global.newDataDescriptor(getObject(index), false, true, true);
...@@ -197,7 +198,7 @@ final class ByteBufferArrayData extends ArrayData { ...@@ -197,7 +198,7 @@ final class ByteBufferArrayData extends ArrayData {
throw unsupported("convert"); throw unsupported("convert");
} }
private UnsupportedOperationException unsupported(final String method) { private static UnsupportedOperationException unsupported(final String method) {
return new UnsupportedOperationException(method); return new UnsupportedOperationException(method);
} }
} }
...@@ -86,7 +86,7 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor ...@@ -86,7 +86,7 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
/** /**
* Maximum program point value. 22 bits should be enough for anyone * 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 * Flag mask to get the program point flags
...@@ -107,6 +107,22 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor ...@@ -107,6 +107,22 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor
private final MethodType methodType; private final MethodType methodType;
private final int flags; 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 * 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). * 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.
先完成此消息的编辑!
想要评论请 注册