Wed, 08 May 2013 15:51:36 +0200
8013912: Nashorn needs to reuse temporary symbols
Reviewed-by: jlaskey, lagergren
1.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Tue May 07 14:43:17 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Wed May 08 15:51:36 2013 +0200 1.3 @@ -33,7 +33,6 @@ 1.4 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 1.5 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 1.6 import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX; 1.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; 1.8 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 1.9 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 1.10 import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; 1.11 @@ -43,7 +42,6 @@ 1.12 import static jdk.nashorn.internal.ir.Symbol.IS_LET; 1.13 import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; 1.14 import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; 1.15 -import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; 1.16 import static jdk.nashorn.internal.ir.Symbol.IS_THIS; 1.17 import static jdk.nashorn.internal.ir.Symbol.IS_VAR; 1.18 import static jdk.nashorn.internal.ir.Symbol.KINDMASK; 1.19 @@ -55,7 +53,6 @@ 1.20 import java.util.Iterator; 1.21 import java.util.List; 1.22 import java.util.Set; 1.23 - 1.24 import jdk.nashorn.internal.codegen.types.Type; 1.25 import jdk.nashorn.internal.ir.AccessNode; 1.26 import jdk.nashorn.internal.ir.BinaryNode; 1.27 @@ -81,6 +78,7 @@ 1.28 import jdk.nashorn.internal.ir.Statement; 1.29 import jdk.nashorn.internal.ir.SwitchNode; 1.30 import jdk.nashorn.internal.ir.Symbol; 1.31 +import jdk.nashorn.internal.ir.TemporarySymbols; 1.32 import jdk.nashorn.internal.ir.TernaryNode; 1.33 import jdk.nashorn.internal.ir.TryNode; 1.34 import jdk.nashorn.internal.ir.UnaryNode; 1.35 @@ -134,10 +132,13 @@ 1.36 private static final DebugLogger LOG = new DebugLogger("attr"); 1.37 private static final boolean DEBUG = LOG.isEnabled(); 1.38 1.39 + private final TemporarySymbols temporarySymbols; 1.40 + 1.41 /** 1.42 * Constructor. 1.43 */ 1.44 - Attr() { 1.45 + Attr(final TemporarySymbols temporarySymbols) { 1.46 + this.temporarySymbols = temporarySymbols; 1.47 this.localDefs = new ArrayDeque<>(); 1.48 this.localUses = new ArrayDeque<>(); 1.49 this.returnTypes = new ArrayDeque<>(); 1.50 @@ -410,7 +411,7 @@ 1.51 final boolean anonymous = functionNode.isAnonymous(); 1.52 final String name = anonymous ? null : functionNode.getIdent().getName(); 1.53 if (anonymous || body.getExistingSymbol(name) != null) { 1.54 - newFunctionNode = (FunctionNode)Attr.ensureSymbol(lc, body, FunctionNode.FUNCTION_TYPE, newFunctionNode); 1.55 + newFunctionNode = (FunctionNode)ensureSymbol(lc, FunctionNode.FUNCTION_TYPE, newFunctionNode); 1.56 } else { 1.57 assert name != null; 1.58 final Symbol self = body.getExistingSymbol(name); 1.59 @@ -421,7 +422,7 @@ 1.60 1.61 //unknown parameters are promoted to object type. 1.62 newFunctionNode = finalizeParameters(newFunctionNode); 1.63 - finalizeTypes(newFunctionNode); 1.64 + newFunctionNode = finalizeTypes(newFunctionNode); 1.65 for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) { 1.66 if (symbol.getSymbolType().isUnknown()) { 1.67 symbol.setType(Type.OBJECT); 1.68 @@ -533,8 +534,7 @@ 1.69 1.70 setBlockScope(name, symbol); 1.71 1.72 - if (symbol != null && !identNode.isInitializedHere()) { 1.73 - 1.74 + if (!identNode.isInitializedHere()) { 1.75 symbol.increaseUseCount(); 1.76 } 1.77 addLocalUse(identNode.getName()); 1.78 @@ -790,7 +790,7 @@ 1.79 // var x; with no init will be treated like a use of x by 1.80 // leaveIdentNode unless we remove the name from the localdef list. 1.81 removeLocalDef(name); 1.82 - return newVarNode.setSymbol(lc, symbol); 1.83 + return end(newVarNode.setSymbol(lc, symbol)); 1.84 } 1.85 1.86 addLocalDef(name); 1.87 @@ -828,10 +828,10 @@ 1.88 @Override 1.89 public Node leaveDECINC(final UnaryNode unaryNode) { 1.90 // @see assignOffset 1.91 - ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs()); 1.92 + final UnaryNode newUnaryNode = unaryNode.setRHS(ensureAssignmentSlots(unaryNode.rhs())); 1.93 final Type type = arithType(); 1.94 - newType(unaryNode.rhs().getSymbol(), type); 1.95 - return end(ensureSymbol(type, unaryNode)); 1.96 + newType(newUnaryNode.rhs().getSymbol(), type); 1.97 + return end(ensureSymbol(type, newUnaryNode)); 1.98 } 1.99 1.100 @Override 1.101 @@ -1384,9 +1384,7 @@ 1.102 final Symbol paramSymbol = defineSymbol(body, param.getName(), flags); 1.103 assert paramSymbol != null; 1.104 1.105 - if (paramSymbol != null) { 1.106 - newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); 1.107 - } 1.108 + newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); 1.109 1.110 LOG.info("Initialized param ", pos, "=", paramSymbol); 1.111 pos++; 1.112 @@ -1521,19 +1519,25 @@ 1.113 * 1.114 * see NASHORN-258 1.115 * 1.116 - * @param functionNode the current function node (has to be passed as it changes in the visitor below) 1.117 * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes 1.118 */ 1.119 - private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) { 1.120 - assignmentDest.accept(new NodeVisitor() { 1.121 + private Node ensureAssignmentSlots(final Node assignmentDest) { 1.122 + final LexicalContext attrLexicalContext = getLexicalContext(); 1.123 + return assignmentDest.accept(new NodeVisitor() { 1.124 @Override 1.125 public Node leaveIndexNode(final IndexNode indexNode) { 1.126 assert indexNode.getSymbol().isTemp(); 1.127 final Node index = indexNode.getIndex(); 1.128 //only temps can be set as needing slots. the others will self resolve 1.129 //it is illegal to take a scope var and force it to be a slot, that breaks 1.130 - if (index.getSymbol().isTemp() && !index.getSymbol().isConstant()) { 1.131 - index.getSymbol().setNeedsSlot(true); 1.132 + Symbol indexSymbol = index.getSymbol(); 1.133 + if (indexSymbol.isTemp() && !indexSymbol.isConstant() && !indexSymbol.hasSlot()) { 1.134 + if(indexSymbol.isShared()) { 1.135 + indexSymbol = temporarySymbols.createUnshared(indexSymbol); 1.136 + } 1.137 + indexSymbol.setNeedsSlot(true); 1.138 + attrLexicalContext.getCurrentBlock().putSymbol(attrLexicalContext, indexSymbol); 1.139 + return indexNode.setIndex(index.setSymbol(attrLexicalContext, indexSymbol)); 1.140 } 1.141 return indexNode; 1.142 } 1.143 @@ -1558,22 +1562,30 @@ 1.144 * 1.145 * @param functionNode 1.146 */ 1.147 - private static void finalizeTypes(final FunctionNode functionNode) { 1.148 + private FunctionNode finalizeTypes(final FunctionNode functionNode) { 1.149 final Set<Node> changed = new HashSet<>(); 1.150 + FunctionNode currentFunctionNode = functionNode; 1.151 do { 1.152 changed.clear(); 1.153 - functionNode.accept(new NodeVisitor() { 1.154 + final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor() { 1.155 1.156 - private void widen(final Node node, final Type to) { 1.157 + private Node widen(final Node node, final Type to) { 1.158 if (node instanceof LiteralNode) { 1.159 - return; 1.160 + return node; 1.161 } 1.162 Type from = node.getType(); 1.163 if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { 1.164 - LOG.fine("Had to post pass widen '", node, "' " + Debug.id(node), " from ", node.getType(), " to ", to); 1.165 - newType(node.getSymbol(), to); 1.166 - changed.add(node); 1.167 + LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to); 1.168 + Symbol symbol = node.getSymbol(); 1.169 + if(symbol.isShared() && symbol.wouldChangeType(to)) { 1.170 + symbol = temporarySymbols.getTypedTemporarySymbol(to); 1.171 + } 1.172 + newType(symbol, to); 1.173 + final Node newNode = node.setSymbol(getLexicalContext(), symbol); 1.174 + changed.add(newNode); 1.175 + return newNode; 1.176 } 1.177 + return node; 1.178 } 1.179 1.180 @Override 1.181 @@ -1599,20 +1611,23 @@ 1.182 @Override 1.183 public Node leaveBinaryNode(final BinaryNode binaryNode) { 1.184 final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 1.185 + BinaryNode newBinaryNode = binaryNode; 1.186 switch (binaryNode.tokenType()) { 1.187 default: 1.188 if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) { 1.189 break; 1.190 } 1.191 - widen(binaryNode.lhs(), widest); 1.192 + newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest)); 1.193 case ADD: 1.194 - widen(binaryNode, widest); 1.195 - break; 1.196 + newBinaryNode = (BinaryNode)widen(newBinaryNode, widest); 1.197 } 1.198 - return binaryNode; 1.199 + return newBinaryNode; 1.200 } 1.201 }); 1.202 + getLexicalContext().replace(currentFunctionNode, newFunctionNode); 1.203 + currentFunctionNode = newFunctionNode; 1.204 } while (!changed.isEmpty()); 1.205 + return currentFunctionNode; 1.206 } 1.207 1.208 private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) { 1.209 @@ -1626,14 +1641,12 @@ 1.210 newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType 1.211 // ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 1.212 1.213 - ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode); 1.214 - 1.215 - return end(ensureSymbol(destType, binaryNode)); 1.216 + return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode))); 1.217 } 1.218 1.219 private Node ensureSymbol(final Type type, final Node node) { 1.220 LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type); 1.221 - return Attr.ensureSymbol(getLexicalContext(), getLexicalContext().getCurrentBlock(), type, node); 1.222 + return ensureSymbol(getLexicalContext(), type, node); 1.223 } 1.224 1.225 private Symbol newInternal(final String name, final Type type) { 1.226 @@ -1694,15 +1707,8 @@ 1.227 localUses.peek().add(name); 1.228 } 1.229 1.230 - static Node ensureSymbol(final LexicalContext lc, final Block block, final Type type, final Node node) { 1.231 - Symbol symbol = node.getSymbol(); 1.232 - if (symbol != null) { 1.233 - return node; 1.234 - } 1.235 - final String uname = lc.getCurrentFunction().uniqueName(TEMP_PREFIX.symbolName()); 1.236 - symbol = new Symbol(uname, IS_TEMP, type); 1.237 - block.putSymbol(lc, symbol); 1.238 - return node.setSymbol(lc, symbol); 1.239 + private Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) { 1.240 + return temporarySymbols.ensureSymbol(lc, type, node); 1.241 } 1.242 1.243 /** 1.244 @@ -1771,6 +1777,10 @@ 1.245 } 1.246 1.247 private Node end(final Node node, final boolean printNode) { 1.248 + if(node instanceof Statement) { 1.249 + // If we're done with a statement, all temporaries can be reused. 1.250 + temporarySymbols.reuse(); 1.251 + } 1.252 if (DEBUG) { 1.253 final StringBuilder sb = new StringBuilder(); 1.254
2.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue May 07 14:43:17 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Wed May 08 15:51:36 2013 +0200 2.3 @@ -21,6 +21,7 @@ 2.4 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 2.5 import jdk.nashorn.internal.ir.LexicalContext; 2.6 import jdk.nashorn.internal.ir.Node; 2.7 +import jdk.nashorn.internal.ir.TemporarySymbols; 2.8 import jdk.nashorn.internal.ir.debug.ASTWriter; 2.9 import jdk.nashorn.internal.ir.debug.PrintVisitor; 2.10 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 2.11 @@ -171,7 +172,12 @@ 2.12 ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { 2.13 @Override 2.14 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 2.15 - return (FunctionNode)enterAttr(fn).accept(new Attr()); 2.16 + final TemporarySymbols ts = compiler.getTemporarySymbols(); 2.17 + final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts)); 2.18 + if(compiler.getEnv()._print_mem_usage) { 2.19 + Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); 2.20 + } 2.21 + return newFunctionNode; 2.22 } 2.23 2.24 /** 2.25 @@ -179,14 +185,14 @@ 2.26 * and the function symbols to object 2.27 * @param functionNode node where to start iterating 2.28 */ 2.29 - private FunctionNode enterAttr(final FunctionNode functionNode) { 2.30 + private FunctionNode enterAttr(final FunctionNode functionNode, final TemporarySymbols ts) { 2.31 return (FunctionNode)functionNode.accept(new NodeVisitor() { 2.32 @Override 2.33 public Node leaveFunctionNode(final FunctionNode node) { 2.34 final LexicalContext lc = getLexicalContext(); 2.35 if (node.isLazy()) { 2.36 FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT); 2.37 - return Attr.ensureSymbol(lc, lc.getCurrentBlock(), Type.OBJECT, newNode); 2.38 + return ts.ensureSymbol(lc, Type.OBJECT, newNode); 2.39 } 2.40 //node may have a reference here that needs to be nulled if it was referred to by 2.41 //its outer context, if it is lazy and not attributed 2.42 @@ -249,7 +255,7 @@ 2.43 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 2.44 final ScriptEnvironment env = compiler.getEnv(); 2.45 2.46 - final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes()); 2.47 + final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes(compiler.getTemporarySymbols())); 2.48 2.49 if (env._print_lower_ast) { 2.50 env.getErr().println(new ASTWriter(newFunctionNode));
3.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Tue May 07 14:43:17 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Wed May 08 15:51:36 2013 +0200 3.3 @@ -36,6 +36,8 @@ 3.4 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 3.5 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 3.6 3.7 +import jdk.nashorn.internal.ir.TemporarySymbols; 3.8 + 3.9 import java.io.File; 3.10 import java.lang.reflect.Field; 3.11 import java.security.AccessController; 3.12 @@ -53,7 +55,6 @@ 3.13 import java.util.Map.Entry; 3.14 import java.util.Set; 3.15 import java.util.logging.Level; 3.16 - 3.17 import jdk.internal.dynalink.support.NameCodec; 3.18 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 3.19 import jdk.nashorn.internal.codegen.types.Type; 3.20 @@ -100,6 +101,8 @@ 3.21 3.22 private CodeInstaller<ScriptEnvironment> installer; 3.23 3.24 + private final TemporarySymbols temporarySymbols = new TemporarySymbols(); 3.25 + 3.26 /** logger for compiler, trampolines, splits and related code generation events 3.27 * that affect classes */ 3.28 public static final DebugLogger LOG = new DebugLogger("compiler"); 3.29 @@ -394,7 +397,7 @@ 3.30 return newFunctionNode; 3.31 } 3.32 3.33 - private Class<?> install(final FunctionNode functionNode, final String className, final byte[] code) { 3.34 + private Class<?> install(final String className, final byte[] code) { 3.35 LOG.fine("Installing class ", className); 3.36 3.37 final Class<?> clazz = installer.install(Compiler.binaryName(className), code); 3.38 @@ -436,7 +439,7 @@ 3.39 3.40 final String rootClassName = firstCompileUnitName(); 3.41 final byte[] rootByteCode = bytecode.get(rootClassName); 3.42 - final Class<?> rootClass = install(functionNode, rootClassName, rootByteCode); 3.43 + final Class<?> rootClass = install(rootClassName, rootByteCode); 3.44 3.45 int length = rootByteCode.length; 3.46 3.47 @@ -450,7 +453,7 @@ 3.48 final byte[] code = entry.getValue(); 3.49 length += code.length; 3.50 3.51 - installedClasses.put(className, install(functionNode, className, code)); 3.52 + installedClasses.put(className, install(className, code)); 3.53 } 3.54 3.55 for (final CompileUnit unit : compileUnits) { 3.56 @@ -508,6 +511,10 @@ 3.57 return installer; 3.58 } 3.59 3.60 + TemporarySymbols getTemporarySymbols() { 3.61 + return temporarySymbols; 3.62 + } 3.63 + 3.64 void addClass(final String name, final byte[] code) { 3.65 bytecode.put(name, code); 3.66 }
4.1 --- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java Tue May 07 14:43:17 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed May 08 15:51:36 2013 +0200 4.3 @@ -105,25 +105,25 @@ 4.4 ARGUMENTS("arguments", Object.class, 2), 4.5 4.6 /** prefix for iterators for for (x in ...) */ 4.7 - ITERATOR_PREFIX(":iter"), 4.8 + ITERATOR_PREFIX(":i"), 4.9 4.10 /** prefix for tag variable used for switch evaluation */ 4.11 - SWITCH_TAG_PREFIX(":tag"), 4.12 + SWITCH_TAG_PREFIX(":s"), 4.13 4.14 /** prefix for all exceptions */ 4.15 - EXCEPTION_PREFIX(":exception"), 4.16 + EXCEPTION_PREFIX(":e"), 4.17 4.18 /** prefix for quick slots generated in Store */ 4.19 - QUICK_PREFIX(":quick"), 4.20 + QUICK_PREFIX(":q"), 4.21 4.22 /** prefix for temporary variables */ 4.23 - TEMP_PREFIX(":temp"), 4.24 + TEMP_PREFIX(":t"), 4.25 4.26 /** prefix for literals */ 4.27 - LITERAL_PREFIX(":lit"), 4.28 + LITERAL_PREFIX(":l"), 4.29 4.30 /** prefix for regexps */ 4.31 - REGEX_PREFIX(":regex"), 4.32 + REGEX_PREFIX(":r"), 4.33 4.34 /** "this" used in non-static Java methods; always in slot 0 */ 4.35 JAVA_THIS(null, 0),
5.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue May 07 14:43:17 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed May 08 15:51:36 2013 +0200 5.3 @@ -55,6 +55,7 @@ 5.4 import jdk.nashorn.internal.ir.RuntimeNode.Request; 5.5 import jdk.nashorn.internal.ir.SwitchNode; 5.6 import jdk.nashorn.internal.ir.Symbol; 5.7 +import jdk.nashorn.internal.ir.TemporarySymbols; 5.8 import jdk.nashorn.internal.ir.TernaryNode; 5.9 import jdk.nashorn.internal.ir.ThrowNode; 5.10 import jdk.nashorn.internal.ir.TypeOverride; 5.11 @@ -87,7 +88,10 @@ 5.12 5.13 private static final DebugLogger LOG = new DebugLogger("finalize"); 5.14 5.15 - FinalizeTypes() { 5.16 + private final TemporarySymbols temporarySymbols; 5.17 + 5.18 + FinalizeTypes(final TemporarySymbols temporarySymbols) { 5.19 + this.temporarySymbols = temporarySymbols; 5.20 } 5.21 5.22 @Override 5.23 @@ -227,21 +231,27 @@ 5.24 return leaveASSIGN(binaryNode); 5.25 } 5.26 5.27 + private boolean symbolIsInteger(Node node) { 5.28 + final Symbol symbol = node.getSymbol(); 5.29 + assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + getLexicalContext().getCurrentFunction().getSource(); 5.30 + return true; 5.31 + } 5.32 + 5.33 @Override 5.34 public Node leaveBIT_AND(final BinaryNode binaryNode) { 5.35 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 5.36 + assert symbolIsInteger(binaryNode); 5.37 return leaveBinary(binaryNode, Type.INT, Type.INT); 5.38 } 5.39 5.40 @Override 5.41 public Node leaveBIT_OR(final BinaryNode binaryNode) { 5.42 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 5.43 + assert symbolIsInteger(binaryNode); 5.44 return leaveBinary(binaryNode, Type.INT, Type.INT); 5.45 } 5.46 5.47 @Override 5.48 public Node leaveBIT_XOR(final BinaryNode binaryNode) { 5.49 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isInteger() : "int coercion expected: " + binaryNode.getSymbol(); 5.50 + assert symbolIsInteger(binaryNode); 5.51 return leaveBinary(binaryNode, Type.INT, Type.INT); 5.52 } 5.53 5.54 @@ -251,8 +261,7 @@ 5.55 final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs())); 5.56 // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed 5.57 // in that case, update the node type as well 5.58 - propagateType(newBinaryNode, newBinaryNode.lhs().getType()); 5.59 - return newBinaryNode; 5.60 + return propagateType(newBinaryNode, newBinaryNode.lhs().getType()); 5.61 } 5.62 5.63 @Override 5.64 @@ -261,8 +270,7 @@ 5.65 final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs())); 5.66 // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed 5.67 // in that case, update the node type as well 5.68 - propagateType(newBinaryNode, newBinaryNode.rhs().getType()); 5.69 - return newBinaryNode; 5.70 + return propagateType(newBinaryNode, newBinaryNode.rhs().getType()); 5.71 } 5.72 5.73 @Override 5.74 @@ -364,6 +372,7 @@ 5.75 5.76 @Override 5.77 public Node leaveExecuteNode(final ExecuteNode executeNode) { 5.78 + temporarySymbols.reuse(); 5.79 return executeNode.setExpression(discard(executeNode.getExpression())); 5.80 } 5.81 5.82 @@ -489,8 +498,8 @@ 5.83 5.84 @Override 5.85 public Node leaveVarNode(final VarNode varNode) { 5.86 - final Node rhs = varNode.getInit(); 5.87 - if (rhs != null) { 5.88 + final Node init = varNode.getInit(); 5.89 + if (init != null) { 5.90 final SpecializedNode specialized = specialize(varNode); 5.91 final VarNode specVarNode = (VarNode)specialized.node; 5.92 Type destType = specialized.type; 5.93 @@ -498,8 +507,11 @@ 5.94 destType = specVarNode.getType(); 5.95 } 5.96 assert specVarNode.hasType() : specVarNode + " doesn't have a type"; 5.97 - return specVarNode.setInit(convert(rhs, destType)); 5.98 + final Node convertedInit = convert(init, destType); 5.99 + temporarySymbols.reuse(); 5.100 + return specVarNode.setInit(convertedInit); 5.101 } 5.102 + temporarySymbols.reuse(); 5.103 return varNode; 5.104 } 5.105 5.106 @@ -678,7 +690,7 @@ 5.107 } 5.108 } 5.109 5.110 - private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) { 5.111 + <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) { 5.112 final Node node = ((Node)assignment); 5.113 final T lhs = assignment.getAssignmentDest(); 5.114 final Node rhs = assignment.getAssignmentSource(); 5.115 @@ -700,9 +712,9 @@ 5.116 } 5.117 5.118 final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); 5.119 - propagateType(newNode, to); 5.120 + final Node typePropagatedNode = propagateType(newNode, to); 5.121 5.122 - return new SpecializedNode(newNode, to); 5.123 + return new SpecializedNode(typePropagatedNode, to); 5.124 } 5.125 5.126 5.127 @@ -741,7 +753,7 @@ 5.128 * @param to new type 5.129 */ 5.130 @SuppressWarnings("unchecked") 5.131 - private static <T extends Node> T setTypeOverride(final T node, final Type to) { 5.132 + <T extends Node> T setTypeOverride(final T node, final Type to) { 5.133 final Type from = node.getType(); 5.134 if (!node.getType().equals(to)) { 5.135 LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to); 5.136 @@ -750,7 +762,7 @@ 5.137 } 5.138 } 5.139 LOG.info("Type override for lhs in '", node, "' => ", to); 5.140 - return ((TypeOverride<T>)node).setType(to); 5.141 + return ((TypeOverride<T>)node).setType(temporarySymbols, getLexicalContext(), to); 5.142 } 5.143 5.144 /** 5.145 @@ -808,7 +820,7 @@ 5.146 final LexicalContext lc = getLexicalContext(); 5.147 //This is the only place in this file that can create new temporaries 5.148 //FinalizeTypes may not introduce ANY node that is not a conversion. 5.149 - return Attr.ensureSymbol(lc, lc.getCurrentBlock(), to, resultNode); 5.150 + return temporarySymbols.ensureSymbol(lc, to, resultNode); 5.151 } 5.152 5.153 private static Node discard(final Node node) { 5.154 @@ -836,12 +848,13 @@ 5.155 * @param node 5.156 * @param to 5.157 */ 5.158 - private static void propagateType(final Node node, final Type to) { 5.159 - final Symbol symbol = node.getSymbol(); 5.160 - if (symbol.isTemp()) { 5.161 - symbol.setTypeOverride(to); 5.162 + private Node propagateType(final Node node, final Type to) { 5.163 + Symbol symbol = node.getSymbol(); 5.164 + if (symbol.isTemp() && symbol.getSymbolType() != to) { 5.165 + symbol = symbol.setTypeOverrideShared(to, temporarySymbols); 5.166 LOG.info("Type override for temporary in '", node, "' => ", to); 5.167 } 5.168 + return node.setSymbol(getLexicalContext(), symbol); 5.169 } 5.170 5.171 /** 5.172 @@ -866,7 +879,7 @@ 5.173 * Whenever an explicit conversion is needed and the convertee is a literal, we can 5.174 * just change the literal 5.175 */ 5.176 - static class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> { 5.177 + class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> { 5.178 private final Type type; 5.179 5.180 LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) { 5.181 @@ -894,7 +907,7 @@ 5.182 5.183 if (literalNode != null) { 5.184 //inherit literal symbol for attr. 5.185 - literalNode = (LiteralNode<?>)literalNode.setSymbol(null, parent.getSymbol()); 5.186 + literalNode = (LiteralNode<?>)literalNode.setSymbol(getLexicalContext(), parent.getSymbol()); 5.187 } 5.188 5.189 return literalNode;
6.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java Tue May 07 14:43:17 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Wed May 08 15:51:36 2013 +0200 6.3 @@ -119,10 +119,10 @@ 6.4 } 6.5 6.6 @Override 6.7 - public AccessNode setType(final Type type) { 6.8 + public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 6.9 logTypeChange(type); 6.10 - getSymbol().setTypeOverride(type); //always a temp so this is fine. 6.11 - return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType()); 6.12 + final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts)); 6.13 + return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType()); 6.14 } 6.15 6.16 @Override
7.1 --- a/src/jdk/nashorn/internal/ir/BlockLexicalContext.java Tue May 07 14:43:17 2013 +0200 7.2 +++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java Wed May 08 15:51:36 2013 +0200 7.3 @@ -64,7 +64,6 @@ 7.4 } 7.5 7.6 @Override 7.7 - @SuppressWarnings("unchecked") 7.8 public <T extends LexicalContextNode> T pop(final T node) { 7.9 T expected = node; 7.10 if (node instanceof Block) {
8.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java Tue May 07 14:43:17 2013 +0200 8.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java Wed May 08 15:51:36 2013 +0200 8.3 @@ -170,7 +170,7 @@ 8.4 } 8.5 8.6 @Override 8.7 - public CallNode setType(final Type type) { 8.8 + public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 8.9 if (this.type == type) { 8.10 return this; 8.11 } 8.12 @@ -200,7 +200,7 @@ 8.13 setFunction(function.accept(visitor)). 8.14 setArgs(Node.accept(visitor, Node.class, args)). 8.15 setFlags(flags). 8.16 - setType(type). 8.17 + setType(null, lc, type). 8.18 setEvalArgs(evalArgs == null ? 8.19 null : 8.20 evalArgs.setCode(evalArgs.getCode().accept(visitor)).
9.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java Tue May 07 14:43:17 2013 +0200 9.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Wed May 08 15:51:36 2013 +0200 9.3 @@ -61,7 +61,7 @@ 9.4 */ 9.5 public IdentNode(final long token, final int finish, final String name) { 9.6 super(token, finish); 9.7 - this.name = name; 9.8 + this.name = name.intern(); 9.9 this.callSiteType = null; 9.10 this.flags = 0; 9.11 } 9.12 @@ -101,7 +101,7 @@ 9.13 } 9.14 9.15 @Override 9.16 - public IdentNode setType(final Type type) { 9.17 + public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 9.18 // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't 9.19 if (this.callSiteType == type) { 9.20 return this;
10.1 --- a/src/jdk/nashorn/internal/ir/IndexNode.java Tue May 07 14:43:17 2013 +0200 10.2 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java Wed May 08 15:51:36 2013 +0200 10.3 @@ -106,6 +106,18 @@ 10.4 return index; 10.5 } 10.6 10.7 + /** 10.8 + * Set the index expression for this node 10.9 + * @param index new index expression 10.10 + * @return a node equivalent to this one except for the requested change. 10.11 + */ 10.12 + public IndexNode setIndex(Node index) { 10.13 + if(this.index == index) { 10.14 + return this; 10.15 + } 10.16 + return new IndexNode(this, base, index, isFunction(), hasCallSiteType()); 10.17 + } 10.18 + 10.19 @Override 10.20 public BaseNode setIsFunction() { 10.21 if (isFunction()) { 10.22 @@ -115,10 +127,10 @@ 10.23 } 10.24 10.25 @Override 10.26 - public IndexNode setType(final Type type) { 10.27 + public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 10.28 logTypeChange(type); 10.29 - getSymbol().setTypeOverride(type); //always a temp so this is fine. 10.30 - return new IndexNode(this, base, index, isFunction(), true); 10.31 + final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts)); 10.32 + return new IndexNode(newIndexNode, base, index, isFunction(), true); 10.33 } 10.34 10.35 }
11.1 --- a/src/jdk/nashorn/internal/ir/Node.java Tue May 07 14:43:17 2013 +0200 11.2 +++ b/src/jdk/nashorn/internal/ir/Node.java Wed May 08 15:51:36 2013 +0200 11.3 @@ -27,7 +27,6 @@ 11.4 11.5 import java.util.ArrayList; 11.6 import java.util.List; 11.7 - 11.8 import jdk.nashorn.internal.codegen.types.Type; 11.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 11.10 import jdk.nashorn.internal.parser.Token;
12.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue May 07 14:43:17 2013 +0200 12.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed May 08 15:51:36 2013 +0200 12.3 @@ -390,7 +390,7 @@ 12.4 } 12.5 12.6 @Override 12.7 - public RuntimeNode setType(final Type type) { 12.8 + public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 12.9 if (this.callSiteType == type) { 12.10 return this; 12.11 }
13.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java Tue May 07 14:43:17 2013 +0200 13.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Wed May 08 15:51:36 2013 +0200 13.3 @@ -29,7 +29,6 @@ 13.4 import java.util.HashSet; 13.5 import java.util.Set; 13.6 import java.util.StringTokenizer; 13.7 - 13.8 import jdk.nashorn.internal.codegen.types.Type; 13.9 import jdk.nashorn.internal.runtime.Context; 13.10 import jdk.nashorn.internal.runtime.Debug; 13.11 @@ -69,6 +68,8 @@ 13.12 public static final int IS_FUNCTION_SELF = 1 << 10; 13.13 /** Is this a specialized param? */ 13.14 public static final int IS_SPECIALIZED_PARAM = 1 << 11; 13.15 + /** Is this symbol a shared temporary? */ 13.16 + public static final int IS_SHARED = 1 << 12; 13.17 13.18 /** Null or name identifying symbol. */ 13.19 private final String name; 13.20 @@ -154,6 +155,16 @@ 13.21 this(name, flags, type, -1); 13.22 } 13.23 13.24 + private Symbol(final Symbol base, final String name, final int flags) { 13.25 + this.flags = flags; 13.26 + this.name = name; 13.27 + 13.28 + this.fieldIndex = base.fieldIndex; 13.29 + this.slot = base.slot; 13.30 + this.type = base.type; 13.31 + this.useCount = base.useCount; 13.32 + } 13.33 + 13.34 private static String align(final String string, final int max) { 13.35 final StringBuilder sb = new StringBuilder(); 13.36 sb.append(string.substring(0, Math.min(string.length(), max))); 13.37 @@ -331,6 +342,24 @@ 13.38 } 13.39 13.40 /** 13.41 + * Returns true if this symbol is a temporary that is being shared across expressions. 13.42 + * @return true if this symbol is a temporary that is being shared across expressions. 13.43 + */ 13.44 + public boolean isShared() { 13.45 + return (flags & IS_SHARED) == IS_SHARED; 13.46 + } 13.47 + 13.48 + /** 13.49 + * Creates an unshared copy of a symbol. The symbol must be currently shared. 13.50 + * @param newName the name for the new symbol. 13.51 + * @return a new, unshared symbol. 13.52 + */ 13.53 + public Symbol createUnshared(final String newName) { 13.54 + assert isShared(); 13.55 + return new Symbol(this, newName, flags & ~IS_SHARED); 13.56 + } 13.57 + 13.58 + /** 13.59 * Flag this symbol as scope as described in {@link Symbol#isScope()} 13.60 */ 13.61 /** 13.62 @@ -339,10 +368,23 @@ 13.63 public void setIsScope() { 13.64 if (!isScope()) { 13.65 trace("SET IS SCOPE"); 13.66 + assert !isShared(); 13.67 + flags |= IS_SCOPE; 13.68 } 13.69 - flags |= IS_SCOPE; 13.70 } 13.71 13.72 + /** 13.73 + * Mark this symbol as one being shared by multiple expressions. The symbol must be a temporary. 13.74 + */ 13.75 + public void setIsShared() { 13.76 + if(!isShared()) { 13.77 + assert isTemp(); 13.78 + trace("SET IS SHARED"); 13.79 + flags |= IS_SHARED; 13.80 + } 13.81 + } 13.82 + 13.83 + 13.84 /** 13.85 * Check if this symbol is a variable 13.86 * @return true if variable 13.87 @@ -397,7 +439,10 @@ 13.88 */ 13.89 public void setCanBeUndefined() { 13.90 assert type.isObject() : type; 13.91 - flags |= CAN_BE_UNDEFINED; 13.92 + if(!canBeUndefined()) { 13.93 + assert !isShared(); 13.94 + flags |= CAN_BE_UNDEFINED; 13.95 + } 13.96 } 13.97 13.98 /** 13.99 @@ -405,7 +450,10 @@ 13.100 * @param type the primitive type it occurs with, currently unused but can be used for width guesses 13.101 */ 13.102 public void setCanBePrimitive(final Type type) { 13.103 - flags |= CAN_BE_PRIMITIVE; 13.104 + if(!canBePrimitive()) { 13.105 + assert !isShared(); 13.106 + flags |= CAN_BE_PRIMITIVE; 13.107 + } 13.108 } 13.109 13.110 /** 13.111 @@ -445,7 +493,10 @@ 13.112 * Flag this symbol as a let 13.113 */ 13.114 public void setIsLet() { 13.115 - flags |= IS_LET; 13.116 + if(!isLet()) { 13.117 + assert !isShared(); 13.118 + flags |= IS_LET; 13.119 + } 13.120 } 13.121 13.122 /** 13.123 @@ -474,7 +525,10 @@ 13.124 * @param fieldIndex field index - a positive integer 13.125 */ 13.126 public void setFieldIndex(final int fieldIndex) { 13.127 - this.fieldIndex = fieldIndex; 13.128 + if(this.fieldIndex != fieldIndex) { 13.129 + assert !isShared(); 13.130 + this.fieldIndex = fieldIndex; 13.131 + } 13.132 } 13.133 13.134 /** 13.135 @@ -490,7 +544,10 @@ 13.136 * @param flags flags 13.137 */ 13.138 public void setFlags(final int flags) { 13.139 - this.flags = flags; 13.140 + if(this.flags != flags) { 13.141 + assert !isShared(); 13.142 + this.flags = flags; 13.143 + } 13.144 } 13.145 13.146 /** 13.147 @@ -530,6 +587,7 @@ 13.148 */ 13.149 public void setSlot(final int slot) { 13.150 if (slot != this.slot) { 13.151 + assert !isShared(); 13.152 trace("SET SLOT " + slot); 13.153 this.slot = slot; 13.154 } 13.155 @@ -555,6 +613,15 @@ 13.156 } 13.157 13.158 /** 13.159 + * Returns true if calling {@link #setType(Type)} on this symbol would effectively change its type. 13.160 + * @param newType the new type to test for 13.161 + * @return true if setting this symbols type to a new value would effectively change its type. 13.162 + */ 13.163 + public boolean wouldChangeType(final Type newType) { 13.164 + return Type.widest(this.type, newType) != this.type; 13.165 + } 13.166 + 13.167 + /** 13.168 * Only use this if you know about an existing type 13.169 * constraint - otherwise a type can only be 13.170 * widened 13.171 @@ -564,12 +631,33 @@ 13.172 public void setTypeOverride(final Type type) { 13.173 final Type old = this.type; 13.174 if (old != type) { 13.175 + assert !isShared(); 13.176 trace("TYPE CHANGE: " + old + "=>" + type + " == " + type); 13.177 this.type = type; 13.178 } 13.179 } 13.180 13.181 /** 13.182 + * Sets the type of the symbol to the specified type. If the type would be changed, but this symbol is a shared 13.183 + * temporary, it will instead return a different temporary symbol of the requested type from the passed temporary 13.184 + * symbols. That way, it never mutates the type of a shared temporary. 13.185 + * @param type the new type for the symbol 13.186 + * @param ts a holder of temporary symbols 13.187 + * @return either this symbol, or a different symbol if this symbol is a shared temporary and it type would have to 13.188 + * be changed. 13.189 + */ 13.190 + public Symbol setTypeOverrideShared(final Type type, final TemporarySymbols ts) { 13.191 + if(getSymbolType() != type) { 13.192 + if(isShared()) { 13.193 + assert !hasSlot(); 13.194 + return ts.getTypedTemporarySymbol(type); 13.195 + } 13.196 + setTypeOverride(type); 13.197 + } 13.198 + return this; 13.199 + } 13.200 + 13.201 + /** 13.202 * From a lexical context, set this symbol as needing scope, which 13.203 * will set flags for the defining block that will be written when 13.204 * block is popped from the lexical context stack, used by codegen
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/jdk/nashorn/internal/ir/TemporarySymbols.java Wed May 08 15:51:36 2013 +0200 14.3 @@ -0,0 +1,169 @@ 14.4 +/* 14.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 14.7 + * 14.8 + * This code is free software; you can redistribute it and/or modify it 14.9 + * under the terms of the GNU General Public License version 2 only, as 14.10 + * published by the Free Software Foundation. Oracle designates this 14.11 + * particular file as subject to the "Classpath" exception as provided 14.12 + * by Oracle in the LICENSE file that accompanied this code. 14.13 + * 14.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 14.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14.17 + * version 2 for more details (a copy is included in the LICENSE file that 14.18 + * accompanied this code). 14.19 + * 14.20 + * You should have received a copy of the GNU General Public License version 14.21 + * 2 along with this work; if not, write to the Free Software Foundation, 14.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 14.23 + * 14.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 14.25 + * or visit www.oracle.com if you need additional information or have any 14.26 + * questions. 14.27 + */ 14.28 + 14.29 +package jdk.nashorn.internal.ir; 14.30 + 14.31 +import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; 14.32 +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; 14.33 + 14.34 +import java.util.HashMap; 14.35 +import java.util.Map; 14.36 +import jdk.nashorn.internal.codegen.types.Type; 14.37 + 14.38 +/** 14.39 + * Class that holds reusable temporary symbols by type. 14.40 + * 14.41 + */ 14.42 +public class TemporarySymbols { 14.43 + private static final String prefix = TEMP_PREFIX.symbolName() + "$"; 14.44 + 14.45 + private int totalSymbolCount; 14.46 + private final Map<Type, TypedTemporarySymbols> temporarySymbolsByType = new HashMap<>(); 14.47 + 14.48 + /** 14.49 + * Associates a temporary symbol of a given type with a node, if the node doesn't already have any symbol. 14.50 + * @param lc the current lexical context 14.51 + * @param type the type of the temporary symbol 14.52 + * @param node the node 14.53 + * @return the node that is guaranteed to have a symbol. 14.54 + */ 14.55 + public Node ensureSymbol(final LexicalContext lc, final Type type, final Node node) { 14.56 + final Symbol symbol = node.getSymbol(); 14.57 + if (symbol != null) { 14.58 + return node; 14.59 + } 14.60 + return node.setSymbol(lc, getTypedTemporarySymbol(type)); 14.61 + } 14.62 + 14.63 + /** 14.64 + * Given a type, returns a temporary symbol of that type. 14.65 + * @param type the required type of the symbol. 14.66 + * @return a temporary symbol of the required type. 14.67 + */ 14.68 + public Symbol getTypedTemporarySymbol(final Type type) { 14.69 + return getTypedTemporarySymbols(type).getTemporarySymbol(type); 14.70 + } 14.71 + 14.72 + private TypedTemporarySymbols getTypedTemporarySymbols(final Type type) { 14.73 + TypedTemporarySymbols temporarySymbols = temporarySymbolsByType.get(type); 14.74 + if(temporarySymbols == null) { 14.75 + temporarySymbols = new TypedTemporarySymbols(); 14.76 + temporarySymbolsByType.put(type, temporarySymbols); 14.77 + } 14.78 + return temporarySymbols; 14.79 + } 14.80 + 14.81 + /** 14.82 + * This method is called to signal to this object that all the symbols it holds can be reused now. 14.83 + */ 14.84 + public void reuse() { 14.85 + for(TypedTemporarySymbols ts: temporarySymbolsByType.values()) { 14.86 + ts.reuse(); 14.87 + } 14.88 + } 14.89 + 14.90 + /** 14.91 + * Given a shared symbol, creates an unshared copy of it with a unique name. 14.92 + * @param symbol the shared symbol 14.93 + * @return the unshared, uniquely named copy of the symbol 14.94 + */ 14.95 + public Symbol createUnshared(Symbol symbol) { 14.96 + return symbol.createUnshared(getUniqueName()); 14.97 + } 14.98 + 14.99 + private String getUniqueName() { 14.100 + return prefix + (++totalSymbolCount); 14.101 + } 14.102 + 14.103 + /** 14.104 + * Returns the total number of symbols this object created during its lifetime. 14.105 + * @return the total number of symbols this object created during its lifetime. 14.106 + */ 14.107 + public int getTotalSymbolCount() { 14.108 + return totalSymbolCount; 14.109 + } 14.110 + 14.111 + private class TypedTemporarySymbols { 14.112 + private Symbol[] symbols = new Symbol[16]; 14.113 + private int nextFreeSymbol = 0; 14.114 + private int symbolCount = 0; 14.115 + 14.116 + Symbol getTemporarySymbol(final Type type) { 14.117 + while(nextFreeSymbol < symbolCount) { 14.118 + final Symbol nextSymbol = symbols[nextFreeSymbol]; 14.119 + assert nextSymbol != null; 14.120 + // If it has a slot, we can't reuse it. 14.121 + if(!nextSymbol.hasSlot()) { 14.122 + final Type symbolType = nextSymbol.getSymbolType(); 14.123 + if(symbolType == type) { 14.124 + assert nextSymbol.isTemp(); 14.125 + assert !nextSymbol.isScope(); 14.126 + // If types match, we can reuse it. 14.127 + nextSymbol.setIsShared(); 14.128 + nextFreeSymbol++; 14.129 + return nextSymbol; 14.130 + } 14.131 + // If its type changed, but it doesn't have a slot then move it to its new home according to its 14.132 + // new type. 14.133 + getTypedTemporarySymbols(symbolType).addSymbol(nextSymbol); 14.134 + } 14.135 + // If we can move another symbol into its place, do that and repeat the analysis for this symbol. 14.136 + --symbolCount; 14.137 + if(symbolCount != nextFreeSymbol) { 14.138 + final Symbol lastFreeSymbol = symbols[symbolCount]; 14.139 + symbols[nextFreeSymbol] = lastFreeSymbol; 14.140 + } 14.141 + symbols[symbolCount] = null; 14.142 + } 14.143 + return createNewSymbol(type); 14.144 + } 14.145 + 14.146 + private Symbol createNewSymbol(final Type type) { 14.147 + ensureCapacity(); 14.148 + final Symbol symbol = symbols[nextFreeSymbol] = new Symbol(getUniqueName(), IS_TEMP, type); 14.149 + nextFreeSymbol++; 14.150 + symbolCount++; 14.151 + return symbol; 14.152 + } 14.153 + 14.154 + private void addSymbol(Symbol symbol) { 14.155 + ensureCapacity(); 14.156 + symbols[symbolCount++] = symbol; 14.157 + } 14.158 + 14.159 + void reuse() { 14.160 + nextFreeSymbol = 0; 14.161 + } 14.162 + 14.163 + private void ensureCapacity() { 14.164 + if(symbolCount == symbols.length) { 14.165 + final Symbol[] newSymbols = new Symbol[symbolCount * 2]; 14.166 + System.arraycopy(symbols, 0, newSymbols, 0, symbolCount); 14.167 + symbols = newSymbols; 14.168 + } 14.169 + } 14.170 + } 14.171 + 14.172 +}
15.1 --- a/src/jdk/nashorn/internal/ir/TypeOverride.java Tue May 07 14:43:17 2013 +0200 15.2 +++ b/src/jdk/nashorn/internal/ir/TypeOverride.java Wed May 08 15:51:36 2013 +0200 15.3 @@ -43,10 +43,12 @@ 15.4 /** 15.5 * Set the override type 15.6 * 15.7 - * @param type the type 15.8 + * @param ts temporary symbols 15.9 + * @param lc the current lexical context 15.10 + * @param type the type 15.11 * @return a node equivalent to this one except for the requested change. 15.12 */ 15.13 - public T setType(final Type type); 15.14 + public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type); 15.15 15.16 /** 15.17 * Returns true if this node can have a callsite override, e.g. all scope ident nodes