View Javadoc
1   /*
2    * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package jdk.nashorn.internal.ir;
27  
28  import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
29  import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
30  
31  import java.util.HashMap;
32  import java.util.Map;
33  import jdk.nashorn.internal.codegen.types.Type;
34  
35  /**
36   * Class that holds reusable temporary symbols by type.
37   *
38   */
39  public class TemporarySymbols {
40      private static final String prefix = TEMP_PREFIX.symbolName() + "$";
41  
42      private int totalSymbolCount;
43      private final Map<Type, TypedTemporarySymbols> temporarySymbolsByType = new HashMap<>();
44  
45      /**
46       * Associates a temporary symbol of a given type with a node, if the node doesn't already have any symbol.
47       * @param lc the current lexical context
48       * @param type the type of the temporary symbol
49       * @param node the node
50       * @return the node that is guaranteed to have a symbol.
51       */
52      public Expression ensureSymbol(final LexicalContext lc, final Type type, final Expression node) {
53          final Symbol symbol = node.getSymbol();
54          if (symbol != null) {
55              return node;
56          }
57          return node.setSymbol(lc, getTypedTemporarySymbol(type));
58      }
59  
60      /**
61       * Given a type, returns a temporary symbol of that type.
62       * @param type the required type of the symbol.
63       * @return a temporary symbol of the required type.
64       */
65      public Symbol getTypedTemporarySymbol(final Type type) {
66          return getTypedTemporarySymbols(type).getTemporarySymbol(type);
67      }
68  
69      private TypedTemporarySymbols getTypedTemporarySymbols(final Type type) {
70          TypedTemporarySymbols temporarySymbols = temporarySymbolsByType.get(type);
71          if(temporarySymbols == null) {
72              temporarySymbols = new TypedTemporarySymbols();
73              temporarySymbolsByType.put(type, temporarySymbols);
74          }
75          return temporarySymbols;
76      }
77  
78      /**
79       * This method is called to signal to this object that all the symbols it holds can be reused now.
80       */
81      public void reuse() {
82          for(TypedTemporarySymbols ts: temporarySymbolsByType.values()) {
83              ts.reuse();
84          }
85      }
86  
87      /**
88       * Given a shared symbol, creates an unshared copy of it with a unique name.
89       * @param symbol the shared symbol
90       * @return the unshared, uniquely named copy of the symbol
91       */
92      public Symbol createUnshared(Symbol symbol) {
93          return symbol.createUnshared(getUniqueName());
94      }
95  
96      private String getUniqueName() {
97          return prefix + (++totalSymbolCount);
98      }
99  
100     /**
101      * Returns the total number of symbols this object created during its lifetime.
102      * @return the total number of symbols this object created during its lifetime.
103      */
104     public int getTotalSymbolCount() {
105         return totalSymbolCount;
106     }
107 
108     private class TypedTemporarySymbols {
109         private Symbol[] symbols = new Symbol[16];
110         private int nextFreeSymbol = 0;
111         private int symbolCount = 0;
112 
113         Symbol getTemporarySymbol(final Type type) {
114             while(nextFreeSymbol < symbolCount) {
115                 final Symbol nextSymbol = symbols[nextFreeSymbol];
116                 assert nextSymbol != null;
117                 // If it has a slot, we can't reuse it.
118                 if(!nextSymbol.hasSlot()) {
119                     final Type symbolType = nextSymbol.getSymbolType();
120                     if(symbolType == type) {
121                         assert nextSymbol.isTemp();
122                         assert !nextSymbol.isScope();
123                         // If types match, we can reuse it.
124                         nextSymbol.setIsShared();
125                         nextFreeSymbol++;
126                         return nextSymbol;
127                     }
128                     // If its type changed, but it doesn't have a slot then move it to its new home according to its
129                     // new type.
130                     getTypedTemporarySymbols(symbolType).addSymbol(nextSymbol);
131                 }
132                 // If we can move another symbol into its place, do that and repeat the analysis for this symbol.
133                 --symbolCount;
134                 if(symbolCount != nextFreeSymbol) {
135                     final Symbol lastFreeSymbol = symbols[symbolCount];
136                     symbols[nextFreeSymbol] = lastFreeSymbol;
137                 }
138                 symbols[symbolCount] = null;
139             }
140             return createNewSymbol(type);
141         }
142 
143         private Symbol createNewSymbol(final Type type) {
144             ensureCapacity();
145             final Symbol symbol = symbols[nextFreeSymbol] = new Symbol(getUniqueName(), IS_TEMP, type);
146             nextFreeSymbol++;
147             symbolCount++;
148             return symbol;
149         }
150 
151         private void addSymbol(Symbol symbol) {
152             ensureCapacity();
153             symbols[symbolCount++] = symbol;
154         }
155 
156         void reuse() {
157             nextFreeSymbol = 0;
158         }
159 
160         private void ensureCapacity() {
161             if(symbolCount == symbols.length) {
162                 final Symbol[] newSymbols = new Symbol[symbolCount * 2];
163                 System.arraycopy(symbols, 0, newSymbols, 0, symbolCount);
164                 symbols = newSymbols;
165             }
166         }
167     }
168 
169 }