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 |