| 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 |