| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/codegen.dart' show CodegenRegistry; | 9 import '../common/codegen.dart' show CodegenRegistry; |
| 10 import '../common/names.dart'; | 10 import '../common/names.dart'; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 | 79 |
| 80 @override | 80 @override |
| 81 JavaScriptBackend get backend => compiler.backend; | 81 JavaScriptBackend get backend => compiler.backend; |
| 82 | 82 |
| 83 @override | 83 @override |
| 84 TreeElements get elements => astAdapter.elements; | 84 TreeElements get elements => astAdapter.elements; |
| 85 | 85 |
| 86 SourceInformationBuilder sourceInformationBuilder; | 86 SourceInformationBuilder sourceInformationBuilder; |
| 87 final KernelToElementMap _elementMap; | 87 final KernelToElementMap _elementMap; |
| 88 final KernelToTypeInferenceMap _typeInferenceMap; | 88 final KernelToTypeInferenceMap _typeInferenceMap; |
| 89 final KernelToLocalsMap _localsMap; | 89 final KernelToLocalsMap localsMap; |
| 90 LoopHandler<ir.Node> loopHandler; | 90 LoopHandler<ir.Node> loopHandler; |
| 91 TypeBuilder typeBuilder; | 91 TypeBuilder typeBuilder; |
| 92 | 92 |
| 93 final Map<ir.VariableDeclaration, HInstruction> letBindings = | 93 final Map<ir.VariableDeclaration, HInstruction> letBindings = |
| 94 <ir.VariableDeclaration, HInstruction>{}; | 94 <ir.VariableDeclaration, HInstruction>{}; |
| 95 | 95 |
| 96 /// True if we are visiting the expression of a throw statement; we assume | 96 /// True if we are visiting the expression of a throw statement; we assume |
| 97 /// this is a slow path. | 97 /// this is a slow path. |
| 98 bool _inExpressionOfThrow = false; | 98 bool _inExpressionOfThrow = false; |
| 99 | 99 |
| 100 KernelSsaBuilder( | 100 KernelSsaBuilder( |
| 101 this.targetElement, | 101 this.targetElement, |
| 102 ClassEntity contextClass, | 102 ClassEntity contextClass, |
| 103 this.target, | 103 this.target, |
| 104 this.compiler, | 104 this.compiler, |
| 105 this._elementMap, | 105 this._elementMap, |
| 106 this._typeInferenceMap, | 106 this._typeInferenceMap, |
| 107 this._localsMap, | 107 this.localsMap, |
| 108 this.closedWorld, | 108 this.closedWorld, |
| 109 this._worldBuilder, | 109 this._worldBuilder, |
| 110 this.registry, | 110 this.registry, |
| 111 this.closureToClassMapper, | 111 this.closureToClassMapper, |
| 112 // TODO(het): Should sourceInformationBuilder be in GraphBuilder? | 112 // TODO(het): Should sourceInformationBuilder be in GraphBuilder? |
| 113 this.sourceInformationBuilder, | 113 this.sourceInformationBuilder, |
| 114 this.functionNode, | 114 this.functionNode, |
| 115 {bool targetIsConstructorBody: false}) | 115 {bool targetIsConstructorBody: false}) |
| 116 : this._targetIsConstructorBody = targetIsConstructorBody { | 116 : this._targetIsConstructorBody = targetIsConstructorBody { |
| 117 this.loopHandler = new KernelLoopHandler(this); | 117 this.loopHandler = new KernelLoopHandler(this); |
| 118 typeBuilder = new TypeBuilder(this); | 118 typeBuilder = new TypeBuilder(this); |
| 119 graph.element = targetElement; | 119 graph.element = targetElement; |
| 120 graph.sourceInformation = | 120 graph.sourceInformation = |
| 121 sourceInformationBuilder.buildVariableDeclaration(); | 121 sourceInformationBuilder.buildVariableDeclaration(); |
| 122 this.localsHandler = new LocalsHandler(this, targetElement, targetElement, | 122 this.localsHandler = new LocalsHandler(this, targetElement, targetElement, |
| 123 contextClass, null, nativeData, interceptorData); | 123 contextClass, null, nativeData, interceptorData); |
| 124 _targetStack.add(targetElement); | 124 _targetStack.add(targetElement); |
| 125 } | 125 } |
| 126 | 126 |
| 127 @deprecated // Use [_elementMap] instead. | 127 @deprecated // Use [_elementMap] instead. |
| 128 KernelAstAdapter get astAdapter => _elementMap; | 128 KernelAstAdapter get astAdapter => _elementMap; |
| 129 | 129 |
| 130 CommonElements get _commonElements => _elementMap.commonElements; | 130 CommonElements get _commonElements => _elementMap.commonElements; |
| 131 | 131 |
| 132 HGraph build() { | 132 HGraph build() { |
| 133 return reporter.withCurrentElement(_localsMap.currentMember, () { | 133 return reporter.withCurrentElement(localsMap.currentMember, () { |
| 134 // TODO(het): no reason to do this here... | 134 // TODO(het): no reason to do this here... |
| 135 HInstruction.idCounter = 0; | 135 HInstruction.idCounter = 0; |
| 136 if (target is ir.Procedure) { | 136 if (target is ir.Procedure) { |
| 137 _targetFunction = (target as ir.Procedure).function; | 137 _targetFunction = (target as ir.Procedure).function; |
| 138 buildFunctionNode(_targetFunction); | 138 buildFunctionNode(_targetFunction); |
| 139 } else if (target is ir.Field) { | 139 } else if (target is ir.Field) { |
| 140 buildField(target); | 140 buildField(target); |
| 141 } else if (target is ir.Constructor) { | 141 } else if (target is ir.Constructor) { |
| 142 if (_targetIsConstructorBody) { | 142 if (_targetIsConstructorBody) { |
| 143 buildConstructorBody(target); | 143 buildConstructorBody(target); |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 bodyCallInputs.add(newObject); | 317 bodyCallInputs.add(newObject); |
| 318 | 318 |
| 319 // Pass uncaptured arguments first, captured arguments in a box, then type | 319 // Pass uncaptured arguments first, captured arguments in a box, then type |
| 320 // arguments. | 320 // arguments. |
| 321 | 321 |
| 322 ConstructorElement constructorElement = _elementMap.getConstructor(body); | 322 ConstructorElement constructorElement = _elementMap.getConstructor(body); |
| 323 ClosureClassMap parameterClosureData = | 323 ClosureClassMap parameterClosureData = |
| 324 closureToClassMapper.getMemberMap(constructorElement); | 324 closureToClassMapper.getMemberMap(constructorElement); |
| 325 | 325 |
| 326 void handleParameter(ir.VariableDeclaration node) { | 326 void handleParameter(ir.VariableDeclaration node) { |
| 327 Local parameter = _localsMap.getLocal(node); | 327 Local parameter = localsMap.getLocal(node); |
| 328 // If [parameter] is boxed, it will be a field in the box passed as the | 328 // If [parameter] is boxed, it will be a field in the box passed as the |
| 329 // last parameter. So no need to directly pass it. | 329 // last parameter. So no need to directly pass it. |
| 330 if (!localsHandler.isBoxed(parameter)) { | 330 if (!localsHandler.isBoxed(parameter)) { |
| 331 bodyCallInputs.add(localsHandler.readLocal(parameter)); | 331 bodyCallInputs.add(localsHandler.readLocal(parameter)); |
| 332 } | 332 } |
| 333 } | 333 } |
| 334 | 334 |
| 335 // Provide the parameters to the generative constructor body. | 335 // Provide the parameters to the generative constructor body. |
| 336 body.function.positionalParameters.forEach(handleParameter); | 336 body.function.positionalParameters.forEach(handleParameter); |
| 337 body.function.namedParameters.toList() | 337 body.function.namedParameters.toList() |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 /// Sets context for generating code that is the result of inlining | 383 /// Sets context for generating code that is the result of inlining |
| 384 /// [inlinedTarget]. | 384 /// [inlinedTarget]. |
| 385 inlinedFrom(MemberEntity inlinedTarget, f()) { | 385 inlinedFrom(MemberEntity inlinedTarget, f()) { |
| 386 reporter.withCurrentElement(inlinedTarget, () { | 386 reporter.withCurrentElement(inlinedTarget, () { |
| 387 SourceInformationBuilder oldSourceInformationBuilder = | 387 SourceInformationBuilder oldSourceInformationBuilder = |
| 388 sourceInformationBuilder; | 388 sourceInformationBuilder; |
| 389 // TODO(sra): Update sourceInformationBuilder to Kernel. | 389 // TODO(sra): Update sourceInformationBuilder to Kernel. |
| 390 // sourceInformationBuilder = | 390 // sourceInformationBuilder = |
| 391 // sourceInformationBuilder.forContext(resolvedAst); | 391 // sourceInformationBuilder.forContext(resolvedAst); |
| 392 | 392 |
| 393 _localsMap.enterInlinedMember(inlinedTarget); | 393 localsMap.enterInlinedMember(inlinedTarget); |
| 394 _targetStack.add(inlinedTarget); | 394 _targetStack.add(inlinedTarget); |
| 395 var result = f(); | 395 var result = f(); |
| 396 sourceInformationBuilder = oldSourceInformationBuilder; | 396 sourceInformationBuilder = oldSourceInformationBuilder; |
| 397 _targetStack.removeLast(); | 397 _targetStack.removeLast(); |
| 398 _localsMap.leaveInlinedMember(inlinedTarget); | 398 localsMap.leaveInlinedMember(inlinedTarget); |
| 399 return result; | 399 return result; |
| 400 }); | 400 }); |
| 401 } | 401 } |
| 402 | 402 |
| 403 /// Maps the instance fields of a class to their SSA values. | 403 /// Maps the instance fields of a class to their SSA values. |
| 404 Map<FieldEntity, HInstruction> _collectFieldValues(ir.Class clazz) { | 404 Map<FieldEntity, HInstruction> _collectFieldValues(ir.Class clazz) { |
| 405 Map<FieldEntity, HInstruction> fieldValues = <FieldEntity, HInstruction>{}; | 405 Map<FieldEntity, HInstruction> fieldValues = <FieldEntity, HInstruction>{}; |
| 406 | 406 |
| 407 for (ir.Field node in clazz.fields) { | 407 for (ir.Field node in clazz.fields) { |
| 408 if (node.isInstanceMember) { | 408 if (node.isInstanceMember) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 421 } | 421 } |
| 422 | 422 |
| 423 return fieldValues; | 423 return fieldValues; |
| 424 } | 424 } |
| 425 | 425 |
| 426 /// Collects field initializers all the way up the inheritance chain. | 426 /// Collects field initializers all the way up the inheritance chain. |
| 427 void _buildInitializers( | 427 void _buildInitializers( |
| 428 ir.Constructor constructor, | 428 ir.Constructor constructor, |
| 429 List<ir.Constructor> constructorChain, | 429 List<ir.Constructor> constructorChain, |
| 430 Map<FieldEntity, HInstruction> fieldValues) { | 430 Map<FieldEntity, HInstruction> fieldValues) { |
| 431 assert(_elementMap.getConstructor(constructor) == _localsMap.currentMember); | 431 assert(_elementMap.getConstructor(constructor) == localsMap.currentMember); |
| 432 constructorChain.add(constructor); | 432 constructorChain.add(constructor); |
| 433 | 433 |
| 434 var foundSuperOrRedirectCall = false; | 434 var foundSuperOrRedirectCall = false; |
| 435 for (var initializer in constructor.initializers) { | 435 for (var initializer in constructor.initializers) { |
| 436 if (initializer is ir.FieldInitializer) { | 436 if (initializer is ir.FieldInitializer) { |
| 437 initializer.value.accept(this); | 437 initializer.value.accept(this); |
| 438 fieldValues[_elementMap.getField(initializer.field)] = pop(); | 438 fieldValues[_elementMap.getField(initializer.field)] = pop(); |
| 439 } else if (initializer is ir.SuperInitializer) { | 439 } else if (initializer is ir.SuperInitializer) { |
| 440 assert(!foundSuperOrRedirectCall); | 440 assert(!foundSuperOrRedirectCall); |
| 441 foundSuperOrRedirectCall = true; | 441 foundSuperOrRedirectCall = true; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 | 573 |
| 574 void _inlineSuperOrRedirectCommon( | 574 void _inlineSuperOrRedirectCommon( |
| 575 ir.Initializer initializer, | 575 ir.Initializer initializer, |
| 576 ir.Constructor constructor, | 576 ir.Constructor constructor, |
| 577 List<HInstruction> arguments, | 577 List<HInstruction> arguments, |
| 578 List<ir.Constructor> constructorChain, | 578 List<ir.Constructor> constructorChain, |
| 579 Map<FieldEntity, HInstruction> fieldValues, | 579 Map<FieldEntity, HInstruction> fieldValues, |
| 580 ir.Constructor caller) { | 580 ir.Constructor caller) { |
| 581 var index = 0; | 581 var index = 0; |
| 582 void handleParameter(ir.VariableDeclaration node) { | 582 void handleParameter(ir.VariableDeclaration node) { |
| 583 Local parameter = _localsMap.getLocal(node); | 583 Local parameter = localsMap.getLocal(node); |
| 584 HInstruction argument = arguments[index++]; | 584 HInstruction argument = arguments[index++]; |
| 585 // Because we are inlining the initializer, we must update | 585 // Because we are inlining the initializer, we must update |
| 586 // what was given as parameter. This will be used in case | 586 // what was given as parameter. This will be used in case |
| 587 // there is a parameter check expression in the initializer. | 587 // there is a parameter check expression in the initializer. |
| 588 parameters[parameter] = argument; | 588 parameters[parameter] = argument; |
| 589 localsHandler.updateLocal(parameter, argument); | 589 localsHandler.updateLocal(parameter, argument); |
| 590 } | 590 } |
| 591 | 591 |
| 592 constructor.function.positionalParameters.forEach(handleParameter); | 592 constructor.function.positionalParameters.forEach(handleParameter); |
| 593 constructor.function.namedParameters.toList() | 593 constructor.function.namedParameters.toList() |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 void removeImplicitInstantiation(DartType type) { | 673 void removeImplicitInstantiation(DartType type) { |
| 674 if (type != null) { | 674 if (type != null) { |
| 675 currentImplicitInstantiations.removeLast(); | 675 currentImplicitInstantiations.removeLast(); |
| 676 } | 676 } |
| 677 } | 677 } |
| 678 | 678 |
| 679 void openFunction([ir.FunctionNode function]) { | 679 void openFunction([ir.FunctionNode function]) { |
| 680 Map<Local, TypeMask> parameterMap = <Local, TypeMask>{}; | 680 Map<Local, TypeMask> parameterMap = <Local, TypeMask>{}; |
| 681 if (function != null) { | 681 if (function != null) { |
| 682 void handleParameter(ir.VariableDeclaration node) { | 682 void handleParameter(ir.VariableDeclaration node) { |
| 683 Local local = _localsMap.getLocal(node); | 683 Local local = localsMap.getLocal(node); |
| 684 parameterMap[local] = | 684 parameterMap[local] = |
| 685 _typeInferenceMap.getInferredTypeOfParameter(local); | 685 _typeInferenceMap.getInferredTypeOfParameter(local); |
| 686 } | 686 } |
| 687 | 687 |
| 688 function.positionalParameters.forEach(handleParameter); | 688 function.positionalParameters.forEach(handleParameter); |
| 689 function.namedParameters.toList() | 689 function.namedParameters.toList() |
| 690 ..sort(namedOrdering) | 690 ..sort(namedOrdering) |
| 691 ..forEach(handleParameter); | 691 ..forEach(handleParameter); |
| 692 } | 692 } |
| 693 | 693 |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 987 // Find a type for the element. Use the element type of the indexer of the | 987 // Find a type for the element. Use the element type of the indexer of the |
| 988 // array, as this is stronger than the iterator's `get current` type, for | 988 // array, as this is stronger than the iterator's `get current` type, for |
| 989 // example, `get current` includes null. | 989 // example, `get current` includes null. |
| 990 // TODO(sra): The element type of a container type mask might be better. | 990 // TODO(sra): The element type of a container type mask might be better. |
| 991 TypeMask type = _typeInferenceMap.inferredIndexType(forInStatement); | 991 TypeMask type = _typeInferenceMap.inferredIndexType(forInStatement); |
| 992 | 992 |
| 993 HInstruction index = localsHandler.readLocal(indexVariable); | 993 HInstruction index = localsHandler.readLocal(indexVariable); |
| 994 HInstruction value = new HIndex(array, index, null, type); | 994 HInstruction value = new HIndex(array, index, null, type); |
| 995 add(value); | 995 add(value); |
| 996 | 996 |
| 997 Local loopVariableLocal = _localsMap.getLocal(forInStatement.variable); | 997 Local loopVariableLocal = localsMap.getLocal(forInStatement.variable); |
| 998 localsHandler.updateLocal(loopVariableLocal, value); | 998 localsHandler.updateLocal(loopVariableLocal, value); |
| 999 // Hint to name loop value after name of loop variable. | 999 // Hint to name loop value after name of loop variable. |
| 1000 if (loopVariableLocal is! SyntheticLocal) { | 1000 if (loopVariableLocal is! SyntheticLocal) { |
| 1001 value.sourceElement ??= loopVariableLocal; | 1001 value.sourceElement ??= loopVariableLocal; |
| 1002 } | 1002 } |
| 1003 | 1003 |
| 1004 forInStatement.body.accept(this); | 1004 forInStatement.body.accept(this); |
| 1005 } | 1005 } |
| 1006 | 1006 |
| 1007 void buildUpdate() { | 1007 void buildUpdate() { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1048 TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(forInStatement); | 1048 TypeMask mask = _typeInferenceMap.typeOfIteratorMoveNext(forInStatement); |
| 1049 _pushDynamicInvocation(forInStatement, mask, <HInstruction>[iterator], | 1049 _pushDynamicInvocation(forInStatement, mask, <HInstruction>[iterator], |
| 1050 selector: Selectors.moveNext); | 1050 selector: Selectors.moveNext); |
| 1051 return popBoolified(); | 1051 return popBoolified(); |
| 1052 } | 1052 } |
| 1053 | 1053 |
| 1054 void buildBody() { | 1054 void buildBody() { |
| 1055 TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(forInStatement); | 1055 TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(forInStatement); |
| 1056 _pushDynamicInvocation(forInStatement, mask, [iterator], | 1056 _pushDynamicInvocation(forInStatement, mask, [iterator], |
| 1057 selector: Selectors.current); | 1057 selector: Selectors.current); |
| 1058 Local loopVariableLocal = _localsMap.getLocal(forInStatement.variable); | 1058 Local loopVariableLocal = localsMap.getLocal(forInStatement.variable); |
| 1059 HInstruction value = pop(); | 1059 HInstruction value = pop(); |
| 1060 localsHandler.updateLocal(loopVariableLocal, value); | 1060 localsHandler.updateLocal(loopVariableLocal, value); |
| 1061 // Hint to name loop value after name of loop variable. | 1061 // Hint to name loop value after name of loop variable. |
| 1062 if (loopVariableLocal is! SyntheticLocal) { | 1062 if (loopVariableLocal is! SyntheticLocal) { |
| 1063 value.sourceElement ??= loopVariableLocal; | 1063 value.sourceElement ??= loopVariableLocal; |
| 1064 } | 1064 } |
| 1065 forInStatement.body.accept(this); | 1065 forInStatement.body.accept(this); |
| 1066 } | 1066 } |
| 1067 | 1067 |
| 1068 loopHandler.handleLoop( | 1068 loopHandler.handleLoop( |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1090 HInstruction future = pop(); | 1090 HInstruction future = pop(); |
| 1091 push(new HAwait(future, closedWorld.commonMasks.dynamicType)); | 1091 push(new HAwait(future, closedWorld.commonMasks.dynamicType)); |
| 1092 return popBoolified(); | 1092 return popBoolified(); |
| 1093 } | 1093 } |
| 1094 | 1094 |
| 1095 void buildBody() { | 1095 void buildBody() { |
| 1096 TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(forInStatement); | 1096 TypeMask mask = _typeInferenceMap.typeOfIteratorCurrent(forInStatement); |
| 1097 _pushDynamicInvocation(forInStatement, mask, [streamIterator], | 1097 _pushDynamicInvocation(forInStatement, mask, [streamIterator], |
| 1098 selector: Selectors.current); | 1098 selector: Selectors.current); |
| 1099 localsHandler.updateLocal( | 1099 localsHandler.updateLocal( |
| 1100 _localsMap.getLocal(forInStatement.variable), pop()); | 1100 localsMap.getLocal(forInStatement.variable), pop()); |
| 1101 forInStatement.body.accept(this); | 1101 forInStatement.body.accept(this); |
| 1102 } | 1102 } |
| 1103 | 1103 |
| 1104 void buildUpdate() {} | 1104 void buildUpdate() {} |
| 1105 | 1105 |
| 1106 // Creates a synthetic try/finally block in case anything async goes amiss. | 1106 // Creates a synthetic try/finally block in case anything async goes amiss. |
| 1107 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this); | 1107 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this); |
| 1108 // Build fake try body: | 1108 // Build fake try body: |
| 1109 loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition, | 1109 loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition, |
| 1110 buildUpdate, buildBody); | 1110 buildUpdate, buildBody); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () { | 1154 loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () { |
| 1155 whileStatement.body.accept(this); | 1155 whileStatement.body.accept(this); |
| 1156 }); | 1156 }); |
| 1157 } | 1157 } |
| 1158 | 1158 |
| 1159 @override | 1159 @override |
| 1160 visitDoStatement(ir.DoStatement doStatement) { | 1160 visitDoStatement(ir.DoStatement doStatement) { |
| 1161 // TODO(efortuna): I think this can be rewritten using | 1161 // TODO(efortuna): I think this can be rewritten using |
| 1162 // LoopHandler.handleLoop with some tricks about when the "update" happens. | 1162 // LoopHandler.handleLoop with some tricks about when the "update" happens. |
| 1163 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 1163 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 1164 localsHandler.startLoop(astAdapter.getNode(doStatement)); | 1164 ClosureScope scopeData = localsMap.getClosureScopeForLoop( |
| 1165 localsHandler.closureData, doStatement); |
| 1166 localsHandler.startLoop(scopeData); |
| 1165 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement); | 1167 JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement); |
| 1166 HLoopInformation loopInfo = current.loopInformation; | 1168 HLoopInformation loopInfo = current.loopInformation; |
| 1167 HBasicBlock loopEntryBlock = current; | 1169 HBasicBlock loopEntryBlock = current; |
| 1168 HBasicBlock bodyEntryBlock = current; | 1170 HBasicBlock bodyEntryBlock = current; |
| 1169 JumpTarget target = _localsMap.getJumpTarget(doStatement); | 1171 JumpTarget target = localsMap.getJumpTarget(doStatement); |
| 1170 bool hasContinues = target != null && target.isContinueTarget; | 1172 bool hasContinues = target != null && target.isContinueTarget; |
| 1171 if (hasContinues) { | 1173 if (hasContinues) { |
| 1172 // Add extra block to hang labels on. | 1174 // Add extra block to hang labels on. |
| 1173 // It doesn't currently work if they are on the same block as the | 1175 // It doesn't currently work if they are on the same block as the |
| 1174 // HLoopInfo. The handling of HLabeledBlockInformation will visit a | 1176 // HLoopInfo. The handling of HLabeledBlockInformation will visit a |
| 1175 // SubGraph that starts at the same block again, so the HLoopInfo is | 1177 // SubGraph that starts at the same block again, so the HLoopInfo is |
| 1176 // either handled twice, or it's handled after the labeled block info, | 1178 // either handled twice, or it's handled after the labeled block info, |
| 1177 // both of which generate the wrong code. | 1179 // both of which generate the wrong code. |
| 1178 // Using a separate block is just a simple workaround. | 1180 // Using a separate block is just a simple workaround. |
| 1179 bodyEntryBlock = openNewBlock(); | 1181 bodyEntryBlock = openNewBlock(); |
| 1180 } | 1182 } |
| 1181 localsHandler.enterLoopBody(astAdapter.getNode(doStatement)); | 1183 localsHandler.enterLoopBody(scopeData); |
| 1182 doStatement.body.accept(this); | 1184 doStatement.body.accept(this); |
| 1183 | 1185 |
| 1184 // If there are no continues we could avoid the creation of the condition | 1186 // If there are no continues we could avoid the creation of the condition |
| 1185 // block. This could also lead to a block having multiple entries and exits. | 1187 // block. This could also lead to a block having multiple entries and exits. |
| 1186 HBasicBlock bodyExitBlock; | 1188 HBasicBlock bodyExitBlock; |
| 1187 bool isAbortingBody = false; | 1189 bool isAbortingBody = false; |
| 1188 if (current != null) { | 1190 if (current != null) { |
| 1189 bodyExitBlock = close(new HGoto()); | 1191 bodyExitBlock = close(new HGoto()); |
| 1190 } else { | 1192 } else { |
| 1191 isAbortingBody = true; | 1193 isAbortingBody = true; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1271 loopEntryBlock.loopInformation = null; | 1273 loopEntryBlock.loopInformation = null; |
| 1272 | 1274 |
| 1273 if (jumpHandler.hasAnyBreak()) { | 1275 if (jumpHandler.hasAnyBreak()) { |
| 1274 // Null branchBlock because the body of the do-while loop always aborts, | 1276 // Null branchBlock because the body of the do-while loop always aborts, |
| 1275 // so we never get to the condition. | 1277 // so we never get to the condition. |
| 1276 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); | 1278 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); |
| 1277 | 1279 |
| 1278 // Since the body of the loop has a break, we attach a synthesized label | 1280 // Since the body of the loop has a break, we attach a synthesized label |
| 1279 // to the body. | 1281 // to the body. |
| 1280 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); | 1282 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); |
| 1281 JumpTarget target = _localsMap.getJumpTarget(doStatement); | 1283 JumpTarget target = localsMap.getJumpTarget(doStatement); |
| 1282 LabelDefinition label = target.addLabel(null, 'loop'); | 1284 LabelDefinition label = target.addLabel(null, 'loop'); |
| 1283 label.setBreakTarget(); | 1285 label.setBreakTarget(); |
| 1284 HLabeledBlockInformation info = new HLabeledBlockInformation( | 1286 HLabeledBlockInformation info = new HLabeledBlockInformation( |
| 1285 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); | 1287 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); |
| 1286 loopEntryBlock.setBlockFlow(info, current); | 1288 loopEntryBlock.setBlockFlow(info, current); |
| 1287 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | 1289 jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
| 1288 HBasicBlock block = breakInstruction.block; | 1290 HBasicBlock block = breakInstruction.block; |
| 1289 block.addAtExit(new HBreak.toLabel(label)); | 1291 block.addAtExit(new HBreak.toLabel(label)); |
| 1290 block.remove(breakInstruction); | 1292 block.remove(breakInstruction); |
| 1291 }); | 1293 }); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1396 } | 1398 } |
| 1397 | 1399 |
| 1398 /// Creates a [JumpHandler] for a statement. The node must be a jump | 1400 /// Creates a [JumpHandler] for a statement. The node must be a jump |
| 1399 /// target. If there are no breaks or continues targeting the statement, | 1401 /// target. If there are no breaks or continues targeting the statement, |
| 1400 /// a special "null handler" is returned. | 1402 /// a special "null handler" is returned. |
| 1401 /// | 1403 /// |
| 1402 /// [isLoopJump] is true when the jump handler is for a loop. This is used | 1404 /// [isLoopJump] is true when the jump handler is for a loop. This is used |
| 1403 /// to distinguish the synthesized loop created for a switch statement with | 1405 /// to distinguish the synthesized loop created for a switch statement with |
| 1404 /// continue statements from simple switch statements. | 1406 /// continue statements from simple switch statements. |
| 1405 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) { | 1407 JumpHandler createJumpHandler(ir.TreeNode node, {bool isLoopJump: false}) { |
| 1406 JumpTarget target = _localsMap.getJumpTarget(node); | 1408 JumpTarget target = localsMap.getJumpTarget(node); |
| 1407 assert(target is KernelJumpTarget); | 1409 assert(target is KernelJumpTarget); |
| 1408 if (target == null) { | 1410 if (target == null) { |
| 1409 // No breaks or continues to this node. | 1411 // No breaks or continues to this node. |
| 1410 return new NullJumpHandler(reporter); | 1412 return new NullJumpHandler(reporter); |
| 1411 } | 1413 } |
| 1412 if (isLoopJump && node is ir.SwitchStatement) { | 1414 if (isLoopJump && node is ir.SwitchStatement) { |
| 1413 return new KernelSwitchCaseJumpHandler(this, target, node, _localsMap); | 1415 return new KernelSwitchCaseJumpHandler(this, target, node, localsMap); |
| 1414 } | 1416 } |
| 1415 | 1417 |
| 1416 return new JumpHandler(this, target); | 1418 return new JumpHandler(this, target); |
| 1417 } | 1419 } |
| 1418 | 1420 |
| 1419 @override | 1421 @override |
| 1420 void visitBreakStatement(ir.BreakStatement breakStatement) { | 1422 void visitBreakStatement(ir.BreakStatement breakStatement) { |
| 1421 assert(!isAborted()); | 1423 assert(!isAborted()); |
| 1422 handleInTryStatement(); | 1424 handleInTryStatement(); |
| 1423 JumpTarget target = _localsMap.getJumpTarget(breakStatement.target); | 1425 JumpTarget target = localsMap.getJumpTarget(breakStatement.target); |
| 1424 assert(target != null); | 1426 assert(target != null); |
| 1425 JumpHandler handler = jumpTargets[target]; | 1427 JumpHandler handler = jumpTargets[target]; |
| 1426 assert(handler != null); | 1428 assert(handler != null); |
| 1427 if (handler.labels.isNotEmpty) { | 1429 if (handler.labels.isNotEmpty) { |
| 1428 handler.generateBreak(handler.labels.first); | 1430 handler.generateBreak(handler.labels.first); |
| 1429 } else { | 1431 } else { |
| 1430 handler.generateBreak(); | 1432 handler.generateBreak(); |
| 1431 } | 1433 } |
| 1432 } | 1434 } |
| 1433 | 1435 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1486 constants[caseExpression] = constant; | 1488 constants[caseExpression] = constant; |
| 1487 } | 1489 } |
| 1488 } | 1490 } |
| 1489 return constants; | 1491 return constants; |
| 1490 } | 1492 } |
| 1491 | 1493 |
| 1492 @override | 1494 @override |
| 1493 void visitContinueSwitchStatement( | 1495 void visitContinueSwitchStatement( |
| 1494 ir.ContinueSwitchStatement switchStatement) { | 1496 ir.ContinueSwitchStatement switchStatement) { |
| 1495 handleInTryStatement(); | 1497 handleInTryStatement(); |
| 1496 JumpTarget target = _localsMap.getJumpTarget(switchStatement.target); | 1498 JumpTarget target = localsMap.getJumpTarget(switchStatement.target); |
| 1497 assert(target != null); | 1499 assert(target != null); |
| 1498 JumpHandler handler = jumpTargets[target]; | 1500 JumpHandler handler = jumpTargets[target]; |
| 1499 assert(handler != null); | 1501 assert(handler != null); |
| 1500 assert(target.labels.isNotEmpty); | 1502 assert(target.labels.isNotEmpty); |
| 1501 handler.generateContinue(target.labels.first); | 1503 handler.generateContinue(target.labels.first); |
| 1502 } | 1504 } |
| 1503 | 1505 |
| 1504 @override | 1506 @override |
| 1505 void visitSwitchStatement(ir.SwitchStatement switchStatement) { | 1507 void visitSwitchStatement(ir.SwitchStatement switchStatement) { |
| 1506 // The switch case indices must match those computed in | 1508 // The switch case indices must match those computed in |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1606 // case 1: s_1; break l; | 1608 // case 1: s_1; break l; |
| 1607 // case 2: s_2; target = i; continue l; | 1609 // case 2: s_2; target = i; continue l; |
| 1608 // ... | 1610 // ... |
| 1609 // case n: s_n; target = j; continue l; | 1611 // case n: s_n; target = j; continue l; |
| 1610 // } | 1612 // } |
| 1611 // } | 1613 // } |
| 1612 // | 1614 // |
| 1613 // This is because JS does not have this same "continue label" semantics so | 1615 // This is because JS does not have this same "continue label" semantics so |
| 1614 // we encode it in the form of a state machine. | 1616 // we encode it in the form of a state machine. |
| 1615 | 1617 |
| 1616 JumpTarget switchTarget = _localsMap.getJumpTarget(switchStatement); | 1618 JumpTarget switchTarget = localsMap.getJumpTarget(switchStatement); |
| 1617 localsHandler.updateLocal(switchTarget, graph.addConstantNull(closedWorld)); | 1619 localsHandler.updateLocal(switchTarget, graph.addConstantNull(closedWorld)); |
| 1618 | 1620 |
| 1619 var switchCases = switchStatement.cases; | 1621 var switchCases = switchStatement.cases; |
| 1620 if (!hasDefault) { | 1622 if (!hasDefault) { |
| 1621 // Use null as the marker for a synthetic default clause. | 1623 // Use null as the marker for a synthetic default clause. |
| 1622 // The synthetic default is added because otherwise there would be no | 1624 // The synthetic default is added because otherwise there would be no |
| 1623 // good place to give a default value to the local. | 1625 // good place to give a default value to the local. |
| 1624 switchCases = new List<ir.SwitchCase>.from(switchCases); | 1626 switchCases = new List<ir.SwitchCase>.from(switchCases); |
| 1625 switchCases.add(null); | 1627 switchCases.add(null); |
| 1626 } | 1628 } |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2078 | 2080 |
| 2079 @override | 2081 @override |
| 2080 void visitVariableGet(ir.VariableGet variableGet) { | 2082 void visitVariableGet(ir.VariableGet variableGet) { |
| 2081 ir.VariableDeclaration variable = variableGet.variable; | 2083 ir.VariableDeclaration variable = variableGet.variable; |
| 2082 HInstruction letBinding = letBindings[variable]; | 2084 HInstruction letBinding = letBindings[variable]; |
| 2083 if (letBinding != null) { | 2085 if (letBinding != null) { |
| 2084 stack.add(letBinding); | 2086 stack.add(letBinding); |
| 2085 return; | 2087 return; |
| 2086 } | 2088 } |
| 2087 | 2089 |
| 2088 Local local = _localsMap.getLocal(variableGet.variable); | 2090 Local local = localsMap.getLocal(variableGet.variable); |
| 2089 stack.add(localsHandler.readLocal(local)); | 2091 stack.add(localsHandler.readLocal(local)); |
| 2090 } | 2092 } |
| 2091 | 2093 |
| 2092 @override | 2094 @override |
| 2093 void visitPropertySet(ir.PropertySet propertySet) { | 2095 void visitPropertySet(ir.PropertySet propertySet) { |
| 2094 propertySet.receiver.accept(this); | 2096 propertySet.receiver.accept(this); |
| 2095 HInstruction receiver = pop(); | 2097 HInstruction receiver = pop(); |
| 2096 propertySet.value.accept(this); | 2098 propertySet.value.accept(this); |
| 2097 HInstruction value = pop(); | 2099 HInstruction value = pop(); |
| 2098 | 2100 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 2126 | 2128 |
| 2127 @override | 2129 @override |
| 2128 void visitVariableSet(ir.VariableSet variableSet) { | 2130 void visitVariableSet(ir.VariableSet variableSet) { |
| 2129 variableSet.value.accept(this); | 2131 variableSet.value.accept(this); |
| 2130 HInstruction value = pop(); | 2132 HInstruction value = pop(); |
| 2131 _visitLocalSetter(variableSet.variable, value); | 2133 _visitLocalSetter(variableSet.variable, value); |
| 2132 } | 2134 } |
| 2133 | 2135 |
| 2134 @override | 2136 @override |
| 2135 void visitVariableDeclaration(ir.VariableDeclaration declaration) { | 2137 void visitVariableDeclaration(ir.VariableDeclaration declaration) { |
| 2136 Local local = _localsMap.getLocal(declaration); | 2138 Local local = localsMap.getLocal(declaration); |
| 2137 if (declaration.initializer == null) { | 2139 if (declaration.initializer == null) { |
| 2138 HInstruction initialValue = graph.addConstantNull(closedWorld); | 2140 HInstruction initialValue = graph.addConstantNull(closedWorld); |
| 2139 localsHandler.updateLocal(local, initialValue); | 2141 localsHandler.updateLocal(local, initialValue); |
| 2140 } else { | 2142 } else { |
| 2141 declaration.initializer.accept(this); | 2143 declaration.initializer.accept(this); |
| 2142 HInstruction initialValue = pop(); | 2144 HInstruction initialValue = pop(); |
| 2143 | 2145 |
| 2144 _visitLocalSetter(declaration, initialValue); | 2146 _visitLocalSetter(declaration, initialValue); |
| 2145 | 2147 |
| 2146 // Ignore value | 2148 // Ignore value |
| 2147 pop(); | 2149 pop(); |
| 2148 } | 2150 } |
| 2149 } | 2151 } |
| 2150 | 2152 |
| 2151 void _visitLocalSetter(ir.VariableDeclaration variable, HInstruction value) { | 2153 void _visitLocalSetter(ir.VariableDeclaration variable, HInstruction value) { |
| 2152 Local local = _localsMap.getLocal(variable); | 2154 Local local = localsMap.getLocal(variable); |
| 2153 | 2155 |
| 2154 // Give the value a name if it doesn't have one already. | 2156 // Give the value a name if it doesn't have one already. |
| 2155 if (value.sourceElement == null) { | 2157 if (value.sourceElement == null) { |
| 2156 value.sourceElement = local; | 2158 value.sourceElement = local; |
| 2157 } | 2159 } |
| 2158 | 2160 |
| 2159 stack.add(value); | 2161 stack.add(value); |
| 2160 localsHandler.updateLocal( | 2162 localsHandler.updateLocal( |
| 2161 local, | 2163 local, |
| 2162 typeBuilder.potentiallyCheckOrTrustType( | 2164 typeBuilder.potentiallyCheckOrTrustType( |
| (...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3367 // `guard` is often `dynamic`, which generates `true`. | 3369 // `guard` is often `dynamic`, which generates `true`. |
| 3368 kernelBuilder.pushIsTest( | 3370 kernelBuilder.pushIsTest( |
| 3369 catchBlock.exception, catchBlock.guard, unwrappedException); | 3371 catchBlock.exception, catchBlock.guard, unwrappedException); |
| 3370 } | 3372 } |
| 3371 | 3373 |
| 3372 void visitThen() { | 3374 void visitThen() { |
| 3373 ir.Catch catchBlock = tryCatch.catches[catchesIndex]; | 3375 ir.Catch catchBlock = tryCatch.catches[catchesIndex]; |
| 3374 catchesIndex++; | 3376 catchesIndex++; |
| 3375 if (catchBlock.exception != null) { | 3377 if (catchBlock.exception != null) { |
| 3376 LocalVariableElement exceptionVariable = | 3378 LocalVariableElement exceptionVariable = |
| 3377 kernelBuilder._localsMap.getLocal(catchBlock.exception); | 3379 kernelBuilder.localsMap.getLocal(catchBlock.exception); |
| 3378 kernelBuilder.localsHandler | 3380 kernelBuilder.localsHandler |
| 3379 .updateLocal(exceptionVariable, unwrappedException); | 3381 .updateLocal(exceptionVariable, unwrappedException); |
| 3380 } | 3382 } |
| 3381 if (catchBlock.stackTrace != null) { | 3383 if (catchBlock.stackTrace != null) { |
| 3382 kernelBuilder._pushStaticInvocation( | 3384 kernelBuilder._pushStaticInvocation( |
| 3383 kernelBuilder._commonElements.traceFromException, | 3385 kernelBuilder._commonElements.traceFromException, |
| 3384 [exception], | 3386 [exception], |
| 3385 kernelBuilder._typeInferenceMap.getReturnTypeOf( | 3387 kernelBuilder._typeInferenceMap.getReturnTypeOf( |
| 3386 kernelBuilder._commonElements.traceFromException)); | 3388 kernelBuilder._commonElements.traceFromException)); |
| 3387 HInstruction traceInstruction = kernelBuilder.pop(); | 3389 HInstruction traceInstruction = kernelBuilder.pop(); |
| 3388 LocalVariableElement traceVariable = | 3390 LocalVariableElement traceVariable = |
| 3389 kernelBuilder._localsMap.getLocal(catchBlock.stackTrace); | 3391 kernelBuilder.localsMap.getLocal(catchBlock.stackTrace); |
| 3390 kernelBuilder.localsHandler | 3392 kernelBuilder.localsHandler |
| 3391 .updateLocal(traceVariable, traceInstruction); | 3393 .updateLocal(traceVariable, traceInstruction); |
| 3392 } | 3394 } |
| 3393 catchBlock.body.accept(kernelBuilder); | 3395 catchBlock.body.accept(kernelBuilder); |
| 3394 } | 3396 } |
| 3395 | 3397 |
| 3396 void visitElse() { | 3398 void visitElse() { |
| 3397 if (catchesIndex >= tryCatch.catches.length) { | 3399 if (catchesIndex >= tryCatch.catches.length) { |
| 3398 kernelBuilder.closeAndGotoExit(new HThrow( | 3400 kernelBuilder.closeAndGotoExit(new HThrow( |
| 3399 exception, exception.sourceInformation, | 3401 exception, exception.sourceInformation, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3439 enterBlock.setBlockFlow( | 3441 enterBlock.setBlockFlow( |
| 3440 new HTryBlockInformation( | 3442 new HTryBlockInformation( |
| 3441 kernelBuilder.wrapStatementGraph(bodyGraph), | 3443 kernelBuilder.wrapStatementGraph(bodyGraph), |
| 3442 exception, | 3444 exception, |
| 3443 kernelBuilder.wrapStatementGraph(catchGraph), | 3445 kernelBuilder.wrapStatementGraph(catchGraph), |
| 3444 kernelBuilder.wrapStatementGraph(finallyGraph)), | 3446 kernelBuilder.wrapStatementGraph(finallyGraph)), |
| 3445 exitBlock); | 3447 exitBlock); |
| 3446 kernelBuilder.inTryStatement = previouslyInTryStatement; | 3448 kernelBuilder.inTryStatement = previouslyInTryStatement; |
| 3447 } | 3449 } |
| 3448 } | 3450 } |
| OLD | NEW |