| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../closure.dart' as closure; | 7 import '../closure.dart' as closure; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/names.dart' show | 9 import '../common/names.dart' show Names, Selectors; |
| 10 Names, | 10 import '../compile_time_constants.dart' show BackendConstantEnvironment; |
| 11 Selectors; | |
| 12 import '../compile_time_constants.dart' show | |
| 13 BackendConstantEnvironment; | |
| 14 import '../constants/constant_system.dart'; | 11 import '../constants/constant_system.dart'; |
| 15 import '../constants/values.dart' show | 12 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; |
| 16 ConstantValue, | |
| 17 PrimitiveConstantValue; | |
| 18 import '../dart_types.dart'; | 13 import '../dart_types.dart'; |
| 19 import '../elements/elements.dart'; | 14 import '../elements/elements.dart'; |
| 20 import '../io/source_information.dart'; | 15 import '../io/source_information.dart'; |
| 21 import '../js/js.dart' as js show | 16 import '../js/js.dart' as js |
| 22 js, | 17 show |
| 23 objectLiteral, | 18 js, |
| 24 Expression, | 19 objectLiteral, |
| 25 LiteralStatement, | 20 Expression, |
| 26 Template, | 21 LiteralStatement, |
| 27 InterpolatedExpression, | 22 Template, |
| 28 isIdentityTemplate; | 23 InterpolatedExpression, |
| 29 import '../native/native.dart' show | 24 isIdentityTemplate; |
| 30 NativeBehavior; | 25 import '../native/native.dart' show NativeBehavior; |
| 31 import '../tree/tree.dart' as ast; | 26 import '../tree/tree.dart' as ast; |
| 32 import '../types/types.dart' show | 27 import '../types/types.dart' show TypeMask; |
| 33 TypeMask; | 28 import '../universe/call_structure.dart' show CallStructure; |
| 34 import '../universe/call_structure.dart' show | 29 import '../universe/selector.dart' show Selector, SelectorKind; |
| 35 CallStructure; | |
| 36 import '../universe/selector.dart' show | |
| 37 Selector, | |
| 38 SelectorKind; | |
| 39 | 30 |
| 40 import 'cps_ir_builder_task.dart' show | 31 import 'cps_ir_builder_task.dart' show GlobalProgramInformation; |
| 41 GlobalProgramInformation; | |
| 42 import 'cps_ir_nodes.dart' as ir; | 32 import 'cps_ir_nodes.dart' as ir; |
| 43 | 33 |
| 44 | |
| 45 /// A mapping from variable elements to their compile-time values. | 34 /// A mapping from variable elements to their compile-time values. |
| 46 /// | 35 /// |
| 47 /// Map elements denoted by parameters and local variables to the | 36 /// Map elements denoted by parameters and local variables to the |
| 48 /// [ir.Primitive] that is their value. Parameters and locals are | 37 /// [ir.Primitive] that is their value. Parameters and locals are |
| 49 /// assigned indexes which can be used to refer to them. | 38 /// assigned indexes which can be used to refer to them. |
| 50 class Environment { | 39 class Environment { |
| 51 /// A map from locals to their environment index. | 40 /// A map from locals to their environment index. |
| 52 final Map<Local, int> variable2index; | 41 final Map<Local, int> variable2index; |
| 53 | 42 |
| 54 /// A reverse map from environment indexes to the variable. | 43 /// A reverse map from environment indexes to the variable. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 ir.Primitive value = index2value.last; | 92 ir.Primitive value = index2value.last; |
| 104 // The map from variables to their index are shared, so we cannot remove | 93 // The map from variables to their index are shared, so we cannot remove |
| 105 // the mapping in `variable2index`. | 94 // the mapping in `variable2index`. |
| 106 index2variable.length -= count; | 95 index2variable.length -= count; |
| 107 index2value.length -= count; | 96 index2value.length -= count; |
| 108 return value; | 97 return value; |
| 109 } | 98 } |
| 110 | 99 |
| 111 ir.Primitive lookup(Local element) { | 100 ir.Primitive lookup(Local element) { |
| 112 assert(invariant(element, variable2index.containsKey(element), | 101 assert(invariant(element, variable2index.containsKey(element), |
| 113 message: "Unknown variable: $element.")); | 102 message: "Unknown variable: $element.")); |
| 114 return index2value[variable2index[element]]; | 103 return index2value[variable2index[element]]; |
| 115 } | 104 } |
| 116 | 105 |
| 117 void update(Local element, ir.Primitive value) { | 106 void update(Local element, ir.Primitive value) { |
| 118 index2value[variable2index[element]] = value; | 107 index2value[variable2index[element]] = value; |
| 119 } | 108 } |
| 120 | 109 |
| 121 /// Verify that the variable2index and index2variable maps agree up to the | 110 /// Verify that the variable2index and index2variable maps agree up to the |
| 122 /// index [length] exclusive. | 111 /// index [length] exclusive. |
| 123 bool sameDomain(int length, Environment other) { | 112 bool sameDomain(int length, Environment other) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 151 final Environment _continuationEnvironment; | 140 final Environment _continuationEnvironment; |
| 152 | 141 |
| 153 final List<Iterable<LocalVariableElement>> _boxedTryVariables = | 142 final List<Iterable<LocalVariableElement>> _boxedTryVariables = |
| 154 <Iterable<LocalVariableElement>>[]; | 143 <Iterable<LocalVariableElement>>[]; |
| 155 | 144 |
| 156 /// Construct a collector for a given environment and optionally a target. | 145 /// Construct a collector for a given environment and optionally a target. |
| 157 /// | 146 /// |
| 158 /// The environment is the one in effect at the point where the jump's | 147 /// The environment is the one in effect at the point where the jump's |
| 159 /// continuation will be bound. Continuations can take an extra argument | 148 /// continuation will be bound. Continuations can take an extra argument |
| 160 /// (see [addJump]). | 149 /// (see [addJump]). |
| 161 JumpCollector(this._continuationEnvironment, this.target, | 150 JumpCollector( |
| 162 bool hasExtraArgument) { | 151 this._continuationEnvironment, this.target, bool hasExtraArgument) { |
| 163 if (hasExtraArgument) _continuationEnvironment.extend(null, null); | 152 if (hasExtraArgument) _continuationEnvironment.extend(null, null); |
| 164 } | 153 } |
| 165 | 154 |
| 166 /// Construct a collector for collecting only return jumps. | 155 /// Construct a collector for collecting only return jumps. |
| 167 /// | 156 /// |
| 168 /// There is no jump target, it is implicitly the exit from the function. | 157 /// There is no jump target, it is implicitly the exit from the function. |
| 169 /// There is no environment at the destination. | 158 /// There is no environment at the destination. |
| 170 JumpCollector.retrn(this._continuation) | 159 JumpCollector.retrn(this._continuation) |
| 171 : _continuationEnvironment = null, target = null; | 160 : _continuationEnvironment = null, |
| 161 target = null; |
| 172 | 162 |
| 173 /// Construct a collector for collecting goto jumps. | 163 /// Construct a collector for collecting goto jumps. |
| 174 /// | 164 /// |
| 175 /// There is no continuation or environment at the destination. | 165 /// There is no continuation or environment at the destination. |
| 176 JumpCollector.goto(this.target) : _continuationEnvironment = null; | 166 JumpCollector.goto(this.target) : _continuationEnvironment = null; |
| 177 | 167 |
| 178 /// True if the collector has not recorded any jumps to its continuation. | 168 /// True if the collector has not recorded any jumps to its continuation. |
| 179 bool get isEmpty; | 169 bool get isEmpty; |
| 180 | 170 |
| 181 /// The continuation encapsulated by this collector. | 171 /// The continuation encapsulated by this collector. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 | 263 |
| 274 Environment get environment { | 264 Environment get environment { |
| 275 if (_continuation == null) _setContinuation(); | 265 if (_continuation == null) _setContinuation(); |
| 276 return _continuationEnvironment; | 266 return _continuationEnvironment; |
| 277 } | 267 } |
| 278 | 268 |
| 279 void addJump(IrBuilder builder, | 269 void addJump(IrBuilder builder, |
| 280 [ir.Primitive value, SourceInformation sourceInformation]) { | 270 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 281 assert(_continuation == null); | 271 assert(_continuation == null); |
| 282 _buildTryExit(builder); | 272 _buildTryExit(builder); |
| 283 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized( | 273 ir.InvokeContinuation invoke = |
| 284 isEscapingTry: isEscapingTry); | 274 new ir.InvokeContinuation.uninitialized(isEscapingTry: isEscapingTry); |
| 285 builder.add(invoke); | 275 builder.add(invoke); |
| 286 _invocations.add(invoke); | 276 _invocations.add(invoke); |
| 287 // Truncate the environment at the invocation site so it only includes | 277 // Truncate the environment at the invocation site so it only includes |
| 288 // values that will be continuation arguments. If an extra value is passed | 278 // values that will be continuation arguments. If an extra value is passed |
| 289 // it will already be included in the continuation environment, but it is | 279 // it will already be included in the continuation environment, but it is |
| 290 // not present in the invocation environment. | 280 // not present in the invocation environment. |
| 291 int delta = builder.environment.length - _continuationEnvironment.length; | 281 int delta = builder.environment.length - _continuationEnvironment.length; |
| 292 if (value != null) ++delta; | 282 if (value != null) ++delta; |
| 293 if (delta > 0) builder.environment.discard(delta); | 283 if (delta > 0) builder.environment.discard(delta); |
| 294 if (value != null) builder.environment.extend(null, value); | 284 if (value != null) builder.environment.extend(null, value); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 309 // that has a different value (from the environment in scope at the | 299 // that has a different value (from the environment in scope at the |
| 310 // continuation binding) on some path. `_environment` is initially a copy | 300 // continuation binding) on some path. `_environment` is initially a copy |
| 311 // of the environment in scope at the continuation binding. Compute the | 301 // of the environment in scope at the continuation binding. Compute the |
| 312 // continuation parameters and add them to `_environment` so it will become | 302 // continuation parameters and add them to `_environment` so it will become |
| 313 // the one in scope for the continuation body. | 303 // the one in scope for the continuation body. |
| 314 List<ir.Parameter> parameters = <ir.Parameter>[]; | 304 List<ir.Parameter> parameters = <ir.Parameter>[]; |
| 315 if (_invocationEnvironments.isNotEmpty) { | 305 if (_invocationEnvironments.isNotEmpty) { |
| 316 int length = _continuationEnvironment.length; | 306 int length = _continuationEnvironment.length; |
| 317 for (int varIndex = 0; varIndex < length; ++varIndex) { | 307 for (int varIndex = 0; varIndex < length; ++varIndex) { |
| 318 for (Environment invocationEnvironment in _invocationEnvironments) { | 308 for (Environment invocationEnvironment in _invocationEnvironments) { |
| 319 assert(invocationEnvironment.sameDomain(length, | 309 assert(invocationEnvironment.sameDomain( |
| 320 _continuationEnvironment)); | 310 length, _continuationEnvironment)); |
| 321 if (invocationEnvironment[varIndex] != | 311 if (invocationEnvironment[varIndex] != |
| 322 _continuationEnvironment[varIndex]) { | 312 _continuationEnvironment[varIndex]) { |
| 323 ir.Parameter parameter = new ir.Parameter( | 313 ir.Parameter parameter = new ir.Parameter( |
| 324 _continuationEnvironment.index2variable[varIndex]); | 314 _continuationEnvironment.index2variable[varIndex]); |
| 325 _continuationEnvironment.index2value[varIndex] = parameter; | 315 _continuationEnvironment.index2value[varIndex] = parameter; |
| 326 parameters.add(parameter); | 316 parameters.add(parameter); |
| 327 break; | 317 break; |
| 328 } | 318 } |
| 329 } | 319 } |
| 330 } | 320 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 isEmpty = false; | 382 isEmpty = false; |
| 393 _buildTryExit(builder); | 383 _buildTryExit(builder); |
| 394 // Truncate the environment at the invocation site so it only includes | 384 // Truncate the environment at the invocation site so it only includes |
| 395 // values that will be continuation arguments. If an extra value is passed | 385 // values that will be continuation arguments. If an extra value is passed |
| 396 // it will already be included in the continuation environment, but it is | 386 // it will already be included in the continuation environment, but it is |
| 397 // not present in the invocation environment. | 387 // not present in the invocation environment. |
| 398 int delta = builder.environment.length - _continuationEnvironment.length; | 388 int delta = builder.environment.length - _continuationEnvironment.length; |
| 399 if (value != null) ++delta; | 389 if (value != null) ++delta; |
| 400 if (delta > 0) builder.environment.discard(delta); | 390 if (delta > 0) builder.environment.discard(delta); |
| 401 if (value != null) builder.environment.extend(null, value); | 391 if (value != null) builder.environment.extend(null, value); |
| 402 builder.add(new ir.InvokeContinuation(_continuation, | 392 builder.add(new ir.InvokeContinuation( |
| 403 builder.environment.index2value, | 393 _continuation, builder.environment.index2value, |
| 404 isRecursive: true, | 394 isRecursive: true, isEscapingTry: isEscapingTry)); |
| 405 isEscapingTry: isEscapingTry)); | |
| 406 builder._current = null; | 395 builder._current = null; |
| 407 } | 396 } |
| 408 } | 397 } |
| 409 | 398 |
| 410 /// Collect 'return' jumps. | 399 /// Collect 'return' jumps. |
| 411 /// | 400 /// |
| 412 /// A return jump is one that targets the return continuation of a function. | 401 /// A return jump is one that targets the return continuation of a function. |
| 413 /// Thus, returns from inside try/finally are not return jumps because they are | 402 /// Thus, returns from inside try/finally are not return jumps because they are |
| 414 /// intercepted by a block that contains the finally handler code. | 403 /// intercepted by a block that contains the finally handler code. |
| 415 class ReturnJumpCollector extends JumpCollector { | 404 class ReturnJumpCollector extends JumpCollector { |
| 416 bool isEmpty = true; | 405 bool isEmpty = true; |
| 417 ir.Continuation get continuation => _continuation; | 406 ir.Continuation get continuation => _continuation; |
| 418 Environment environment = null; | 407 Environment environment = null; |
| 419 | 408 |
| 420 /// Construct a return jump collector for a given return continuation. | 409 /// Construct a return jump collector for a given return continuation. |
| 421 ReturnJumpCollector(ir.Continuation continuation) : super.retrn(continuation); | 410 ReturnJumpCollector(ir.Continuation continuation) : super.retrn(continuation); |
| 422 | 411 |
| 423 void addJump(IrBuilder builder, | 412 void addJump(IrBuilder builder, |
| 424 [ir.Primitive value, SourceInformation sourceInformation]) { | 413 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 425 isEmpty = false; | 414 isEmpty = false; |
| 426 builder.add(new ir.InvokeContinuation(continuation, <ir.Primitive>[value], | 415 builder.add(new ir.InvokeContinuation(continuation, <ir.Primitive>[value], |
| 427 isEscapingTry: isEscapingTry, | 416 isEscapingTry: isEscapingTry, sourceInformation: sourceInformation)); |
| 428 sourceInformation: sourceInformation)); | |
| 429 builder._current = null; | 417 builder._current = null; |
| 430 } | 418 } |
| 431 } | 419 } |
| 432 | 420 |
| 433 /// Collect 'goto' jumps, continue to a labeled case from within a switch. | 421 /// Collect 'goto' jumps, continue to a labeled case from within a switch. |
| 434 /// | 422 /// |
| 435 /// These jumps are unrestricted within the switch. They can be forward or | 423 /// These jumps are unrestricted within the switch. They can be forward or |
| 436 /// backward. They are implemented by assigning to a state variable. | 424 /// backward. They are implemented by assigning to a state variable. |
| 437 class GotoJumpCollector extends JumpCollector { | 425 class GotoJumpCollector extends JumpCollector { |
| 438 bool isEmpty = true; | 426 bool isEmpty = true; |
| 439 final ir.Continuation continuation = null; | 427 final ir.Continuation continuation = null; |
| 440 final Environment environment = null; | 428 final Environment environment = null; |
| 441 | 429 |
| 442 int _stateVariableIndex; | 430 int _stateVariableIndex; |
| 443 int _stateValue; | 431 int _stateValue; |
| 444 JumpCollector _breakJoin; | 432 JumpCollector _breakJoin; |
| 445 | 433 |
| 446 GotoJumpCollector(JumpTarget target, this._stateVariableIndex, | 434 GotoJumpCollector(JumpTarget target, this._stateVariableIndex, |
| 447 this._stateValue, this._breakJoin) : super.goto(target); | 435 this._stateValue, this._breakJoin) |
| 436 : super.goto(target); |
| 448 | 437 |
| 449 void addJump(IrBuilder builder, | 438 void addJump(IrBuilder builder, |
| 450 [ir.Primitive value, SourceInformation sourceInformation]) { | 439 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 451 isEmpty = false; | 440 isEmpty = false; |
| 452 ir.Primitive constant = builder.buildIntegerConstant(_stateValue); | 441 ir.Primitive constant = builder.buildIntegerConstant(_stateValue); |
| 453 builder.environment.index2value[_stateVariableIndex] = constant; | 442 builder.environment.index2value[_stateVariableIndex] = constant; |
| 454 builder.jumpTo(_breakJoin); | 443 builder.jumpTo(_breakJoin); |
| 455 } | 444 } |
| 456 } | 445 } |
| 457 | 446 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 /// Mutable variables are treated as boxed. Writes to them are observable | 581 /// Mutable variables are treated as boxed. Writes to them are observable |
| 593 /// side effects. | 582 /// side effects. |
| 594 Map<Local, ir.MutableVariable> mutableVariables; | 583 Map<Local, ir.MutableVariable> mutableVariables; |
| 595 | 584 |
| 596 ir.Expression root = null; | 585 ir.Expression root = null; |
| 597 ir.Expression _current = null; | 586 ir.Expression _current = null; |
| 598 | 587 |
| 599 GlobalProgramInformation get program => state.program; | 588 GlobalProgramInformation get program => state.program; |
| 600 | 589 |
| 601 IrBuilder(GlobalProgramInformation program, | 590 IrBuilder(GlobalProgramInformation program, |
| 602 BackendConstantEnvironment constants, | 591 BackendConstantEnvironment constants, ExecutableElement currentElement) |
| 603 ExecutableElement currentElement) | 592 : state = new IrBuilderSharedState(program, constants, currentElement), |
| 604 : state = new IrBuilderSharedState(program, constants, currentElement), | 593 environment = new Environment.empty(), |
| 605 environment = new Environment.empty(), | 594 mutableVariables = <Local, ir.MutableVariable>{}; |
| 606 mutableVariables = <Local, ir.MutableVariable>{}; | |
| 607 | 595 |
| 608 IrBuilder._internal(this.state, this.environment, this.mutableVariables); | 596 IrBuilder._internal(this.state, this.environment, this.mutableVariables); |
| 609 | 597 |
| 610 /// Construct a delimited visitor for visiting a subtree. | 598 /// Construct a delimited visitor for visiting a subtree. |
| 611 /// | 599 /// |
| 612 /// Build a subterm that is not (yet) connected to the CPS term. The | 600 /// Build a subterm that is not (yet) connected to the CPS term. The |
| 613 /// delimited visitor has its own has its own context for building an IR | 601 /// delimited visitor has its own has its own context for building an IR |
| 614 /// expression, so the built expression is not plugged into the parent's | 602 /// expression, so the built expression is not plugged into the parent's |
| 615 /// context. It has its own compile-time environment mapping local | 603 /// context. It has its own compile-time environment mapping local |
| 616 /// variables to their values. If an optional environment argument is | 604 /// variables to their values. If an optional environment argument is |
| 617 /// supplied, it is used as the builder's initial environment. Otherwise | 605 /// supplied, it is used as the builder's initial environment. Otherwise |
| 618 /// the environment is initially a copy of the parent builder's environment. | 606 /// the environment is initially a copy of the parent builder's environment. |
| 619 IrBuilder makeDelimitedBuilder([Environment env = null]) { | 607 IrBuilder makeDelimitedBuilder([Environment env = null]) { |
| 620 return new IrBuilder._internal( | 608 return new IrBuilder._internal( |
| 621 state, | 609 state, |
| 622 env != null ? env : new Environment.from(environment), | 610 env != null ? env : new Environment.from(environment), |
| 623 mutableVariables); | 611 mutableVariables); |
| 624 } | 612 } |
| 625 | 613 |
| 626 /// True if [local] should currently be accessed from a [ir.MutableVariable]. | 614 /// True if [local] should currently be accessed from a [ir.MutableVariable]. |
| 627 bool isInMutableVariable(Local local) { | 615 bool isInMutableVariable(Local local) { |
| 628 return mutableVariables.containsKey(local); | 616 return mutableVariables.containsKey(local); |
| 629 } | 617 } |
| 630 | 618 |
| 631 /// Creates a [ir.MutableVariable] for the given local. | 619 /// Creates a [ir.MutableVariable] for the given local. |
| 632 void makeMutableVariable(Local local) { | 620 void makeMutableVariable(Local local) { |
| 633 mutableVariables[local] = | 621 mutableVariables[local] = new ir.MutableVariable(local); |
| 634 new ir.MutableVariable(local); | |
| 635 } | 622 } |
| 636 | 623 |
| 637 /// Remove an [ir.MutableVariable] for a local. | 624 /// Remove an [ir.MutableVariable] for a local. |
| 638 /// | 625 /// |
| 639 /// Subsequent access to the local will be direct rather than through the | 626 /// Subsequent access to the local will be direct rather than through the |
| 640 /// mutable variable. | 627 /// mutable variable. |
| 641 void removeMutableVariable(Local local) { | 628 void removeMutableVariable(Local local) { |
| 642 mutableVariables.remove(local); | 629 mutableVariables.remove(local); |
| 643 } | 630 } |
| 644 | 631 |
| 645 /// Gets the [MutableVariable] containing the value of [local]. | 632 /// Gets the [MutableVariable] containing the value of [local]. |
| 646 ir.MutableVariable getMutableVariable(Local local) { | 633 ir.MutableVariable getMutableVariable(Local local) { |
| 647 return mutableVariables[local]; | 634 return mutableVariables[local]; |
| 648 } | 635 } |
| 649 | 636 |
| 650 bool get isOpen => root == null || _current != null; | 637 bool get isOpen => root == null || _current != null; |
| 651 | 638 |
| 652 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, | 639 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, |
| 653 {ClosureScope closureScope, | 640 {ClosureScope closureScope, ClosureEnvironment env}) { |
| 654 ClosureEnvironment env}) { | |
| 655 _createThisParameter(); | 641 _createThisParameter(); |
| 656 _enterClosureEnvironment(env); | 642 _enterClosureEnvironment(env); |
| 657 _enterScope(closureScope); | 643 _enterScope(closureScope); |
| 658 parameters.forEach(_createFunctionParameter); | 644 parameters.forEach(_createFunctionParameter); |
| 659 return _parameters; | 645 return _parameters; |
| 660 } | 646 } |
| 661 | 647 |
| 662 /// Creates a parameter for [local] and adds it to the current environment. | 648 /// Creates a parameter for [local] and adds it to the current environment. |
| 663 ir.Parameter _createLocalParameter(Local local) { | 649 ir.Parameter _createLocalParameter(Local local) { |
| 664 ir.Parameter parameter = new ir.Parameter(local); | 650 ir.Parameter parameter = new ir.Parameter(local); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 680 _current = _current.plug(expr); | 666 _current = _current.plug(expr); |
| 681 } | 667 } |
| 682 } | 668 } |
| 683 | 669 |
| 684 /// Create and add a new [LetPrim] for [primitive]. | 670 /// Create and add a new [LetPrim] for [primitive]. |
| 685 ir.Primitive addPrimitive(ir.Primitive primitive) { | 671 ir.Primitive addPrimitive(ir.Primitive primitive) { |
| 686 add(new ir.LetPrim(primitive)); | 672 add(new ir.LetPrim(primitive)); |
| 687 return primitive; | 673 return primitive; |
| 688 } | 674 } |
| 689 | 675 |
| 690 ir.Primitive buildInvokeStatic(Element element, | 676 ir.Primitive buildInvokeStatic(Element element, Selector selector, |
| 691 Selector selector, | 677 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 692 List<ir.Primitive> arguments, | |
| 693 SourceInformation sourceInformation) { | |
| 694 assert(!element.isLocal); | 678 assert(!element.isLocal); |
| 695 assert(!element.isInstanceMember); | 679 assert(!element.isInstanceMember); |
| 696 assert(isOpen); | 680 assert(isOpen); |
| 697 if (program.isJsInterop(element)) { | 681 if (program.isJsInterop(element)) { |
| 698 return buildInvokeJsInteropMember(element, arguments, sourceInformation); | 682 return buildInvokeJsInteropMember(element, arguments, sourceInformation); |
| 699 } | 683 } |
| 700 return addPrimitive( | 684 return addPrimitive( |
| 701 new ir.InvokeStatic(element, selector, arguments, sourceInformation)); | 685 new ir.InvokeStatic(element, selector, arguments, sourceInformation)); |
| 702 } | 686 } |
| 703 | 687 |
| 704 ir.Primitive _buildInvokeSuper(Element target, | 688 ir.Primitive _buildInvokeSuper(Element target, Selector selector, |
| 705 Selector selector, | 689 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 706 List<ir.Primitive> arguments, | |
| 707 SourceInformation sourceInformation) { | |
| 708 assert(target.isInstanceMember); | 690 assert(target.isInstanceMember); |
| 709 assert(isOpen); | 691 assert(isOpen); |
| 710 return addPrimitive(new ir.InvokeMethodDirectly( | 692 return addPrimitive(new ir.InvokeMethodDirectly( |
| 711 buildThis(), target, selector, arguments, sourceInformation)); | 693 buildThis(), target, selector, arguments, sourceInformation)); |
| 712 } | 694 } |
| 713 | 695 |
| 714 ir.Primitive _buildInvokeDynamic(ir.Primitive receiver, | 696 ir.Primitive _buildInvokeDynamic( |
| 715 Selector selector, | 697 ir.Primitive receiver, |
| 716 TypeMask mask, | 698 Selector selector, |
| 717 List<ir.Primitive> arguments, | 699 TypeMask mask, |
| 718 SourceInformation sourceInformation) { | 700 List<ir.Primitive> arguments, |
| 701 SourceInformation sourceInformation) { |
| 719 assert(isOpen); | 702 assert(isOpen); |
| 720 return addPrimitive(new ir.InvokeMethod( | 703 return addPrimitive(new ir.InvokeMethod(receiver, selector, mask, arguments, |
| 721 receiver, selector, mask, arguments, | |
| 722 sourceInformation: sourceInformation)); | 704 sourceInformation: sourceInformation)); |
| 723 } | 705 } |
| 724 | 706 |
| 725 ir.Primitive _buildInvokeCall(ir.Primitive target, | 707 ir.Primitive _buildInvokeCall( |
| 726 CallStructure callStructure, | 708 ir.Primitive target, |
| 727 TypeMask mask, | 709 CallStructure callStructure, |
| 728 List<ir.Definition> arguments, | 710 TypeMask mask, |
| 729 SourceInformation sourceInformation) { | 711 List<ir.Definition> arguments, |
| 712 SourceInformation sourceInformation) { |
| 730 Selector selector = callStructure.callSelector; | 713 Selector selector = callStructure.callSelector; |
| 731 return _buildInvokeDynamic( | 714 return _buildInvokeDynamic( |
| 732 target, selector, mask, arguments, sourceInformation); | 715 target, selector, mask, arguments, sourceInformation); |
| 733 } | 716 } |
| 734 | 717 |
| 735 ir.Primitive buildStaticNoSuchMethod( | 718 ir.Primitive buildStaticNoSuchMethod(Selector selector, |
| 736 Selector selector, | 719 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 737 List<ir.Primitive> arguments, | |
| 738 SourceInformation sourceInformation) { | |
| 739 ir.Primitive receiver = buildStringConstant(''); | 720 ir.Primitive receiver = buildStringConstant(''); |
| 740 ir.Primitive name = buildStringConstant(selector.name); | 721 ir.Primitive name = buildStringConstant(selector.name); |
| 741 ir.Primitive argumentList = buildListLiteral(null, arguments); | 722 ir.Primitive argumentList = buildListLiteral(null, arguments); |
| 742 ir.Primitive expectedArgumentNames = buildNullConstant(); | 723 ir.Primitive expectedArgumentNames = buildNullConstant(); |
| 743 return buildStaticFunctionInvocation( | 724 return buildStaticFunctionInvocation( |
| 744 program.throwNoSuchMethod, | 725 program.throwNoSuchMethod, |
| 745 <ir.Primitive>[receiver, name, argumentList, expectedArgumentNames], | 726 <ir.Primitive>[receiver, name, argumentList, expectedArgumentNames], |
| 746 sourceInformation); | 727 sourceInformation); |
| 747 } | 728 } |
| 748 | 729 |
| 749 /// Create a [ir.Constant] from [value] and add it to the CPS term. | 730 /// Create a [ir.Constant] from [value] and add it to the CPS term. |
| 750 ir.Constant buildConstant(ConstantValue value, | 731 ir.Constant buildConstant(ConstantValue value, |
| 751 {SourceInformation sourceInformation}) { | 732 {SourceInformation sourceInformation}) { |
| 752 assert(isOpen); | 733 assert(isOpen); |
| 753 return addPrimitive( | 734 return addPrimitive( |
| 754 new ir.Constant(value, sourceInformation: sourceInformation)); | 735 new ir.Constant(value, sourceInformation: sourceInformation)); |
| 755 } | 736 } |
| 756 | 737 |
| 757 /// Create an integer constant and add it to the CPS term. | 738 /// Create an integer constant and add it to the CPS term. |
| 758 ir.Constant buildIntegerConstant(int value) { | 739 ir.Constant buildIntegerConstant(int value) { |
| 759 return buildConstant(state.constantSystem.createInt(value)); | 740 return buildConstant(state.constantSystem.createInt(value)); |
| 760 } | 741 } |
| 761 | 742 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 780 state.constantSystem.createString(new ast.DartString.literal(value))); | 761 state.constantSystem.createString(new ast.DartString.literal(value))); |
| 781 } | 762 } |
| 782 | 763 |
| 783 /// Create a string constant and add it to the CPS term. | 764 /// Create a string constant and add it to the CPS term. |
| 784 ir.Constant buildDartStringConstant(ast.DartString value) { | 765 ir.Constant buildDartStringConstant(ast.DartString value) { |
| 785 return buildConstant(state.constantSystem.createString(value)); | 766 return buildConstant(state.constantSystem.createString(value)); |
| 786 } | 767 } |
| 787 | 768 |
| 788 /// Creates a non-constant list literal of the provided [type] and with the | 769 /// Creates a non-constant list literal of the provided [type] and with the |
| 789 /// provided [values]. | 770 /// provided [values]. |
| 790 ir.Primitive buildListLiteral(InterfaceType type, | 771 ir.Primitive buildListLiteral( |
| 791 Iterable<ir.Primitive> values, | 772 InterfaceType type, Iterable<ir.Primitive> values, |
| 792 {TypeMask allocationSiteType}) { | 773 {TypeMask allocationSiteType}) { |
| 793 assert(isOpen); | 774 assert(isOpen); |
| 794 return addPrimitive(new ir.LiteralList(type, values.toList(), | 775 return addPrimitive(new ir.LiteralList(type, values.toList(), |
| 795 allocationSiteType: allocationSiteType)); | 776 allocationSiteType: allocationSiteType)); |
| 796 } | 777 } |
| 797 | 778 |
| 798 /// Creates a conditional expression with the provided [condition] where the | 779 /// Creates a conditional expression with the provided [condition] where the |
| 799 /// then and else expression are created through the [buildThenExpression] | 780 /// then and else expression are created through the [buildThenExpression] |
| 800 /// and [buildElseExpression] functions, respectively. | 781 /// and [buildElseExpression] functions, respectively. |
| 801 ir.Primitive buildConditional( | 782 ir.Primitive buildConditional( |
| 802 ir.Primitive condition, | 783 ir.Primitive condition, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 825 // Build the term | 806 // Build the term |
| 826 // let cont join(x, ..., result) = [] in | 807 // let cont join(x, ..., result) = [] in |
| 827 // let cont then() = [[thenPart]]; join(v, ...) | 808 // let cont then() = [[thenPart]]; join(v, ...) |
| 828 // and else() = [[elsePart]]; join(v, ...) | 809 // and else() = [[elsePart]]; join(v, ...) |
| 829 // in | 810 // in |
| 830 // if condition (then, else) | 811 // if condition (then, else) |
| 831 ir.Continuation thenContinuation = new ir.Continuation([]); | 812 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 832 ir.Continuation elseContinuation = new ir.Continuation([]); | 813 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 833 thenContinuation.body = thenBuilder.root; | 814 thenContinuation.body = thenBuilder.root; |
| 834 elseContinuation.body = elseBuilder.root; | 815 elseContinuation.body = elseBuilder.root; |
| 835 add(new ir.LetCont(join.continuation, | 816 add(new ir.LetCont( |
| 836 new ir.LetCont.two(thenContinuation, elseContinuation, | 817 join.continuation, |
| 837 new ir.Branch.strict(condition, | 818 new ir.LetCont.two( |
| 838 thenContinuation, | 819 thenContinuation, |
| 839 elseContinuation, | 820 elseContinuation, |
| 840 sourceInformation)))); | 821 new ir.Branch.strict(condition, thenContinuation, elseContinuation, |
| 822 sourceInformation)))); |
| 841 environment = join.environment; | 823 environment = join.environment; |
| 842 return environment.discard(1); | 824 return environment.discard(1); |
| 843 } | 825 } |
| 844 | 826 |
| 845 /** | 827 /** |
| 846 * Add an explicit `return null` for functions that don't have a return | 828 * Add an explicit `return null` for functions that don't have a return |
| 847 * statement on each branch. This includes functions with an empty body, | 829 * statement on each branch. This includes functions with an empty body, |
| 848 * such as `foo(){ }`. | 830 * such as `foo(){ }`. |
| 849 */ | 831 */ |
| 850 void _ensureReturn() { | 832 void _ensureReturn() { |
| 851 if (!isOpen) return; | 833 if (!isOpen) return; |
| 852 ir.Constant constant = buildNullConstant(); | 834 ir.Constant constant = buildNullConstant(); |
| 853 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); | 835 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); |
| 854 _current = null; | 836 _current = null; |
| 855 } | 837 } |
| 856 | 838 |
| 857 /// Create a [ir.FunctionDefinition] using [root] as the body. | 839 /// Create a [ir.FunctionDefinition] using [root] as the body. |
| 858 /// | 840 /// |
| 859 /// The protocol for building a function is: | 841 /// The protocol for building a function is: |
| 860 /// 1. Call [buildFunctionHeader]. | 842 /// 1. Call [buildFunctionHeader]. |
| 861 /// 2. Call `buildXXX` methods to build the body. | 843 /// 2. Call `buildXXX` methods to build the body. |
| 862 /// 3. Call [makeFunctionDefinition] to finish. | 844 /// 3. Call [makeFunctionDefinition] to finish. |
| 863 ir.FunctionDefinition makeFunctionDefinition( | 845 ir.FunctionDefinition makeFunctionDefinition( |
| 864 SourceInformation sourceInformation) { | 846 SourceInformation sourceInformation) { |
| 865 _ensureReturn(); | 847 _ensureReturn(); |
| 866 return new ir.FunctionDefinition( | 848 return new ir.FunctionDefinition(state.currentElement, state.thisParameter, |
| 867 state.currentElement, | 849 state.functionParameters, state.returnContinuation, root, |
| 868 state.thisParameter, | |
| 869 state.functionParameters, | |
| 870 state.returnContinuation, | |
| 871 root, | |
| 872 sourceInformation: sourceInformation); | 850 sourceInformation: sourceInformation); |
| 873 } | 851 } |
| 874 | 852 |
| 875 /// Create a invocation of the [method] on the super class where the call | 853 /// Create a invocation of the [method] on the super class where the call |
| 876 /// structure is defined [callStructure] and the argument values are defined | 854 /// structure is defined [callStructure] and the argument values are defined |
| 877 /// by [arguments]. | 855 /// by [arguments]. |
| 878 ir.Primitive buildSuperMethodInvocation( | 856 ir.Primitive buildSuperMethodInvocation( |
| 879 MethodElement method, | 857 MethodElement method, |
| 880 CallStructure callStructure, | 858 CallStructure callStructure, |
| 881 List<ir.Primitive> arguments, | 859 List<ir.Primitive> arguments, |
| 882 SourceInformation sourceInformation) { | 860 SourceInformation sourceInformation) { |
| 883 // TODO(johnniwinther): This shouldn't be necessary. | 861 // TODO(johnniwinther): This shouldn't be necessary. |
| 884 SelectorKind kind = Elements.isOperatorName(method.name) | 862 SelectorKind kind = Elements.isOperatorName(method.name) |
| 885 ? SelectorKind.OPERATOR : SelectorKind.CALL; | 863 ? SelectorKind.OPERATOR |
| 886 Selector selector = | 864 : SelectorKind.CALL; |
| 887 new Selector(kind, method.memberName, callStructure); | 865 Selector selector = new Selector(kind, method.memberName, callStructure); |
| 888 return _buildInvokeSuper(method, selector, arguments, sourceInformation); | 866 return _buildInvokeSuper(method, selector, arguments, sourceInformation); |
| 889 } | 867 } |
| 890 | 868 |
| 891 /// Create a read access of the [method] on the super class, i.e. a | 869 /// Create a read access of the [method] on the super class, i.e. a |
| 892 /// closurization of [method]. | 870 /// closurization of [method]. |
| 893 ir.Primitive buildSuperMethodGet(MethodElement method, | 871 ir.Primitive buildSuperMethodGet( |
| 894 SourceInformation sourceInformation) { | 872 MethodElement method, SourceInformation sourceInformation) { |
| 895 // TODO(johnniwinther): This should have its own ir node. | 873 // TODO(johnniwinther): This should have its own ir node. |
| 896 return _buildInvokeSuper( | 874 return _buildInvokeSuper(method, new Selector.getter(method.memberName), |
| 897 method, | 875 const <ir.Primitive>[], sourceInformation); |
| 898 new Selector.getter(method.memberName), | |
| 899 const <ir.Primitive>[], | |
| 900 sourceInformation); | |
| 901 } | 876 } |
| 902 | 877 |
| 903 /// Create a getter invocation of the [getter] on the super class. | 878 /// Create a getter invocation of the [getter] on the super class. |
| 904 ir.Primitive buildSuperGetterGet(MethodElement getter, | 879 ir.Primitive buildSuperGetterGet( |
| 905 SourceInformation sourceInformation) { | 880 MethodElement getter, SourceInformation sourceInformation) { |
| 906 // TODO(johnniwinther): This should have its own ir node. | 881 // TODO(johnniwinther): This should have its own ir node. |
| 907 return _buildInvokeSuper( | 882 return _buildInvokeSuper(getter, new Selector.getter(getter.memberName), |
| 908 getter, | 883 const <ir.Primitive>[], sourceInformation); |
| 909 new Selector.getter(getter.memberName), | |
| 910 const <ir.Primitive>[], | |
| 911 sourceInformation); | |
| 912 } | 884 } |
| 913 | 885 |
| 914 /// Create an setter invocation of the [setter] on the super class with | 886 /// Create an setter invocation of the [setter] on the super class with |
| 915 /// [value]. | 887 /// [value]. |
| 916 ir.Primitive buildSuperSetterSet(MethodElement setter, | 888 ir.Primitive buildSuperSetterSet(MethodElement setter, ir.Primitive value, |
| 917 ir.Primitive value, | 889 SourceInformation sourceInformation) { |
| 918 SourceInformation sourceInformation) { | |
| 919 // TODO(johnniwinther): This should have its own ir node. | 890 // TODO(johnniwinther): This should have its own ir node. |
| 920 _buildInvokeSuper( | 891 _buildInvokeSuper(setter, new Selector.setter(setter.memberName), |
| 921 setter, | 892 <ir.Primitive>[value], sourceInformation); |
| 922 new Selector.setter(setter.memberName), | |
| 923 <ir.Primitive>[value], | |
| 924 sourceInformation); | |
| 925 return value; | 893 return value; |
| 926 } | 894 } |
| 927 | 895 |
| 928 /// Create an invocation of the index [method] on the super class with | 896 /// Create an invocation of the index [method] on the super class with |
| 929 /// the provided [index]. | 897 /// the provided [index]. |
| 930 ir.Primitive buildSuperIndex(MethodElement method, | 898 ir.Primitive buildSuperIndex(MethodElement method, ir.Primitive index, |
| 931 ir.Primitive index, | 899 SourceInformation sourceInformation) { |
| 932 SourceInformation sourceInformation) { | |
| 933 return _buildInvokeSuper( | 900 return _buildInvokeSuper( |
| 934 method, new Selector.index(), <ir.Primitive>[index], | 901 method, new Selector.index(), <ir.Primitive>[index], sourceInformation); |
| 935 sourceInformation); | |
| 936 } | 902 } |
| 937 | 903 |
| 938 /// Create an invocation of the index set [method] on the super class with | 904 /// Create an invocation of the index set [method] on the super class with |
| 939 /// the provided [index] and [value]. | 905 /// the provided [index] and [value]. |
| 940 ir.Primitive buildSuperIndexSet(MethodElement method, | 906 ir.Primitive buildSuperIndexSet(MethodElement method, ir.Primitive index, |
| 941 ir.Primitive index, | 907 ir.Primitive value, SourceInformation sourceInformation) { |
| 942 ir.Primitive value, | |
| 943 SourceInformation sourceInformation) { | |
| 944 _buildInvokeSuper(method, new Selector.indexSet(), | 908 _buildInvokeSuper(method, new Selector.indexSet(), |
| 945 <ir.Primitive>[index, value], sourceInformation); | 909 <ir.Primitive>[index, value], sourceInformation); |
| 946 return value; | 910 return value; |
| 947 } | 911 } |
| 948 | 912 |
| 949 /// Create a dynamic invocation on [receiver] where the method name and | 913 /// Create a dynamic invocation on [receiver] where the method name and |
| 950 /// argument structure are defined by [selector] and the argument values are | 914 /// argument structure are defined by [selector] and the argument values are |
| 951 /// defined by [arguments]. | 915 /// defined by [arguments]. |
| 952 ir.Primitive buildDynamicInvocation(ir.Primitive receiver, | 916 ir.Primitive buildDynamicInvocation( |
| 953 Selector selector, | 917 ir.Primitive receiver, |
| 954 TypeMask mask, | 918 Selector selector, |
| 955 List<ir.Primitive> arguments, | 919 TypeMask mask, |
| 956 SourceInformation sourceInformation) { | 920 List<ir.Primitive> arguments, |
| 921 SourceInformation sourceInformation) { |
| 957 return _buildInvokeDynamic( | 922 return _buildInvokeDynamic( |
| 958 receiver, selector, mask, arguments, sourceInformation); | 923 receiver, selector, mask, arguments, sourceInformation); |
| 959 } | 924 } |
| 960 | 925 |
| 961 /// Create a dynamic getter invocation on [receiver] where the getter name is | 926 /// Create a dynamic getter invocation on [receiver] where the getter name is |
| 962 /// defined by [selector]. | 927 /// defined by [selector]. |
| 963 ir.Primitive buildDynamicGet(ir.Primitive receiver, | 928 ir.Primitive buildDynamicGet(ir.Primitive receiver, Selector selector, |
| 964 Selector selector, | 929 TypeMask mask, SourceInformation sourceInformation) { |
| 965 TypeMask mask, | |
| 966 SourceInformation sourceInformation) { | |
| 967 assert(selector.isGetter); | 930 assert(selector.isGetter); |
| 968 FieldElement field = program.locateSingleField(selector, mask); | 931 FieldElement field = program.locateSingleField(selector, mask); |
| 969 if (field != null) { | 932 if (field != null) { |
| 970 // If the world says this resolves to a unique field, then it MUST be | 933 // If the world says this resolves to a unique field, then it MUST be |
| 971 // treated as a field access, since the getter might not be emitted. | 934 // treated as a field access, since the getter might not be emitted. |
| 972 return buildFieldGet(receiver, field, sourceInformation); | 935 return buildFieldGet(receiver, field, sourceInformation); |
| 973 } else { | 936 } else { |
| 974 return _buildInvokeDynamic( | 937 return _buildInvokeDynamic( |
| 975 receiver, selector, mask, const <ir.Primitive>[], sourceInformation); | 938 receiver, selector, mask, const <ir.Primitive>[], sourceInformation); |
| 976 } | 939 } |
| 977 } | 940 } |
| 978 | 941 |
| 979 /// Create a dynamic setter invocation on [receiver] where the setter name and | 942 /// Create a dynamic setter invocation on [receiver] where the setter name and |
| 980 /// argument are defined by [selector] and [value], respectively. | 943 /// argument are defined by [selector] and [value], respectively. |
| 981 ir.Primitive buildDynamicSet(ir.Primitive receiver, | 944 ir.Primitive buildDynamicSet(ir.Primitive receiver, Selector selector, |
| 982 Selector selector, | 945 TypeMask mask, ir.Primitive value, SourceInformation sourceInformation) { |
| 983 TypeMask mask, | |
| 984 ir.Primitive value, | |
| 985 SourceInformation sourceInformation) { | |
| 986 assert(selector.isSetter); | 946 assert(selector.isSetter); |
| 987 FieldElement field = program.locateSingleField(selector, mask); | 947 FieldElement field = program.locateSingleField(selector, mask); |
| 988 if (field != null) { | 948 if (field != null) { |
| 989 // If the world says this resolves to a unique field, then it MUST be | 949 // If the world says this resolves to a unique field, then it MUST be |
| 990 // treated as a field access, since the setter might not be emitted. | 950 // treated as a field access, since the setter might not be emitted. |
| 991 buildFieldSet(receiver, field, value, sourceInformation); | 951 buildFieldSet(receiver, field, value, sourceInformation); |
| 992 } else { | 952 } else { |
| 993 _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value], | 953 _buildInvokeDynamic( |
| 994 sourceInformation); | 954 receiver, selector, mask, <ir.Primitive>[value], sourceInformation); |
| 995 } | 955 } |
| 996 return value; | 956 return value; |
| 997 } | 957 } |
| 998 | 958 |
| 999 /// Create a dynamic index set invocation on [receiver] with the provided | 959 /// Create a dynamic index set invocation on [receiver] with the provided |
| 1000 /// [index] and [value]. | 960 /// [index] and [value]. |
| 1001 ir.Primitive buildDynamicIndexSet(ir.Primitive receiver, | 961 ir.Primitive buildDynamicIndexSet( |
| 1002 TypeMask mask, | 962 ir.Primitive receiver, |
| 1003 ir.Primitive index, | 963 TypeMask mask, |
| 1004 ir.Primitive value, | 964 ir.Primitive index, |
| 1005 SourceInformation sourceInformation) { | 965 ir.Primitive value, |
| 1006 _buildInvokeDynamic( | 966 SourceInformation sourceInformation) { |
| 1007 receiver, new Selector.indexSet(), mask, <ir.Primitive>[index, value], | 967 _buildInvokeDynamic(receiver, new Selector.indexSet(), mask, |
| 1008 sourceInformation); | 968 <ir.Primitive>[index, value], sourceInformation); |
| 1009 return value; | 969 return value; |
| 1010 } | 970 } |
| 1011 | 971 |
| 1012 /// Create an invocation of the local [function] where argument structure is | 972 /// Create an invocation of the local [function] where argument structure is |
| 1013 /// defined by [callStructure] and the argument values are defined by | 973 /// defined by [callStructure] and the argument values are defined by |
| 1014 /// [arguments]. | 974 /// [arguments]. |
| 1015 ir.Primitive buildLocalFunctionInvocation( | 975 ir.Primitive buildLocalFunctionInvocation( |
| 1016 LocalFunctionElement function, | 976 LocalFunctionElement function, |
| 1017 CallStructure callStructure, | 977 CallStructure callStructure, |
| 1018 List<ir.Primitive> arguments, | 978 List<ir.Primitive> arguments, |
| 1019 SourceInformation sourceInformation) { | 979 SourceInformation sourceInformation) { |
| 1020 // TODO(johnniwinther): Maybe this should have its own ir node. | 980 // TODO(johnniwinther): Maybe this should have its own ir node. |
| 1021 return buildCallInvocation( | 981 return buildCallInvocation( |
| 1022 buildLocalGet(function), callStructure, arguments, | 982 buildLocalGet(function), callStructure, arguments, sourceInformation); |
| 1023 sourceInformation); | |
| 1024 } | 983 } |
| 1025 | 984 |
| 1026 /// Create a static invocation of [function]. | 985 /// Create a static invocation of [function]. |
| 1027 /// | 986 /// |
| 1028 /// The arguments are not named and their values are defined by [arguments]. | 987 /// The arguments are not named and their values are defined by [arguments]. |
| 1029 ir.Primitive buildStaticFunctionInvocation( | 988 ir.Primitive buildStaticFunctionInvocation(MethodElement function, |
| 1030 MethodElement function, | 989 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 1031 List<ir.Primitive> arguments, | |
| 1032 SourceInformation sourceInformation) { | |
| 1033 Selector selector = new Selector.call( | 990 Selector selector = new Selector.call( |
| 1034 function.memberName, new CallStructure(arguments.length)); | 991 function.memberName, new CallStructure(arguments.length)); |
| 1035 return buildInvokeStatic(function, selector, arguments, sourceInformation); | 992 return buildInvokeStatic(function, selector, arguments, sourceInformation); |
| 1036 } | 993 } |
| 1037 | 994 |
| 1038 /// Create a getter invocation of the static [getter]. | 995 /// Create a getter invocation of the static [getter]. |
| 1039 ir.Primitive buildStaticGetterGet(MethodElement getter, | 996 ir.Primitive buildStaticGetterGet( |
| 1040 SourceInformation sourceInformation) { | 997 MethodElement getter, SourceInformation sourceInformation) { |
| 1041 Selector selector = new Selector.getter(getter.memberName); | 998 Selector selector = new Selector.getter(getter.memberName); |
| 1042 return buildInvokeStatic( | 999 return buildInvokeStatic( |
| 1043 getter, selector, const <ir.Primitive>[], sourceInformation); | 1000 getter, selector, const <ir.Primitive>[], sourceInformation); |
| 1044 } | 1001 } |
| 1045 | 1002 |
| 1046 /// Create a write access to the static [field] with the [value]. | 1003 /// Create a write access to the static [field] with the [value]. |
| 1047 ir.Primitive buildStaticFieldSet(FieldElement field, | 1004 ir.Primitive buildStaticFieldSet(FieldElement field, ir.Primitive value, |
| 1048 ir.Primitive value, | 1005 SourceInformation sourceInformation) { |
| 1049 SourceInformation sourceInformation) { | |
| 1050 addPrimitive(new ir.SetStatic(field, value, sourceInformation)); | 1006 addPrimitive(new ir.SetStatic(field, value, sourceInformation)); |
| 1051 return value; | 1007 return value; |
| 1052 } | 1008 } |
| 1053 | 1009 |
| 1054 /// Create a setter invocation of the static [setter] with the [value]. | 1010 /// Create a setter invocation of the static [setter] with the [value]. |
| 1055 ir.Primitive buildStaticSetterSet(MethodElement setter, | 1011 ir.Primitive buildStaticSetterSet(MethodElement setter, ir.Primitive value, |
| 1056 ir.Primitive value, | 1012 SourceInformation sourceInformation) { |
| 1057 SourceInformation sourceInformation) { | |
| 1058 Selector selector = new Selector.setter(setter.memberName); | 1013 Selector selector = new Selector.setter(setter.memberName); |
| 1059 buildInvokeStatic( | 1014 buildInvokeStatic( |
| 1060 setter, selector, <ir.Primitive>[value], sourceInformation); | 1015 setter, selector, <ir.Primitive>[value], sourceInformation); |
| 1061 return value; | 1016 return value; |
| 1062 } | 1017 } |
| 1063 | 1018 |
| 1064 /// Create an erroneous invocation where argument structure is defined by | 1019 /// Create an erroneous invocation where argument structure is defined by |
| 1065 /// [selector] and the argument values are defined by [arguments]. | 1020 /// [selector] and the argument values are defined by [arguments]. |
| 1066 // TODO(johnniwinther): Make this more fine-grained. | 1021 // TODO(johnniwinther): Make this more fine-grained. |
| 1067 ir.Primitive buildErroneousInvocation( | 1022 ir.Primitive buildErroneousInvocation(Element element, Selector selector, |
| 1068 Element element, | 1023 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 1069 Selector selector, | |
| 1070 List<ir.Primitive> arguments, | |
| 1071 SourceInformation sourceInformation) { | |
| 1072 // TODO(johnniwinther): This should have its own ir node. | 1024 // TODO(johnniwinther): This should have its own ir node. |
| 1073 return buildInvokeStatic(element, selector, arguments, sourceInformation); | 1025 return buildInvokeStatic(element, selector, arguments, sourceInformation); |
| 1074 } | 1026 } |
| 1075 | 1027 |
| 1076 /// Concatenate string values. The arguments must be strings. | 1028 /// Concatenate string values. The arguments must be strings. |
| 1077 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments, | 1029 ir.Primitive buildStringConcatenation( |
| 1078 SourceInformation sourceInformation) { | 1030 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 1079 assert(isOpen); | 1031 assert(isOpen); |
| 1080 return addPrimitive(new ir.ApplyBuiltinOperator( | 1032 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 1081 ir.BuiltinOperator.StringConcatenate, | 1033 ir.BuiltinOperator.StringConcatenate, arguments, sourceInformation)); |
| 1082 arguments, | |
| 1083 sourceInformation)); | |
| 1084 } | 1034 } |
| 1085 | 1035 |
| 1086 /// Create an invocation of the `call` method of [functionExpression], where | 1036 /// Create an invocation of the `call` method of [functionExpression], where |
| 1087 /// the structure of arguments are given by [callStructure]. | 1037 /// the structure of arguments are given by [callStructure]. |
| 1088 // TODO(johnniwinther): This should take a [TypeMask]. | 1038 // TODO(johnniwinther): This should take a [TypeMask]. |
| 1089 ir.Primitive buildCallInvocation( | 1039 ir.Primitive buildCallInvocation( |
| 1090 ir.Primitive functionExpression, | 1040 ir.Primitive functionExpression, |
| 1091 CallStructure callStructure, | 1041 CallStructure callStructure, |
| 1092 List<ir.Definition> arguments, | 1042 List<ir.Definition> arguments, |
| 1093 SourceInformation sourceInformation) { | 1043 SourceInformation sourceInformation) { |
| 1094 return _buildInvokeCall( | 1044 return _buildInvokeCall( |
| 1095 functionExpression, callStructure, null, arguments, sourceInformation); | 1045 functionExpression, callStructure, null, arguments, sourceInformation); |
| 1096 } | 1046 } |
| 1097 | 1047 |
| 1098 /// Creates an if-then-else statement with the provided [condition] where the | 1048 /// Creates an if-then-else statement with the provided [condition] where the |
| 1099 /// then and else branches are created through the [buildThenPart] and | 1049 /// then and else branches are created through the [buildThenPart] and |
| 1100 /// [buildElsePart] functions, respectively. | 1050 /// [buildElsePart] functions, respectively. |
| 1101 /// | 1051 /// |
| 1102 /// An if-then statement is created if [buildElsePart] is a no-op. | 1052 /// An if-then statement is created if [buildElsePart] is a no-op. |
| 1103 // TODO(johnniwinther): Unify implementation with [buildConditional] and | 1053 // TODO(johnniwinther): Unify implementation with [buildConditional] and |
| 1104 // [_buildLogicalOperator]. | 1054 // [_buildLogicalOperator]. |
| 1105 void buildIf(ir.Primitive condition, | 1055 void buildIf( |
| 1106 void buildThenPart(IrBuilder builder), | 1056 ir.Primitive condition, |
| 1107 void buildElsePart(IrBuilder builder), | 1057 void buildThenPart(IrBuilder builder), |
| 1108 SourceInformation sourceInformation) { | 1058 void buildElsePart(IrBuilder builder), |
| 1059 SourceInformation sourceInformation) { |
| 1109 assert(isOpen); | 1060 assert(isOpen); |
| 1110 | 1061 |
| 1111 // The then and else parts are delimited. | 1062 // The then and else parts are delimited. |
| 1112 IrBuilder thenBuilder = makeDelimitedBuilder(); | 1063 IrBuilder thenBuilder = makeDelimitedBuilder(); |
| 1113 IrBuilder elseBuilder = makeDelimitedBuilder(); | 1064 IrBuilder elseBuilder = makeDelimitedBuilder(); |
| 1114 buildThenPart(thenBuilder); | 1065 buildThenPart(thenBuilder); |
| 1115 buildElsePart(elseBuilder); | 1066 buildElsePart(elseBuilder); |
| 1116 | 1067 |
| 1117 // Build the term | 1068 // Build the term |
| 1118 // (Result =) let cont then() = [[thenPart]] | 1069 // (Result =) let cont then() = [[thenPart]] |
| 1119 // and else() = [[elsePart]] | 1070 // and else() = [[elsePart]] |
| 1120 // in | 1071 // in |
| 1121 // if condition (then, else) | 1072 // if condition (then, else) |
| 1122 ir.Continuation thenContinuation = new ir.Continuation([]); | 1073 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1123 ir.Continuation elseContinuation = new ir.Continuation([]); | 1074 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1124 // If exactly one of the then and else continuation bodies is open (i.e., | 1075 // If exactly one of the then and else continuation bodies is open (i.e., |
| 1125 // the other one has an exit on all paths), then Continuation.plug expects | 1076 // the other one has an exit on all paths), then Continuation.plug expects |
| 1126 // that continuation to be listed first. Arbitrarily use [then, else] | 1077 // that continuation to be listed first. Arbitrarily use [then, else] |
| 1127 // order otherwise. | 1078 // order otherwise. |
| 1128 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen | 1079 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen |
| 1129 ? <ir.Continuation>[elseContinuation, thenContinuation] | 1080 ? <ir.Continuation>[elseContinuation, thenContinuation] |
| 1130 : <ir.Continuation>[thenContinuation, elseContinuation]; | 1081 : <ir.Continuation>[thenContinuation, elseContinuation]; |
| 1131 | 1082 |
| 1132 ir.Expression result = | 1083 ir.Expression result = new ir.LetCont.many( |
| 1133 new ir.LetCont.many(arms, | 1084 arms, |
| 1134 new ir.Branch.strict(condition, | 1085 new ir.Branch.strict( |
| 1135 thenContinuation, | 1086 condition, thenContinuation, elseContinuation, sourceInformation)); |
| 1136 elseContinuation, | |
| 1137 sourceInformation)); | |
| 1138 | 1087 |
| 1139 JumpCollector join; // Null if there is no join. | 1088 JumpCollector join; // Null if there is no join. |
| 1140 if (thenBuilder.isOpen && elseBuilder.isOpen) { | 1089 if (thenBuilder.isOpen && elseBuilder.isOpen) { |
| 1141 // There is a join-point continuation. Build the term | 1090 // There is a join-point continuation. Build the term |
| 1142 // 'let cont join(x, ...) = [] in Result' and plug invocations of the | 1091 // 'let cont join(x, ...) = [] in Result' and plug invocations of the |
| 1143 // join-point continuation into the then and else continuations. | 1092 // join-point continuation into the then and else continuations. |
| 1144 join = new ForwardJumpCollector(environment); | 1093 join = new ForwardJumpCollector(environment); |
| 1145 thenBuilder.jumpTo(join); | 1094 thenBuilder.jumpTo(join); |
| 1146 elseBuilder.jumpTo(join); | 1095 elseBuilder.jumpTo(join); |
| 1147 result = new ir.LetCont(join.continuation, result); | 1096 result = new ir.LetCont(join.continuation, result); |
| 1148 } | 1097 } |
| 1149 | 1098 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1174 } | 1123 } |
| 1175 } | 1124 } |
| 1176 | 1125 |
| 1177 void jumpTo(JumpCollector collector, | 1126 void jumpTo(JumpCollector collector, |
| 1178 [ir.Primitive value, SourceInformation sourceInformation]) { | 1127 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 1179 collector.addJump(this, value, sourceInformation); | 1128 collector.addJump(this, value, sourceInformation); |
| 1180 } | 1129 } |
| 1181 | 1130 |
| 1182 void addRecursiveContinuation(BackwardJumpCollector collector) { | 1131 void addRecursiveContinuation(BackwardJumpCollector collector) { |
| 1183 assert(environment.length == collector.environment.length); | 1132 assert(environment.length == collector.environment.length); |
| 1184 add(new ir.LetCont(collector.continuation, | 1133 add(new ir.LetCont( |
| 1185 new ir.InvokeContinuation(collector.continuation, | 1134 collector.continuation, |
| 1186 environment.index2value))); | 1135 new ir.InvokeContinuation( |
| 1136 collector.continuation, environment.index2value))); |
| 1187 environment = collector.environment; | 1137 environment = collector.environment; |
| 1188 } | 1138 } |
| 1189 | 1139 |
| 1190 /// Creates a for loop in which the initializer, condition, body, update are | 1140 /// Creates a for loop in which the initializer, condition, body, update are |
| 1191 /// created by [buildInitializer], [buildCondition], [buildBody] and | 1141 /// created by [buildInitializer], [buildCondition], [buildBody] and |
| 1192 /// [buildUpdate], respectively. | 1142 /// [buildUpdate], respectively. |
| 1193 /// | 1143 /// |
| 1194 /// The jump [target] is used to identify which `break` and `continue` | 1144 /// The jump [target] is used to identify which `break` and `continue` |
| 1195 /// statements that have this `for` statement as their target. | 1145 /// statements that have this `for` statement as their target. |
| 1196 /// | 1146 /// |
| 1197 /// The [closureScope] identifies variables that should be boxed in this loop. | 1147 /// The [closureScope] identifies variables that should be boxed in this loop. |
| 1198 /// This includes variables declared inside the body of the loop as well as | 1148 /// This includes variables declared inside the body of the loop as well as |
| 1199 /// in the for-loop initializer. | 1149 /// in the for-loop initializer. |
| 1200 /// | 1150 /// |
| 1201 /// [loopVariables] is the list of variables declared in the for-loop | 1151 /// [loopVariables] is the list of variables declared in the for-loop |
| 1202 /// initializer. | 1152 /// initializer. |
| 1203 void buildFor({SubbuildFunction buildInitializer, | 1153 void buildFor( |
| 1204 SubbuildFunction buildCondition, | 1154 {SubbuildFunction buildInitializer, |
| 1205 SourceInformation conditionSourceInformation, | 1155 SubbuildFunction buildCondition, |
| 1206 SubbuildFunction buildBody, | 1156 SourceInformation conditionSourceInformation, |
| 1207 SubbuildFunction buildUpdate, | 1157 SubbuildFunction buildBody, |
| 1208 JumpTarget target, | 1158 SubbuildFunction buildUpdate, |
| 1209 ClosureScope closureScope, | 1159 JumpTarget target, |
| 1210 List<LocalElement> loopVariables}) { | 1160 ClosureScope closureScope, |
| 1161 List<LocalElement> loopVariables}) { |
| 1211 assert(isOpen); | 1162 assert(isOpen); |
| 1212 | 1163 |
| 1213 // For loops use four named continuations: the entry to the condition, | 1164 // For loops use four named continuations: the entry to the condition, |
| 1214 // the entry to the body, the loop exit, and the loop successor (break). | 1165 // the entry to the body, the loop exit, and the loop successor (break). |
| 1215 // The CPS translation of | 1166 // The CPS translation of |
| 1216 // [[for (initializer; condition; update) body; successor]] is: | 1167 // [[for (initializer; condition; update) body; successor]] is: |
| 1217 // | 1168 // |
| 1218 // _enterForLoopInitializer(); | 1169 // _enterForLoopInitializer(); |
| 1219 // [[initializer]]; | 1170 // [[initializer]]; |
| 1220 // let cont loop(x, ...) = | 1171 // let cont loop(x, ...) = |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1283 updateBuilder = makeDelimitedBuilder(continueCollector.environment); | 1234 updateBuilder = makeDelimitedBuilder(continueCollector.environment); |
| 1284 } else { | 1235 } else { |
| 1285 updateBuilder = innerBodyBuilder; | 1236 updateBuilder = innerBodyBuilder; |
| 1286 } | 1237 } |
| 1287 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); | 1238 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); |
| 1288 buildUpdate(updateBuilder); | 1239 buildUpdate(updateBuilder); |
| 1289 if (updateBuilder.isOpen) updateBuilder.jumpTo(loop); | 1240 if (updateBuilder.isOpen) updateBuilder.jumpTo(loop); |
| 1290 // Connect the inner and outer body builders. This is done only after | 1241 // Connect the inner and outer body builders. This is done only after |
| 1291 // it is guaranteed that the updateBuilder has a non-empty term. | 1242 // it is guaranteed that the updateBuilder has a non-empty term. |
| 1292 if (hasContinues) { | 1243 if (hasContinues) { |
| 1293 outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation, | 1244 outerBodyBuilder.add(new ir.LetCont( |
| 1294 innerBodyBuilder.root)); | 1245 continueCollector.continuation, innerBodyBuilder.root)); |
| 1295 continueCollector.continuation.body = updateBuilder.root; | 1246 continueCollector.continuation.body = updateBuilder.root; |
| 1296 } else { | 1247 } else { |
| 1297 outerBodyBuilder.add(innerBodyBuilder.root); | 1248 outerBodyBuilder.add(innerBodyBuilder.root); |
| 1298 } | 1249 } |
| 1299 | 1250 |
| 1300 // Create loop exit and body entry continuations and a branch to them. | 1251 // Create loop exit and body entry continuations and a branch to them. |
| 1301 ir.Continuation exitContinuation = new ir.Continuation([]); | 1252 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1302 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1253 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1303 bodyContinuation.body = outerBodyBuilder.root; | 1254 bodyContinuation.body = outerBodyBuilder.root; |
| 1304 // Note the order of continuations: the first one is the one that will | 1255 // Note the order of continuations: the first one is the one that will |
| 1305 // be filled by LetCont.plug. | 1256 // be filled by LetCont.plug. |
| 1306 ir.LetCont branch = | 1257 ir.LetCont branch = new ir.LetCont.two( |
| 1307 new ir.LetCont.two(exitContinuation, bodyContinuation, | 1258 exitContinuation, |
| 1308 new ir.Branch.strict(condition, | 1259 bodyContinuation, |
| 1309 bodyContinuation, | 1260 new ir.Branch.strict(condition, bodyContinuation, exitContinuation, |
| 1310 exitContinuation, | 1261 conditionSourceInformation)); |
| 1311 conditionSourceInformation)); | |
| 1312 // If there are breaks in the body, then there must be a join-point | 1262 // If there are breaks in the body, then there must be a join-point |
| 1313 // continuation for the normal exit and the breaks. Otherwise, the | 1263 // continuation for the normal exit and the breaks. Otherwise, the |
| 1314 // successor is translated in the hole in the exit continuation. | 1264 // successor is translated in the hole in the exit continuation. |
| 1315 bool hasBreaks = !breakCollector.isEmpty; | 1265 bool hasBreaks = !breakCollector.isEmpty; |
| 1316 ir.LetCont letBreak; | 1266 ir.LetCont letBreak; |
| 1317 if (hasBreaks) { | 1267 if (hasBreaks) { |
| 1318 IrBuilder exitBuilder = makeDelimitedBuilder(); | 1268 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1319 exitBuilder.jumpTo(breakCollector); | 1269 exitBuilder.jumpTo(breakCollector); |
| 1320 exitContinuation.body = exitBuilder.root; | 1270 exitContinuation.body = exitBuilder.root; |
| 1321 letBreak = new ir.LetCont(breakCollector.continuation, branch); | 1271 letBreak = new ir.LetCont(breakCollector.continuation, branch); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1335 /// creates its declaration and [variableElement] is the element for | 1285 /// creates its declaration and [variableElement] is the element for |
| 1336 /// the declared variable, | 1286 /// the declared variable, |
| 1337 /// 2) `v` is predeclared statically known variable, that is top-level, | 1287 /// 2) `v` is predeclared statically known variable, that is top-level, |
| 1338 /// static, or local variable, in which case [variableElement] is the | 1288 /// static, or local variable, in which case [variableElement] is the |
| 1339 /// variable element, and [variableSelector] defines its write access, | 1289 /// variable element, and [variableSelector] defines its write access, |
| 1340 /// 3) `v` is an instance variable in which case [variableSelector] | 1290 /// 3) `v` is an instance variable in which case [variableSelector] |
| 1341 /// defines its write access. | 1291 /// defines its write access. |
| 1342 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used | 1292 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used |
| 1343 /// to identify which `break` and `continue` statements that have this for-in | 1293 /// to identify which `break` and `continue` statements that have this for-in |
| 1344 /// statement as their target. | 1294 /// statement as their target. |
| 1345 void buildForIn({SubbuildFunction buildExpression, | 1295 void buildForIn( |
| 1346 SubbuildFunction buildVariableDeclaration, | 1296 {SubbuildFunction buildExpression, |
| 1347 Element variableElement, | 1297 SubbuildFunction buildVariableDeclaration, |
| 1348 Selector variableSelector, | 1298 Element variableElement, |
| 1349 TypeMask variableMask, | 1299 Selector variableSelector, |
| 1350 SourceInformation variableSetSourceInformation, | 1300 TypeMask variableMask, |
| 1351 TypeMask currentMask, | 1301 SourceInformation variableSetSourceInformation, |
| 1352 SourceInformation currentSourceInformation, | 1302 TypeMask currentMask, |
| 1353 TypeMask iteratorMask, | 1303 SourceInformation currentSourceInformation, |
| 1354 SourceInformation iteratorSourceInformation, | 1304 TypeMask iteratorMask, |
| 1355 TypeMask moveNextMask, | 1305 SourceInformation iteratorSourceInformation, |
| 1356 SourceInformation moveNextSourceInformation, | 1306 TypeMask moveNextMask, |
| 1357 SubbuildFunction buildBody, | 1307 SourceInformation moveNextSourceInformation, |
| 1358 JumpTarget target, | 1308 SubbuildFunction buildBody, |
| 1359 ClosureScope closureScope, | 1309 JumpTarget target, |
| 1360 SourceInformation conditionSourceInformation}) { | 1310 ClosureScope closureScope, |
| 1311 SourceInformation conditionSourceInformation}) { |
| 1361 // The for-in loop | 1312 // The for-in loop |
| 1362 // | 1313 // |
| 1363 // for (a in e) s; | 1314 // for (a in e) s; |
| 1364 // | 1315 // |
| 1365 // Is compiled analogously to: | 1316 // Is compiled analogously to: |
| 1366 // | 1317 // |
| 1367 // it = e.iterator; | 1318 // it = e.iterator; |
| 1368 // while (it.moveNext()) { | 1319 // while (it.moveNext()) { |
| 1369 // var a = it.current; | 1320 // var a = it.current; |
| 1370 // s; | 1321 // s; |
| 1371 // } | 1322 // } |
| 1372 | 1323 |
| 1373 // Fill the current hole with: | 1324 // Fill the current hole with: |
| 1374 // let prim expressionReceiver = [[e]] in | 1325 // let prim expressionReceiver = [[e]] in |
| 1375 // let cont iteratorInvoked(iterator) = | 1326 // let cont iteratorInvoked(iterator) = |
| 1376 // [ ] | 1327 // [ ] |
| 1377 // in expressionReceiver.iterator () iteratorInvoked | 1328 // in expressionReceiver.iterator () iteratorInvoked |
| 1378 ir.Primitive expressionReceiver = buildExpression(this); | 1329 ir.Primitive expressionReceiver = buildExpression(this); |
| 1379 List<ir.Primitive> emptyArguments = <ir.Primitive>[]; | 1330 List<ir.Primitive> emptyArguments = <ir.Primitive>[]; |
| 1380 ir.Primitive iterator = addPrimitive( | 1331 ir.Primitive iterator = addPrimitive(new ir.InvokeMethod( |
| 1381 new ir.InvokeMethod(expressionReceiver, | 1332 expressionReceiver, Selectors.iterator, iteratorMask, emptyArguments)); |
| 1382 Selectors.iterator, | |
| 1383 iteratorMask, | |
| 1384 emptyArguments)); | |
| 1385 | 1333 |
| 1386 // Fill with: | 1334 // Fill with: |
| 1387 // let cont loop(x, ...) = | 1335 // let cont loop(x, ...) = |
| 1388 // let cont moveNextInvoked(condition) = | 1336 // let cont moveNextInvoked(condition) = |
| 1389 // [ ] | 1337 // [ ] |
| 1390 // in iterator.moveNext () moveNextInvoked | 1338 // in iterator.moveNext () moveNextInvoked |
| 1391 // in loop(v, ...) | 1339 // in loop(v, ...) |
| 1392 JumpCollector loop = new BackwardJumpCollector(environment, target: target); | 1340 JumpCollector loop = new BackwardJumpCollector(environment, target: target); |
| 1393 addRecursiveContinuation(loop); | 1341 addRecursiveContinuation(loop); |
| 1394 ir.Primitive condition = addPrimitive( | 1342 ir.Primitive condition = addPrimitive(new ir.InvokeMethod( |
| 1395 new ir.InvokeMethod(iterator, | 1343 iterator, Selectors.moveNext, moveNextMask, emptyArguments)); |
| 1396 Selectors.moveNext, | |
| 1397 moveNextMask, | |
| 1398 emptyArguments)); | |
| 1399 | 1344 |
| 1400 // As a delimited term, build: | 1345 // As a delimited term, build: |
| 1401 // <<BODY>> = | 1346 // <<BODY>> = |
| 1402 // _enterScope(); | 1347 // _enterScope(); |
| 1403 // [[variableDeclaration]] | 1348 // [[variableDeclaration]] |
| 1404 // let cont currentInvoked(currentValue) = | 1349 // let cont currentInvoked(currentValue) = |
| 1405 // [[a = currentValue]]; | 1350 // [[a = currentValue]]; |
| 1406 // [ ] | 1351 // [ ] |
| 1407 // in iterator.current () currentInvoked | 1352 // in iterator.current () currentInvoked |
| 1408 IrBuilder bodyBuilder = makeDelimitedBuilder(); | 1353 IrBuilder bodyBuilder = makeDelimitedBuilder(); |
| 1409 bodyBuilder._enterScope(closureScope); | 1354 bodyBuilder._enterScope(closureScope); |
| 1410 if (buildVariableDeclaration != null) { | 1355 if (buildVariableDeclaration != null) { |
| 1411 buildVariableDeclaration(bodyBuilder); | 1356 buildVariableDeclaration(bodyBuilder); |
| 1412 } | 1357 } |
| 1413 ir.Primitive currentValue = bodyBuilder.addPrimitive( | 1358 ir.Primitive currentValue = bodyBuilder.addPrimitive(new ir.InvokeMethod( |
| 1414 new ir.InvokeMethod( | 1359 iterator, Selectors.current, currentMask, emptyArguments, |
| 1415 iterator, | 1360 sourceInformation: currentSourceInformation)); |
| 1416 Selectors.current, | |
| 1417 currentMask, | |
| 1418 emptyArguments, | |
| 1419 sourceInformation: currentSourceInformation)); | |
| 1420 // TODO(johnniwinther): Extract this as a provided strategy. | 1361 // TODO(johnniwinther): Extract this as a provided strategy. |
| 1421 if (Elements.isLocal(variableElement)) { | 1362 if (Elements.isLocal(variableElement)) { |
| 1422 bodyBuilder.buildLocalVariableSet( | 1363 bodyBuilder.buildLocalVariableSet( |
| 1423 variableElement, | 1364 variableElement, currentValue, variableSetSourceInformation); |
| 1424 currentValue, | |
| 1425 variableSetSourceInformation); | |
| 1426 } else if (Elements.isError(variableElement) || | 1365 } else if (Elements.isError(variableElement) || |
| 1427 Elements.isMalformed(variableElement)) { | 1366 Elements.isMalformed(variableElement)) { |
| 1428 Selector selector = new Selector.setter( | 1367 Selector selector = new Selector.setter( |
| 1429 new Name(variableElement.name, variableElement.library)); | 1368 new Name(variableElement.name, variableElement.library)); |
| 1430 List<ir.Primitive> value = <ir.Primitive>[currentValue]; | 1369 List<ir.Primitive> value = <ir.Primitive>[currentValue]; |
| 1431 // Note the comparison below. It can be the case that an element isError | 1370 // Note the comparison below. It can be the case that an element isError |
| 1432 // and isMalformed. | 1371 // and isMalformed. |
| 1433 if (Elements.isError(variableElement)) { | 1372 if (Elements.isError(variableElement)) { |
| 1434 bodyBuilder.buildStaticNoSuchMethod(selector, value, | 1373 bodyBuilder.buildStaticNoSuchMethod( |
| 1435 variableSetSourceInformation); | 1374 selector, value, variableSetSourceInformation); |
| 1436 } else { | 1375 } else { |
| 1437 bodyBuilder.buildErroneousInvocation( | 1376 bodyBuilder.buildErroneousInvocation( |
| 1438 variableElement, selector, value, variableSetSourceInformation); | 1377 variableElement, selector, value, variableSetSourceInformation); |
| 1439 } | 1378 } |
| 1440 } else if (Elements.isStaticOrTopLevel(variableElement)) { | 1379 } else if (Elements.isStaticOrTopLevel(variableElement)) { |
| 1441 if (variableElement.isField) { | 1380 if (variableElement.isField) { |
| 1442 bodyBuilder.addPrimitive( | 1381 bodyBuilder.addPrimitive(new ir.SetStatic( |
| 1443 new ir.SetStatic( | 1382 variableElement, currentValue, variableSetSourceInformation)); |
| 1444 variableElement, currentValue, variableSetSourceInformation)); | |
| 1445 } else { | 1383 } else { |
| 1446 bodyBuilder.buildStaticSetterSet( | 1384 bodyBuilder.buildStaticSetterSet( |
| 1447 variableElement, currentValue, variableSetSourceInformation); | 1385 variableElement, currentValue, variableSetSourceInformation); |
| 1448 } | 1386 } |
| 1449 } else { | 1387 } else { |
| 1450 ir.Primitive receiver = bodyBuilder.buildThis(); | 1388 ir.Primitive receiver = bodyBuilder.buildThis(); |
| 1451 assert(receiver != null); | 1389 assert(receiver != null); |
| 1452 bodyBuilder.buildDynamicSet( | 1390 bodyBuilder.buildDynamicSet(receiver, variableSelector, variableMask, |
| 1453 receiver, variableSelector, variableMask, currentValue, | 1391 currentValue, variableSetSourceInformation); |
| 1454 variableSetSourceInformation); | |
| 1455 } | 1392 } |
| 1456 | 1393 |
| 1457 // Translate the body in the hole in the delimited term above, and add | 1394 // Translate the body in the hole in the delimited term above, and add |
| 1458 // a jump to the loop if control flow is live after the body. | 1395 // a jump to the loop if control flow is live after the body. |
| 1459 JumpCollector breakCollector = | 1396 JumpCollector breakCollector = |
| 1460 new ForwardJumpCollector(environment, target: target); | 1397 new ForwardJumpCollector(environment, target: target); |
| 1461 state.breakCollectors.add(breakCollector); | 1398 state.breakCollectors.add(breakCollector); |
| 1462 state.continueCollectors.add(loop); | 1399 state.continueCollectors.add(loop); |
| 1463 buildBody(bodyBuilder); | 1400 buildBody(bodyBuilder); |
| 1464 assert(state.breakCollectors.last == breakCollector); | 1401 assert(state.breakCollectors.last == breakCollector); |
| 1465 assert(state.continueCollectors.last == loop); | 1402 assert(state.continueCollectors.last == loop); |
| 1466 state.breakCollectors.removeLast(); | 1403 state.breakCollectors.removeLast(); |
| 1467 state.continueCollectors.removeLast(); | 1404 state.continueCollectors.removeLast(); |
| 1468 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); | 1405 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); |
| 1469 | 1406 |
| 1470 // Create body entry and loop exit continuations and a branch to them. | 1407 // Create body entry and loop exit continuations and a branch to them. |
| 1471 // | 1408 // |
| 1472 // let cont exit() = [ ] | 1409 // let cont exit() = [ ] |
| 1473 // and body() = <<BODY>> | 1410 // and body() = <<BODY>> |
| 1474 // in branch condition (body, exit) | 1411 // in branch condition (body, exit) |
| 1475 ir.Continuation exitContinuation = new ir.Continuation([]); | 1412 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1476 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1413 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1477 bodyContinuation.body = bodyBuilder.root; | 1414 bodyContinuation.body = bodyBuilder.root; |
| 1478 // Note the order of continuations: the first one is the one that will | 1415 // Note the order of continuations: the first one is the one that will |
| 1479 // be filled by LetCont.plug. | 1416 // be filled by LetCont.plug. |
| 1480 ir.LetCont branch = | 1417 ir.LetCont branch = new ir.LetCont.two( |
| 1481 new ir.LetCont.two(exitContinuation, bodyContinuation, | 1418 exitContinuation, |
| 1482 new ir.Branch.strict(condition, | 1419 bodyContinuation, |
| 1483 bodyContinuation, | 1420 new ir.Branch.strict(condition, bodyContinuation, exitContinuation, |
| 1484 exitContinuation, | 1421 conditionSourceInformation)); |
| 1485 conditionSourceInformation)); | |
| 1486 // If there are breaks in the body, then there must be a join-point | 1422 // If there are breaks in the body, then there must be a join-point |
| 1487 // continuation for the normal exit and the breaks. Otherwise, the | 1423 // continuation for the normal exit and the breaks. Otherwise, the |
| 1488 // successor is translated in the hole in the exit continuation. | 1424 // successor is translated in the hole in the exit continuation. |
| 1489 bool hasBreaks = !breakCollector.isEmpty; | 1425 bool hasBreaks = !breakCollector.isEmpty; |
| 1490 ir.LetCont letBreak; | 1426 ir.LetCont letBreak; |
| 1491 if (hasBreaks) { | 1427 if (hasBreaks) { |
| 1492 IrBuilder exitBuilder = makeDelimitedBuilder(); | 1428 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1493 exitBuilder.jumpTo(breakCollector); | 1429 exitBuilder.jumpTo(breakCollector); |
| 1494 exitContinuation.body = exitBuilder.root; | 1430 exitContinuation.body = exitBuilder.root; |
| 1495 letBreak = new ir.LetCont(breakCollector.continuation, branch); | 1431 letBreak = new ir.LetCont(breakCollector.continuation, branch); |
| 1496 add(letBreak); | 1432 add(letBreak); |
| 1497 environment = breakCollector.environment; | 1433 environment = breakCollector.environment; |
| 1498 } else { | 1434 } else { |
| 1499 add(branch); | 1435 add(branch); |
| 1500 } | 1436 } |
| 1501 } | 1437 } |
| 1502 | 1438 |
| 1503 /// Creates a while loop in which the condition and body are created by | 1439 /// Creates a while loop in which the condition and body are created by |
| 1504 /// [buildCondition] and [buildBody], respectively. | 1440 /// [buildCondition] and [buildBody], respectively. |
| 1505 /// | 1441 /// |
| 1506 /// The jump [target] is used to identify which `break` and `continue` | 1442 /// The jump [target] is used to identify which `break` and `continue` |
| 1507 /// statements that have this `while` statement as their target. | 1443 /// statements that have this `while` statement as their target. |
| 1508 void buildWhile({SubbuildFunction buildCondition, | 1444 void buildWhile( |
| 1509 SubbuildFunction buildBody, | 1445 {SubbuildFunction buildCondition, |
| 1510 JumpTarget target, | 1446 SubbuildFunction buildBody, |
| 1511 ClosureScope closureScope, | 1447 JumpTarget target, |
| 1512 SourceInformation sourceInformation}) { | 1448 ClosureScope closureScope, |
| 1449 SourceInformation sourceInformation}) { |
| 1513 assert(isOpen); | 1450 assert(isOpen); |
| 1514 // While loops use four named continuations: the entry to the body, the | 1451 // While loops use four named continuations: the entry to the body, the |
| 1515 // loop exit, the loop back edge (continue), and the loop exit (break). | 1452 // loop exit, the loop back edge (continue), and the loop exit (break). |
| 1516 // The CPS translation of [[while (condition) body; successor]] is: | 1453 // The CPS translation of [[while (condition) body; successor]] is: |
| 1517 // | 1454 // |
| 1518 // let cont continue(x, ...) = | 1455 // let cont continue(x, ...) = |
| 1519 // let prim cond = [[condition]] in | 1456 // let prim cond = [[condition]] in |
| 1520 // let cont break(x, ...) = [[successor]] in | 1457 // let cont break(x, ...) = [[successor]] in |
| 1521 // let cont exit() = break(v, ...) | 1458 // let cont exit() = break(v, ...) |
| 1522 // and body() = | 1459 // and body() = |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1547 state.breakCollectors.removeLast(); | 1484 state.breakCollectors.removeLast(); |
| 1548 state.continueCollectors.removeLast(); | 1485 state.continueCollectors.removeLast(); |
| 1549 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); | 1486 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); |
| 1550 | 1487 |
| 1551 // Create body entry and loop exit continuations and a branch to them. | 1488 // Create body entry and loop exit continuations and a branch to them. |
| 1552 ir.Continuation exitContinuation = new ir.Continuation([]); | 1489 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1553 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1490 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1554 bodyContinuation.body = bodyBuilder.root; | 1491 bodyContinuation.body = bodyBuilder.root; |
| 1555 // Note the order of continuations: the first one is the one that will | 1492 // Note the order of continuations: the first one is the one that will |
| 1556 // be filled by LetCont.plug. | 1493 // be filled by LetCont.plug. |
| 1557 ir.LetCont branch = | 1494 ir.LetCont branch = new ir.LetCont.two( |
| 1558 new ir.LetCont.two(exitContinuation, bodyContinuation, | 1495 exitContinuation, |
| 1559 new ir.Branch.strict(condition, | 1496 bodyContinuation, |
| 1560 bodyContinuation, | 1497 new ir.Branch.strict( |
| 1561 exitContinuation, | 1498 condition, bodyContinuation, exitContinuation, sourceInformation)); |
| 1562 sourceInformation)); | |
| 1563 // If there are breaks in the body, then there must be a join-point | 1499 // If there are breaks in the body, then there must be a join-point |
| 1564 // continuation for the normal exit and the breaks. Otherwise, the | 1500 // continuation for the normal exit and the breaks. Otherwise, the |
| 1565 // successor is translated in the hole in the exit continuation. | 1501 // successor is translated in the hole in the exit continuation. |
| 1566 bool hasBreaks = !breakCollector.isEmpty; | 1502 bool hasBreaks = !breakCollector.isEmpty; |
| 1567 ir.LetCont letBreak; | 1503 ir.LetCont letBreak; |
| 1568 if (hasBreaks) { | 1504 if (hasBreaks) { |
| 1569 IrBuilder exitBuilder = makeDelimitedBuilder(); | 1505 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1570 exitBuilder.jumpTo(breakCollector); | 1506 exitBuilder.jumpTo(breakCollector); |
| 1571 exitContinuation.body = exitBuilder.root; | 1507 exitContinuation.body = exitBuilder.root; |
| 1572 letBreak = new ir.LetCont(breakCollector.continuation, branch); | 1508 letBreak = new ir.LetCont(breakCollector.continuation, branch); |
| 1573 add(letBreak); | 1509 add(letBreak); |
| 1574 environment = breakCollector.environment; | 1510 environment = breakCollector.environment; |
| 1575 } else { | 1511 } else { |
| 1576 add(branch); | 1512 add(branch); |
| 1577 } | 1513 } |
| 1578 } | 1514 } |
| 1579 | 1515 |
| 1580 | |
| 1581 /// Creates a do-while loop. | 1516 /// Creates a do-while loop. |
| 1582 /// | 1517 /// |
| 1583 /// The body and condition are created by [buildBody] and [buildCondition]. | 1518 /// The body and condition are created by [buildBody] and [buildCondition]. |
| 1584 /// The jump target [target] is the target of `break` and `continue` | 1519 /// The jump target [target] is the target of `break` and `continue` |
| 1585 /// statements in the body that have the loop as their target. | 1520 /// statements in the body that have the loop as their target. |
| 1586 /// [closureScope] contains all the variables declared in the loop (but not | 1521 /// [closureScope] contains all the variables declared in the loop (but not |
| 1587 /// declared in some inner closure scope). | 1522 /// declared in some inner closure scope). |
| 1588 void buildDoWhile({SubbuildFunction buildBody, | 1523 void buildDoWhile( |
| 1589 SubbuildFunction buildCondition, | 1524 {SubbuildFunction buildBody, |
| 1590 JumpTarget target, | 1525 SubbuildFunction buildCondition, |
| 1591 ClosureScope closureScope, | 1526 JumpTarget target, |
| 1592 SourceInformation sourceInformation}) { | 1527 ClosureScope closureScope, |
| 1528 SourceInformation sourceInformation}) { |
| 1593 assert(isOpen); | 1529 assert(isOpen); |
| 1594 // The CPS translation of [[do body; while (condition); successor]] is: | 1530 // The CPS translation of [[do body; while (condition); successor]] is: |
| 1595 // | 1531 // |
| 1596 // let cont break(x, ...) = [[successor]] in | 1532 // let cont break(x, ...) = [[successor]] in |
| 1597 // let cont rec loop(x, ...) = | 1533 // let cont rec loop(x, ...) = |
| 1598 // let cont continue(x, ...) = | 1534 // let cont continue(x, ...) = |
| 1599 // let prim cond = [[condition]] in | 1535 // let prim cond = [[condition]] in |
| 1600 // let cont exit() = break(v, ...) | 1536 // let cont exit() = break(v, ...) |
| 1601 // and repeat() = loop(v, ...) | 1537 // and repeat() = loop(v, ...) |
| 1602 // in branch cond (repeat, exit) | 1538 // in branch cond (repeat, exit) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1635 | 1571 |
| 1636 ir.Continuation exitContinuation = new ir.Continuation([]); | 1572 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1637 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder(); | 1573 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder(); |
| 1638 exitBuilder.jumpTo(breakCollector); | 1574 exitBuilder.jumpTo(breakCollector); |
| 1639 exitContinuation.body = exitBuilder.root; | 1575 exitContinuation.body = exitBuilder.root; |
| 1640 ir.Continuation repeatContinuation = new ir.Continuation([]); | 1576 ir.Continuation repeatContinuation = new ir.Continuation([]); |
| 1641 IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder(); | 1577 IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder(); |
| 1642 repeatBuilder.jumpTo(loop); | 1578 repeatBuilder.jumpTo(loop); |
| 1643 repeatContinuation.body = repeatBuilder.root; | 1579 repeatContinuation.body = repeatBuilder.root; |
| 1644 | 1580 |
| 1645 continueBuilder.add( | 1581 continueBuilder.add(new ir.LetCont.two( |
| 1646 new ir.LetCont.two(exitContinuation, repeatContinuation, | 1582 exitContinuation, |
| 1647 new ir.Branch.strict(condition, | 1583 repeatContinuation, |
| 1648 repeatContinuation, | 1584 new ir.Branch.strict(condition, repeatContinuation, exitContinuation, |
| 1649 exitContinuation, | 1585 sourceInformation))); |
| 1650 sourceInformation))); | |
| 1651 continueCollector.continuation.body = continueBuilder.root; | 1586 continueCollector.continuation.body = continueBuilder.root; |
| 1652 | 1587 |
| 1653 // Construct the loop continuation (i.e., the body and condition). | 1588 // Construct the loop continuation (i.e., the body and condition). |
| 1654 // <Loop> = | 1589 // <Loop> = |
| 1655 // let cont continue(x, ...) = | 1590 // let cont continue(x, ...) = |
| 1656 // <Continue> | 1591 // <Continue> |
| 1657 // in [[body]]; continue(v, ...) | 1592 // in [[body]]; continue(v, ...) |
| 1658 loopBuilder.add( | 1593 loopBuilder |
| 1659 new ir.LetCont(continueCollector.continuation, | 1594 .add(new ir.LetCont(continueCollector.continuation, bodyBuilder.root)); |
| 1660 bodyBuilder.root)); | |
| 1661 | 1595 |
| 1662 // And tie it all together. | 1596 // And tie it all together. |
| 1663 add(new ir.LetCont(breakCollector.continuation, loopBuilder.root)); | 1597 add(new ir.LetCont(breakCollector.continuation, loopBuilder.root)); |
| 1664 environment = breakCollector.environment; | 1598 environment = breakCollector.environment; |
| 1665 } | 1599 } |
| 1666 | 1600 |
| 1667 void buildSimpleSwitch(JumpCollector join, | 1601 void buildSimpleSwitch(JumpCollector join, List<SwitchCaseInfo> cases, |
| 1668 List<SwitchCaseInfo> cases, | 1602 SubbuildFunction buildDefaultBody) { |
| 1669 SubbuildFunction buildDefaultBody) { | |
| 1670 IrBuilder casesBuilder = makeDelimitedBuilder(); | 1603 IrBuilder casesBuilder = makeDelimitedBuilder(); |
| 1671 for (SwitchCaseInfo caseInfo in cases) { | 1604 for (SwitchCaseInfo caseInfo in cases) { |
| 1672 ir.Primitive condition = caseInfo.buildCondition(casesBuilder); | 1605 ir.Primitive condition = caseInfo.buildCondition(casesBuilder); |
| 1673 IrBuilder thenBuilder = makeDelimitedBuilder(); | 1606 IrBuilder thenBuilder = makeDelimitedBuilder(); |
| 1674 caseInfo.buildBody(thenBuilder); | 1607 caseInfo.buildBody(thenBuilder); |
| 1675 ir.Continuation thenContinuation = new ir.Continuation([]); | 1608 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1676 thenContinuation.body = thenBuilder.root; | 1609 thenContinuation.body = thenBuilder.root; |
| 1677 ir.Continuation elseContinuation = new ir.Continuation([]); | 1610 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1678 // A LetCont.two term has a hole as the body of the first listed | 1611 // A LetCont.two term has a hole as the body of the first listed |
| 1679 // continuation, to be plugged by the translation. Therefore put the | 1612 // continuation, to be plugged by the translation. Therefore put the |
| 1680 // else continuation first. | 1613 // else continuation first. |
| 1681 casesBuilder.add( | 1614 casesBuilder.add(new ir.LetCont.two( |
| 1682 new ir.LetCont.two(elseContinuation, thenContinuation, | 1615 elseContinuation, |
| 1683 new ir.Branch.strict(condition, | 1616 thenContinuation, |
| 1684 thenContinuation, | 1617 new ir.Branch.strict(condition, thenContinuation, elseContinuation, |
| 1685 elseContinuation, | 1618 caseInfo.sourceInformation))); |
| 1686 caseInfo.sourceInformation))); | |
| 1687 } | 1619 } |
| 1688 | 1620 |
| 1689 if (buildDefaultBody == null) { | 1621 if (buildDefaultBody == null) { |
| 1690 casesBuilder.jumpTo(join); | 1622 casesBuilder.jumpTo(join); |
| 1691 } else { | 1623 } else { |
| 1692 buildDefaultBody(casesBuilder); | 1624 buildDefaultBody(casesBuilder); |
| 1693 } | 1625 } |
| 1694 | 1626 |
| 1695 if (!join.isEmpty) { | 1627 if (!join.isEmpty) { |
| 1696 add(new ir.LetCont(join.continuation, casesBuilder.root)); | 1628 add(new ir.LetCont(join.continuation, casesBuilder.root)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1708 /// | 1640 /// |
| 1709 /// The translation treats try/finally and try/catch/finally as if they | 1641 /// The translation treats try/finally and try/catch/finally as if they |
| 1710 /// were macro-expanded into try/catch. This utility function generates | 1642 /// were macro-expanded into try/catch. This utility function generates |
| 1711 /// that try/catch. The function is parameterized over a list of variables | 1643 /// that try/catch. The function is parameterized over a list of variables |
| 1712 /// that should be boxed on entry to the try, and over functions to emit | 1644 /// that should be boxed on entry to the try, and over functions to emit |
| 1713 /// code for entering the try, building the try body, leaving the try body, | 1645 /// code for entering the try, building the try body, leaving the try body, |
| 1714 /// building the catch body, and leaving the entire try/catch. | 1646 /// building the catch body, and leaving the entire try/catch. |
| 1715 /// | 1647 /// |
| 1716 /// Please see the function's implementation for where these functions are | 1648 /// Please see the function's implementation for where these functions are |
| 1717 /// called. | 1649 /// called. |
| 1718 void _helpBuildTryCatch(TryStatementInfo variables, | 1650 void _helpBuildTryCatch( |
| 1651 TryStatementInfo variables, |
| 1719 void enterTry(IrBuilder builder), | 1652 void enterTry(IrBuilder builder), |
| 1720 SubbuildFunction buildTryBlock, | 1653 SubbuildFunction buildTryBlock, |
| 1721 void leaveTry(IrBuilder builder), | 1654 void leaveTry(IrBuilder builder), |
| 1722 List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join), | 1655 List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join), |
| 1723 void leaveTryCatch(IrBuilder builder, JumpCollector join, | 1656 void leaveTryCatch( |
| 1724 ir.Expression body)) { | 1657 IrBuilder builder, JumpCollector join, ir.Expression body)) { |
| 1725 JumpCollector join = new ForwardJumpCollector(environment); | 1658 JumpCollector join = new ForwardJumpCollector(environment); |
| 1726 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | 1659 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); |
| 1727 | 1660 |
| 1728 // Variables treated as mutable in a try are not mutable outside of it. | 1661 // Variables treated as mutable in a try are not mutable outside of it. |
| 1729 // Work with a copy of the outer builder's mutable variables. | 1662 // Work with a copy of the outer builder's mutable variables. |
| 1730 tryCatchBuilder.mutableVariables = | 1663 tryCatchBuilder.mutableVariables = |
| 1731 new Map<Local, ir.MutableVariable>.from(mutableVariables); | 1664 new Map<Local, ir.MutableVariable>.from(mutableVariables); |
| 1732 for (LocalVariableElement variable in variables.boxedOnEntry) { | 1665 for (LocalVariableElement variable in variables.boxedOnEntry) { |
| 1733 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1666 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1734 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); | 1667 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1752 ir.Primitive value = catchBuilder.buildLocalGet(variable); | 1685 ir.Primitive value = catchBuilder.buildLocalGet(variable); |
| 1753 // After this point, the variables that were boxed on entry to the try | 1686 // After this point, the variables that were boxed on entry to the try |
| 1754 // are no longer treated as mutable. | 1687 // are no longer treated as mutable. |
| 1755 catchBuilder.removeMutableVariable(variable); | 1688 catchBuilder.removeMutableVariable(variable); |
| 1756 catchBuilder.environment.update(variable, value); | 1689 catchBuilder.environment.update(variable, value); |
| 1757 } | 1690 } |
| 1758 | 1691 |
| 1759 List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join); | 1692 List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join); |
| 1760 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | 1693 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); |
| 1761 catchContinuation.body = catchBuilder.root; | 1694 catchContinuation.body = catchBuilder.root; |
| 1762 tryCatchBuilder.add( | 1695 tryCatchBuilder.add(new ir.LetHandler(catchContinuation, tryBuilder.root)); |
| 1763 new ir.LetHandler(catchContinuation, tryBuilder.root)); | |
| 1764 | 1696 |
| 1765 leaveTryCatch(this, join, tryCatchBuilder.root); | 1697 leaveTryCatch(this, join, tryCatchBuilder.root); |
| 1766 } | 1698 } |
| 1767 | 1699 |
| 1768 /// Translates a try/catch. | 1700 /// Translates a try/catch. |
| 1769 /// | 1701 /// |
| 1770 /// [variables] provides information on local variables declared and boxed | 1702 /// [variables] provides information on local variables declared and boxed |
| 1771 /// within the try body. | 1703 /// within the try body. |
| 1772 /// [buildTryBlock] builds the try block. | 1704 /// [buildTryBlock] builds the try block. |
| 1773 /// [catchClauseInfos] provides access to the catch type, exception variable, | 1705 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1774 /// and stack trace variable, and a function for building the catch block. | 1706 /// and stack trace variable, and a function for building the catch block. |
| 1775 void buildTryCatch(TryStatementInfo variables, | 1707 void buildTryCatch(TryStatementInfo variables, SubbuildFunction buildTryBlock, |
| 1776 SubbuildFunction buildTryBlock, | 1708 List<CatchClauseInfo> catchClauseInfos) { |
| 1777 List<CatchClauseInfo> catchClauseInfos) { | |
| 1778 assert(isOpen); | 1709 assert(isOpen); |
| 1779 // Catch handlers are in scope for their body. The CPS translation of | 1710 // Catch handlers are in scope for their body. The CPS translation of |
| 1780 // [[try tryBlock catch (ex, st) catchBlock; successor]] is: | 1711 // [[try tryBlock catch (ex, st) catchBlock; successor]] is: |
| 1781 // | 1712 // |
| 1782 // let cont join(v0, v1, ...) = [[successor]] in | 1713 // let cont join(v0, v1, ...) = [[successor]] in |
| 1783 // let mutable m0 = x0 in | 1714 // let mutable m0 = x0 in |
| 1784 // let mutable m1 = x1 in | 1715 // let mutable m1 = x1 in |
| 1785 // ... | 1716 // ... |
| 1786 // let handler catch_(ex, st) = | 1717 // let handler catch_(ex, st) = |
| 1787 // let prim p0 = GetMutable(m0) in | 1718 // let prim p0 = GetMutable(m0) in |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1821 // On exit from try of try/catch, update the builder's state to reflect | 1752 // On exit from try of try/catch, update the builder's state to reflect |
| 1822 // the variables that are no longer boxed. | 1753 // the variables that are no longer boxed. |
| 1823 void restoreJump(JumpCollector collector) { | 1754 void restoreJump(JumpCollector collector) { |
| 1824 collector.leaveTry(); | 1755 collector.leaveTry(); |
| 1825 } | 1756 } |
| 1826 builder.state.breakCollectors.forEach(restoreJump); | 1757 builder.state.breakCollectors.forEach(restoreJump); |
| 1827 builder.state.continueCollectors.forEach(restoreJump); | 1758 builder.state.continueCollectors.forEach(restoreJump); |
| 1828 restoreJump(builder.state.returnCollector); | 1759 restoreJump(builder.state.returnCollector); |
| 1829 } | 1760 } |
| 1830 | 1761 |
| 1831 List<ir.Parameter> buildCatch(IrBuilder builder, | 1762 List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join) { |
| 1832 JumpCollector join) { | |
| 1833 // Translate the catch clauses. Multiple clauses are translated as if | 1763 // Translate the catch clauses. Multiple clauses are translated as if |
| 1834 // they were explicitly cascaded if/else type tests. | 1764 // they were explicitly cascaded if/else type tests. |
| 1835 | 1765 |
| 1836 // Handlers are always translated as having both exception and stack trace | 1766 // Handlers are always translated as having both exception and stack trace |
| 1837 // parameters. Multiple clauses do not have to use the same names for | 1767 // parameters. Multiple clauses do not have to use the same names for |
| 1838 // them. Choose the first of each as the name hint for the respective | 1768 // them. Choose the first of each as the name hint for the respective |
| 1839 // handler parameter. | 1769 // handler parameter. |
| 1840 ir.Parameter exceptionParameter = | 1770 ir.Parameter exceptionParameter = |
| 1841 new ir.Parameter(catchClauseInfos.first.exceptionVariable); | 1771 new ir.Parameter(catchClauseInfos.first.exceptionVariable); |
| 1842 LocalVariableElement traceVariable; | 1772 LocalVariableElement traceVariable; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1864 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, | 1794 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, |
| 1865 initialValue: traceParameter); | 1795 initialValue: traceParameter); |
| 1866 } | 1796 } |
| 1867 clause.buildCatchBlock(clauseBuilder); | 1797 clause.buildCatchBlock(clauseBuilder); |
| 1868 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | 1798 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); |
| 1869 return clauseBuilder.root; | 1799 return clauseBuilder.root; |
| 1870 } | 1800 } |
| 1871 | 1801 |
| 1872 // Expand multiple catch clauses into an explicit if/then/else. Iterate | 1802 // Expand multiple catch clauses into an explicit if/then/else. Iterate |
| 1873 // them in reverse so the current block becomes the next else block. | 1803 // them in reverse so the current block becomes the next else block. |
| 1874 ir.Expression catchBody = (catchAll == null) | 1804 ir.Expression catchBody = |
| 1875 ? new ir.Rethrow() | 1805 (catchAll == null) ? new ir.Rethrow() : buildCatchClause(catchAll); |
| 1876 : buildCatchClause(catchAll); | |
| 1877 for (CatchClauseInfo clause in catchClauseInfos.reversed) { | 1806 for (CatchClauseInfo clause in catchClauseInfos.reversed) { |
| 1878 ir.Continuation thenContinuation = new ir.Continuation([]); | 1807 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1879 ir.Continuation elseContinuation = new ir.Continuation([]); | 1808 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1880 thenContinuation.body = buildCatchClause(clause); | 1809 thenContinuation.body = buildCatchClause(clause); |
| 1881 elseContinuation.body = catchBody; | 1810 elseContinuation.body = catchBody; |
| 1882 | 1811 |
| 1883 // Build the type test guarding this clause. We can share the | 1812 // Build the type test guarding this clause. We can share the |
| 1884 // environment with the nested builder because this part cannot mutate | 1813 // environment with the nested builder because this part cannot mutate |
| 1885 // it. | 1814 // it. |
| 1886 IrBuilder checkBuilder = builder.makeDelimitedBuilder(environment); | 1815 IrBuilder checkBuilder = builder.makeDelimitedBuilder(environment); |
| 1887 ir.Primitive typeMatches = | 1816 ir.Primitive typeMatches = checkBuilder.buildTypeOperator( |
| 1888 checkBuilder.buildTypeOperator(exceptionParameter, | 1817 exceptionParameter, clause.type, clause.sourceInformation, |
| 1889 clause.type, | 1818 isTypeTest: true); |
| 1890 clause.sourceInformation, | 1819 checkBuilder.add(new ir.LetCont.two( |
| 1891 isTypeTest: true); | 1820 thenContinuation, |
| 1892 checkBuilder.add(new ir.LetCont.two(thenContinuation, elseContinuation, | 1821 elseContinuation, |
| 1893 new ir.Branch.strict(typeMatches, | 1822 new ir.Branch.strict(typeMatches, thenContinuation, |
| 1894 thenContinuation, | 1823 elseContinuation, clause.sourceInformation))); |
| 1895 elseContinuation, | |
| 1896 clause.sourceInformation))); | |
| 1897 catchBody = checkBuilder.root; | 1824 catchBody = checkBuilder.root; |
| 1898 } | 1825 } |
| 1899 builder.add(catchBody); | 1826 builder.add(catchBody); |
| 1900 | 1827 |
| 1901 return <ir.Parameter>[exceptionParameter, traceParameter]; | 1828 return <ir.Parameter>[exceptionParameter, traceParameter]; |
| 1902 } | 1829 } |
| 1903 | 1830 |
| 1904 void leaveTryCatch(IrBuilder builder, JumpCollector join, | 1831 void leaveTryCatch( |
| 1905 ir.Expression body) { | 1832 IrBuilder builder, JumpCollector join, ir.Expression body) { |
| 1906 // Add the binding for the join-point continuation and continue the | 1833 // Add the binding for the join-point continuation and continue the |
| 1907 // translation in its body. | 1834 // translation in its body. |
| 1908 builder.add(new ir.LetCont(join.continuation, body)); | 1835 builder.add(new ir.LetCont(join.continuation, body)); |
| 1909 builder.environment = join.environment; | 1836 builder.environment = join.environment; |
| 1910 } | 1837 } |
| 1911 | 1838 |
| 1912 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, | 1839 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, buildCatch, |
| 1913 buildCatch, leaveTryCatch); | 1840 leaveTryCatch); |
| 1914 } | 1841 } |
| 1915 | 1842 |
| 1916 /// Translates a try/finally. | 1843 /// Translates a try/finally. |
| 1917 /// | 1844 /// |
| 1918 /// [variables] provides information on local variables declared and boxed | 1845 /// [variables] provides information on local variables declared and boxed |
| 1919 /// within the try body. | 1846 /// within the try body. |
| 1920 /// [buildTryBlock] builds the try block. | 1847 /// [buildTryBlock] builds the try block. |
| 1921 /// [buildFinallyBlock] builds the finally block. | 1848 /// [buildFinallyBlock] builds the finally block. |
| 1922 void buildTryFinally(TryStatementInfo variables, | 1849 void buildTryFinally(TryStatementInfo variables, |
| 1923 SubbuildFunction buildTryBlock, | 1850 SubbuildFunction buildTryBlock, SubbuildFunction buildFinallyBlock) { |
| 1924 SubbuildFunction buildFinallyBlock) { | |
| 1925 assert(isOpen); | 1851 assert(isOpen); |
| 1926 // Try/finally is implemented in terms of try/catch and by duplicating the | 1852 // Try/finally is implemented in terms of try/catch and by duplicating the |
| 1927 // code for finally at all exits. The encoding is: | 1853 // code for finally at all exits. The encoding is: |
| 1928 // | 1854 // |
| 1929 // try tryBlock finally finallyBlock | 1855 // try tryBlock finally finallyBlock |
| 1930 // ==> | 1856 // ==> |
| 1931 // try tryBlock catch (ex, st) { finallyBlock; rethrow } finallyBlock | 1857 // try tryBlock catch (ex, st) { finallyBlock; rethrow } finallyBlock |
| 1932 // | 1858 // |
| 1933 // Where in tryBlock, all of the break, continue, and return exits are | 1859 // Where in tryBlock, all of the break, continue, and return exits are |
| 1934 // translated as jumps to continuations (bound outside the catch handler) | 1860 // translated as jumps to continuations (bound outside the catch handler) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1945 JumpCollector interceptJump(JumpCollector collector) { | 1871 JumpCollector interceptJump(JumpCollector collector) { |
| 1946 JumpCollector result = | 1872 JumpCollector result = |
| 1947 new ForwardJumpCollector(environment, target: collector.target); | 1873 new ForwardJumpCollector(environment, target: collector.target); |
| 1948 result.enterTry(variables.boxedOnEntry); | 1874 result.enterTry(variables.boxedOnEntry); |
| 1949 return result; | 1875 return result; |
| 1950 } | 1876 } |
| 1951 savedBreaks = builder.state.breakCollectors; | 1877 savedBreaks = builder.state.breakCollectors; |
| 1952 savedContinues = builder.state.continueCollectors; | 1878 savedContinues = builder.state.continueCollectors; |
| 1953 savedReturn = builder.state.returnCollector; | 1879 savedReturn = builder.state.returnCollector; |
| 1954 | 1880 |
| 1955 builder.state.breakCollectors = newBreaks = | 1881 builder.state.breakCollectors = |
| 1956 savedBreaks.map(interceptJump).toList(); | 1882 newBreaks = savedBreaks.map(interceptJump).toList(); |
| 1957 builder.state.continueCollectors = newContinues = | 1883 builder.state.continueCollectors = |
| 1958 savedContinues.map(interceptJump).toList(); | 1884 newContinues = savedContinues.map(interceptJump).toList(); |
| 1959 builder.state.returnCollector = newReturn = | 1885 builder.state.returnCollector = newReturn = |
| 1960 new ForwardJumpCollector(environment, hasExtraArgument: true) | 1886 new ForwardJumpCollector(environment, hasExtraArgument: true) |
| 1961 ..enterTry(variables.boxedOnEntry); | 1887 ..enterTry(variables.boxedOnEntry); |
| 1962 } | 1888 } |
| 1963 | 1889 |
| 1964 void leaveTry(IrBuilder builder) { | 1890 void leaveTry(IrBuilder builder) { |
| 1965 // On exit from the try of try/finally, update the builder's state to | 1891 // On exit from the try of try/finally, update the builder's state to |
| 1966 // reflect the variables that are no longer boxed and restore the | 1892 // reflect the variables that are no longer boxed and restore the |
| 1967 // original, unintercepted break, continue, and return targets. | 1893 // original, unintercepted break, continue, and return targets. |
| 1968 void restoreJump(JumpCollector collector) { | 1894 void restoreJump(JumpCollector collector) { |
| 1969 collector.leaveTry(); | 1895 collector.leaveTry(); |
| 1970 } | 1896 } |
| 1971 newBreaks.forEach(restoreJump); | 1897 newBreaks.forEach(restoreJump); |
| 1972 newContinues.forEach(restoreJump); | 1898 newContinues.forEach(restoreJump); |
| 1973 newReturn.leaveTry(); | 1899 newReturn.leaveTry(); |
| 1974 builder.state.breakCollectors = savedBreaks; | 1900 builder.state.breakCollectors = savedBreaks; |
| 1975 builder.state.continueCollectors = savedContinues; | 1901 builder.state.continueCollectors = savedContinues; |
| 1976 builder.state.returnCollector = savedReturn; | 1902 builder.state.returnCollector = savedReturn; |
| 1977 } | 1903 } |
| 1978 | 1904 |
| 1979 List<ir.Parameter> buildCatch(IrBuilder builder, | 1905 List<ir.Parameter> buildCatch(IrBuilder builder, JumpCollector join) { |
| 1980 JumpCollector join) { | |
| 1981 // The catch block of the try/catch used for try/finally is the finally | 1906 // The catch block of the try/catch used for try/finally is the finally |
| 1982 // code followed by a rethrow. | 1907 // code followed by a rethrow. |
| 1983 buildFinallyBlock(builder); | 1908 buildFinallyBlock(builder); |
| 1984 if (builder.isOpen) { | 1909 if (builder.isOpen) { |
| 1985 builder.add(new ir.Rethrow()); | 1910 builder.add(new ir.Rethrow()); |
| 1986 builder._current = null; | 1911 builder._current = null; |
| 1987 } | 1912 } |
| 1988 return <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)]; | 1913 return <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)]; |
| 1989 } | 1914 } |
| 1990 | 1915 |
| 1991 void leaveTryCatch(IrBuilder builder, JumpCollector join, | 1916 void leaveTryCatch( |
| 1992 ir.Expression body) { | 1917 IrBuilder builder, JumpCollector join, ir.Expression body) { |
| 1993 // Build a list of continuations for jumps from the try block and | 1918 // Build a list of continuations for jumps from the try block and |
| 1994 // duplicate the finally code before jumping to the actual target. | 1919 // duplicate the finally code before jumping to the actual target. |
| 1995 List<ir.Continuation> exits = <ir.Continuation>[join.continuation]; | 1920 List<ir.Continuation> exits = <ir.Continuation>[join.continuation]; |
| 1996 void addJump(JumpCollector newCollector, | 1921 void addJump( |
| 1997 JumpCollector originalCollector) { | 1922 JumpCollector newCollector, JumpCollector originalCollector) { |
| 1998 if (newCollector.isEmpty) return; | 1923 if (newCollector.isEmpty) return; |
| 1999 IrBuilder builder = makeDelimitedBuilder(newCollector.environment); | 1924 IrBuilder builder = makeDelimitedBuilder(newCollector.environment); |
| 2000 buildFinallyBlock(builder); | 1925 buildFinallyBlock(builder); |
| 2001 if (builder.isOpen) builder.jumpTo(originalCollector); | 1926 if (builder.isOpen) builder.jumpTo(originalCollector); |
| 2002 newCollector.continuation.body = builder.root; | 1927 newCollector.continuation.body = builder.root; |
| 2003 exits.add(newCollector.continuation); | 1928 exits.add(newCollector.continuation); |
| 2004 } | 1929 } |
| 2005 for (int i = 0; i < newBreaks.length; ++i) { | 1930 for (int i = 0; i < newBreaks.length; ++i) { |
| 2006 addJump(newBreaks[i], savedBreaks[i]); | 1931 addJump(newBreaks[i], savedBreaks[i]); |
| 2007 } | 1932 } |
| 2008 for (int i = 0; i < newContinues.length; ++i) { | 1933 for (int i = 0; i < newContinues.length; ++i) { |
| 2009 addJump(newContinues[i], savedContinues[i]); | 1934 addJump(newContinues[i], savedContinues[i]); |
| 2010 } | 1935 } |
| 2011 if (!newReturn.isEmpty) { | 1936 if (!newReturn.isEmpty) { |
| 2012 IrBuilder builder = makeDelimitedBuilder(newReturn.environment); | 1937 IrBuilder builder = makeDelimitedBuilder(newReturn.environment); |
| 2013 ir.Primitive value = builder.environment.discard(1); | 1938 ir.Primitive value = builder.environment.discard(1); |
| 2014 buildFinallyBlock(builder); | 1939 buildFinallyBlock(builder); |
| 2015 if (builder.isOpen) builder.buildReturn(value: value); | 1940 if (builder.isOpen) builder.buildReturn(value: value); |
| 2016 newReturn.continuation.body = builder.root; | 1941 newReturn.continuation.body = builder.root; |
| 2017 exits.add(newReturn.continuation); | 1942 exits.add(newReturn.continuation); |
| 2018 } | 1943 } |
| 2019 builder.add(new ir.LetCont.many(exits, body)); | 1944 builder.add(new ir.LetCont.many(exits, body)); |
| 2020 builder.environment = join.environment; | 1945 builder.environment = join.environment; |
| 2021 buildFinallyBlock(builder); | 1946 buildFinallyBlock(builder); |
| 2022 } | 1947 } |
| 2023 | 1948 |
| 2024 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, | 1949 _helpBuildTryCatch(variables, enterTry, buildTryBlock, leaveTry, buildCatch, |
| 2025 buildCatch, leaveTryCatch); | 1950 leaveTryCatch); |
| 2026 } | 1951 } |
| 2027 | 1952 |
| 2028 /// Create a return statement `return value;` or `return;` if [value] is | 1953 /// Create a return statement `return value;` or `return;` if [value] is |
| 2029 /// null. | 1954 /// null. |
| 2030 void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) { | 1955 void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) { |
| 2031 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1956 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 2032 // where (C', x) = Build(e, C) | 1957 // where (C', x) = Build(e, C) |
| 2033 // | 1958 // |
| 2034 // Return without a subexpression is translated as if it were return null. | 1959 // Return without a subexpression is translated as if it were return null. |
| 2035 assert(isOpen); | 1960 assert(isOpen); |
| 2036 if (value == null) { | 1961 if (value == null) { |
| 2037 value = buildNullConstant(); | 1962 value = buildNullConstant(); |
| 2038 } | 1963 } |
| 2039 jumpTo(state.returnCollector, value, sourceInformation); | 1964 jumpTo(state.returnCollector, value, sourceInformation); |
| 2040 } | 1965 } |
| 2041 | 1966 |
| 2042 /// Generate the body for a native function [function] that is annotated with | 1967 /// Generate the body for a native function [function] that is annotated with |
| 2043 /// an implementation in JavaScript (provided as string in [javaScriptCode]). | 1968 /// an implementation in JavaScript (provided as string in [javaScriptCode]). |
| 2044 void buildNativeFunctionBody( | 1969 void buildNativeFunctionBody(FunctionElement function, String javaScriptCode, |
| 2045 FunctionElement function, | |
| 2046 String javaScriptCode, | |
| 2047 SourceInformation sourceInformation) { | 1970 SourceInformation sourceInformation) { |
| 2048 NativeBehavior behavior = new NativeBehavior(); | 1971 NativeBehavior behavior = new NativeBehavior(); |
| 2049 behavior.sideEffects.setAllSideEffects(); | 1972 behavior.sideEffects.setAllSideEffects(); |
| 2050 // Generate a [ForeignCode] statement from the given native code. | 1973 // Generate a [ForeignCode] statement from the given native code. |
| 2051 buildForeignCode( | 1974 buildForeignCode( |
| 2052 js.js.statementTemplateYielding( | 1975 js.js |
| 2053 new js.LiteralStatement(javaScriptCode)), | 1976 .statementTemplateYielding(new js.LiteralStatement(javaScriptCode)), |
| 2054 <ir.Primitive>[], | 1977 <ir.Primitive>[], |
| 2055 behavior, | 1978 behavior, |
| 2056 sourceInformation); | 1979 sourceInformation); |
| 2057 } | 1980 } |
| 2058 | 1981 |
| 2059 /// Generate the body for a native function that redirects to a native | 1982 /// Generate the body for a native function that redirects to a native |
| 2060 /// JavaScript function, getter, or setter. | 1983 /// JavaScript function, getter, or setter. |
| 2061 /// | 1984 /// |
| 2062 /// Generates a call to the real target, which is given by [functions]'s | 1985 /// Generates a call to the real target, which is given by [functions]'s |
| 2063 /// `fixedBackendName`, passing all parameters as arguments. The target can | 1986 /// `fixedBackendName`, passing all parameters as arguments. The target can |
| 2064 /// be the JavaScript implementation of a function, getter, or setter. | 1987 /// be the JavaScript implementation of a function, getter, or setter. |
| 2065 void buildRedirectingNativeFunctionBody(FunctionElement function, | 1988 void buildRedirectingNativeFunctionBody(FunctionElement function, String name, |
| 2066 String name, | 1989 SourceInformation sourceInformation) { |
| 2067 SourceInformation sourceInformation) { | |
| 2068 List<ir.Primitive> arguments = <ir.Primitive>[]; | 1990 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 2069 NativeBehavior behavior = new NativeBehavior(); | 1991 NativeBehavior behavior = new NativeBehavior(); |
| 2070 behavior.sideEffects.setAllSideEffects(); | 1992 behavior.sideEffects.setAllSideEffects(); |
| 2071 program.addNativeMethod(function); | 1993 program.addNativeMethod(function); |
| 2072 // Construct the access of the target element. | 1994 // Construct the access of the target element. |
| 2073 String code = function.isInstanceMember ? '#.$name' : name; | 1995 String code = function.isInstanceMember ? '#.$name' : name; |
| 2074 if (function.isInstanceMember) { | 1996 if (function.isInstanceMember) { |
| 2075 arguments.add(state.thisParameter); | 1997 arguments.add(state.thisParameter); |
| 2076 } | 1998 } |
| 2077 // Collect all parameters of the function and templates for them to be | 1999 // Collect all parameters of the function and templates for them to be |
| 2078 // inserted into the JavaScript code. | 2000 // inserted into the JavaScript code. |
| 2079 List<String> argumentTemplates = <String>[]; | 2001 List<String> argumentTemplates = <String>[]; |
| 2080 function.functionSignature.forEachParameter((ParameterElement parameter) { | 2002 function.functionSignature.forEachParameter((ParameterElement parameter) { |
| 2081 ir.Primitive input = environment.lookup(parameter); | 2003 ir.Primitive input = environment.lookup(parameter); |
| 2082 DartType type = program.unaliasType(parameter.type); | 2004 DartType type = program.unaliasType(parameter.type); |
| 2083 if (type is FunctionType) { | 2005 if (type is FunctionType) { |
| 2084 // The parameter type is a function type either directly or through | 2006 // The parameter type is a function type either directly or through |
| 2085 // typedef(s). | 2007 // typedef(s). |
| 2086 ir.Constant arity = buildIntegerConstant(type.computeArity()); | 2008 ir.Constant arity = buildIntegerConstant(type.computeArity()); |
| 2087 input = buildStaticFunctionInvocation( | 2009 input = buildStaticFunctionInvocation(program.closureConverter, |
| 2088 program.closureConverter, <ir.Primitive>[input, arity], | 2010 <ir.Primitive>[input, arity], sourceInformation); |
| 2089 sourceInformation); | |
| 2090 } | 2011 } |
| 2091 arguments.add(input); | 2012 arguments.add(input); |
| 2092 argumentTemplates.add('#'); | 2013 argumentTemplates.add('#'); |
| 2093 }); | 2014 }); |
| 2094 // Construct the application of parameters for functions and setters. | 2015 // Construct the application of parameters for functions and setters. |
| 2095 if (function.kind == ElementKind.FUNCTION) { | 2016 if (function.kind == ElementKind.FUNCTION) { |
| 2096 code = "$code(${argumentTemplates.join(', ')})"; | 2017 code = "$code(${argumentTemplates.join(', ')})"; |
| 2097 } else if (function.kind == ElementKind.SETTER) { | 2018 } else if (function.kind == ElementKind.SETTER) { |
| 2098 code = "$code = ${argumentTemplates.single}"; | 2019 code = "$code = ${argumentTemplates.single}"; |
| 2099 } else { | 2020 } else { |
| 2100 assert(argumentTemplates.isEmpty); | 2021 assert(argumentTemplates.isEmpty); |
| 2101 assert(function.kind == ElementKind.GETTER); | 2022 assert(function.kind == ElementKind.GETTER); |
| 2102 } | 2023 } |
| 2103 // Generate the [ForeignCode] expression and a return statement to return | 2024 // Generate the [ForeignCode] expression and a return statement to return |
| 2104 // its value. | 2025 // its value. |
| 2105 ir.Primitive value = buildForeignCode( | 2026 ir.Primitive value = buildForeignCode( |
| 2106 js.js.uncachedExpressionTemplate(code), | 2027 js.js.uncachedExpressionTemplate(code), |
| 2107 arguments, | 2028 arguments, |
| 2108 behavior, | 2029 behavior, |
| 2109 sourceInformation, | 2030 sourceInformation, |
| 2110 type: program.getTypeMaskForNativeFunction(function)); | 2031 type: program.getTypeMaskForNativeFunction(function)); |
| 2111 buildReturn(value: value, sourceInformation: sourceInformation); | 2032 buildReturn(value: value, sourceInformation: sourceInformation); |
| 2112 } | 2033 } |
| 2113 | 2034 |
| 2114 static _isNotNull(ir.Primitive value) => | 2035 static _isNotNull(ir.Primitive value) => |
| 2115 !(value is ir.Constant && value.value.isNull); | 2036 !(value is ir.Constant && value.value.isNull); |
| 2116 | 2037 |
| 2117 /// Builds a call to a resolved js-interop element. | 2038 /// Builds a call to a resolved js-interop element. |
| 2118 ir.Primitive buildInvokeJsInteropMember( | 2039 ir.Primitive buildInvokeJsInteropMember(FunctionElement element, |
| 2119 FunctionElement element, | 2040 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 2120 List<ir.Primitive> arguments, | |
| 2121 SourceInformation sourceInformation) { | |
| 2122 program.addNativeMethod(element); | 2041 program.addNativeMethod(element); |
| 2123 String target = program.getJsInteropTargetPath(element); | 2042 String target = program.getJsInteropTargetPath(element); |
| 2124 // Strip off trailing arguments that were not specified. | 2043 // Strip off trailing arguments that were not specified. |
| 2125 // TODO(jacobr,sigmund): assert that the trailing arguments are all null. | 2044 // TODO(jacobr,sigmund): assert that the trailing arguments are all null. |
| 2126 // TODO(jacobr): rewrite named arguments to an object literal matching | 2045 // TODO(jacobr): rewrite named arguments to an object literal matching |
| 2127 // the factory constructor case. | 2046 // the factory constructor case. |
| 2128 var inputs = arguments.where(_isNotNull).toList(); | 2047 var inputs = arguments.where(_isNotNull).toList(); |
| 2129 | 2048 |
| 2130 var behavior = new NativeBehavior()..sideEffects.setAllSideEffects(); | 2049 var behavior = new NativeBehavior()..sideEffects.setAllSideEffects(); |
| 2131 DartType type = element.isConstructor ? | 2050 DartType type = element.isConstructor |
| 2132 element.enclosingClass.thisType : element.type.returnType; | 2051 ? element.enclosingClass.thisType |
| 2052 : element.type.returnType; |
| 2133 // Native behavior effects here are similar to native/behavior.dart. | 2053 // Native behavior effects here are similar to native/behavior.dart. |
| 2134 // The return type is dynamic if we don't trust js-interop type | 2054 // The return type is dynamic if we don't trust js-interop type |
| 2135 // declarations. | 2055 // declarations. |
| 2136 behavior.typesReturned.add( | 2056 behavior.typesReturned.add( |
| 2137 program.trustJSInteropTypeAnnotations ? type : const DynamicType()); | 2057 program.trustJSInteropTypeAnnotations ? type : const DynamicType()); |
| 2138 | 2058 |
| 2139 // The allocation effects include the declared type if it is native (which | 2059 // The allocation effects include the declared type if it is native (which |
| 2140 // includes js interop types). | 2060 // includes js interop types). |
| 2141 if (type.element != null && program.isNative(type.element)) { | 2061 if (type.element != null && program.isNative(type.element)) { |
| 2142 behavior.typesInstantiated.add(type); | 2062 behavior.typesInstantiated.add(type); |
| 2143 } | 2063 } |
| 2144 | 2064 |
| 2145 // It also includes any other JS interop type if we don't trust the | 2065 // It also includes any other JS interop type if we don't trust the |
| 2146 // annotation or if is declared too broad. | 2066 // annotation or if is declared too broad. |
| 2147 if (!program.trustJSInteropTypeAnnotations || type.isObject || | 2067 if (!program.trustJSInteropTypeAnnotations || |
| 2068 type.isObject || |
| 2148 type.isDynamic) { | 2069 type.isDynamic) { |
| 2149 behavior.typesInstantiated.add(program.jsJavascriptObjectType); | 2070 behavior.typesInstantiated.add(program.jsJavascriptObjectType); |
| 2150 } | 2071 } |
| 2151 | 2072 |
| 2152 String code; | 2073 String code; |
| 2153 if (element.isGetter) { | 2074 if (element.isGetter) { |
| 2154 code = target; | 2075 code = target; |
| 2155 } else if (element.isSetter) { | 2076 } else if (element.isSetter) { |
| 2156 code = "$target = #"; | 2077 code = "$target = #"; |
| 2157 } else { | 2078 } else { |
| 2158 var args = new List.filled(inputs.length, '#').join(','); | 2079 var args = new List.filled(inputs.length, '#').join(','); |
| 2159 code = element.isConstructor ? "new $target($args)" : "$target($args)"; | 2080 code = element.isConstructor ? "new $target($args)" : "$target($args)"; |
| 2160 } | 2081 } |
| 2161 return buildForeignCode(js.js.parseForeignJS(code), | 2082 return buildForeignCode( |
| 2162 inputs, behavior, sourceInformation); | 2083 js.js.parseForeignJS(code), inputs, behavior, sourceInformation); |
| 2163 // TODO(sigmund): should we record the source-information here? | 2084 // TODO(sigmund): should we record the source-information here? |
| 2164 } | 2085 } |
| 2165 | 2086 |
| 2166 /// Builds an object literal that results from invoking a factory constructor | 2087 /// Builds an object literal that results from invoking a factory constructor |
| 2167 /// of a js-interop anonymous type. | 2088 /// of a js-interop anonymous type. |
| 2168 ir.Primitive buildJsInteropObjectLiteral( | 2089 ir.Primitive buildJsInteropObjectLiteral(ConstructorElement constructor, |
| 2169 ConstructorElement constructor, | 2090 List<ir.Primitive> arguments, SourceInformation sourceInformation) { |
| 2170 List<ir.Primitive> arguments, | |
| 2171 SourceInformation sourceInformation) { | |
| 2172 assert(program.isJsInteropAnonymous(constructor)); | 2091 assert(program.isJsInteropAnonymous(constructor)); |
| 2173 program.addNativeMethod(constructor); | 2092 program.addNativeMethod(constructor); |
| 2174 FunctionSignature params = constructor.functionSignature; | 2093 FunctionSignature params = constructor.functionSignature; |
| 2175 int i = 0; | 2094 int i = 0; |
| 2176 var filteredArguments = <ir.Primitive>[]; | 2095 var filteredArguments = <ir.Primitive>[]; |
| 2177 var entries = new Map<String, js.Expression>(); | 2096 var entries = new Map<String, js.Expression>(); |
| 2178 params.orderedForEachParameter((ParameterElement parameter) { | 2097 params.orderedForEachParameter((ParameterElement parameter) { |
| 2179 // TODO(jacobr): throw if parameter names do not match names of property | 2098 // TODO(jacobr): throw if parameter names do not match names of property |
| 2180 // names in the class. | 2099 // names in the class. |
| 2181 assert (parameter.isNamed); | 2100 assert(parameter.isNamed); |
| 2182 ir.Primitive argument = arguments[i++]; | 2101 ir.Primitive argument = arguments[i++]; |
| 2183 if (_isNotNull(argument)) { | 2102 if (_isNotNull(argument)) { |
| 2184 filteredArguments.add(argument); | 2103 filteredArguments.add(argument); |
| 2185 entries[parameter.name] = | 2104 entries[parameter.name] = |
| 2186 new js.InterpolatedExpression(filteredArguments.length - 1); | 2105 new js.InterpolatedExpression(filteredArguments.length - 1); |
| 2187 } | 2106 } |
| 2188 }); | 2107 }); |
| 2189 var code = new js.Template(null, js.objectLiteral(entries)); | 2108 var code = new js.Template(null, js.objectLiteral(entries)); |
| 2190 var behavior = new NativeBehavior(); | 2109 var behavior = new NativeBehavior(); |
| 2191 if (program.trustJSInteropTypeAnnotations) { | 2110 if (program.trustJSInteropTypeAnnotations) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2213 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses | 2132 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses |
| 2214 // `List` instead of `Link`. | 2133 // `List` instead of `Link`. |
| 2215 void buildSequence(var nodes, BuildFunction build) { | 2134 void buildSequence(var nodes, BuildFunction build) { |
| 2216 for (var node in nodes) { | 2135 for (var node in nodes) { |
| 2217 if (!isOpen) return; | 2136 if (!isOpen) return; |
| 2218 build(node); | 2137 build(node); |
| 2219 } | 2138 } |
| 2220 } | 2139 } |
| 2221 | 2140 |
| 2222 /// Creates a labeled statement | 2141 /// Creates a labeled statement |
| 2223 void buildLabeledStatement({SubbuildFunction buildBody, | 2142 void buildLabeledStatement({SubbuildFunction buildBody, JumpTarget target}) { |
| 2224 JumpTarget target}) { | |
| 2225 JumpCollector join = new ForwardJumpCollector(environment, target: target); | 2143 JumpCollector join = new ForwardJumpCollector(environment, target: target); |
| 2226 IrBuilder innerBuilder = makeDelimitedBuilder(); | 2144 IrBuilder innerBuilder = makeDelimitedBuilder(); |
| 2227 innerBuilder.state.breakCollectors.add(join); | 2145 innerBuilder.state.breakCollectors.add(join); |
| 2228 buildBody(innerBuilder); | 2146 buildBody(innerBuilder); |
| 2229 innerBuilder.state.breakCollectors.removeLast(); | 2147 innerBuilder.state.breakCollectors.removeLast(); |
| 2230 bool hasBreaks = !join.isEmpty; | 2148 bool hasBreaks = !join.isEmpty; |
| 2231 if (hasBreaks) { | 2149 if (hasBreaks) { |
| 2232 if (innerBuilder.isOpen) innerBuilder.jumpTo(join); | 2150 if (innerBuilder.isOpen) innerBuilder.jumpTo(join); |
| 2233 add(new ir.LetCont(join.continuation, innerBuilder.root)); | 2151 add(new ir.LetCont(join.continuation, innerBuilder.root)); |
| 2234 environment = join.environment; | 2152 environment = join.environment; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2250 } | 2168 } |
| 2251 | 2169 |
| 2252 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] | 2170 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] |
| 2253 // | 2171 // |
| 2254 // The continuation and arguments are filled in later after translating | 2172 // The continuation and arguments are filled in later after translating |
| 2255 // the body containing the continue. | 2173 // the body containing the continue. |
| 2256 bool buildContinue(JumpTarget target) { | 2174 bool buildContinue(JumpTarget target) { |
| 2257 return buildJumpInternal(target, state.continueCollectors); | 2175 return buildJumpInternal(target, state.continueCollectors); |
| 2258 } | 2176 } |
| 2259 | 2177 |
| 2260 bool buildJumpInternal(JumpTarget target, | 2178 bool buildJumpInternal( |
| 2261 Iterable<JumpCollector> collectors) { | 2179 JumpTarget target, Iterable<JumpCollector> collectors) { |
| 2262 assert(isOpen); | 2180 assert(isOpen); |
| 2263 for (JumpCollector collector in collectors) { | 2181 for (JumpCollector collector in collectors) { |
| 2264 if (target == collector.target) { | 2182 if (target == collector.target) { |
| 2265 jumpTo(collector); | 2183 jumpTo(collector); |
| 2266 return true; | 2184 return true; |
| 2267 } | 2185 } |
| 2268 } | 2186 } |
| 2269 return false; | 2187 return false; |
| 2270 } | 2188 } |
| 2271 | 2189 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2284 } | 2202 } |
| 2285 | 2203 |
| 2286 void buildRethrow() { | 2204 void buildRethrow() { |
| 2287 assert(isOpen); | 2205 assert(isOpen); |
| 2288 add(new ir.Rethrow()); | 2206 add(new ir.Rethrow()); |
| 2289 _current = null; | 2207 _current = null; |
| 2290 } | 2208 } |
| 2291 | 2209 |
| 2292 /// Create a negation of [condition]. | 2210 /// Create a negation of [condition]. |
| 2293 ir.Primitive buildNegation( | 2211 ir.Primitive buildNegation( |
| 2294 ir.Primitive condition, | 2212 ir.Primitive condition, SourceInformation sourceInformation) { |
| 2295 SourceInformation sourceInformation) { | |
| 2296 // ! e is translated as e ? false : true | 2213 // ! e is translated as e ? false : true |
| 2297 | 2214 |
| 2298 // Add a continuation parameter for the result of the expression. | 2215 // Add a continuation parameter for the result of the expression. |
| 2299 ir.Parameter resultParameter = new ir.Parameter(null); | 2216 ir.Parameter resultParameter = new ir.Parameter(null); |
| 2300 | 2217 |
| 2301 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); | 2218 ir.Continuation joinContinuation = new ir.Continuation([resultParameter]); |
| 2302 ir.Continuation thenContinuation = new ir.Continuation([]); | 2219 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 2303 ir.Continuation elseContinuation = new ir.Continuation([]); | 2220 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 2304 | 2221 |
| 2305 ir.Constant makeBoolConstant(bool value) { | 2222 ir.Constant makeBoolConstant(bool value) { |
| 2306 return new ir.Constant(state.constantSystem.createBool(value)); | 2223 return new ir.Constant(state.constantSystem.createBool(value)); |
| 2307 } | 2224 } |
| 2308 | 2225 |
| 2309 ir.Constant trueConstant = makeBoolConstant(true); | 2226 ir.Constant trueConstant = makeBoolConstant(true); |
| 2310 ir.Constant falseConstant = makeBoolConstant(false); | 2227 ir.Constant falseConstant = makeBoolConstant(false); |
| 2311 | 2228 |
| 2312 thenContinuation.body = new ir.LetPrim(falseConstant) | 2229 thenContinuation.body = new ir.LetPrim(falseConstant) |
| 2313 ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); | 2230 ..plug(new ir.InvokeContinuation(joinContinuation, [falseConstant])); |
| 2314 elseContinuation.body = new ir.LetPrim(trueConstant) | 2231 elseContinuation.body = new ir.LetPrim(trueConstant) |
| 2315 ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); | 2232 ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant])); |
| 2316 | 2233 |
| 2317 add(new ir.LetCont(joinContinuation, | 2234 add(new ir.LetCont( |
| 2318 new ir.LetCont.two(thenContinuation, elseContinuation, | 2235 joinContinuation, |
| 2319 new ir.Branch.strict(condition, | 2236 new ir.LetCont.two( |
| 2320 thenContinuation, | 2237 thenContinuation, |
| 2321 elseContinuation, | 2238 elseContinuation, |
| 2322 sourceInformation)))); | 2239 new ir.Branch.strict(condition, thenContinuation, elseContinuation, |
| 2240 sourceInformation)))); |
| 2323 return resultParameter; | 2241 return resultParameter; |
| 2324 } | 2242 } |
| 2325 | 2243 |
| 2326 /// Create a lazy and/or expression. [leftValue] is the value of the left | 2244 /// Create a lazy and/or expression. [leftValue] is the value of the left |
| 2327 /// operand and [buildRightValue] is called to process the value of the right | 2245 /// operand and [buildRightValue] is called to process the value of the right |
| 2328 /// operand in the context of its own [IrBuilder]. | 2246 /// operand in the context of its own [IrBuilder]. |
| 2329 ir.Primitive buildLogicalOperator( | 2247 ir.Primitive buildLogicalOperator( |
| 2330 ir.Primitive leftValue, | 2248 ir.Primitive leftValue, |
| 2331 ir.Primitive buildRightValue(IrBuilder builder), | 2249 ir.Primitive buildRightValue(IrBuilder builder), |
| 2332 SourceInformation sourceInformation, | 2250 SourceInformation sourceInformation, |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2369 emptyBuilder.jumpTo(join, leftBool); | 2287 emptyBuilder.jumpTo(join, leftBool); |
| 2370 rightTrueBuilder.jumpTo(join, rightTrue); | 2288 rightTrueBuilder.jumpTo(join, rightTrue); |
| 2371 rightFalseBuilder.jumpTo(join, rightFalse); | 2289 rightFalseBuilder.jumpTo(join, rightFalse); |
| 2372 ir.Continuation leftTrueContinuation = new ir.Continuation([]); | 2290 ir.Continuation leftTrueContinuation = new ir.Continuation([]); |
| 2373 ir.Continuation leftFalseContinuation = new ir.Continuation([]); | 2291 ir.Continuation leftFalseContinuation = new ir.Continuation([]); |
| 2374 ir.Continuation rightTrueContinuation = new ir.Continuation([]); | 2292 ir.Continuation rightTrueContinuation = new ir.Continuation([]); |
| 2375 ir.Continuation rightFalseContinuation = new ir.Continuation([]); | 2293 ir.Continuation rightFalseContinuation = new ir.Continuation([]); |
| 2376 rightTrueContinuation.body = rightTrueBuilder.root; | 2294 rightTrueContinuation.body = rightTrueBuilder.root; |
| 2377 rightFalseContinuation.body = rightFalseBuilder.root; | 2295 rightFalseContinuation.body = rightFalseBuilder.root; |
| 2378 // The right subexpression has two continuations. | 2296 // The right subexpression has two continuations. |
| 2379 rightBuilder.add( | 2297 rightBuilder.add(new ir.LetCont.two( |
| 2380 new ir.LetCont.two(rightTrueContinuation, rightFalseContinuation, | 2298 rightTrueContinuation, |
| 2381 new ir.Branch.strict(rightValue, | 2299 rightFalseContinuation, |
| 2382 rightTrueContinuation, | 2300 new ir.Branch.strict(rightValue, rightTrueContinuation, |
| 2383 rightFalseContinuation, | 2301 rightFalseContinuation, sourceInformation))); |
| 2384 sourceInformation))); | |
| 2385 // Depending on the operator, the left subexpression's continuations are | 2302 // Depending on the operator, the left subexpression's continuations are |
| 2386 // either the right subexpression or an invocation of the join-point | 2303 // either the right subexpression or an invocation of the join-point |
| 2387 // continuation. | 2304 // continuation. |
| 2388 if (isLazyOr) { | 2305 if (isLazyOr) { |
| 2389 leftTrueContinuation.body = emptyBuilder.root; | 2306 leftTrueContinuation.body = emptyBuilder.root; |
| 2390 leftFalseContinuation.body = rightBuilder.root; | 2307 leftFalseContinuation.body = rightBuilder.root; |
| 2391 } else { | 2308 } else { |
| 2392 leftTrueContinuation.body = rightBuilder.root; | 2309 leftTrueContinuation.body = rightBuilder.root; |
| 2393 leftFalseContinuation.body = emptyBuilder.root; | 2310 leftFalseContinuation.body = emptyBuilder.root; |
| 2394 } | 2311 } |
| 2395 | 2312 |
| 2396 add(new ir.LetCont(join.continuation, | 2313 add(new ir.LetCont( |
| 2397 new ir.LetCont.two(leftTrueContinuation, leftFalseContinuation, | 2314 join.continuation, |
| 2398 new ir.Branch.strict(leftValue, | 2315 new ir.LetCont.two( |
| 2399 leftTrueContinuation, | 2316 leftTrueContinuation, |
| 2400 leftFalseContinuation, | 2317 leftFalseContinuation, |
| 2401 sourceInformation)))); | 2318 new ir.Branch.strict(leftValue, leftTrueContinuation, |
| 2319 leftFalseContinuation, sourceInformation)))); |
| 2402 environment = join.environment; | 2320 environment = join.environment; |
| 2403 return environment.discard(1); | 2321 return environment.discard(1); |
| 2404 } | 2322 } |
| 2405 | 2323 |
| 2406 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y, | 2324 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y, |
| 2407 {SourceInformation sourceInformation}) { | 2325 {SourceInformation sourceInformation}) { |
| 2408 return addPrimitive(new ir.ApplyBuiltinOperator( | 2326 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 2409 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y], | 2327 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y], sourceInformation)); |
| 2410 sourceInformation)); | |
| 2411 } | 2328 } |
| 2412 | 2329 |
| 2413 /// Called when entering a nested function with free variables. | 2330 /// Called when entering a nested function with free variables. |
| 2414 /// | 2331 /// |
| 2415 /// The free variables must subsequently be accessible using [buildLocalGet] | 2332 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 2416 /// and [buildLocalSet]. | 2333 /// and [buildLocalSet]. |
| 2417 void _enterClosureEnvironment(ClosureEnvironment env) { | 2334 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 2418 if (env == null) return; | 2335 if (env == null) return; |
| 2419 | 2336 |
| 2420 // Obtain a reference to the function object (this). | 2337 // Obtain a reference to the function object (this). |
| 2421 ir.Parameter thisPrim = state.thisParameter; | 2338 ir.Parameter thisPrim = state.thisParameter; |
| 2422 | 2339 |
| 2423 // Obtain access to the free variables. | 2340 // Obtain access to the free variables. |
| 2424 env.freeVariables.forEach((Local local, ClosureLocation location) { | 2341 env.freeVariables.forEach((Local local, ClosureLocation location) { |
| 2425 if (location.isBox) { | 2342 if (location.isBox) { |
| 2426 // Boxed variables are loaded from their box on-demand. | 2343 // Boxed variables are loaded from their box on-demand. |
| 2427 state.boxedVariables[local] = location; | 2344 state.boxedVariables[local] = location; |
| 2428 } else { | 2345 } else { |
| 2429 // Unboxed variables are loaded from the function object immediately. | 2346 // Unboxed variables are loaded from the function object immediately. |
| 2430 // This includes BoxLocals which are themselves unboxed variables. | 2347 // This includes BoxLocals which are themselves unboxed variables. |
| 2431 environment.extend(local, | 2348 environment.extend( |
| 2432 addPrimitive(new ir.GetField(thisPrim, location.field))); | 2349 local, addPrimitive(new ir.GetField(thisPrim, location.field))); |
| 2433 } | 2350 } |
| 2434 }); | 2351 }); |
| 2435 | 2352 |
| 2436 // If the function captures a reference to the receiver from the | 2353 // If the function captures a reference to the receiver from the |
| 2437 // enclosing method, remember which primitive refers to the receiver object. | 2354 // enclosing method, remember which primitive refers to the receiver object. |
| 2438 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { | 2355 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { |
| 2439 state.enclosingThis = environment.lookup(env.thisLocal); | 2356 state.enclosingThis = environment.lookup(env.thisLocal); |
| 2440 } | 2357 } |
| 2441 | 2358 |
| 2442 // If the function has a self-reference, use the value of `this`. | 2359 // If the function has a self-reference, use the value of `this`. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2475 | 2392 |
| 2476 /// Add the given function parameter to the IR, and bind it in the environment | 2393 /// Add the given function parameter to the IR, and bind it in the environment |
| 2477 /// or put it in its box, if necessary. | 2394 /// or put it in its box, if necessary. |
| 2478 void _createFunctionParameter(Local parameterElement) { | 2395 void _createFunctionParameter(Local parameterElement) { |
| 2479 ir.Parameter parameter = new ir.Parameter(parameterElement); | 2396 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 2480 _parameters.add(parameter); | 2397 _parameters.add(parameter); |
| 2481 state.functionParameters.add(parameter); | 2398 state.functionParameters.add(parameter); |
| 2482 ClosureLocation location = state.boxedVariables[parameterElement]; | 2399 ClosureLocation location = state.boxedVariables[parameterElement]; |
| 2483 if (location != null) { | 2400 if (location != null) { |
| 2484 addPrimitive(new ir.SetField( | 2401 addPrimitive(new ir.SetField( |
| 2485 environment.lookup(location.box), | 2402 environment.lookup(location.box), location.field, parameter)); |
| 2486 location.field, | |
| 2487 parameter)); | |
| 2488 } else { | 2403 } else { |
| 2489 environment.extend(parameterElement, parameter); | 2404 environment.extend(parameterElement, parameter); |
| 2490 } | 2405 } |
| 2491 } | 2406 } |
| 2492 | 2407 |
| 2493 void _createThisParameter() { | 2408 void _createThisParameter() { |
| 2494 assert(state.thisParameter == null); | 2409 assert(state.thisParameter == null); |
| 2495 if (Elements.isStaticOrTopLevel(state.currentElement)) return; | 2410 if (Elements.isStaticOrTopLevel(state.currentElement)) return; |
| 2496 if (state.currentElement.isLocal) return; | 2411 if (state.currentElement.isLocal) return; |
| 2497 state.thisParameter = | 2412 state.thisParameter = |
| 2498 new ir.Parameter(new ThisParameterLocal(state.currentElement)); | 2413 new ir.Parameter(new ThisParameterLocal(state.currentElement)); |
| 2499 } | 2414 } |
| 2500 | 2415 |
| 2501 void declareLocalVariable(LocalElement variableElement, | 2416 void declareLocalVariable(LocalElement variableElement, |
| 2502 {ir.Primitive initialValue}) { | 2417 {ir.Primitive initialValue}) { |
| 2503 assert(isOpen); | 2418 assert(isOpen); |
| 2504 if (initialValue == null) { | 2419 if (initialValue == null) { |
| 2505 initialValue = buildNullConstant(); | 2420 initialValue = buildNullConstant(); |
| 2506 } | 2421 } |
| 2507 ClosureLocation location = state.boxedVariables[variableElement]; | 2422 ClosureLocation location = state.boxedVariables[variableElement]; |
| 2508 if (location != null) { | 2423 if (location != null) { |
| 2509 addPrimitive(new ir.SetField( | 2424 addPrimitive(new ir.SetField( |
| 2510 environment.lookup(location.box), | 2425 environment.lookup(location.box), location.field, initialValue)); |
| 2511 location.field, | |
| 2512 initialValue)); | |
| 2513 } else if (isInMutableVariable(variableElement)) { | 2426 } else if (isInMutableVariable(variableElement)) { |
| 2514 add(new ir.LetMutable( | 2427 add(new ir.LetMutable(getMutableVariable(variableElement), initialValue)); |
| 2515 getMutableVariable(variableElement), | |
| 2516 initialValue)); | |
| 2517 } else { | 2428 } else { |
| 2518 initialValue.useElementAsHint(variableElement); | 2429 initialValue.useElementAsHint(variableElement); |
| 2519 environment.extend(variableElement, initialValue); | 2430 environment.extend(variableElement, initialValue); |
| 2520 } | 2431 } |
| 2521 } | 2432 } |
| 2522 | 2433 |
| 2523 /// Add [functionElement] to the environment with provided [definition]. | 2434 /// Add [functionElement] to the environment with provided [definition]. |
| 2524 void declareLocalFunction(LocalFunctionElement functionElement, | 2435 void declareLocalFunction( |
| 2525 closure.ClosureClassElement classElement, | 2436 LocalFunctionElement functionElement, |
| 2526 SourceInformation sourceInformation) { | 2437 closure.ClosureClassElement classElement, |
| 2438 SourceInformation sourceInformation) { |
| 2527 ir.Primitive closure = | 2439 ir.Primitive closure = |
| 2528 buildFunctionExpression(classElement, sourceInformation); | 2440 buildFunctionExpression(classElement, sourceInformation); |
| 2529 declareLocalVariable(functionElement, initialValue: closure); | 2441 declareLocalVariable(functionElement, initialValue: closure); |
| 2530 } | 2442 } |
| 2531 | 2443 |
| 2532 ir.Primitive buildFunctionExpression(closure.ClosureClassElement classElement, | 2444 ir.Primitive buildFunctionExpression(closure.ClosureClassElement classElement, |
| 2533 SourceInformation sourceInformation) { | 2445 SourceInformation sourceInformation) { |
| 2534 List<ir.Primitive> arguments = <ir.Primitive>[]; | 2446 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 2535 for (closure.ClosureFieldElement field in classElement.closureFields) { | 2447 for (closure.ClosureFieldElement field in classElement.closureFields) { |
| 2536 // Captured 'this' and type variables are not always available as locals | 2448 // Captured 'this' and type variables are not always available as locals |
| 2537 // in the environment, so treat those specially. | 2449 // in the environment, so treat those specially. |
| 2538 ir.Primitive value; | 2450 ir.Primitive value; |
| 2539 if (field.local is closure.ThisLocal) { | 2451 if (field.local is closure.ThisLocal) { |
| 2540 value = buildThis(); | 2452 value = buildThis(); |
| 2541 } else if (field.local is closure.TypeVariableLocal) { | 2453 } else if (field.local is closure.TypeVariableLocal) { |
| 2542 closure.TypeVariableLocal variable = field.local; | 2454 closure.TypeVariableLocal variable = field.local; |
| 2543 value = buildTypeVariableAccess(variable.typeVariable); | 2455 value = buildTypeVariableAccess(variable.typeVariable); |
| 2544 } else { | 2456 } else { |
| 2545 value = environment.lookup(field.local); | 2457 value = environment.lookup(field.local); |
| 2546 } | 2458 } |
| 2547 arguments.add(value); | 2459 arguments.add(value); |
| 2548 } | 2460 } |
| 2549 return addPrimitive(new ir.CreateInstance( | 2461 return addPrimitive(new ir.CreateInstance( |
| 2550 classElement, arguments, null, sourceInformation)); | 2462 classElement, arguments, null, sourceInformation)); |
| 2551 } | 2463 } |
| 2552 | 2464 |
| 2553 /// Create a read access of [local] function, variable, or parameter. | 2465 /// Create a read access of [local] function, variable, or parameter. |
| 2554 // TODO(johnniwinther): Make [sourceInformation] mandatory. | 2466 // TODO(johnniwinther): Make [sourceInformation] mandatory. |
| 2555 ir.Primitive buildLocalGet( | 2467 ir.Primitive buildLocalGet(LocalElement local, |
| 2556 LocalElement local, | |
| 2557 {SourceInformation sourceInformation}) { | 2468 {SourceInformation sourceInformation}) { |
| 2558 assert(isOpen); | 2469 assert(isOpen); |
| 2559 ClosureLocation location = state.boxedVariables[local]; | 2470 ClosureLocation location = state.boxedVariables[local]; |
| 2560 if (location != null) { | 2471 if (location != null) { |
| 2561 ir.Primitive result = new ir.GetField( | 2472 ir.Primitive result = new ir.GetField( |
| 2562 environment.lookup(location.box), | 2473 environment.lookup(location.box), location.field, |
| 2563 location.field, | |
| 2564 sourceInformation: sourceInformation); | 2474 sourceInformation: sourceInformation); |
| 2565 result.useElementAsHint(local); | 2475 result.useElementAsHint(local); |
| 2566 return addPrimitive(result); | 2476 return addPrimitive(result); |
| 2567 } else if (isInMutableVariable(local)) { | 2477 } else if (isInMutableVariable(local)) { |
| 2568 return addPrimitive( | 2478 return addPrimitive(new ir.GetMutable(getMutableVariable(local), |
| 2569 new ir.GetMutable( | 2479 sourceInformation: sourceInformation)); |
| 2570 getMutableVariable(local), sourceInformation: sourceInformation)); | |
| 2571 } else { | 2480 } else { |
| 2572 return environment.lookup(local); | 2481 return environment.lookup(local); |
| 2573 } | 2482 } |
| 2574 } | 2483 } |
| 2575 | 2484 |
| 2576 /// Create a write access to [local] variable or parameter with the provided | 2485 /// Create a write access to [local] variable or parameter with the provided |
| 2577 /// [value]. | 2486 /// [value]. |
| 2578 ir.Primitive buildLocalVariableSet( | 2487 ir.Primitive buildLocalVariableSet(LocalElement local, ir.Primitive value, |
| 2579 LocalElement local, | |
| 2580 ir.Primitive value, | |
| 2581 SourceInformation sourceInformation) { | 2488 SourceInformation sourceInformation) { |
| 2582 assert(isOpen); | 2489 assert(isOpen); |
| 2583 ClosureLocation location = state.boxedVariables[local]; | 2490 ClosureLocation location = state.boxedVariables[local]; |
| 2584 if (location != null) { | 2491 if (location != null) { |
| 2585 addPrimitive(new ir.SetField( | 2492 addPrimitive(new ir.SetField( |
| 2586 environment.lookup(location.box), | 2493 environment.lookup(location.box), location.field, value, |
| 2587 location.field, | |
| 2588 value, | |
| 2589 sourceInformation: sourceInformation)); | 2494 sourceInformation: sourceInformation)); |
| 2590 } else if (isInMutableVariable(local)) { | 2495 } else if (isInMutableVariable(local)) { |
| 2591 addPrimitive(new ir.SetMutable( | 2496 addPrimitive(new ir.SetMutable(getMutableVariable(local), value, |
| 2592 getMutableVariable(local), | |
| 2593 value, | |
| 2594 sourceInformation: sourceInformation)); | 2497 sourceInformation: sourceInformation)); |
| 2595 } else { | 2498 } else { |
| 2596 value.useElementAsHint(local); | 2499 value.useElementAsHint(local); |
| 2597 environment.update(local, value); | 2500 environment.update(local, value); |
| 2598 } | 2501 } |
| 2599 return value; | 2502 return value; |
| 2600 } | 2503 } |
| 2601 | 2504 |
| 2602 /// Called before building the initializer of a for-loop. | 2505 /// Called before building the initializer of a for-loop. |
| 2603 /// | 2506 /// |
| 2604 /// The loop variables will subsequently be declared using | 2507 /// The loop variables will subsequently be declared using |
| 2605 /// [declareLocalVariable]. | 2508 /// [declareLocalVariable]. |
| 2606 void _enterForLoopInitializer(ClosureScope scope, | 2509 void _enterForLoopInitializer( |
| 2607 List<LocalElement> loopVariables) { | 2510 ClosureScope scope, List<LocalElement> loopVariables) { |
| 2608 if (scope == null) return; | 2511 if (scope == null) return; |
| 2609 // If there are no boxed loop variables, don't create the box here, let | 2512 // If there are no boxed loop variables, don't create the box here, let |
| 2610 // it be created inside the body instead. | 2513 // it be created inside the body instead. |
| 2611 if (scope.boxedLoopVariables.isEmpty) return; | 2514 if (scope.boxedLoopVariables.isEmpty) return; |
| 2612 _enterScope(scope); | 2515 _enterScope(scope); |
| 2613 } | 2516 } |
| 2614 | 2517 |
| 2615 /// Called before building the body of a for-loop. | 2518 /// Called before building the body of a for-loop. |
| 2616 void _enterForLoopBody(ClosureScope scope, | 2519 void _enterForLoopBody(ClosureScope scope, List<LocalElement> loopVariables) { |
| 2617 List<LocalElement> loopVariables) { | |
| 2618 if (scope == null) return; | 2520 if (scope == null) return; |
| 2619 // If there are boxed loop variables, the box has already been created | 2521 // If there are boxed loop variables, the box has already been created |
| 2620 // at the initializer. | 2522 // at the initializer. |
| 2621 if (!scope.boxedLoopVariables.isEmpty) return; | 2523 if (!scope.boxedLoopVariables.isEmpty) return; |
| 2622 _enterScope(scope); | 2524 _enterScope(scope); |
| 2623 } | 2525 } |
| 2624 | 2526 |
| 2625 /// Called before building the update of a for-loop. | 2527 /// Called before building the update of a for-loop. |
| 2626 void _enterForLoopUpdate(ClosureScope scope, | 2528 void _enterForLoopUpdate( |
| 2627 List<LocalElement> loopVariables) { | 2529 ClosureScope scope, List<LocalElement> loopVariables) { |
| 2628 if (scope == null) return; | 2530 if (scope == null) return; |
| 2629 // If there are no boxed loop variables, then the box is created inside the | 2531 // If there are no boxed loop variables, then the box is created inside the |
| 2630 // body, so there is no need to explicitly renew it. | 2532 // body, so there is no need to explicitly renew it. |
| 2631 if (scope.boxedLoopVariables.isEmpty) return; | 2533 if (scope.boxedLoopVariables.isEmpty) return; |
| 2632 ir.Primitive box = environment.lookup(scope.box); | 2534 ir.Primitive box = environment.lookup(scope.box); |
| 2633 ir.Primitive newBox = addPrimitive(new ir.CreateBox()); | 2535 ir.Primitive newBox = addPrimitive(new ir.CreateBox()); |
| 2634 newBox.useElementAsHint(scope.box); | 2536 newBox.useElementAsHint(scope.box); |
| 2635 for (VariableElement loopVar in scope.boxedLoopVariables) { | 2537 for (VariableElement loopVar in scope.boxedLoopVariables) { |
| 2636 ClosureLocation location = scope.capturedVariables[loopVar]; | 2538 ClosureLocation location = scope.capturedVariables[loopVar]; |
| 2637 ir.Primitive value = addPrimitive(new ir.GetField(box, location.field)); | 2539 ir.Primitive value = addPrimitive(new ir.GetField(box, location.field)); |
| 2638 addPrimitive(new ir.SetField(newBox, location.field, value)); | 2540 addPrimitive(new ir.SetField(newBox, location.field, value)); |
| 2639 } | 2541 } |
| 2640 environment.update(scope.box, newBox); | 2542 environment.update(scope.box, newBox); |
| 2641 } | 2543 } |
| 2642 | 2544 |
| 2643 /// Creates an access to the receiver from the current (or enclosing) method. | 2545 /// Creates an access to the receiver from the current (or enclosing) method. |
| 2644 /// | 2546 /// |
| 2645 /// If inside a closure class, [buildThis] will redirect access through | 2547 /// If inside a closure class, [buildThis] will redirect access through |
| 2646 /// closure fields in order to access the receiver from the enclosing method. | 2548 /// closure fields in order to access the receiver from the enclosing method. |
| 2647 ir.Primitive buildThis() { | 2549 ir.Primitive buildThis() { |
| 2648 if (state.enclosingThis != null) return state.enclosingThis; | 2550 if (state.enclosingThis != null) return state.enclosingThis; |
| 2649 assert(state.thisParameter != null); | 2551 assert(state.thisParameter != null); |
| 2650 return state.thisParameter; | 2552 return state.thisParameter; |
| 2651 } | 2553 } |
| 2652 | 2554 |
| 2653 ir.Primitive buildFieldGet( | 2555 ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target, |
| 2654 ir.Primitive receiver, | |
| 2655 FieldElement target, | |
| 2656 SourceInformation sourceInformation) { | 2556 SourceInformation sourceInformation) { |
| 2657 return addPrimitive(new ir.GetField(receiver, target, | 2557 return addPrimitive(new ir.GetField(receiver, target, |
| 2658 sourceInformation: sourceInformation, | 2558 sourceInformation: sourceInformation, |
| 2659 isFinal: program.fieldNeverChanges(target))); | 2559 isFinal: program.fieldNeverChanges(target))); |
| 2660 } | 2560 } |
| 2661 | 2561 |
| 2662 void buildFieldSet(ir.Primitive receiver, | 2562 void buildFieldSet(ir.Primitive receiver, FieldElement target, |
| 2663 FieldElement target, | 2563 ir.Primitive value, SourceInformation sourceInformation) { |
| 2664 ir.Primitive value, | 2564 addPrimitive(new ir.SetField(receiver, target, value, |
| 2665 SourceInformation sourceInformation) { | 2565 sourceInformation: sourceInformation)); |
| 2666 addPrimitive(new ir.SetField( | |
| 2667 receiver, target, value, sourceInformation: sourceInformation)); | |
| 2668 } | 2566 } |
| 2669 | 2567 |
| 2670 ir.Primitive buildSuperFieldGet( | 2568 ir.Primitive buildSuperFieldGet( |
| 2671 FieldElement target, | 2569 FieldElement target, SourceInformation sourceInformation) { |
| 2672 SourceInformation sourceInformation) { | 2570 return addPrimitive(new ir.GetField(buildThis(), target, |
| 2673 return addPrimitive( | 2571 sourceInformation: sourceInformation)); |
| 2674 new ir.GetField( | |
| 2675 buildThis(), target, sourceInformation: sourceInformation)); | |
| 2676 } | 2572 } |
| 2677 | 2573 |
| 2678 ir.Primitive buildSuperFieldSet( | 2574 ir.Primitive buildSuperFieldSet(FieldElement target, ir.Primitive value, |
| 2679 FieldElement target, | |
| 2680 ir.Primitive value, | |
| 2681 SourceInformation sourceInformation) { | 2575 SourceInformation sourceInformation) { |
| 2682 addPrimitive( | 2576 addPrimitive(new ir.SetField(buildThis(), target, value, |
| 2683 new ir.SetField( | 2577 sourceInformation: sourceInformation)); |
| 2684 buildThis(), target, value, sourceInformation: sourceInformation)); | |
| 2685 return value; | 2578 return value; |
| 2686 } | 2579 } |
| 2687 | 2580 |
| 2688 /// Loads parameters to a constructor body into the environment. | 2581 /// Loads parameters to a constructor body into the environment. |
| 2689 /// | 2582 /// |
| 2690 /// The header for a constructor body differs from other functions in that | 2583 /// The header for a constructor body differs from other functions in that |
| 2691 /// some parameters are already boxed, and the box is passed as an argument | 2584 /// some parameters are already boxed, and the box is passed as an argument |
| 2692 /// instead of being created in the header. | 2585 /// instead of being created in the header. |
| 2693 void buildConstructorBodyHeader(Iterable<Local> parameters, | 2586 void buildConstructorBodyHeader( |
| 2694 ClosureScope closureScope) { | 2587 Iterable<Local> parameters, ClosureScope closureScope) { |
| 2695 _createThisParameter(); | 2588 _createThisParameter(); |
| 2696 for (Local param in parameters) { | 2589 for (Local param in parameters) { |
| 2697 ir.Parameter parameter = _createLocalParameter(param); | 2590 ir.Parameter parameter = _createLocalParameter(param); |
| 2698 state.functionParameters.add(parameter); | 2591 state.functionParameters.add(parameter); |
| 2699 } | 2592 } |
| 2700 if (closureScope != null) { | 2593 if (closureScope != null) { |
| 2701 state.boxedVariables.addAll(closureScope.capturedVariables); | 2594 state.boxedVariables.addAll(closureScope.capturedVariables); |
| 2702 } | 2595 } |
| 2703 } | 2596 } |
| 2704 | 2597 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2724 return buildInvokeJsInteropMember(element, arguments, sourceInformation); | 2617 return buildInvokeJsInteropMember(element, arguments, sourceInformation); |
| 2725 } | 2618 } |
| 2726 if (program.requiresRuntimeTypesFor(cls)) { | 2619 if (program.requiresRuntimeTypesFor(cls)) { |
| 2727 InterfaceType interface = type; | 2620 InterfaceType interface = type; |
| 2728 Iterable<ir.Primitive> typeArguments = | 2621 Iterable<ir.Primitive> typeArguments = |
| 2729 interface.typeArguments.map((DartType argument) { | 2622 interface.typeArguments.map((DartType argument) { |
| 2730 return type.treatAsRaw | 2623 return type.treatAsRaw |
| 2731 ? buildNullConstant() | 2624 ? buildNullConstant() |
| 2732 : buildTypeExpression(argument); | 2625 : buildTypeExpression(argument); |
| 2733 }); | 2626 }); |
| 2734 arguments = new List<ir.Primitive>.from(arguments) | 2627 arguments = new List<ir.Primitive>.from(arguments)..addAll(typeArguments); |
| 2735 ..addAll(typeArguments); | |
| 2736 } | 2628 } |
| 2737 return addPrimitive(new ir.InvokeConstructor( | 2629 return addPrimitive(new ir.InvokeConstructor( |
| 2738 type, element, selector, arguments, sourceInformation, | 2630 type, element, selector, arguments, sourceInformation, |
| 2739 allocationSiteType: allocationSiteType)); | 2631 allocationSiteType: allocationSiteType)); |
| 2740 } | 2632 } |
| 2741 | 2633 |
| 2742 ir.Primitive buildTypeExpression(DartType type) { | 2634 ir.Primitive buildTypeExpression(DartType type) { |
| 2743 type = program.unaliasType(type); | 2635 type = program.unaliasType(type); |
| 2744 if (type is TypeVariableType) { | 2636 if (type is TypeVariableType) { |
| 2745 return buildTypeVariableAccess(type); | 2637 return buildTypeVariableAccess(type); |
| 2746 } else if (type is InterfaceType || type is FunctionType) { | 2638 } else if (type is InterfaceType || type is FunctionType) { |
| 2747 List<ir.Primitive> arguments = <ir.Primitive>[]; | 2639 List<ir.Primitive> arguments = <ir.Primitive>[]; |
| 2748 type.forEachTypeVariable((TypeVariableType variable) { | 2640 type.forEachTypeVariable((TypeVariableType variable) { |
| 2749 ir.Primitive value = buildTypeVariableAccess(variable); | 2641 ir.Primitive value = buildTypeVariableAccess(variable); |
| 2750 arguments.add(value); | 2642 arguments.add(value); |
| 2751 }); | 2643 }); |
| 2752 return addPrimitive(new ir.TypeExpression(ir.TypeExpressionKind.COMPLETE, | 2644 return addPrimitive(new ir.TypeExpression( |
| 2753 type, arguments)); | 2645 ir.TypeExpressionKind.COMPLETE, type, arguments)); |
| 2754 } else if (type.treatAsDynamic) { | 2646 } else if (type.treatAsDynamic) { |
| 2755 return buildNullConstant(); | 2647 return buildNullConstant(); |
| 2756 } else { | 2648 } else { |
| 2757 // TypedefType can reach here, and possibly other things. | 2649 // TypedefType can reach here, and possibly other things. |
| 2758 throw 'unimplemented translation of type expression $type (${type.kind})'; | 2650 throw 'unimplemented translation of type expression $type (${type.kind})'; |
| 2759 } | 2651 } |
| 2760 } | 2652 } |
| 2761 | 2653 |
| 2762 /// Obtains the internal type representation of the type held in [variable]. | 2654 /// Obtains the internal type representation of the type held in [variable]. |
| 2763 /// | 2655 /// |
| 2764 /// The value of [variable] is taken from the current receiver object, or | 2656 /// The value of [variable] is taken from the current receiver object, or |
| 2765 /// if we are currently building a constructor field initializer, from the | 2657 /// if we are currently building a constructor field initializer, from the |
| 2766 /// corresponding type argument (field initializers are evaluated before the | 2658 /// corresponding type argument (field initializers are evaluated before the |
| 2767 /// receiver object is created). | 2659 /// receiver object is created). |
| 2768 ir.Primitive buildTypeVariableAccess(TypeVariableType variable, | 2660 ir.Primitive buildTypeVariableAccess(TypeVariableType variable, |
| 2769 {SourceInformation sourceInformation}) { | 2661 {SourceInformation sourceInformation}) { |
| 2770 // If the local exists in the environment, use that. | 2662 // If the local exists in the environment, use that. |
| 2771 // This is put here when we are inside a constructor or field initializer, | 2663 // This is put here when we are inside a constructor or field initializer, |
| 2772 // (or possibly a closure inside one of these). | 2664 // (or possibly a closure inside one of these). |
| 2773 Local local = new closure.TypeVariableLocal(variable, state.currentElement); | 2665 Local local = new closure.TypeVariableLocal(variable, state.currentElement); |
| 2774 if (environment.contains(local)) { | 2666 if (environment.contains(local)) { |
| 2775 return environment.lookup(local); | 2667 return environment.lookup(local); |
| 2776 } | 2668 } |
| 2777 | 2669 |
| 2778 // If the type variable is not in a local, read its value from the | 2670 // If the type variable is not in a local, read its value from the |
| 2779 // receiver object. | 2671 // receiver object. |
| 2780 ir.Primitive target = buildThis(); | 2672 ir.Primitive target = buildThis(); |
| 2781 return addPrimitive( | 2673 return addPrimitive( |
| 2782 new ir.ReadTypeVariable(variable, target, sourceInformation)); | 2674 new ir.ReadTypeVariable(variable, target, sourceInformation)); |
| 2783 } | 2675 } |
| 2784 | 2676 |
| 2785 /// Make the given type variable accessible through the local environment | 2677 /// Make the given type variable accessible through the local environment |
| 2786 /// with the value of [binding]. | 2678 /// with the value of [binding]. |
| 2787 void declareTypeVariable(TypeVariableType variable, DartType binding) { | 2679 void declareTypeVariable(TypeVariableType variable, DartType binding) { |
| 2788 environment.extend( | 2680 environment.extend( |
| 2789 new closure.TypeVariableLocal(variable, state.currentElement), | 2681 new closure.TypeVariableLocal(variable, state.currentElement), |
| 2790 buildTypeExpression(binding)); | 2682 buildTypeExpression(binding)); |
| 2791 } | 2683 } |
| 2792 | 2684 |
| 2793 /// Reifies the value of [variable] on the current receiver object. | 2685 /// Reifies the value of [variable] on the current receiver object. |
| 2794 ir.Primitive buildReifyTypeVariable(TypeVariableType variable, | 2686 ir.Primitive buildReifyTypeVariable( |
| 2795 SourceInformation sourceInformation) { | 2687 TypeVariableType variable, SourceInformation sourceInformation) { |
| 2796 ir.Primitive typeArgument = | 2688 ir.Primitive typeArgument = |
| 2797 buildTypeVariableAccess(variable, sourceInformation: sourceInformation); | 2689 buildTypeVariableAccess(variable, sourceInformation: sourceInformation); |
| 2798 return addPrimitive( | 2690 return addPrimitive( |
| 2799 new ir.ReifyRuntimeType(typeArgument, sourceInformation)); | 2691 new ir.ReifyRuntimeType(typeArgument, sourceInformation)); |
| 2800 } | 2692 } |
| 2801 | 2693 |
| 2802 ir.Primitive buildInvocationMirror(Selector selector, | 2694 ir.Primitive buildInvocationMirror( |
| 2803 List<ir.Primitive> arguments) { | 2695 Selector selector, List<ir.Primitive> arguments) { |
| 2804 return addPrimitive(new ir.CreateInvocationMirror(selector, arguments)); | 2696 return addPrimitive(new ir.CreateInvocationMirror(selector, arguments)); |
| 2805 } | 2697 } |
| 2806 | 2698 |
| 2807 ir.Primitive buildForeignCode(js.Template codeTemplate, | 2699 ir.Primitive buildForeignCode( |
| 2808 List<ir.Primitive> arguments, | 2700 js.Template codeTemplate, |
| 2809 NativeBehavior behavior, | 2701 List<ir.Primitive> arguments, |
| 2810 SourceInformation sourceInformation, | 2702 NativeBehavior behavior, |
| 2811 {Element dependency, | 2703 SourceInformation sourceInformation, |
| 2812 TypeMask type}) { | 2704 {Element dependency, |
| 2705 TypeMask type}) { |
| 2813 assert(behavior != null); | 2706 assert(behavior != null); |
| 2814 if (type == null) { | 2707 if (type == null) { |
| 2815 type = program.getTypeMaskForForeign(behavior); | 2708 type = program.getTypeMaskForForeign(behavior); |
| 2816 } | 2709 } |
| 2817 if (js.isIdentityTemplate(codeTemplate) && !program.isArrayType(type)) { | 2710 if (js.isIdentityTemplate(codeTemplate) && !program.isArrayType(type)) { |
| 2818 // JS expression is just a refinement. | 2711 // JS expression is just a refinement. |
| 2819 // Do not do this for arrays - those are special because array types can | 2712 // Do not do this for arrays - those are special because array types can |
| 2820 // change after creation. The input and output must therefore be modeled | 2713 // change after creation. The input and output must therefore be modeled |
| 2821 // as distinct values. | 2714 // as distinct values. |
| 2822 return addPrimitive(new ir.Refinement(arguments.single, type)); | 2715 return addPrimitive(new ir.Refinement(arguments.single, type)); |
| 2823 } | 2716 } |
| 2824 ir.Primitive result = addPrimitive(new ir.ForeignCode( | 2717 ir.Primitive result = addPrimitive(new ir.ForeignCode( |
| 2825 codeTemplate, | 2718 codeTemplate, type, arguments, behavior, sourceInformation, |
| 2826 type, | |
| 2827 arguments, | |
| 2828 behavior, | |
| 2829 sourceInformation, | |
| 2830 dependency: dependency)); | 2719 dependency: dependency)); |
| 2831 if (!codeTemplate.isExpression) { | 2720 if (!codeTemplate.isExpression) { |
| 2832 // Close the term if this is a "throw" expression or native body. | 2721 // Close the term if this is a "throw" expression or native body. |
| 2833 add(new ir.Unreachable()); | 2722 add(new ir.Unreachable()); |
| 2834 _current = null; | 2723 _current = null; |
| 2835 } | 2724 } |
| 2836 return result; | 2725 return result; |
| 2837 } | 2726 } |
| 2838 | 2727 |
| 2839 /// Creates a type test or type cast of [value] against [type]. | 2728 /// Creates a type test or type cast of [value] against [type]. |
| 2840 ir.Primitive buildTypeOperator(ir.Primitive value, | 2729 ir.Primitive buildTypeOperator( |
| 2841 DartType type, | 2730 ir.Primitive value, DartType type, SourceInformation sourceInformation, |
| 2842 SourceInformation sourceInformation, | 2731 {bool isTypeTest}) { |
| 2843 {bool isTypeTest}) { | |
| 2844 assert(isOpen); | 2732 assert(isOpen); |
| 2845 assert(isTypeTest != null); | 2733 assert(isTypeTest != null); |
| 2846 | 2734 |
| 2847 type = program.unaliasType(type); | 2735 type = program.unaliasType(type); |
| 2848 | 2736 |
| 2849 if (type.isMalformed) { | 2737 if (type.isMalformed) { |
| 2850 ErroneousElement element = type.element; | 2738 ErroneousElement element = type.element; |
| 2851 ir.Primitive message = buildStringConstant(element.message); | 2739 ir.Primitive message = buildStringConstant(element.message); |
| 2852 return buildStaticFunctionInvocation( | 2740 return buildStaticFunctionInvocation(program.throwTypeErrorHelper, |
| 2853 program.throwTypeErrorHelper, | 2741 <ir.Primitive>[message], sourceInformation); |
| 2854 <ir.Primitive>[message], | |
| 2855 sourceInformation); | |
| 2856 } | 2742 } |
| 2857 | 2743 |
| 2858 List<ir.Primitive> typeArguments = const <ir.Primitive>[]; | 2744 List<ir.Primitive> typeArguments = const <ir.Primitive>[]; |
| 2859 if (type is GenericType && type.typeArguments.isNotEmpty) { | 2745 if (type is GenericType && type.typeArguments.isNotEmpty) { |
| 2860 typeArguments = type.typeArguments.map(buildTypeExpression).toList(); | 2746 typeArguments = type.typeArguments.map(buildTypeExpression).toList(); |
| 2861 } else if (type is TypeVariableType) { | 2747 } else if (type is TypeVariableType) { |
| 2862 typeArguments = <ir.Primitive>[buildTypeVariableAccess(type)]; | 2748 typeArguments = <ir.Primitive>[buildTypeVariableAccess(type)]; |
| 2863 } else if (type is FunctionType) { | 2749 } else if (type is FunctionType) { |
| 2864 typeArguments = <ir.Primitive>[buildTypeExpression(type)]; | 2750 typeArguments = <ir.Primitive>[buildTypeExpression(type)]; |
| 2865 } | 2751 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2884 return value; | 2770 return value; |
| 2885 } | 2771 } |
| 2886 return addPrimitive(new ir.TypeCast(value, type, typeArguments)); | 2772 return addPrimitive(new ir.TypeCast(value, type, typeArguments)); |
| 2887 } | 2773 } |
| 2888 } | 2774 } |
| 2889 | 2775 |
| 2890 /// Create an if-null expression. This is equivalent to a conditional | 2776 /// Create an if-null expression. This is equivalent to a conditional |
| 2891 /// expression whose result is either [value] if [value] is not null, or | 2777 /// expression whose result is either [value] if [value] is not null, or |
| 2892 /// `right` if [value] is null. Only when [value] is null, [buildRight] is | 2778 /// `right` if [value] is null. Only when [value] is null, [buildRight] is |
| 2893 /// evaluated to produce the `right` value. | 2779 /// evaluated to produce the `right` value. |
| 2894 ir.Primitive buildIfNull(ir.Primitive value, | 2780 ir.Primitive buildIfNull( |
| 2895 ir.Primitive buildRight(IrBuilder builder), | 2781 ir.Primitive value, |
| 2896 SourceInformation sourceInformation) { | 2782 ir.Primitive buildRight(IrBuilder builder), |
| 2897 ir.Primitive condition = | 2783 SourceInformation sourceInformation) { |
| 2898 _buildCheckNull(value, sourceInformation); | 2784 ir.Primitive condition = _buildCheckNull(value, sourceInformation); |
| 2899 return buildConditional( | 2785 return buildConditional( |
| 2900 condition, buildRight, (_) => value, sourceInformation); | 2786 condition, buildRight, (_) => value, sourceInformation); |
| 2901 } | 2787 } |
| 2902 | 2788 |
| 2903 /// Create a conditional send. This is equivalent to a conditional expression | 2789 /// Create a conditional send. This is equivalent to a conditional expression |
| 2904 /// that checks if [receiver] is null, if so, it returns null, otherwise it | 2790 /// that checks if [receiver] is null, if so, it returns null, otherwise it |
| 2905 /// evaluates the [buildSend] expression. | 2791 /// evaluates the [buildSend] expression. |
| 2906 ir.Primitive buildIfNotNullSend(ir.Primitive receiver, | 2792 ir.Primitive buildIfNotNullSend( |
| 2907 ir.Primitive buildSend(IrBuilder builder), | 2793 ir.Primitive receiver, |
| 2908 SourceInformation sourceInformation) { | 2794 ir.Primitive buildSend(IrBuilder builder), |
| 2909 ir.Primitive condition = | 2795 SourceInformation sourceInformation) { |
| 2910 _buildCheckNull(receiver, sourceInformation); | 2796 ir.Primitive condition = _buildCheckNull(receiver, sourceInformation); |
| 2911 return buildConditional( | 2797 return buildConditional( |
| 2912 condition, (_) => receiver, buildSend, sourceInformation); | 2798 condition, (_) => receiver, buildSend, sourceInformation); |
| 2913 } | 2799 } |
| 2914 | 2800 |
| 2915 /// Creates a type test checking whether [value] is null. | 2801 /// Creates a type test checking whether [value] is null. |
| 2916 ir.Primitive _buildCheckNull(ir.Primitive value, | 2802 ir.Primitive _buildCheckNull( |
| 2917 SourceInformation sourceInformation) { | 2803 ir.Primitive value, SourceInformation sourceInformation) { |
| 2918 assert(isOpen); | 2804 assert(isOpen); |
| 2919 return buildIdentical(value, buildNullConstant(), | 2805 return buildIdentical(value, buildNullConstant(), |
| 2920 sourceInformation: sourceInformation); | 2806 sourceInformation: sourceInformation); |
| 2921 } | 2807 } |
| 2922 } | 2808 } |
| 2923 | 2809 |
| 2924 /// Location of a variable relative to a given closure. | 2810 /// Location of a variable relative to a given closure. |
| 2925 class ClosureLocation { | 2811 class ClosureLocation { |
| 2926 /// If not `null`, this location is [box].[field]. | 2812 /// If not `null`, this location is [box].[field]. |
| 2927 /// The location of [box] can be obtained separately from an | 2813 /// The location of [box] can be obtained separately from an |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3010 new Set<LocalVariableElement>(); | 2896 new Set<LocalVariableElement>(); |
| 3011 } | 2897 } |
| 3012 | 2898 |
| 3013 class CatchClauseInfo { | 2899 class CatchClauseInfo { |
| 3014 final DartType type; | 2900 final DartType type; |
| 3015 final LocalVariableElement exceptionVariable; | 2901 final LocalVariableElement exceptionVariable; |
| 3016 final LocalVariableElement stackTraceVariable; | 2902 final LocalVariableElement stackTraceVariable; |
| 3017 final SubbuildFunction buildCatchBlock; | 2903 final SubbuildFunction buildCatchBlock; |
| 3018 final SourceInformation sourceInformation; | 2904 final SourceInformation sourceInformation; |
| 3019 | 2905 |
| 3020 CatchClauseInfo({this.type, | 2906 CatchClauseInfo( |
| 3021 this.exceptionVariable, | 2907 {this.type, |
| 3022 this.stackTraceVariable, | 2908 this.exceptionVariable, |
| 3023 this.buildCatchBlock, | 2909 this.stackTraceVariable, |
| 3024 this.sourceInformation}); | 2910 this.buildCatchBlock, |
| 2911 this.sourceInformation}); |
| 3025 } | 2912 } |
| 3026 | 2913 |
| 3027 class SwitchCaseInfo { | 2914 class SwitchCaseInfo { |
| 3028 final SubbuildFunction buildCondition; | 2915 final SubbuildFunction buildCondition; |
| 3029 final SubbuildFunction buildBody; | 2916 final SubbuildFunction buildBody; |
| 3030 final SourceInformation sourceInformation; | 2917 final SourceInformation sourceInformation; |
| 3031 | 2918 |
| 3032 SwitchCaseInfo(this.buildCondition, this.buildBody, this.sourceInformation); | 2919 SwitchCaseInfo(this.buildCondition, this.buildBody, this.sourceInformation); |
| 3033 } | 2920 } |
| OLD | NEW |