OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:collection'; | 5 import 'dart:collection'; |
6 | 6 |
7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
8 | 8 |
9 import '../closure.dart'; | 9 import '../closure.dart'; |
10 import '../common.dart'; | 10 import '../common.dart'; |
(...skipping 22 matching lines...) Expand all Loading... |
33 import '../tree/tree.dart' as ast; | 33 import '../tree/tree.dart' as ast; |
34 import '../types/types.dart'; | 34 import '../types/types.dart'; |
35 import '../universe/call_structure.dart' show CallStructure; | 35 import '../universe/call_structure.dart' show CallStructure; |
36 import '../universe/selector.dart' show Selector; | 36 import '../universe/selector.dart' show Selector; |
37 import '../universe/side_effects.dart' show SideEffects; | 37 import '../universe/side_effects.dart' show SideEffects; |
38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; | 38 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse; |
39 import '../util/util.dart'; | 39 import '../util/util.dart'; |
40 import '../world.dart' show ClassWorld; | 40 import '../world.dart' show ClassWorld; |
41 | 41 |
42 import 'graph_builder.dart'; | 42 import 'graph_builder.dart'; |
| 43 import 'jump_handler.dart'; |
43 import 'locals_handler.dart'; | 44 import 'locals_handler.dart'; |
| 45 import 'loop_handler.dart'; |
44 import 'nodes.dart'; | 46 import 'nodes.dart'; |
45 import 'optimize.dart'; | 47 import 'optimize.dart'; |
46 import 'ssa_branch_builder.dart'; | 48 import 'ssa_branch_builder.dart'; |
47 import 'types.dart'; | 49 import 'types.dart'; |
48 | 50 |
49 /// A synthetic local variable only used with the SSA graph. | 51 /// A synthetic local variable only used with the SSA graph. |
50 /// | 52 /// |
51 /// For instance used for holding return value of function or the exception of a | 53 /// For instance used for holding return value of function or the exception of a |
52 /// try-catch statement. | 54 /// try-catch statement. |
53 class SyntheticLocal extends Local { | 55 class SyntheticLocal extends Local { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 } | 120 } |
119 compiler.tracer.traceCompilation(name); | 121 compiler.tracer.traceCompilation(name); |
120 compiler.tracer.traceGraph('builder', graph); | 122 compiler.tracer.traceGraph('builder', graph); |
121 } | 123 } |
122 return graph; | 124 return graph; |
123 }); | 125 }); |
124 }); | 126 }); |
125 } | 127 } |
126 } | 128 } |
127 | 129 |
128 // Represents a single break/continue instruction. | |
129 class JumpHandlerEntry { | |
130 final HJump jumpInstruction; | |
131 final LocalsHandler locals; | |
132 bool isBreak() => jumpInstruction is HBreak; | |
133 bool isContinue() => jumpInstruction is HContinue; | |
134 JumpHandlerEntry(this.jumpInstruction, this.locals); | |
135 } | |
136 | |
137 abstract class JumpHandler { | |
138 factory JumpHandler(SsaBuilder builder, JumpTarget target) { | |
139 return new TargetJumpHandler(builder, target); | |
140 } | |
141 void generateBreak([LabelDefinition label]); | |
142 void generateContinue([LabelDefinition label]); | |
143 void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); | |
144 void forEachContinue( | |
145 void action(HContinue instruction, LocalsHandler locals)); | |
146 bool hasAnyContinue(); | |
147 bool hasAnyBreak(); | |
148 void close(); | |
149 final JumpTarget target; | |
150 List<LabelDefinition> labels(); | |
151 } | |
152 | |
153 // Insert break handler used to avoid null checks when a target isn't | |
154 // used as the target of a break, and therefore doesn't need a break | |
155 // handler associated with it. | |
156 class NullJumpHandler implements JumpHandler { | |
157 final DiagnosticReporter reporter; | |
158 | |
159 NullJumpHandler(this.reporter); | |
160 | |
161 void generateBreak([LabelDefinition label]) { | |
162 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
163 'NullJumpHandler.generateBreak should not be called.'); | |
164 } | |
165 | |
166 void generateContinue([LabelDefinition label]) { | |
167 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | |
168 'NullJumpHandler.generateContinue should not be called.'); | |
169 } | |
170 | |
171 void forEachBreak(Function ignored) {} | |
172 void forEachContinue(Function ignored) {} | |
173 void close() {} | |
174 bool hasAnyContinue() => false; | |
175 bool hasAnyBreak() => false; | |
176 | |
177 List<LabelDefinition> labels() => const <LabelDefinition>[]; | |
178 JumpTarget get target => null; | |
179 } | |
180 | |
181 // Records breaks until a target block is available. | |
182 // Breaks are always forward jumps. | |
183 // Continues in loops are implemented as breaks of the body. | |
184 // Continues in switches is currently not handled. | |
185 class TargetJumpHandler implements JumpHandler { | |
186 final SsaBuilder builder; | |
187 final JumpTarget target; | |
188 final List<JumpHandlerEntry> jumps; | |
189 | |
190 TargetJumpHandler(SsaBuilder builder, this.target) | |
191 : this.builder = builder, | |
192 jumps = <JumpHandlerEntry>[] { | |
193 assert(builder.jumpTargets[target] == null); | |
194 builder.jumpTargets[target] = this; | |
195 } | |
196 | |
197 void generateBreak([LabelDefinition label]) { | |
198 HInstruction breakInstruction; | |
199 if (label == null) { | |
200 breakInstruction = new HBreak(target); | |
201 } else { | |
202 breakInstruction = new HBreak.toLabel(label); | |
203 } | |
204 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
205 builder.close(breakInstruction); | |
206 jumps.add(new JumpHandlerEntry(breakInstruction, locals)); | |
207 } | |
208 | |
209 void generateContinue([LabelDefinition label]) { | |
210 HInstruction continueInstruction; | |
211 if (label == null) { | |
212 continueInstruction = new HContinue(target); | |
213 } else { | |
214 continueInstruction = new HContinue.toLabel(label); | |
215 // Switch case continue statements must be handled by the | |
216 // [SwitchCaseJumpHandler]. | |
217 assert(label.target.statement is! ast.SwitchCase); | |
218 } | |
219 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
220 builder.close(continueInstruction); | |
221 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | |
222 } | |
223 | |
224 void forEachBreak(Function action) { | |
225 for (JumpHandlerEntry entry in jumps) { | |
226 if (entry.isBreak()) action(entry.jumpInstruction, entry.locals); | |
227 } | |
228 } | |
229 | |
230 void forEachContinue(Function action) { | |
231 for (JumpHandlerEntry entry in jumps) { | |
232 if (entry.isContinue()) action(entry.jumpInstruction, entry.locals); | |
233 } | |
234 } | |
235 | |
236 bool hasAnyContinue() { | |
237 for (JumpHandlerEntry entry in jumps) { | |
238 if (entry.isContinue()) return true; | |
239 } | |
240 return false; | |
241 } | |
242 | |
243 bool hasAnyBreak() { | |
244 for (JumpHandlerEntry entry in jumps) { | |
245 if (entry.isBreak()) return true; | |
246 } | |
247 return false; | |
248 } | |
249 | |
250 void close() { | |
251 // The mapping from TargetElement to JumpHandler is no longer needed. | |
252 builder.jumpTargets.remove(target); | |
253 } | |
254 | |
255 List<LabelDefinition> labels() { | |
256 List<LabelDefinition> result = null; | |
257 for (LabelDefinition element in target.labels) { | |
258 if (result == null) result = <LabelDefinition>[]; | |
259 result.add(element); | |
260 } | |
261 return (result == null) ? const <LabelDefinition>[] : result; | |
262 } | |
263 } | |
264 | |
265 /// Special [JumpHandler] implementation used to handle continue statements | |
266 /// targeting switch cases. | |
267 class SwitchCaseJumpHandler extends TargetJumpHandler { | |
268 /// Map from switch case targets to indices used to encode the flow of the | |
269 /// switch case loop. | |
270 final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); | |
271 | |
272 SwitchCaseJumpHandler( | |
273 SsaBuilder builder, JumpTarget target, ast.SwitchStatement node) | |
274 : super(builder, target) { | |
275 // The switch case indices must match those computed in | |
276 // [SsaFromAstMixin.buildSwitchCaseConstants]. | |
277 // Switch indices are 1-based so we can bypass the synthetic loop when no | |
278 // cases match simply by branching on the index (which defaults to null). | |
279 int switchIndex = 1; | |
280 for (ast.SwitchCase switchCase in node.cases) { | |
281 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | |
282 ast.Node label = labelOrCase.asLabel(); | |
283 if (label != null) { | |
284 LabelDefinition labelElement = | |
285 builder.elements.getLabelDefinition(label); | |
286 if (labelElement != null && labelElement.isContinueTarget) { | |
287 JumpTarget continueTarget = labelElement.target; | |
288 targetIndexMap[continueTarget] = switchIndex; | |
289 assert(builder.jumpTargets[continueTarget] == null); | |
290 builder.jumpTargets[continueTarget] = this; | |
291 } | |
292 } | |
293 } | |
294 switchIndex++; | |
295 } | |
296 } | |
297 | |
298 void generateBreak([LabelDefinition label]) { | |
299 if (label == null) { | |
300 // Creates a special break instruction for the synthetic loop generated | |
301 // for a switch statement with continue statements. See | |
302 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. | |
303 | |
304 HInstruction breakInstruction = | |
305 new HBreak(target, breakSwitchContinueLoop: true); | |
306 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
307 builder.close(breakInstruction); | |
308 jumps.add(new JumpHandlerEntry(breakInstruction, locals)); | |
309 } else { | |
310 super.generateBreak(label); | |
311 } | |
312 } | |
313 | |
314 bool isContinueToSwitchCase(LabelDefinition label) { | |
315 return label != null && targetIndexMap.containsKey(label.target); | |
316 } | |
317 | |
318 void generateContinue([LabelDefinition label]) { | |
319 if (isContinueToSwitchCase(label)) { | |
320 // Creates the special instructions 'label = i; continue l;' used in | |
321 // switch statements with continue statements. See | |
322 // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. | |
323 | |
324 assert(label != null); | |
325 HInstruction value = builder.graph | |
326 .addConstantInt(targetIndexMap[label.target], builder.compiler); | |
327 builder.localsHandler.updateLocal(target, value); | |
328 | |
329 assert(label.target.labels.contains(label)); | |
330 HInstruction continueInstruction = new HContinue(target); | |
331 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
332 builder.close(continueInstruction); | |
333 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | |
334 } else { | |
335 super.generateContinue(label); | |
336 } | |
337 } | |
338 | |
339 void close() { | |
340 // The mapping from TargetElement to JumpHandler is no longer needed. | |
341 for (JumpTarget target in targetIndexMap.keys) { | |
342 builder.jumpTargets.remove(target); | |
343 } | |
344 super.close(); | |
345 } | |
346 } | |
347 | |
348 /** | 130 /** |
349 * This class builds SSA nodes for functions represented in AST. | 131 * This class builds SSA nodes for functions represented in AST. |
350 */ | 132 */ |
351 class SsaBuilder extends ast.Visitor | 133 class SsaBuilder extends ast.Visitor |
352 with | 134 with |
353 BaseImplementationOfCompoundsMixin, | 135 BaseImplementationOfCompoundsMixin, |
354 BaseImplementationOfSetIfNullsMixin, | 136 BaseImplementationOfSetIfNullsMixin, |
355 BaseImplementationOfSuperIndexSetIfNullMixin, | 137 BaseImplementationOfSuperIndexSetIfNullMixin, |
356 SemanticSendResolvedMixin, | 138 SemanticSendResolvedMixin, |
357 NewBulkMixin, | 139 NewBulkMixin, |
(...skipping 11 matching lines...) Expand all Loading... |
369 | 151 |
370 /// Registry used to enqueue work during codegen, may be null to avoid | 152 /// Registry used to enqueue work during codegen, may be null to avoid |
371 /// enqueing any work. | 153 /// enqueing any work. |
372 // TODO(sigmund,johnniwinther): get rid of registry entirely. We should be | 154 // TODO(sigmund,johnniwinther): get rid of registry entirely. We should be |
373 // able to return the impact as a result after building and avoid enqueing | 155 // able to return the impact as a result after building and avoid enqueing |
374 // things here. Later the codegen task can decide whether to enqueue | 156 // things here. Later the codegen task can decide whether to enqueue |
375 // something. In the past this didn't matter as much because the SSA graph was | 157 // something. In the past this didn't matter as much because the SSA graph was |
376 // used only for codegen, but currently we want to experiment using it for | 158 // used only for codegen, but currently we want to experiment using it for |
377 // code-analysis too. | 159 // code-analysis too. |
378 final CodegenRegistry registry; | 160 final CodegenRegistry registry; |
379 final Compiler compiler; | |
380 final GlobalTypeInferenceResults inferenceResults; | 161 final GlobalTypeInferenceResults inferenceResults; |
381 final JavaScriptBackend backend; | 162 final JavaScriptBackend backend; |
382 final ConstantSystem constantSystem; | 163 final ConstantSystem constantSystem; |
383 final RuntimeTypes rti; | 164 final RuntimeTypes rti; |
384 | 165 |
385 SourceInformationBuilder sourceInformationBuilder; | 166 SourceInformationBuilder sourceInformationBuilder; |
386 | 167 |
387 bool inLazyInitializerExpression = false; | 168 bool inLazyInitializerExpression = false; |
388 | 169 |
389 // TODO(sigmund): make all comments /// instead of /* */ | 170 // TODO(sigmund): make all comments /// instead of /* */ |
390 /* This field is used by the native handler. */ | 171 /* This field is used by the native handler. */ |
391 final NativeEmitter nativeEmitter; | 172 final NativeEmitter nativeEmitter; |
392 | 173 |
393 /** | 174 /** |
394 * True if we are visiting the expression of a throw statement; we assume this | 175 * True if we are visiting the expression of a throw statement; we assume this |
395 * is a slow path. | 176 * is a slow path. |
396 */ | 177 */ |
397 bool inExpressionOfThrow = false; | 178 bool inExpressionOfThrow = false; |
398 | 179 |
399 /** | 180 /** |
400 * The loop nesting is consulted when inlining a function invocation in | |
401 * [tryInlineMethod]. The inlining heuristics take this information into | |
402 * account. | |
403 */ | |
404 int loopNesting = 0; | |
405 | |
406 /** | |
407 * This stack contains declaration elements of the functions being built | 181 * This stack contains declaration elements of the functions being built |
408 * or inlined by this builder. | 182 * or inlined by this builder. |
409 */ | 183 */ |
410 final List<Element> sourceElementStack = <Element>[]; | 184 final List<Element> sourceElementStack = <Element>[]; |
411 | 185 |
412 HInstruction rethrowableException; | 186 HInstruction rethrowableException; |
413 | 187 |
414 Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; | |
415 | |
416 /// Returns `true` if the current element is an `async` function. | 188 /// Returns `true` if the current element is an `async` function. |
417 bool get isBuildingAsyncFunction { | 189 bool get isBuildingAsyncFunction { |
418 Element element = sourceElement; | 190 Element element = sourceElement; |
419 return (element is FunctionElement && | 191 return (element is FunctionElement && |
420 element.asyncMarker == AsyncMarker.ASYNC); | 192 element.asyncMarker == AsyncMarker.ASYNC); |
421 } | 193 } |
422 | 194 |
| 195 /// Handles the building of loops. |
| 196 LoopHandler<ast.Node> loopHandler; |
| 197 |
423 // TODO(sigmund): make most args optional | 198 // TODO(sigmund): make most args optional |
424 SsaBuilder( | 199 SsaBuilder( |
425 this.target, | 200 this.target, |
426 this.resolvedAst, | 201 this.resolvedAst, |
427 this.registry, | 202 this.registry, |
428 JavaScriptBackend backend, | 203 JavaScriptBackend backend, |
429 this.nativeEmitter, | 204 this.nativeEmitter, |
430 SourceInformationStrategy sourceInformationFactory) | 205 SourceInformationStrategy sourceInformationFactory) |
431 : this.compiler = backend.compiler, | 206 : this.infoReporter = backend.compiler.dumpInfoTask, |
432 this.infoReporter = backend.compiler.dumpInfoTask, | |
433 this.backend = backend, | 207 this.backend = backend, |
434 this.constantSystem = backend.constantSystem, | 208 this.constantSystem = backend.constantSystem, |
435 this.rti = backend.rti, | 209 this.rti = backend.rti, |
436 this.inferenceResults = backend.compiler.globalInference.results { | 210 this.inferenceResults = backend.compiler.globalInference.results { |
437 assert(target.isImplementation); | 211 assert(target.isImplementation); |
| 212 compiler = backend.compiler; |
438 graph.element = target; | 213 graph.element = target; |
439 sourceElementStack.add(target); | 214 sourceElementStack.add(target); |
440 sourceInformationBuilder = | 215 sourceInformationBuilder = |
441 sourceInformationFactory.createBuilderForContext(resolvedAst); | 216 sourceInformationFactory.createBuilderForContext(resolvedAst); |
442 graph.sourceInformation = | 217 graph.sourceInformation = |
443 sourceInformationBuilder.buildVariableDeclaration(); | 218 sourceInformationBuilder.buildVariableDeclaration(); |
444 localsHandler = new LocalsHandler(this, target, null, compiler); | 219 localsHandler = new LocalsHandler(this, target, null, compiler); |
| 220 loopHandler = new SsaLoopHandler(this); |
445 } | 221 } |
446 | 222 |
447 BackendHelpers get helpers => backend.helpers; | 223 BackendHelpers get helpers => backend.helpers; |
448 | 224 |
449 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; | 225 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; |
450 | 226 |
451 DiagnosticReporter get reporter => compiler.reporter; | 227 DiagnosticReporter get reporter => compiler.reporter; |
452 | 228 |
453 CoreClasses get coreClasses => compiler.coreClasses; | 229 CoreClasses get coreClasses => compiler.coreClasses; |
454 | 230 |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 return false; | 401 return false; |
626 } | 402 } |
627 | 403 |
628 // Ensure that [element] is an implementation element. | 404 // Ensure that [element] is an implementation element. |
629 element = element.implementation; | 405 element = element.implementation; |
630 | 406 |
631 if (compiler.elementHasCompileTimeError(element)) return false; | 407 if (compiler.elementHasCompileTimeError(element)) return false; |
632 | 408 |
633 FunctionElement function = element; | 409 FunctionElement function = element; |
634 ResolvedAst functionResolvedAst = function.resolvedAst; | 410 ResolvedAst functionResolvedAst = function.resolvedAst; |
635 bool insideLoop = loopNesting > 0 || graph.calledInLoop; | 411 bool insideLoop = loopDepth > 0 || graph.calledInLoop; |
636 | 412 |
637 // Bail out early if the inlining decision is in the cache and we can't | 413 // Bail out early if the inlining decision is in the cache and we can't |
638 // inline (no need to check the hard constraints). | 414 // inline (no need to check the hard constraints). |
639 bool cachedCanBeInlined = | 415 bool cachedCanBeInlined = |
640 backend.inlineCache.canInline(function, insideLoop: insideLoop); | 416 backend.inlineCache.canInline(function, insideLoop: insideLoop); |
641 if (cachedCanBeInlined == false) return false; | 417 if (cachedCanBeInlined == false) return false; |
642 | 418 |
643 bool meetsHardConstraints() { | 419 bool meetsHardConstraints() { |
644 if (compiler.options.disableInlining) return false; | 420 if (compiler.options.disableInlining) return false; |
645 | 421 |
(...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1946 visitThrowExpression(throwExpression.expression); | 1722 visitThrowExpression(throwExpression.expression); |
1947 handleInTryStatement(); | 1723 handleInTryStatement(); |
1948 closeAndGotoExit( | 1724 closeAndGotoExit( |
1949 new HThrow(pop(), sourceInformationBuilder.buildThrow(node))); | 1725 new HThrow(pop(), sourceInformationBuilder.buildThrow(node))); |
1950 } else { | 1726 } else { |
1951 visit(node.expression); | 1727 visit(node.expression); |
1952 pop(); | 1728 pop(); |
1953 } | 1729 } |
1954 } | 1730 } |
1955 | 1731 |
1956 /** | |
1957 * Creates a new loop-header block. The previous [current] block | |
1958 * is closed with an [HGoto] and replaced by the newly created block. | |
1959 * Also notifies the locals handler that we're entering a loop. | |
1960 */ | |
1961 JumpHandler beginLoopHeader(ast.Node node) { | |
1962 assert(!isAborted()); | |
1963 HBasicBlock previousBlock = close(new HGoto()); | |
1964 | |
1965 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); | |
1966 HBasicBlock loopEntry = | |
1967 graph.addNewLoopHeaderBlock(jumpHandler.target, jumpHandler.labels()); | |
1968 previousBlock.addSuccessor(loopEntry); | |
1969 open(loopEntry); | |
1970 | |
1971 localsHandler.beginLoopHeader(loopEntry); | |
1972 return jumpHandler; | |
1973 } | |
1974 | |
1975 /** | |
1976 * Ends the loop: | |
1977 * - creates a new block and adds it as successor to the [branchExitBlock] and | |
1978 * any blocks that end in break. | |
1979 * - opens the new block (setting as [current]). | |
1980 * - notifies the locals handler that we're exiting a loop. | |
1981 * [savedLocals] are the locals from the end of the loop condition. | |
1982 * [branchExitBlock] is the exit (branching) block of the condition. Generally | |
1983 * this is not the top of the loop, since this would lead to critical edges. | |
1984 * It is null for degenerate do-while loops that have | |
1985 * no back edge because they abort (throw/return/break in the body and have | |
1986 * no continues). | |
1987 */ | |
1988 void endLoop(HBasicBlock loopEntry, HBasicBlock branchExitBlock, | |
1989 JumpHandler jumpHandler, LocalsHandler savedLocals) { | |
1990 HBasicBlock loopExitBlock = addNewBlock(); | |
1991 | |
1992 List<LocalsHandler> breakHandlers = <LocalsHandler>[]; | |
1993 // Collect data for the successors and the phis at each break. | |
1994 jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { | |
1995 breakInstruction.block.addSuccessor(loopExitBlock); | |
1996 breakHandlers.add(locals); | |
1997 }); | |
1998 | |
1999 // The exit block is a successor of the loop condition if it is reached. | |
2000 // We don't add the successor in the case of a while/for loop that aborts | |
2001 // because the caller of endLoop will be wiring up a special empty else | |
2002 // block instead. | |
2003 if (branchExitBlock != null) { | |
2004 branchExitBlock.addSuccessor(loopExitBlock); | |
2005 } | |
2006 // Update the phis at the loop entry with the current values of locals. | |
2007 localsHandler.endLoop(loopEntry); | |
2008 | |
2009 // Start generating code for the exit block. | |
2010 open(loopExitBlock); | |
2011 | |
2012 // Create a new localsHandler for the loopExitBlock with the correct phis. | |
2013 if (!breakHandlers.isEmpty) { | |
2014 if (branchExitBlock != null) { | |
2015 // Add the values of the locals at the end of the condition block to | |
2016 // the phis. These are the values that flow to the exit if the | |
2017 // condition fails. | |
2018 breakHandlers.add(savedLocals); | |
2019 } | |
2020 localsHandler = savedLocals.mergeMultiple(breakHandlers, loopExitBlock); | |
2021 } else { | |
2022 localsHandler = savedLocals; | |
2023 } | |
2024 } | |
2025 | |
2026 HSubGraphBlockInformation wrapStatementGraph(SubGraph statements) { | |
2027 if (statements == null) return null; | |
2028 return new HSubGraphBlockInformation(statements); | |
2029 } | |
2030 | |
2031 HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { | |
2032 if (expression == null) return null; | |
2033 return new HSubExpressionBlockInformation(expression); | |
2034 } | |
2035 | |
2036 // For while loops, initializer and update are null. | |
2037 // The condition function must return a boolean result. | |
2038 // None of the functions must leave anything on the stack. | |
2039 void handleLoop(ast.Node loop, void initialize(), HInstruction condition(), | |
2040 void update(), void body()) { | |
2041 // Generate: | |
2042 // <initializer> | |
2043 // loop-entry: | |
2044 // if (!<condition>) goto loop-exit; | |
2045 // <body> | |
2046 // <updates> | |
2047 // goto loop-entry; | |
2048 // loop-exit: | |
2049 | |
2050 localsHandler.startLoop(loop); | |
2051 | |
2052 // The initializer. | |
2053 SubExpression initializerGraph = null; | |
2054 HBasicBlock startBlock; | |
2055 if (initialize != null) { | |
2056 HBasicBlock initializerBlock = openNewBlock(); | |
2057 startBlock = initializerBlock; | |
2058 initialize(); | |
2059 assert(!isAborted()); | |
2060 initializerGraph = new SubExpression(initializerBlock, current); | |
2061 } | |
2062 | |
2063 loopNesting++; | |
2064 JumpHandler jumpHandler = beginLoopHeader(loop); | |
2065 HLoopInformation loopInfo = current.loopInformation; | |
2066 HBasicBlock conditionBlock = current; | |
2067 if (startBlock == null) startBlock = conditionBlock; | |
2068 | |
2069 HInstruction conditionInstruction = condition(); | |
2070 HBasicBlock conditionEndBlock = | |
2071 close(new HLoopBranch(conditionInstruction)); | |
2072 SubExpression conditionExpression = | |
2073 new SubExpression(conditionBlock, conditionEndBlock); | |
2074 | |
2075 // Save the values of the local variables at the end of the condition | |
2076 // block. These are the values that will flow to the loop exit if the | |
2077 // condition fails. | |
2078 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | |
2079 | |
2080 // The body. | |
2081 HBasicBlock beginBodyBlock = addNewBlock(); | |
2082 conditionEndBlock.addSuccessor(beginBodyBlock); | |
2083 open(beginBodyBlock); | |
2084 | |
2085 localsHandler.enterLoopBody(loop); | |
2086 body(); | |
2087 | |
2088 SubGraph bodyGraph = new SubGraph(beginBodyBlock, lastOpenedBlock); | |
2089 HBasicBlock bodyBlock = current; | |
2090 if (current != null) close(new HGoto()); | |
2091 | |
2092 SubExpression updateGraph; | |
2093 | |
2094 bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null; | |
2095 if (!loopIsDegenerate) { | |
2096 // Update. | |
2097 // We create an update block, even when we are in a while loop. There the | |
2098 // update block is the jump-target for continue statements. We could avoid | |
2099 // the creation if there is no continue, but for now we always create it. | |
2100 HBasicBlock updateBlock = addNewBlock(); | |
2101 | |
2102 List<LocalsHandler> continueHandlers = <LocalsHandler>[]; | |
2103 jumpHandler | |
2104 .forEachContinue((HContinue instruction, LocalsHandler locals) { | |
2105 instruction.block.addSuccessor(updateBlock); | |
2106 continueHandlers.add(locals); | |
2107 }); | |
2108 | |
2109 if (bodyBlock != null) { | |
2110 continueHandlers.add(localsHandler); | |
2111 bodyBlock.addSuccessor(updateBlock); | |
2112 } | |
2113 | |
2114 open(updateBlock); | |
2115 localsHandler = | |
2116 continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); | |
2117 | |
2118 List<LabelDefinition> labels = jumpHandler.labels(); | |
2119 JumpTarget target = elements.getTargetDefinition(loop); | |
2120 if (!labels.isEmpty) { | |
2121 beginBodyBlock.setBlockFlow( | |
2122 new HLabeledBlockInformation( | |
2123 new HSubGraphBlockInformation(bodyGraph), jumpHandler.labels(), | |
2124 isContinue: true), | |
2125 updateBlock); | |
2126 } else if (target != null && target.isContinueTarget) { | |
2127 beginBodyBlock.setBlockFlow( | |
2128 new HLabeledBlockInformation.implicit( | |
2129 new HSubGraphBlockInformation(bodyGraph), target, | |
2130 isContinue: true), | |
2131 updateBlock); | |
2132 } | |
2133 | |
2134 localsHandler.enterLoopUpdates(loop); | |
2135 | |
2136 update(); | |
2137 | |
2138 HBasicBlock updateEndBlock = close(new HGoto()); | |
2139 // The back-edge completing the cycle. | |
2140 updateEndBlock.addSuccessor(conditionBlock); | |
2141 updateGraph = new SubExpression(updateBlock, updateEndBlock); | |
2142 | |
2143 // Avoid a critical edge from the condition to the loop-exit body. | |
2144 HBasicBlock conditionExitBlock = addNewBlock(); | |
2145 open(conditionExitBlock); | |
2146 close(new HGoto()); | |
2147 conditionEndBlock.addSuccessor(conditionExitBlock); | |
2148 | |
2149 endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); | |
2150 | |
2151 conditionBlock.postProcessLoopHeader(); | |
2152 HLoopBlockInformation info = new HLoopBlockInformation( | |
2153 _loopKind(loop), | |
2154 wrapExpressionGraph(initializerGraph), | |
2155 wrapExpressionGraph(conditionExpression), | |
2156 wrapStatementGraph(bodyGraph), | |
2157 wrapExpressionGraph(updateGraph), | |
2158 conditionBlock.loopInformation.target, | |
2159 conditionBlock.loopInformation.labels, | |
2160 sourceInformationBuilder.buildLoop(loop)); | |
2161 | |
2162 startBlock.setBlockFlow(info, current); | |
2163 loopInfo.loopBlockInformation = info; | |
2164 } else { | |
2165 // The body of the for/while loop always aborts, so there is no back edge. | |
2166 // We turn the code into: | |
2167 // if (condition) { | |
2168 // body; | |
2169 // } else { | |
2170 // // We always create an empty else block to avoid critical edges. | |
2171 // } | |
2172 // | |
2173 // If there is any break in the body, we attach a synthetic | |
2174 // label to the if. | |
2175 HBasicBlock elseBlock = addNewBlock(); | |
2176 open(elseBlock); | |
2177 close(new HGoto()); | |
2178 // Pass the elseBlock as the branchBlock, because that's the block we go | |
2179 // to just before leaving the 'loop'. | |
2180 endLoop(conditionBlock, elseBlock, jumpHandler, savedLocals); | |
2181 | |
2182 SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); | |
2183 // Remove the loop information attached to the header. | |
2184 conditionBlock.loopInformation = null; | |
2185 | |
2186 // Remove the [HLoopBranch] instruction and replace it with | |
2187 // [HIf]. | |
2188 HInstruction condition = conditionEndBlock.last.inputs[0]; | |
2189 conditionEndBlock.addAtExit(new HIf(condition)); | |
2190 conditionEndBlock.addSuccessor(elseBlock); | |
2191 conditionEndBlock.remove(conditionEndBlock.last); | |
2192 HIfBlockInformation info = new HIfBlockInformation( | |
2193 wrapExpressionGraph(conditionExpression), | |
2194 wrapStatementGraph(bodyGraph), | |
2195 wrapStatementGraph(elseGraph)); | |
2196 | |
2197 conditionEndBlock.setBlockFlow(info, current); | |
2198 HIf ifBlock = conditionEndBlock.last; | |
2199 ifBlock.blockInformation = conditionEndBlock.blockFlow; | |
2200 | |
2201 // If the body has any break, attach a synthesized label to the | |
2202 // if block. | |
2203 if (jumpHandler.hasAnyBreak()) { | |
2204 JumpTarget target = elements.getTargetDefinition(loop); | |
2205 LabelDefinition label = target.addLabel(null, 'loop'); | |
2206 label.setBreakTarget(); | |
2207 SubGraph labelGraph = new SubGraph(conditionBlock, current); | |
2208 HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( | |
2209 new HSubGraphBlockInformation(labelGraph), | |
2210 <LabelDefinition>[label]); | |
2211 | |
2212 conditionBlock.setBlockFlow(labelInfo, current); | |
2213 | |
2214 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | |
2215 HBasicBlock block = breakInstruction.block; | |
2216 block.addAtExit(new HBreak.toLabel(label)); | |
2217 block.remove(breakInstruction); | |
2218 }); | |
2219 } | |
2220 } | |
2221 jumpHandler.close(); | |
2222 loopNesting--; | |
2223 } | |
2224 | |
2225 visitFor(ast.For node) { | 1732 visitFor(ast.For node) { |
2226 assert(isReachable); | 1733 assert(isReachable); |
2227 assert(node.body != null); | 1734 assert(node.body != null); |
2228 void buildInitializer() { | 1735 void buildInitializer() { |
2229 ast.Node initializer = node.initializer; | 1736 ast.Node initializer = node.initializer; |
2230 if (initializer == null) return; | 1737 if (initializer == null) return; |
2231 visit(initializer); | 1738 visit(initializer); |
2232 if (initializer.asExpression() != null) { | 1739 if (initializer.asExpression() != null) { |
2233 pop(); | 1740 pop(); |
2234 } | 1741 } |
(...skipping 14 matching lines...) Expand all Loading... |
2249 // The result of the update instruction isn't used, and can just | 1756 // The result of the update instruction isn't used, and can just |
2250 // be dropped. | 1757 // be dropped. |
2251 pop(); | 1758 pop(); |
2252 } | 1759 } |
2253 } | 1760 } |
2254 | 1761 |
2255 void buildBody() { | 1762 void buildBody() { |
2256 visit(node.body); | 1763 visit(node.body); |
2257 } | 1764 } |
2258 | 1765 |
2259 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 1766 loopHandler.handleLoop( |
| 1767 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
2260 } | 1768 } |
2261 | 1769 |
2262 visitWhile(ast.While node) { | 1770 visitWhile(ast.While node) { |
2263 assert(isReachable); | 1771 assert(isReachable); |
2264 HInstruction buildCondition() { | 1772 HInstruction buildCondition() { |
2265 visit(node.condition); | 1773 visit(node.condition); |
2266 return popBoolified(); | 1774 return popBoolified(); |
2267 } | 1775 } |
2268 | 1776 |
2269 handleLoop(node, () {}, buildCondition, () {}, () { | 1777 loopHandler.handleLoop(node, () {}, buildCondition, () {}, () { |
2270 visit(node.body); | 1778 visit(node.body); |
2271 }); | 1779 }); |
2272 } | 1780 } |
2273 | 1781 |
2274 visitDoWhile(ast.DoWhile node) { | 1782 visitDoWhile(ast.DoWhile node) { |
2275 assert(isReachable); | 1783 assert(isReachable); |
2276 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 1784 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
2277 localsHandler.startLoop(node); | 1785 localsHandler.startLoop(node); |
2278 loopNesting++; | 1786 loopDepth++; |
2279 JumpHandler jumpHandler = beginLoopHeader(node); | 1787 JumpHandler jumpHandler = loopHandler.beginLoopHeader(node); |
2280 HLoopInformation loopInfo = current.loopInformation; | 1788 HLoopInformation loopInfo = current.loopInformation; |
2281 HBasicBlock loopEntryBlock = current; | 1789 HBasicBlock loopEntryBlock = current; |
2282 HBasicBlock bodyEntryBlock = current; | 1790 HBasicBlock bodyEntryBlock = current; |
2283 JumpTarget target = elements.getTargetDefinition(node); | 1791 JumpTarget target = elements.getTargetDefinition(node); |
2284 bool hasContinues = target != null && target.isContinueTarget; | 1792 bool hasContinues = target != null && target.isContinueTarget; |
2285 if (hasContinues) { | 1793 if (hasContinues) { |
2286 // Add extra block to hang labels on. | 1794 // Add extra block to hang labels on. |
2287 // It doesn't currently work if they are on the same block as the | 1795 // It doesn't currently work if they are on the same block as the |
2288 // HLoopInfo. The handling of HLabeledBlockInformation will visit a | 1796 // HLoopInfo. The handling of HLabeledBlockInformation will visit a |
2289 // SubGraph that starts at the same block again, so the HLoopInfo is | 1797 // SubGraph that starts at the same block again, so the HLoopInfo is |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2356 | 1864 |
2357 conditionExpression = | 1865 conditionExpression = |
2358 new SubExpression(conditionBlock, conditionEndBlock); | 1866 new SubExpression(conditionBlock, conditionEndBlock); |
2359 | 1867 |
2360 // Avoid a critical edge from the condition to the loop-exit body. | 1868 // Avoid a critical edge from the condition to the loop-exit body. |
2361 HBasicBlock conditionExitBlock = addNewBlock(); | 1869 HBasicBlock conditionExitBlock = addNewBlock(); |
2362 open(conditionExitBlock); | 1870 open(conditionExitBlock); |
2363 close(new HGoto()); | 1871 close(new HGoto()); |
2364 conditionEndBlock.addSuccessor(conditionExitBlock); | 1872 conditionEndBlock.addSuccessor(conditionExitBlock); |
2365 | 1873 |
2366 endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); | 1874 loopHandler.endLoop( |
| 1875 loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); |
2367 | 1876 |
2368 loopEntryBlock.postProcessLoopHeader(); | 1877 loopEntryBlock.postProcessLoopHeader(); |
2369 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); | 1878 SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); |
2370 HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation( | 1879 HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation( |
2371 HLoopBlockInformation.DO_WHILE_LOOP, | 1880 HLoopBlockInformation.DO_WHILE_LOOP, |
2372 null, | 1881 null, |
2373 wrapExpressionGraph(conditionExpression), | 1882 wrapExpressionGraph(conditionExpression), |
2374 wrapStatementGraph(bodyGraph), | 1883 wrapStatementGraph(bodyGraph), |
2375 null, | 1884 null, |
2376 loopEntryBlock.loopInformation.target, | 1885 loopEntryBlock.loopInformation.target, |
2377 loopEntryBlock.loopInformation.labels, | 1886 loopEntryBlock.loopInformation.labels, |
2378 sourceInformationBuilder.buildLoop(node)); | 1887 sourceInformationBuilder.buildLoop(node)); |
2379 loopEntryBlock.setBlockFlow(loopBlockInfo, current); | 1888 loopEntryBlock.setBlockFlow(loopBlockInfo, current); |
2380 loopInfo.loopBlockInformation = loopBlockInfo; | 1889 loopInfo.loopBlockInformation = loopBlockInfo; |
2381 } else { | 1890 } else { |
2382 // Since the loop has no back edge, we remove the loop information on the | 1891 // Since the loop has no back edge, we remove the loop information on the |
2383 // header. | 1892 // header. |
2384 loopEntryBlock.loopInformation = null; | 1893 loopEntryBlock.loopInformation = null; |
2385 | 1894 |
2386 if (jumpHandler.hasAnyBreak()) { | 1895 if (jumpHandler.hasAnyBreak()) { |
2387 // Null branchBlock because the body of the do-while loop always aborts, | 1896 // Null branchBlock because the body of the do-while loop always aborts, |
2388 // so we never get to the condition. | 1897 // so we never get to the condition. |
2389 endLoop(loopEntryBlock, null, jumpHandler, localsHandler); | 1898 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); |
2390 | 1899 |
2391 // Since the body of the loop has a break, we attach a synthesized label | 1900 // Since the body of the loop has a break, we attach a synthesized label |
2392 // to the body. | 1901 // to the body. |
2393 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); | 1902 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); |
2394 JumpTarget target = elements.getTargetDefinition(node); | 1903 JumpTarget target = elements.getTargetDefinition(node); |
2395 LabelDefinition label = target.addLabel(null, 'loop'); | 1904 LabelDefinition label = target.addLabel(null, 'loop'); |
2396 label.setBreakTarget(); | 1905 label.setBreakTarget(); |
2397 HLabeledBlockInformation info = new HLabeledBlockInformation( | 1906 HLabeledBlockInformation info = new HLabeledBlockInformation( |
2398 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); | 1907 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); |
2399 loopEntryBlock.setBlockFlow(info, current); | 1908 loopEntryBlock.setBlockFlow(info, current); |
2400 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | 1909 jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
2401 HBasicBlock block = breakInstruction.block; | 1910 HBasicBlock block = breakInstruction.block; |
2402 block.addAtExit(new HBreak.toLabel(label)); | 1911 block.addAtExit(new HBreak.toLabel(label)); |
2403 block.remove(breakInstruction); | 1912 block.remove(breakInstruction); |
2404 }); | 1913 }); |
2405 } | 1914 } |
2406 } | 1915 } |
2407 jumpHandler.close(); | 1916 jumpHandler.close(); |
2408 loopNesting--; | 1917 loopDepth--; |
2409 } | 1918 } |
2410 | 1919 |
2411 visitFunctionExpression(ast.FunctionExpression node) { | 1920 visitFunctionExpression(ast.FunctionExpression node) { |
2412 ClosureClassMap nestedClosureData = | 1921 ClosureClassMap nestedClosureData = |
2413 compiler.closureToClassMapper.getMappingForNestedFunction(node); | 1922 compiler.closureToClassMapper.getMappingForNestedFunction(node); |
2414 assert(nestedClosureData != null); | 1923 assert(nestedClosureData != null); |
2415 assert(nestedClosureData.closureClassElement != null); | 1924 assert(nestedClosureData.closureClassElement != null); |
2416 ClosureClassElement closureClassElement = | 1925 ClosureClassElement closureClassElement = |
2417 nestedClosureData.closureClassElement; | 1926 nestedClosureData.closureClassElement; |
2418 FunctionElement callElement = nestedClosureData.callElement; | 1927 FunctionElement callElement = nestedClosureData.callElement; |
(...skipping 3630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6049 handler.generateContinue(label); | 5558 handler.generateContinue(label); |
6050 } | 5559 } |
6051 } | 5560 } |
6052 | 5561 |
6053 /** | 5562 /** |
6054 * Creates a [JumpHandler] for a statement. The node must be a jump | 5563 * Creates a [JumpHandler] for a statement. The node must be a jump |
6055 * target. If there are no breaks or continues targeting the statement, | 5564 * target. If there are no breaks or continues targeting the statement, |
6056 * a special "null handler" is returned. | 5565 * a special "null handler" is returned. |
6057 * | 5566 * |
6058 * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used | 5567 * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used |
6059 * to distinguish the synthetized loop created for a switch statement with | 5568 * to distinguish the synthesized loop created for a switch statement with |
6060 * continue statements from simple switch statements. | 5569 * continue statements from simple switch statements. |
6061 */ | 5570 */ |
6062 JumpHandler createJumpHandler(ast.Statement node, {bool isLoopJump}) { | 5571 JumpHandler createJumpHandler(ast.Statement node, {bool isLoopJump}) { |
6063 JumpTarget element = elements.getTargetDefinition(node); | 5572 JumpTarget element = elements.getTargetDefinition(node); |
6064 if (element == null || !identical(element.statement, node)) { | 5573 if (element == null || !identical(element.statement, node)) { |
6065 // No breaks or continues to this node. | 5574 // No breaks or continues to this node. |
6066 return new NullJumpHandler(reporter); | 5575 return new NullJumpHandler(reporter); |
6067 } | 5576 } |
6068 if (isLoopJump && node is ast.SwitchStatement) { | 5577 if (isLoopJump && node is ast.SwitchStatement) { |
6069 // Create a special jump handler for loops created for switch statements | 5578 // Create a special jump handler for loops created for switch statements |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6118 generateNonInstanceSetter(null, variable, value, location: identifier); | 5627 generateNonInstanceSetter(null, variable, value, location: identifier); |
6119 } | 5628 } |
6120 pop(); // Pop the value pushed by the setter call. | 5629 pop(); // Pop the value pushed by the setter call. |
6121 | 5630 |
6122 visit(node.body); | 5631 visit(node.body); |
6123 } | 5632 } |
6124 | 5633 |
6125 void buildUpdate() {} | 5634 void buildUpdate() {} |
6126 | 5635 |
6127 buildProtectedByFinally(() { | 5636 buildProtectedByFinally(() { |
6128 handleLoop( | 5637 loopHandler.handleLoop( |
6129 node, buildInitializer, buildCondition, buildUpdate, buildBody); | 5638 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
6130 }, () { | 5639 }, () { |
6131 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); | 5640 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
6132 push(new HAwait( | 5641 push(new HAwait( |
6133 pop(), | 5642 pop(), |
6134 new TypeMask.subclass( | 5643 new TypeMask.subclass( |
6135 coreClasses.objectClass, compiler.closedWorld))); | 5644 coreClasses.objectClass, compiler.closedWorld))); |
6136 pop(); | 5645 pop(); |
6137 }); | 5646 }); |
6138 } | 5647 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6188 } | 5697 } |
6189 | 5698 |
6190 void buildBody() { | 5699 void buildBody() { |
6191 Selector call = Selectors.current; | 5700 Selector call = Selectors.current; |
6192 TypeMask mask = inferenceResults.typeOfIteratorCurrent(node, elements); | 5701 TypeMask mask = inferenceResults.typeOfIteratorCurrent(node, elements); |
6193 pushInvokeDynamic(node, call, mask, [iterator]); | 5702 pushInvokeDynamic(node, call, mask, [iterator]); |
6194 buildAssignLoopVariable(node, pop()); | 5703 buildAssignLoopVariable(node, pop()); |
6195 visit(node.body); | 5704 visit(node.body); |
6196 } | 5705 } |
6197 | 5706 |
6198 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); | 5707 loopHandler.handleLoop( |
| 5708 node, buildInitializer, buildCondition, () {}, buildBody); |
6199 } | 5709 } |
6200 | 5710 |
6201 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 5711 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
6202 ast.Node identifier = node.declaredIdentifier; | 5712 ast.Node identifier = node.declaredIdentifier; |
6203 Element variable = elements.getForInVariable(node); | 5713 Element variable = elements.getForInVariable(node); |
6204 Selector selector = elements.getSelector(identifier); | 5714 Selector selector = elements.getSelector(identifier); |
6205 | 5715 |
6206 if (identifier.asSend() != null && | 5716 if (identifier.asSend() != null && |
6207 Elements.isInstanceSend(identifier, elements)) { | 5717 Elements.isInstanceSend(identifier, elements)) { |
6208 TypeMask mask = inferenceResults.typeOfSend(identifier, elements); | 5718 TypeMask mask = inferenceResults.typeOfSend(identifier, elements); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6307 // but the code is horrible as `i+1` is carried around the loop in an | 5817 // but the code is horrible as `i+1` is carried around the loop in an |
6308 // additional variable. | 5818 // additional variable. |
6309 HInstruction index = localsHandler.readLocal(indexVariable); | 5819 HInstruction index = localsHandler.readLocal(indexVariable); |
6310 HInstruction one = graph.addConstantInt(1, compiler); | 5820 HInstruction one = graph.addConstantInt(1, compiler); |
6311 HInstruction addInstruction = | 5821 HInstruction addInstruction = |
6312 new HAdd(index, one, null, backend.positiveIntType); | 5822 new HAdd(index, one, null, backend.positiveIntType); |
6313 add(addInstruction); | 5823 add(addInstruction); |
6314 localsHandler.updateLocal(indexVariable, addInstruction); | 5824 localsHandler.updateLocal(indexVariable, addInstruction); |
6315 } | 5825 } |
6316 | 5826 |
6317 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 5827 loopHandler.handleLoop( |
| 5828 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
6318 } | 5829 } |
6319 | 5830 |
6320 visitLabel(ast.Label node) { | 5831 visitLabel(ast.Label node) { |
6321 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); | 5832 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); |
6322 } | 5833 } |
6323 | 5834 |
6324 visitLabeledStatement(ast.LabeledStatement node) { | 5835 visitLabeledStatement(ast.LabeledStatement node) { |
6325 ast.Statement body = node.statement; | 5836 ast.Statement body = node.statement; |
6326 if (body is ast.Loop || | 5837 if (body is ast.Loop || |
6327 body is ast.SwitchStatement || | 5838 body is ast.SwitchStatement || |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6651 node, | 6162 node, |
6652 new NullJumpHandler(reporter), | 6163 new NullJumpHandler(reporter), |
6653 buildExpression, | 6164 buildExpression, |
6654 node.cases, | 6165 node.cases, |
6655 getConstants, | 6166 getConstants, |
6656 (_) => false, // No case is default. | 6167 (_) => false, // No case is default. |
6657 buildSwitchCase); | 6168 buildSwitchCase); |
6658 } | 6169 } |
6659 | 6170 |
6660 void buildLoop() { | 6171 void buildLoop() { |
6661 handleLoop(node, () {}, buildCondition, () {}, buildSwitch); | 6172 loopHandler.handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
6662 } | 6173 } |
6663 | 6174 |
6664 if (hasDefault) { | 6175 if (hasDefault) { |
6665 buildLoop(); | 6176 buildLoop(); |
6666 } else { | 6177 } else { |
6667 // If the switch statement has no default case, surround the loop with | 6178 // If the switch statement has no default case, surround the loop with |
6668 // a test of the target. | 6179 // a test of the target. |
6669 void buildCondition() { | 6180 void buildCondition() { |
6670 js.Template code = js.js.parseForeignJS('#'); | 6181 js.Template code = js.js.parseForeignJS('#'); |
6671 push(new HForeignCode( | 6182 push(new HForeignCode( |
(...skipping 881 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7553 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7064 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
7554 unaliased.accept(this, builder); | 7065 unaliased.accept(this, builder); |
7555 } | 7066 } |
7556 | 7067 |
7557 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7068 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
7558 JavaScriptBackend backend = builder.compiler.backend; | 7069 JavaScriptBackend backend = builder.compiler.backend; |
7559 ClassElement cls = backend.helpers.DynamicRuntimeType; | 7070 ClassElement cls = backend.helpers.DynamicRuntimeType; |
7560 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7071 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
7561 } | 7072 } |
7562 } | 7073 } |
7563 | |
7564 /// Determine what kind of loop [node] represents. The result is one of the | |
7565 /// kinds defined in [HLoopBlockInformation]. | |
7566 int _loopKind(ast.Node node) => node.accept(const _LoopTypeVisitor()); | |
7567 | |
7568 class _LoopTypeVisitor extends ast.Visitor { | |
7569 const _LoopTypeVisitor(); | |
7570 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | |
7571 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | |
7572 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | |
7573 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | |
7574 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | |
7575 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | |
7576 int visitSwitchStatement(ast.SwitchStatement node) => | |
7577 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | |
7578 } | |
OLD | NEW |