9 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; |
9 import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT; |
10 |
10 |
11 import java.io.File; |
11 import java.io.File; |
12 import java.io.FileOutputStream; |
12 import java.io.FileOutputStream; |
13 import java.io.IOException; |
13 import java.io.IOException; |
|
14 import java.util.ArrayDeque; |
|
15 import java.util.ArrayList; |
|
16 import java.util.Deque; |
14 import java.util.EnumSet; |
17 import java.util.EnumSet; |
15 import java.util.HashSet; |
18 import java.util.HashSet; |
|
19 import java.util.List; |
16 import java.util.Set; |
20 import java.util.Set; |
|
21 |
|
22 import jdk.nashorn.internal.codegen.types.Range; |
17 import jdk.nashorn.internal.codegen.types.Type; |
23 import jdk.nashorn.internal.codegen.types.Type; |
18 import jdk.nashorn.internal.ir.Block; |
24 import jdk.nashorn.internal.ir.Block; |
19 import jdk.nashorn.internal.ir.CallNode; |
25 import jdk.nashorn.internal.ir.CallNode; |
20 import jdk.nashorn.internal.ir.FunctionNode; |
26 import jdk.nashorn.internal.ir.FunctionNode; |
|
27 import jdk.nashorn.internal.ir.ReturnNode; |
|
28 import jdk.nashorn.internal.ir.Symbol; |
21 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; |
29 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; |
22 import jdk.nashorn.internal.ir.LexicalContext; |
30 import jdk.nashorn.internal.ir.LexicalContext; |
23 import jdk.nashorn.internal.ir.Node; |
31 import jdk.nashorn.internal.ir.Node; |
24 import jdk.nashorn.internal.ir.TemporarySymbols; |
32 import jdk.nashorn.internal.ir.TemporarySymbols; |
25 import jdk.nashorn.internal.ir.debug.ASTWriter; |
33 import jdk.nashorn.internal.ir.debug.ASTWriter; |
172 ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { |
180 ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { |
173 @Override |
181 @Override |
174 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { |
182 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { |
175 final TemporarySymbols ts = compiler.getTemporarySymbols(); |
183 final TemporarySymbols ts = compiler.getTemporarySymbols(); |
176 final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts)); |
184 final FunctionNode newFunctionNode = (FunctionNode)enterAttr(fn, ts).accept(new Attr(ts)); |
177 if(compiler.getEnv()._print_mem_usage) { |
185 if (compiler.getEnv()._print_mem_usage) { |
178 Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); |
186 Compiler.LOG.info("Attr temporary symbol count: " + ts.getTotalSymbolCount()); |
179 } |
187 } |
180 return newFunctionNode; |
188 return newFunctionNode; |
181 } |
189 } |
182 |
190 |
206 return "[Type Attribution]"; |
214 return "[Type Attribution]"; |
207 } |
215 } |
208 }, |
216 }, |
209 |
217 |
210 /* |
218 /* |
|
219 * Range analysis |
|
220 * Conservatively prove that certain variables can be narrower than |
|
221 * the most generic number type |
|
222 */ |
|
223 RANGE_ANALYSIS_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { |
|
224 @Override |
|
225 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { |
|
226 if (!compiler.getEnv()._range_analysis) { |
|
227 return fn; |
|
228 } |
|
229 |
|
230 FunctionNode newFunctionNode = (FunctionNode)fn.accept(new RangeAnalyzer()); |
|
231 final List<ReturnNode> returns = new ArrayList<>(); |
|
232 |
|
233 newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() { |
|
234 private final Deque<ArrayList<ReturnNode>> returnStack = new ArrayDeque<>(); |
|
235 |
|
236 @Override |
|
237 public boolean enterFunctionNode(final FunctionNode functionNode) { |
|
238 returnStack.push(new ArrayList<ReturnNode>()); |
|
239 return true; |
|
240 } |
|
241 |
|
242 @Override |
|
243 public Node leaveFunctionNode(final FunctionNode functionNode) { |
|
244 Type returnType = Type.UNKNOWN; |
|
245 for (final ReturnNode ret : returnStack.pop()) { |
|
246 if (ret.getExpression() == null) { |
|
247 returnType = Type.OBJECT; |
|
248 break; |
|
249 } |
|
250 returnType = Type.widest(returnType, ret.getExpression().getType()); |
|
251 } |
|
252 return functionNode.setReturnType(getLexicalContext(), returnType); |
|
253 } |
|
254 |
|
255 @Override |
|
256 public Node leaveReturnNode(final ReturnNode returnNode) { |
|
257 final ReturnNode result = (ReturnNode)leaveDefault(returnNode); |
|
258 returns.add(result); |
|
259 return result; |
|
260 } |
|
261 |
|
262 @Override |
|
263 public Node leaveDefault(final Node node) { |
|
264 final Symbol symbol = node.getSymbol(); |
|
265 if (symbol != null) { |
|
266 final Range range = symbol.getRange(); |
|
267 final Type symbolType = symbol.getSymbolType(); |
|
268 if (!symbolType.isNumeric()) { |
|
269 return node; |
|
270 } |
|
271 final Type rangeType = range.getType(); |
|
272 if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range |
|
273 RangeAnalyzer.LOG.info("[", getLexicalContext().getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange()); |
|
274 return node.setSymbol(getLexicalContext(), symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols())); |
|
275 } |
|
276 } |
|
277 return node; |
|
278 } |
|
279 }); |
|
280 |
|
281 Type returnType = Type.UNKNOWN; |
|
282 for (final ReturnNode node : returns) { |
|
283 if (node.getExpression() != null) { |
|
284 returnType = Type.widest(returnType, node.getExpression().getType()); |
|
285 } else { |
|
286 returnType = Type.OBJECT; |
|
287 break; |
|
288 } |
|
289 } |
|
290 |
|
291 return newFunctionNode.setReturnType(null, returnType); |
|
292 } |
|
293 |
|
294 @Override |
|
295 public String toString() { |
|
296 return "[Range Analysis]"; |
|
297 } |
|
298 }, |
|
299 |
|
300 |
|
301 /* |
211 * Splitter Split the AST into several compile units based on a size |
302 * Splitter Split the AST into several compile units based on a size |
212 * heuristic Splitter needs attributed AST for weight calculations (e.g. is |
303 * heuristic Splitter needs attributed AST for weight calculations (e.g. is |
213 * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less). |
304 * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less). |
214 * Split IR can lead to scope information being changed. |
305 * Split IR can lead to scope information being changed. |
215 */ |
306 */ |
216 SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { |
307 SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { |
217 @Override |
308 @Override |
218 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { |
309 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { |
219 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); |
310 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); |
220 |
311 |
221 // assert fn.isProgram() ; |
|
222 final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); |
312 final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); |
223 |
313 |
224 assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; |
314 assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; |
225 |
315 |
226 if (newFunctionNode.isStrict()) { |
316 if (newFunctionNode.isStrict()) { |