From ca1752f33779db4349f50946210e27d296d2cf14 Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Thu, 20 Mar 2014 16:16:42 +0100 Subject: [PATCH] 8033334: Make sure that scope depth information is maintained in the RecompilableScriptFunctionDatas, to avoid unnecessary slow proto linkage when doing on demand compilation Compute RecompiledScriptFunctionDatas eagerly, annotate them with scope depth information and use them in recompilations. Reviewed-by: attila, hannesw, jlaskey --- .../jdk/nashorn/internal/codegen/Attr.java | 81 ++++-- .../internal/codegen/ClassEmitter.java | 35 +-- .../internal/codegen/CodeGenerator.java | 146 +++++----- .../codegen/CompilationEnvironment.java | 66 +++-- .../internal/codegen/CompilationPhase.java | 22 +- .../internal/codegen/CompilerConstants.java | 10 + .../internal/codegen/FindScopeDepths.java | 275 ++++++++++++++++++ .../internal/codegen/MethodEmitter.java | 46 ++- .../internal/codegen/SharedScopeCall.java | 8 +- .../nashorn/internal/codegen/types/Type.java | 10 +- .../src/jdk/nashorn/internal/ir/Block.java | 25 +- .../jdk/nashorn/internal/ir/FunctionNode.java | 20 +- .../nashorn/internal/ir/LexicalContext.java | 23 +- .../src/jdk/nashorn/internal/ir/Symbol.java | 7 +- .../internal/ir/debug/NashornTextifier.java | 67 ++--- .../jdk/nashorn/internal/parser/Parser.java | 9 +- .../internal/runtime/CompiledFunction.java | 20 +- .../jdk/nashorn/internal/runtime/Context.java | 18 +- .../jdk/nashorn/internal/runtime/Debug.java | 3 +- .../nashorn/internal/runtime/Property.java | 17 +- .../internal/runtime/PropertyDescriptor.java | 4 +- .../nashorn/internal/runtime/PropertyMap.java | 19 +- .../RecompilableScriptFunctionData.java | 129 +++++--- .../internal/runtime/ScriptFunction.java | 2 +- .../internal/runtime/ScriptObject.java | 27 +- .../internal/runtime/ScriptRuntime.java | 26 +- .../runtime/arrays/ByteBufferArrayData.java | 3 +- .../linker/NashornCallSiteDescriptor.java | 18 +- 28 files changed, 835 insertions(+), 301 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java index d2fed14df29..e24ee97f2f9 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java @@ -52,10 +52,13 @@ import static jdk.nashorn.internal.ir.Symbol.KINDMASK; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; + import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.AccessNode; import jdk.nashorn.internal.ir.BinaryNode; @@ -139,6 +142,7 @@ final class Attr extends NodeOperatorVisitor { private final Set optimistic = new HashSet<>(); private final Set neverOptimistic = new HashSet<>(); + private final Map globalSymbols = new HashMap<>(); //reuse the same global symbol private int catchNestingLevel; @@ -454,7 +458,7 @@ final class Attr extends NodeOperatorVisitor { } // Create and add to appropriate block. - symbol = new Symbol(name, flags); + symbol = createSymbol(name, flags); symbolBlock.putSymbol(lc, symbol); if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { @@ -467,6 +471,19 @@ final class Attr extends NodeOperatorVisitor { return symbol; } + private Symbol createSymbol(final String name, final int flags) { + if ((flags & Symbol.KINDMASK) == IS_GLOBAL) { + //reuse global symbols so they can be hashed + Symbol global = globalSymbols.get(name); + if (global == null) { + global = new Symbol(name, flags); + globalSymbols.put(name, global); + } + return global; + } + return new Symbol(name, flags); + } + @Override public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) { final Expression expr = expressionStatement.getExpression(); @@ -555,10 +572,16 @@ final class Attr extends NodeOperatorVisitor { } final int optimisticFlag = lc.hasOptimisticAssumptions() ? FunctionNode.IS_OPTIMISTIC : 0; + newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR).setFlag(lc, optimisticFlag); popLocals(); + if (!env.isOnDemandCompilation() && newFunctionNode.isProgram()) { + newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setFlag(lc, Block.IS_GLOBAL_SCOPE)); + assert newFunctionNode.getId() == 1; + } + return end(newFunctionNode, false); } @@ -576,7 +599,7 @@ final class Attr extends NodeOperatorVisitor { final IdentNode init = compilerConstant(initConstant); assert init.getSymbol() != null && init.getSymbol().hasSlot(); - VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init); + final VarNode synthVar = new VarNode(fn.getLineNumber(), fn.getToken(), fn.getFinish(), name, init); final Symbol nameSymbol = fn.getBody().getExistingSymbol(name.getName()); assert nameSymbol != null; @@ -631,7 +654,7 @@ final class Attr extends NodeOperatorVisitor { maybeForceScope(symbol); } else { LOG.info("No symbol exists. Declare undefined: ", symbol); - symbol = defineSymbol(block, name, IS_GLOBAL); + symbol = defineGlobalSymbol(block, name); // we have never seen this before, it can be undefined newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? symbol.setCanBeUndefined(); @@ -652,6 +675,10 @@ final class Attr extends NodeOperatorVisitor { return end(node); } + private Symbol defineGlobalSymbol(final Block block, final String name) { + return defineSymbol(block, name, IS_GLOBAL); + } + private boolean inCatch() { return catchNestingLevel > 0; } @@ -908,7 +935,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterNOT(UnaryNode unaryNode) { + public boolean enterNOT(final UnaryNode unaryNode) { tagNeverOptimistic(unaryNode.getExpression()); return true; } @@ -1021,7 +1048,7 @@ final class Attr extends NodeOperatorVisitor { return end(coerce(unaryNode, Type.BOOLEAN)); } - private IdentNode compilerConstant(CompilerConstants cc) { + private IdentNode compilerConstant(final CompilerConstants cc) { return (IdentNode)createImplicitIdentifier(cc.symbolName()).setSymbol(lc, lc.getCurrentFunction().compilerConstant(cc)); } @@ -1040,7 +1067,7 @@ final class Attr extends NodeOperatorVisitor { public Node leaveTYPEOF(final UnaryNode unaryNode) { final Expression rhs = unaryNode.getExpression(); - List args = new ArrayList<>(); + final List args = new ArrayList<>(); if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) { args.add(compilerConstant(SCOPE)); args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null @@ -1099,7 +1126,7 @@ final class Attr extends NodeOperatorVisitor { //which will be corrected in the post pass if unknown at this stage Type argumentsType = Type.widest(lhs.getType(), rhs.getType()); - if(argumentsType.getTypeClass() == String.class) { + if (argumentsType.getTypeClass() == String.class) { assert binaryNode.isTokenType(TokenType.ADD); argumentsType = Type.OBJECT; } @@ -1151,7 +1178,7 @@ final class Attr extends NodeOperatorVisitor { final Symbol symbol = findSymbol(block, name); if (symbol == null) { - defineSymbol(block, name, IS_GLOBAL); + defineGlobalSymbol(block, name); } else { maybeForceScope(symbol); } @@ -1169,7 +1196,7 @@ final class Attr extends NodeOperatorVisitor { return end(ensureSymbol(binaryNode, type)); } - private boolean isLocal(FunctionNode function, Symbol symbol) { + private boolean isLocal(final FunctionNode function, final Symbol symbol) { final FunctionNode definingFn = lc.getDefiningFunction(symbol); // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local return definingFn == null || definingFn == function; @@ -1372,7 +1399,7 @@ final class Attr extends NodeOperatorVisitor { final Type type = Type.narrowest(lhs.getType(), rhs.getType(), Type.INT); inferParameter(lhs, type); inferParameter(rhs, type); - Type widest = Type.widest(lhs.getType(), rhs.getType()); + final Type widest = Type.widest(lhs.getType(), rhs.getType()); ensureSymbol(lhs, widest); ensureSymbol(rhs, widest); return end(ensureSymbol(binaryNode, Type.BOOLEAN)); @@ -1390,7 +1417,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterEQ(BinaryNode binaryNode) { + public boolean enterEQ(final BinaryNode binaryNode) { return enterBinaryArithmetic(binaryNode); } @@ -1549,7 +1576,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterForNode(ForNode forNode) { + public boolean enterForNode(final ForNode forNode) { tagNeverOptimistic(forNode.getTest()); return true; } @@ -1570,7 +1597,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterTernaryNode(TernaryNode ternaryNode) { + public boolean enterTernaryNode(final TernaryNode ternaryNode) { tagNeverOptimistic(ternaryNode.getTest()); return true; } @@ -1675,7 +1702,7 @@ final class Attr extends NodeOperatorVisitor { newParams.add((IdentNode)param.setSymbol(lc, paramSymbol)); assert paramSymbol != null; - Type type = paramSymbol.getSymbolType(); + final Type type = paramSymbol.getSymbolType(); // all param types are initialized to unknown // first we check if we do have a type (inferred during generation) @@ -1705,7 +1732,7 @@ final class Attr extends NodeOperatorVisitor { } } - FunctionNode newFunctionNode = functionNode; + final FunctionNode newFunctionNode = functionNode; return newFunctionNode.setParameters(lc, newParams); } @@ -1721,7 +1748,7 @@ final class Attr extends NodeOperatorVisitor { for (final Property property : map.getProperties()) { final String key = property.getKey(); - final Symbol symbol = defineSymbol(block, key, IS_GLOBAL); + final Symbol symbol = defineGlobalSymbol(block, key); newType(symbol, Type.OBJECT); LOG.info("Added global symbol from property map ", symbol); } @@ -1761,9 +1788,11 @@ final class Attr extends NodeOperatorVisitor { if (node instanceof LiteralNode) { return node; } - Type from = node.getType(); + final Type from = node.getType(); if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { - LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to); + if (LOG.isEnabled()) { + LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to); + } Symbol symbol = node.getSymbol(); if (symbol.isShared() && symbol.wouldChangeType(to)) { symbol = temporarySymbols.getTypedTemporarySymbol(to); @@ -1875,7 +1904,7 @@ final class Attr extends NodeOperatorVisitor { } @Override - public Node leaveTernaryNode(TernaryNode ternaryNode) { + public Node leaveTernaryNode(final TernaryNode ternaryNode) { return widen(ternaryNode, Type.widest(ternaryNode.getTrueExpression().getType(), ternaryNode.getFalseExpression().getType())); } @@ -1938,19 +1967,19 @@ final class Attr extends NodeOperatorVisitor { } @Override - public boolean enterReturnNode(ReturnNode returnNode) { + public boolean enterReturnNode(final ReturnNode returnNode) { tagOptimistic(returnNode.getExpression()); return true; } @Override - public boolean enterIfNode(IfNode ifNode) { + public boolean enterIfNode(final IfNode ifNode) { tagNeverOptimistic(ifNode.getTest()); return true; } @Override - public boolean enterWhileNode(WhileNode whileNode) { + public boolean enterWhileNode(final WhileNode whileNode) { tagNeverOptimistic(whileNode.getTest()); return true; } @@ -1966,7 +1995,7 @@ final class Attr extends NodeOperatorVisitor { * @param expr an expression that is to be tagged as optimistic. */ private long tag(final Optimistic expr) { - return ((long)lc.getCurrentFunction().getId() << 32) | expr.getProgramPoint(); + return (long)lc.getCurrentFunction().getId() << 32 | expr.getProgramPoint(); } /** @@ -2000,7 +2029,7 @@ final class Attr extends NodeOperatorVisitor { return optimistic.contains(tag(expr)); } - private Type getOptimisticType(Optimistic expr) { + private Type getOptimisticType(final Optimistic expr) { return useOptimisticTypes() ? env.getOptimisticType(expr) : expr.getMostPessimisticType(); } @@ -2138,7 +2167,7 @@ final class Attr extends NodeOperatorVisitor { } private BinaryNode coerce(final BinaryNode binaryNode, final Type pessimisticType, final Type argumentsType) { - BinaryNode newNode = ensureSymbolTypeOverride(binaryNode, pessimisticType, argumentsType); + final BinaryNode newNode = ensureSymbolTypeOverride(binaryNode, pessimisticType, argumentsType); inferParameter(binaryNode.lhs(), newNode.getType()); inferParameter(binaryNode.rhs(), newNode.getType()); return newNode; @@ -2161,7 +2190,7 @@ final class Attr extends NodeOperatorVisitor { private static String name(final Node node) { final String cn = node.getClass().getName(); - int lastDot = cn.lastIndexOf('.'); + final int lastDot = cn.lastIndexOf('.'); if (lastDot == -1) { return cn; } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java index 0b7dc1b2920..7e0c4536ebf 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java @@ -277,51 +277,52 @@ public class ClassEmitter implements Emitter { } // $getXXXX$array - get the ith entry from the constants table and cast to XXXX[]. - for (final Class cls : constantMethodNeeded) { - if (cls.isArray()) { - defineGetArrayMethod(cls); + for (final Class clazz : constantMethodNeeded) { + if (clazz.isArray()) { + defineGetArrayMethod(clazz); } } } /** * Constructs a primitive specific method for getting the ith entry from the constants table and cast. - * @param cls Array class. + * @param clazz Array class. */ - private void defineGetArrayMethod(final Class cls) { + private void defineGetArrayMethod(final Class clazz) { assert unitClassName != null; - final String methodName = getArrayMethodName(cls); - final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); + final String methodName = getArrayMethodName(clazz); + final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, clazz, int.class); getArrayMethod.begin(); getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) .load(Type.INT, 0) .arrayload() - .checkcast(cls) + .checkcast(clazz) .dup() .arraylength() - .invoke(staticCallNoLookup(Arrays.class, "copyOf", cls, cls, int.class)) + .invoke(staticCallNoLookup(Arrays.class, "copyOf", clazz, clazz, int.class)) ._return(); getArrayMethod.end(); } + /** * Generate the name of a get array from constant pool method. - * @param cls Name of array class. + * @param clazz Name of array class. * @return Method name. */ - static String getArrayMethodName(final Class cls) { - assert cls.isArray(); - return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); + static String getArrayMethodName(final Class clazz) { + assert clazz.isArray(); + return GET_ARRAY_PREFIX.symbolName() + clazz.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); } /** * Ensure a get constant method is issued for the class. - * @param cls Class of constant. + * @param clazz Class of constant. */ - void needGetConstantMethod(final Class cls) { - constantMethodNeeded.add(cls); + void needGetConstantMethod(final Class clazz) { + constantMethodNeeded.add(clazz); } /** @@ -672,7 +673,7 @@ public class ClassEmitter implements Emitter { } } - private MethodVisitor methodVisitor(EnumSet flags, final String methodName, final Class rtype, final Class... ptypes) { + private MethodVisitor methodVisitor(final EnumSet flags, final String methodName, final Class rtype, final Class... ptypes) { return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null); } diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 1e4493eeeb9..0355d647be6 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -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.virtualCallNoLookup; 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_TEMP; import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; @@ -76,6 +74,7 @@ import java.util.Map; import java.util.RandomAccess; import java.util.Set; import java.util.TreeMap; + import jdk.nashorn.internal.codegen.ClassEmitter.Flag; import jdk.nashorn.internal.codegen.CompilerConstants.Call; import jdk.nashorn.internal.codegen.RuntimeCallSite.SpecializedRuntimeNode; @@ -224,11 +223,10 @@ final class CodeGenerator extends NodeOperatorVisitor ContinuationInfo. Used by compilation of rest-of function only. private final Map fnIdToContinuationInfo = new HashMap<>(); - // Function Id -> (Function Id -> Function Data)). Used by compilation of most-optimistic function only. - private final Map> fnIdToNestedFunctions = new HashMap<>(); - private final Deque