Mon, 03 Nov 2014 11:47:41 +0100
8060204: Fix warnings in Joni and tests
Reviewed-by: hannesw, sundar, attila
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 */
26 package jdk.nashorn.internal.codegen;
28 import java.util.ArrayDeque;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.Deque;
32 import java.util.HashMap;
33 import java.util.Map;
34 import jdk.nashorn.internal.IntDeque;
35 import jdk.nashorn.internal.codegen.types.Type;
36 import jdk.nashorn.internal.ir.Block;
37 import jdk.nashorn.internal.ir.FunctionNode;
38 import jdk.nashorn.internal.ir.LexicalContext;
39 import jdk.nashorn.internal.ir.LexicalContextNode;
40 import jdk.nashorn.internal.ir.Node;
41 import jdk.nashorn.internal.ir.Symbol;
42 import jdk.nashorn.internal.ir.WithNode;
44 /**
45 * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
46 * variables introduced into them at run time - a with block or a function directly containing an eval call.
47 * Furthermore, this class keeps track of current discard state, which the current method emitter being used is,
48 * the current compile unit, and local variable indexes
49 */
50 final class CodeGeneratorLexicalContext extends LexicalContext {
51 private int dynamicScopeCount;
53 /** Map of shared scope call sites */
54 private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
56 /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */
57 private final Deque<CompileUnit> compileUnits = new ArrayDeque<>();
59 /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
60 private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
62 /** The discard stack - whenever we enter a discard node we keep track of its return value status -
63 * i.e. should we keep it or throw it away */
64 private final Deque<Node> discard = new ArrayDeque<>();
66 private final Deque<Map<String, Collection<Label>>> unwarrantedOptimismHandlers = new ArrayDeque<>();
67 private final Deque<StringBuilder> slotTypesDescriptors = new ArrayDeque<>();
68 private final IntDeque splitNodes = new IntDeque();
70 /** A stack tracking the next free local variable slot in the blocks. There's one entry for every block
71 * currently on the lexical context stack. */
72 private int[] nextFreeSlots = new int[16];
74 /** size of next free slot vector */
75 private int nextFreeSlotsSize;
77 private boolean isWithBoundary(final LexicalContextNode node) {
78 return node instanceof Block && !isEmpty() && peek() instanceof WithNode;
79 }
81 @Override
82 public <T extends LexicalContextNode> T push(final T node) {
83 if (isWithBoundary(node)) {
84 dynamicScopeCount++;
85 } else if (node instanceof FunctionNode) {
86 if (((FunctionNode)node).inDynamicContext()) {
87 dynamicScopeCount++;
88 }
89 splitNodes.push(0);
90 }
91 return super.push(node);
92 }
94 void enterSplitNode() {
95 splitNodes.getAndIncrement();
96 pushFreeSlots(methodEmitters.peek().getUsedSlotsWithLiveTemporaries());
97 }
99 void exitSplitNode() {
100 final int count = splitNodes.decrementAndGet();
101 assert count >= 0;
102 }
104 @Override
105 public <T extends LexicalContextNode> T pop(final T node) {
106 final T popped = super.pop(node);
107 if (isWithBoundary(node)) {
108 dynamicScopeCount--;
109 assert dynamicScopeCount >= 0;
110 } else if (node instanceof FunctionNode) {
111 if (((FunctionNode)node).inDynamicContext()) {
112 dynamicScopeCount--;
113 assert dynamicScopeCount >= 0;
114 }
115 assert splitNodes.peek() == 0;
116 splitNodes.pop();
117 }
118 return popped;
119 }
121 boolean inDynamicScope() {
122 return dynamicScopeCount > 0;
123 }
125 boolean inSplitNode() {
126 return !splitNodes.isEmpty() && splitNodes.peek() > 0;
127 }
129 MethodEmitter pushMethodEmitter(final MethodEmitter newMethod) {
130 methodEmitters.push(newMethod);
131 return newMethod;
132 }
134 MethodEmitter popMethodEmitter(final MethodEmitter oldMethod) {
135 assert methodEmitters.peek() == oldMethod;
136 methodEmitters.pop();
137 return methodEmitters.isEmpty() ? null : methodEmitters.peek();
138 }
140 void pushUnwarrantedOptimismHandlers() {
141 unwarrantedOptimismHandlers.push(new HashMap<String, Collection<Label>>());
142 slotTypesDescriptors.push(new StringBuilder());
143 }
145 Map<String, Collection<Label>> getUnwarrantedOptimismHandlers() {
146 return unwarrantedOptimismHandlers.peek();
147 }
149 Map<String, Collection<Label>> popUnwarrantedOptimismHandlers() {
150 slotTypesDescriptors.pop();
151 return unwarrantedOptimismHandlers.pop();
152 }
154 CompileUnit pushCompileUnit(final CompileUnit newUnit) {
155 compileUnits.push(newUnit);
156 return newUnit;
157 }
159 CompileUnit popCompileUnit(final CompileUnit oldUnit) {
160 assert compileUnits.peek() == oldUnit;
161 final CompileUnit unit = compileUnits.pop();
162 assert unit.hasCode() : "compile unit popped without code";
163 unit.setUsed();
164 return compileUnits.isEmpty() ? null : compileUnits.peek();
165 }
167 boolean hasCompileUnits() {
168 return !compileUnits.isEmpty();
169 }
171 Collection<SharedScopeCall> getScopeCalls() {
172 return Collections.unmodifiableCollection(scopeCalls.values());
173 }
175 /**
176 * Get a shared static method representing a dynamic scope callsite.
177 *
178 * @param unit current compile unit
179 * @param symbol the symbol
180 * @param valueType the value type of the symbol
181 * @param returnType the return type
182 * @param paramTypes the parameter types
183 * @param flags the callsite flags
184 * @return an object representing a shared scope call
185 */
186 SharedScopeCall getScopeCall(final CompileUnit unit, final Symbol symbol, final Type valueType, final Type returnType, final Type[] paramTypes, final int flags) {
187 final SharedScopeCall scopeCall = new SharedScopeCall(symbol, valueType, returnType, paramTypes, flags);
188 if (scopeCalls.containsKey(scopeCall)) {
189 return scopeCalls.get(scopeCall);
190 }
191 scopeCall.setClassAndName(unit, getCurrentFunction().uniqueName(":scopeCall"));
192 scopeCalls.put(scopeCall, scopeCall);
193 return scopeCall;
194 }
196 /**
197 * Get a shared static method representing a dynamic scope get access.
198 *
199 * @param unit current compile unit
200 * @param symbol the symbol
201 * @param valueType the type of the variable
202 * @param flags the callsite flags
203 * @return an object representing a shared scope call
204 */
205 SharedScopeCall getScopeGet(final CompileUnit unit, final Symbol symbol, final Type valueType, final int flags) {
206 return getScopeCall(unit, symbol, valueType, valueType, null, flags);
207 }
209 void onEnterBlock(final Block block) {
210 pushFreeSlots(assignSlots(block, isFunctionBody() ? 0 : getUsedSlotCount()));
211 }
213 private void pushFreeSlots(final int freeSlots) {
214 if (nextFreeSlotsSize == nextFreeSlots.length) {
215 final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
216 System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
217 nextFreeSlots = newNextFreeSlots;
218 }
219 nextFreeSlots[nextFreeSlotsSize++] = freeSlots;
220 }
222 int getUsedSlotCount() {
223 return nextFreeSlots[nextFreeSlotsSize - 1];
224 }
226 void releaseSlots() {
227 --nextFreeSlotsSize;
228 final int undefinedFromSlot = nextFreeSlotsSize == 0 ? 0 : nextFreeSlots[nextFreeSlotsSize - 1];
229 if(!slotTypesDescriptors.isEmpty()) {
230 slotTypesDescriptors.peek().setLength(undefinedFromSlot);
231 }
232 methodEmitters.peek().undefineLocalVariables(undefinedFromSlot, false);
233 }
235 private int assignSlots(final Block block, final int firstSlot) {
236 int fromSlot = firstSlot;
237 final MethodEmitter method = methodEmitters.peek();
238 for (final Symbol symbol : block.getSymbols()) {
239 if (symbol.hasSlot()) {
240 symbol.setFirstSlot(fromSlot);
241 final int toSlot = fromSlot + symbol.slotCount();
242 method.defineBlockLocalVariable(fromSlot, toSlot);
243 fromSlot = toSlot;
244 }
245 }
246 return fromSlot;
247 }
249 static Type getTypeForSlotDescriptor(final char typeDesc) {
250 // Recognizing both lowercase and uppercase as we're using both to signify symbol boundaries; see
251 // MethodEmitter.markSymbolBoundariesInLvarTypesDescriptor().
252 switch (typeDesc) {
253 case 'I':
254 case 'i':
255 return Type.INT;
256 case 'J':
257 case 'j':
258 return Type.LONG;
259 case 'D':
260 case 'd':
261 return Type.NUMBER;
262 case 'A':
263 case 'a':
264 return Type.OBJECT;
265 case 'U':
266 case 'u':
267 return Type.UNKNOWN;
268 default:
269 throw new AssertionError();
270 }
271 }
273 void pushDiscard(final Node node) {
274 discard.push(node);
275 }
277 Node popDiscard() {
278 return discard.pop();
279 }
281 Node getCurrentDiscard() {
282 return discard.peek();
283 }
285 int quickSlot(final Type type) {
286 return methodEmitters.peek().defineTemporaryLocalVariable(type.getSlots());
287 }
288 }