| 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 '../constants/constant_system.dart'; | 7 import '../constants/constant_system.dart'; |
| 8 import '../constants/expressions.dart'; | 8 import '../constants/expressions.dart'; |
| 9 import '../constants/values.dart' show PrimitiveConstantValue; | 9 import '../constants/values.dart' show PrimitiveConstantValue; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses | 369 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses |
| 370 // `List` instead of `Link`. | 370 // `List` instead of `Link`. |
| 371 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { | 371 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { |
| 372 return (IrBuilder builder) { | 372 return (IrBuilder builder) { |
| 373 return withBuilder(builder, () => builder.buildSequence(nodes, build)); | 373 return withBuilder(builder, () => builder.buildSequence(nodes, build)); |
| 374 }; | 374 }; |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 | 377 |
| 378 /// Shared state between delimited IrBuilders within the same function. | 378 /// Shared state between delimited IrBuilders within the same function. |
| 379 class IrBuilderSharedState { | 379 class IrBuilderDelimitedState { |
| 380 final ConstantSystem constantSystem; | 380 final ConstantSystem constantSystem; |
| 381 | 381 |
| 382 /// A stack of collectors for breaks. | 382 /// A stack of collectors for breaks. |
| 383 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 383 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 384 | 384 |
| 385 /// A stack of collectors for continues. | 385 /// A stack of collectors for continues. |
| 386 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 386 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 387 | 387 |
| 388 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 388 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
| 389 | 389 |
| 390 final ExecutableElement currentElement; | 390 final ExecutableElement currentElement; |
| 391 | 391 |
| 392 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 392 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 393 ir.Parameter _thisParameter; | 393 ir.Parameter _thisParameter; |
| 394 ir.Parameter enclosingMethodThisParameter; | 394 ir.Parameter enclosingMethodThisParameter; |
| 395 | 395 |
| 396 final List<ir.Definition> functionParameters = <ir.Definition>[]; | 396 final List<ir.Definition> functionParameters = <ir.Definition>[]; |
| 397 | 397 |
| 398 IrBuilderSharedState(this.constantSystem, this.currentElement); | 398 IrBuilderDelimitedState(this.constantSystem, this.currentElement); |
| 399 | 399 |
| 400 ir.Parameter get thisParameter => _thisParameter; | 400 ir.Parameter get thisParameter => _thisParameter; |
| 401 void set thisParameter(ir.Parameter value) { | 401 void set thisParameter(ir.Parameter value) { |
| 402 assert(_thisParameter == null); | 402 assert(_thisParameter == null); |
| 403 _thisParameter = value; | 403 _thisParameter = value; |
| 404 } | 404 } |
| 405 } | 405 } |
| 406 | 406 |
| 407 class ThisParameterLocal implements Local { | 407 class ThisParameterLocal implements Local { |
| 408 final ExecutableElement executableContext; | 408 final ExecutableElement executableContext; |
| 409 ThisParameterLocal(this.executableContext); | 409 ThisParameterLocal(this.executableContext); |
| 410 String get name => 'this'; | 410 String get name => 'this'; |
| 411 toString() => 'ThisParameterLocal($executableContext)'; | 411 toString() => 'ThisParameterLocal($executableContext)'; |
| 412 } | 412 } |
| 413 | 413 |
| 414 /// A factory for building the cps IR. | 414 /// A factory for building the cps IR. |
| 415 /// | 415 /// |
| 416 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured | 416 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured |
| 417 /// variables in different ways. | 417 /// variables in different ways. |
| 418 abstract class IrBuilder { | 418 abstract class IrBuilder { |
| 419 IrBuilder _makeInstance(); | 419 IrBuilder _makeInstance(); |
| 420 | 420 |
| 421 /// True if [local] should currently be accessed from a [ir.MutableVariable]. |
| 422 bool isInMutableVariable(Local local); |
| 423 |
| 424 /// Creates a [ir.MutableVariable] for the given local. |
| 425 void makeMutableVariable(Local local); |
| 426 |
| 427 /// Remove an [ir.MutableVariable] for a local. |
| 428 /// |
| 429 /// Subsequent access to the local will be direct rather than through the |
| 430 /// mutable variable. This is used for variables that do not spend their |
| 431 /// entire lifetime as mutable variables (e.g., variables that are boxed |
| 432 /// in mutable variables for a try block). |
| 433 void removeMutableVariable(Local local); |
| 434 |
| 421 void declareLocalVariable(LocalVariableElement element, | 435 void declareLocalVariable(LocalVariableElement element, |
| 422 {ir.Primitive initialValue}); | 436 {ir.Primitive initialValue}); |
| 423 | 437 |
| 424 /// Called when entering a nested function with free variables. | 438 /// Called when entering a nested function with free variables. |
| 425 /// | 439 /// |
| 426 /// The free variables must subsequently be accessible using [buildLocalGet] | 440 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 427 /// and [buildLocalSet]. | 441 /// and [buildLocalSet]. |
| 428 void _enterClosureEnvironment(ClosureEnvironment env); | 442 void _enterClosureEnvironment(ClosureEnvironment env); |
| 429 | 443 |
| 430 /// Called when entering a function body or loop body. | 444 /// Called when entering a function body or loop body. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 461 /// | 475 /// |
| 462 /// If inside a closure class, [buildThis] will redirect access through | 476 /// If inside a closure class, [buildThis] will redirect access through |
| 463 /// closure fields in order to access the receiver from the enclosing method. | 477 /// closure fields in order to access the receiver from the enclosing method. |
| 464 ir.Primitive buildThis(); | 478 ir.Primitive buildThis(); |
| 465 | 479 |
| 466 // TODO(johnniwinther): Make these field final and remove the default values | 480 // TODO(johnniwinther): Make these field final and remove the default values |
| 467 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | 481 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. |
| 468 | 482 |
| 469 final List<ir.Parameter> _parameters = <ir.Parameter>[]; | 483 final List<ir.Parameter> _parameters = <ir.Parameter>[]; |
| 470 | 484 |
| 471 IrBuilderSharedState state; | 485 IrBuilderDelimitedState state; |
| 472 | 486 |
| 473 /// A map from variable indexes to their values. | 487 /// A map from variable indexes to their values. |
| 474 /// | 488 /// |
| 475 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not | 489 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not |
| 476 /// in the map; look up their [BoxLocal] instead. | 490 /// in the map; look up their [BoxLocal] instead. |
| 477 Environment environment; | 491 Environment environment; |
| 478 | 492 |
| 479 /// A map from mutable local variables to their [ir.MutableVariable]s. | |
| 480 /// | |
| 481 /// Mutable variables are treated as boxed. Writes to them are observable | |
| 482 /// side effects. | |
| 483 Map<Local, ir.MutableVariable> mutableVariables; | |
| 484 | |
| 485 /// True if [local] should currently be accessed from a [ir.MutableVariable]. | |
| 486 bool isInMutableVariable(Local local) { | |
| 487 return mutableVariables.containsKey(local); | |
| 488 } | |
| 489 | |
| 490 /// Creates a [ir.MutableVariable] for the given local. | |
| 491 void makeMutableVariable(Local local) { | |
| 492 mutableVariables[local] = | |
| 493 new ir.MutableVariable(local.executableContext, local); | |
| 494 } | |
| 495 | |
| 496 /// Remove an [ir.MutableVariable] for a local. | |
| 497 /// | |
| 498 /// Subsequent access to the local will be direct rather than through the | |
| 499 /// mutable variable. | |
| 500 void removeMutableVariable(Local local) { | |
| 501 mutableVariables.remove(local); | |
| 502 } | |
| 503 | |
| 504 /// Gets the [MutableVariable] containing the value of [local]. | |
| 505 ir.MutableVariable getMutableVariable(Local local) { | |
| 506 return mutableVariables[local]; | |
| 507 } | |
| 508 | |
| 509 // The IR builder maintains a context, which is an expression with a hole in | 493 // The IR builder maintains a context, which is an expression with a hole in |
| 510 // it. The hole represents the focus where new expressions can be added. | 494 // it. The hole represents the focus where new expressions can be added. |
| 511 // The context is implemented by 'root' which is the root of the expression | 495 // The context is implemented by 'root' which is the root of the expression |
| 512 // and 'current' which is the expression that immediately contains the hole. | 496 // and 'current' which is the expression that immediately contains the hole. |
| 513 // Not all expressions have a hole (e.g., invocations, which always occur in | 497 // Not all expressions have a hole (e.g., invocations, which always occur in |
| 514 // tail position, do not have a hole). Expressions with a hole have a plug | 498 // tail position, do not have a hole). Expressions with a hole have a plug |
| 515 // method. | 499 // method. |
| 516 // | 500 // |
| 517 // Conceptually, visiting a statement takes a context as input and returns | 501 // Conceptually, visiting a statement takes a context as input and returns |
| 518 // either a new context or else an expression without a hole if all | 502 // either a new context or else an expression without a hole if all |
| 519 // control-flow paths through the statement have exited. An expression | 503 // control-flow paths through the statement have exited. An expression |
| 520 // without a hole is represented by a (root, current) pair where root is the | 504 // without a hole is represented by a (root, current) pair where root is the |
| 521 // expression and current is null. | 505 // expression and current is null. |
| 522 // | 506 // |
| 523 // Conceptually again, visiting an expression takes a context as input and | 507 // Conceptually again, visiting an expression takes a context as input and |
| 524 // returns either a pair of a new context and a definition denoting | 508 // returns either a pair of a new context and a definition denoting |
| 525 // the expression's value, or else an expression without a hole if all | 509 // the expression's value, or else an expression without a hole if all |
| 526 // control-flow paths through the expression have exited. | 510 // control-flow paths through the expression have exited. |
| 527 // | 511 // |
| 528 // We do not pass contexts as arguments or return them. Rather we use the | 512 // We do not pass contexts as arguments or return them. Rather we use the |
| 529 // current context (root, current) as the visitor state and mutate current. | 513 // current context (root, current) as the visitor state and mutate current. |
| 530 // Visiting a statement returns null; visiting an expression returns the | 514 // Visiting a statement returns null; visiting an expression returns the |
| 531 // primitive denoting its value. | 515 // primitive denoting its value. |
| 532 | 516 |
| 533 ir.Expression _root = null; | 517 ir.Expression _root = null; |
| 534 ir.Expression _current = null; | 518 ir.Expression _current = null; |
| 535 | 519 |
| 536 /// Initialize a new top-level IR builder. | 520 /// Initialize a new top-level IR builder. |
| 537 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { | 521 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { |
| 538 state = new IrBuilderSharedState(constantSystem, currentElement); | 522 state = new IrBuilderDelimitedState(constantSystem, currentElement); |
| 539 environment = new Environment.empty(); | 523 environment = new Environment.empty(); |
| 540 mutableVariables = <Local, ir.MutableVariable>{}; | |
| 541 } | 524 } |
| 542 | 525 |
| 543 /// Construct a delimited visitor for visiting a subtree. | 526 /// Construct a delimited visitor for visiting a subtree. |
| 544 /// | 527 /// |
| 545 /// Build a subterm that is not (yet) connected to the CPS term. The | 528 /// Build a subterm that is not (yet) connected to the CPS term. The |
| 546 /// delimited visitor has its own has its own context for building an IR | 529 /// delimited visitor has its own has its own context for building an IR |
| 547 /// expression, so the built expression is not plugged into the parent's | 530 /// expression, so the built expression is not plugged into the parent's |
| 548 /// context. It has its own compile-time environment mapping local | 531 /// context. It has its own compile-time environment mapping local |
| 549 /// variables to their values. If an optional environment argument is | 532 /// variables to their values. If an optional environment argument is |
| 550 /// supplied, it is used as the builder's initial environment. Otherwise | 533 /// supplied, it is used as the builder's initial environment. Otherwise |
| 551 /// the environment is initially a copy of the parent builder's environment. | 534 /// the environment is initially a copy of the parent builder's environment. |
| 552 IrBuilder makeDelimitedBuilder([Environment env = null]) { | 535 IrBuilder makeDelimitedBuilder([Environment env = null]) { |
| 553 return _makeInstance() | 536 return _makeInstance() |
| 554 ..state = state | 537 ..state = state |
| 555 ..environment = env != null ? env : new Environment.from(environment) | 538 ..environment = env != null ? env : new Environment.from(environment); |
| 556 ..mutableVariables = mutableVariables; | |
| 557 } | 539 } |
| 558 | 540 |
| 559 /// Construct a builder for making constructor field initializers. | 541 /// Construct a builder for making constructor field initializers. |
| 560 IrBuilder makeInitializerBuilder() { | 542 IrBuilder makeInitializerBuilder() { |
| 561 return _makeInstance() | 543 return _makeInstance() |
| 562 ..state = new IrBuilderSharedState(state.constantSystem, | 544 ..state = new IrBuilderDelimitedState(state.constantSystem, |
| 563 state.currentElement) | 545 state.currentElement) |
| 564 ..environment = new Environment.from(environment) | 546 ..environment = new Environment.from(environment); |
| 565 ..mutableVariables = mutableVariables; | |
| 566 } | 547 } |
| 567 | 548 |
| 568 /// Construct a builder for an inner function. | 549 /// Construct a builder for an inner function. |
| 569 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { | 550 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { |
| 570 IrBuilderSharedState innerState = | 551 IrBuilderDelimitedState innerState = |
| 571 new IrBuilderSharedState(state.constantSystem, currentElement) | 552 new IrBuilderDelimitedState(state.constantSystem, currentElement) |
| 572 ..enclosingMethodThisParameter = state.enclosingMethodThisParameter; | 553 ..enclosingMethodThisParameter = state.enclosingMethodThisParameter; |
| 573 return _makeInstance() | 554 return _makeInstance() |
| 574 ..state = innerState | 555 ..state = innerState |
| 575 ..environment = new Environment.empty() | 556 ..environment = new Environment.empty(); |
| 576 ..mutableVariables = <Local, ir.MutableVariable>{}; | |
| 577 } | 557 } |
| 578 | 558 |
| 579 bool get isOpen => _root == null || _current != null; | 559 bool get isOpen => _root == null || _current != null; |
| 580 | 560 |
| 581 | 561 |
| 582 void buildFieldInitializerHeader({ClosureScope closureScope}) { | 562 void buildFieldInitializerHeader({ClosureScope closureScope}) { |
| 583 _enterScope(closureScope); | 563 _enterScope(closureScope); |
| 584 } | 564 } |
| 585 | 565 |
| 586 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, | 566 List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters, |
| (...skipping 1141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1728 // of mutable bindings for the variables assigned in the try. The join- | 1708 // of mutable bindings for the variables assigned in the try. The join- |
| 1729 // point continuation is not in the scope of these mutable bindings. | 1709 // point continuation is not in the scope of these mutable bindings. |
| 1730 // The tryBlock is in the scope of a binding for the catch handler. Each | 1710 // The tryBlock is in the scope of a binding for the catch handler. Each |
| 1731 // instruction (specifically, each call) in the tryBlock is in the dynamic | 1711 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1732 // scope of the handler. The mutable bindings are dereferenced at the end | 1712 // scope of the handler. The mutable bindings are dereferenced at the end |
| 1733 // of the try block and at the beginning of the catch block, so the | 1713 // of the try block and at the beginning of the catch block, so the |
| 1734 // variables are unboxed in the catch block and at the join point. | 1714 // variables are unboxed in the catch block and at the join point. |
| 1735 JumpCollector join = new ForwardJumpCollector(environment); | 1715 JumpCollector join = new ForwardJumpCollector(environment); |
| 1736 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | 1716 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); |
| 1737 | 1717 |
| 1738 // Variables treated as mutable in a try are not mutable outside of it. | 1718 // Variables that are boxed due to being captured in a closure are boxed |
| 1739 // Work with a copy of the outer builder's mutable variables. | 1719 // for their entire lifetime, and so they do not need to be boxed on |
| 1740 tryCatchBuilder.mutableVariables = | 1720 // entry to any try block. They are not filtered out before this because |
| 1741 new Map<Local, ir.MutableVariable>.from(mutableVariables); | 1721 // we can not identify all of them in the same pass where we identify the |
| 1722 // variables assigned in the try (they may be captured by a closure after |
| 1723 // the try statement). |
| 1742 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | 1724 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1743 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1725 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1744 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); | 1726 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); |
| 1745 tryCatchBuilder.makeMutableVariable(variable); | 1727 tryCatchBuilder.makeMutableVariable(variable); |
| 1746 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); | 1728 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1747 } | 1729 } |
| 1748 | 1730 |
| 1749 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | 1731 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1750 | 1732 |
| 1751 void interceptJumps(JumpCollector collector) { | 1733 void interceptJumps(JumpCollector collector) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1762 tryBuilder.jumpTo(join); | 1744 tryBuilder.jumpTo(join); |
| 1763 restoreJumps(join); | 1745 restoreJumps(join); |
| 1764 } | 1746 } |
| 1765 tryBuilder.state.breakCollectors.forEach(restoreJumps); | 1747 tryBuilder.state.breakCollectors.forEach(restoreJumps); |
| 1766 tryBuilder.state.continueCollectors.forEach(restoreJumps); | 1748 tryBuilder.state.continueCollectors.forEach(restoreJumps); |
| 1767 | 1749 |
| 1768 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | 1750 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1769 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | 1751 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1770 assert(catchBuilder.isInMutableVariable(variable)); | 1752 assert(catchBuilder.isInMutableVariable(variable)); |
| 1771 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | 1753 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); |
| 1772 // After this point, the variables that were boxed on entry to the try | 1754 // Note that we remove the variable from the set of mutable variables |
| 1773 // are no longer treated as mutable. | 1755 // here (and not above for the try body). This is because the set of |
| 1756 // mutable variables is global for the whole function and not local to |
| 1757 // a delimited builder. |
| 1774 catchBuilder.removeMutableVariable(variable); | 1758 catchBuilder.removeMutableVariable(variable); |
| 1775 catchBuilder.environment.update(variable, value); | 1759 catchBuilder.environment.update(variable, value); |
| 1776 } | 1760 } |
| 1777 | 1761 |
| 1778 // TODO(kmillikin): Handle multiple catch clauses. | 1762 // TODO(kmillikin): Handle multiple catch clauses. |
| 1779 assert(catchClauseInfos.length == 1); | 1763 assert(catchClauseInfos.length == 1); |
| 1780 for (CatchClauseInfo catchClauseInfo in catchClauseInfos) { | 1764 for (CatchClauseInfo catchClauseInfo in catchClauseInfos) { |
| 1781 LocalVariableElement exceptionVariable = | 1765 LocalVariableElement exceptionVariable = |
| 1782 catchClauseInfo.exceptionVariable; | 1766 catchClauseInfo.exceptionVariable; |
| 1783 ir.Parameter exceptionParameter = new ir.Parameter(exceptionVariable); | 1767 ir.Parameter exceptionParameter = new ir.Parameter(exceptionVariable); |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2050 environment = join.environment; | 2034 environment = join.environment; |
| 2051 environment.discard(1); | 2035 environment.discard(1); |
| 2052 // There is always a join parameter for the result value, because it | 2036 // There is always a join parameter for the result value, because it |
| 2053 // is different on at least two paths. | 2037 // is different on at least two paths. |
| 2054 return join.continuation.parameters.last; | 2038 return join.continuation.parameters.last; |
| 2055 } | 2039 } |
| 2056 } | 2040 } |
| 2057 | 2041 |
| 2058 /// Shared state between DartIrBuilders within the same method. | 2042 /// Shared state between DartIrBuilders within the same method. |
| 2059 class DartIrBuilderSharedState { | 2043 class DartIrBuilderSharedState { |
| 2044 /// Maps local variables to their corresponding [MutableVariable] object. |
| 2045 final Map<Local, ir.MutableVariable> local2mutable = |
| 2046 <Local, ir.MutableVariable>{}; |
| 2047 |
| 2048 /// Creates a [MutableVariable] for the given local. |
| 2049 void makeMutableVariable(Local local) { |
| 2050 ir.MutableVariable variable = |
| 2051 new ir.MutableVariable(local.executableContext, local); |
| 2052 local2mutable[local] = variable; |
| 2053 } |
| 2054 |
| 2060 /// [MutableVariable]s that should temporarily be treated as registers. | 2055 /// [MutableVariable]s that should temporarily be treated as registers. |
| 2061 final Set<Local> registerizedMutableVariables = new Set<Local>(); | 2056 final Set<Local> registerizedMutableVariables = new Set<Local>(); |
| 2057 |
| 2058 DartIrBuilderSharedState(Set<Local> capturedVariables) { |
| 2059 capturedVariables.forEach(makeMutableVariable); |
| 2060 } |
| 2062 } | 2061 } |
| 2063 | 2062 |
| 2064 /// Dart-specific subclass of [IrBuilder]. | 2063 /// Dart-specific subclass of [IrBuilder]. |
| 2065 /// | 2064 /// |
| 2066 /// Inner functions are represented by a [FunctionDefinition] with the | 2065 /// Inner functions are represented by a [FunctionDefinition] with the |
| 2067 /// IR for the inner function nested inside. | 2066 /// IR for the inner function nested inside. |
| 2068 /// | 2067 /// |
| 2069 /// Captured variables are translated to ref cells (see [MutableVariable]) | 2068 /// Captured variables are translated to ref cells (see [MutableVariable]) |
| 2070 /// using [GetMutableVariable] and [SetMutableVariable]. | 2069 /// using [GetMutableVariable] and [SetMutableVariable]. |
| 2071 class DartIrBuilder extends IrBuilder { | 2070 class DartIrBuilder extends IrBuilder { |
| 2072 final DartIrBuilderSharedState dartState = new DartIrBuilderSharedState(); | 2071 final DartIrBuilderSharedState dartState; |
| 2073 | 2072 |
| 2074 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); | 2073 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); |
| 2075 DartIrBuilder._blank(this.dartState); | 2074 DartIrBuilder._blank(this.dartState); |
| 2076 | 2075 |
| 2077 DartIrBuilder(ConstantSystem constantSystem, | 2076 DartIrBuilder(ConstantSystem constantSystem, |
| 2078 ExecutableElement currentElement, | 2077 ExecutableElement currentElement, |
| 2079 Set<Local> capturedVariables) { | 2078 Set<Local> capturedVariables) |
| 2079 : dartState = new DartIrBuilderSharedState(capturedVariables) { |
| 2080 _init(constantSystem, currentElement); | 2080 _init(constantSystem, currentElement); |
| 2081 capturedVariables.forEach(makeMutableVariable); | |
| 2082 } | 2081 } |
| 2083 | 2082 |
| 2084 @override | |
| 2085 bool isInMutableVariable(Local local) { | 2083 bool isInMutableVariable(Local local) { |
| 2086 return mutableVariables.containsKey(local) && | 2084 return dartState.local2mutable.containsKey(local) && |
| 2087 !dartState.registerizedMutableVariables.contains(local); | 2085 !dartState.registerizedMutableVariables.contains(local); |
| 2088 } | 2086 } |
| 2089 | 2087 |
| 2088 void makeMutableVariable(Local local) { |
| 2089 dartState.makeMutableVariable(local); |
| 2090 } |
| 2091 |
| 2092 void removeMutableVariable(Local local) { |
| 2093 dartState.local2mutable.remove(local); |
| 2094 } |
| 2095 |
| 2096 /// Gets the [MutableVariable] containing the value of [local]. |
| 2097 ir.MutableVariable getMutableVariable(Local local) { |
| 2098 return dartState.local2mutable[local]; |
| 2099 } |
| 2100 |
| 2090 void _enterScope(ClosureScope scope) { | 2101 void _enterScope(ClosureScope scope) { |
| 2091 assert(scope == null); | 2102 assert(scope == null); |
| 2092 } | 2103 } |
| 2093 | 2104 |
| 2094 void _enterClosureEnvironment(ClosureEnvironment env) { | 2105 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 2095 assert(env == null); | 2106 assert(env == null); |
| 2096 } | 2107 } |
| 2097 | 2108 |
| 2098 void _enterForLoopInitializer(ClosureScope scope, | 2109 void _enterForLoopInitializer(ClosureScope scope, |
| 2099 List<LocalElement> loopVariables) { | 2110 List<LocalElement> loopVariables) { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2274 | 2285 |
| 2275 IrBuilder _makeInstance() => new JsIrBuilder._blank(program, jsState); | 2286 IrBuilder _makeInstance() => new JsIrBuilder._blank(program, jsState); |
| 2276 JsIrBuilder._blank(this.program, this.jsState); | 2287 JsIrBuilder._blank(this.program, this.jsState); |
| 2277 | 2288 |
| 2278 JsIrBuilder(this.program, ConstantSystem constantSystem, | 2289 JsIrBuilder(this.program, ConstantSystem constantSystem, |
| 2279 ExecutableElement currentElement) | 2290 ExecutableElement currentElement) |
| 2280 : jsState = new JsIrBuilderSharedState() { | 2291 : jsState = new JsIrBuilderSharedState() { |
| 2281 _init(constantSystem, currentElement); | 2292 _init(constantSystem, currentElement); |
| 2282 } | 2293 } |
| 2283 | 2294 |
| 2295 Map<ast.TryStatement, TryStatementInfo> get tryStatements => null; |
| 2296 Set<Local> get mutableCapturedVariables => null; |
| 2297 bool isInMutableVariable(Local local) => false; |
| 2298 void makeMutableVariable(Local local) {} |
| 2299 void removeMutableVariable(Local local) {} |
| 2300 |
| 2284 void enterInitializers() { | 2301 void enterInitializers() { |
| 2285 assert(jsState.inInitializers == false); | 2302 assert(jsState.inInitializers == false); |
| 2286 jsState.inInitializers = true; | 2303 jsState.inInitializers = true; |
| 2287 } | 2304 } |
| 2288 | 2305 |
| 2289 void leaveInitializers() { | 2306 void leaveInitializers() { |
| 2290 assert(jsState.inInitializers == true); | 2307 assert(jsState.inInitializers == true); |
| 2291 jsState.inInitializers = false; | 2308 jsState.inInitializers = false; |
| 2292 } | 2309 } |
| 2293 | 2310 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2367 {ir.Primitive initialValue}) { | 2384 {ir.Primitive initialValue}) { |
| 2368 assert(isOpen); | 2385 assert(isOpen); |
| 2369 if (initialValue == null) { | 2386 if (initialValue == null) { |
| 2370 initialValue = buildNullLiteral(); | 2387 initialValue = buildNullLiteral(); |
| 2371 } | 2388 } |
| 2372 ClosureLocation location = jsState.boxedVariables[variableElement]; | 2389 ClosureLocation location = jsState.boxedVariables[variableElement]; |
| 2373 if (location != null) { | 2390 if (location != null) { |
| 2374 add(new ir.SetField(environment.lookup(location.box), | 2391 add(new ir.SetField(environment.lookup(location.box), |
| 2375 location.field, | 2392 location.field, |
| 2376 initialValue)); | 2393 initialValue)); |
| 2377 } else if (isInMutableVariable(variableElement)) { | |
| 2378 add(new ir.LetMutable(getMutableVariable(variableElement), | |
| 2379 initialValue)); | |
| 2380 } else { | 2394 } else { |
| 2381 initialValue.useElementAsHint(variableElement); | 2395 initialValue.useElementAsHint(variableElement); |
| 2382 environment.extend(variableElement, initialValue); | 2396 environment.extend(variableElement, initialValue); |
| 2383 } | 2397 } |
| 2384 } | 2398 } |
| 2385 | 2399 |
| 2386 /// Add [functionElement] to the environment with provided [definition]. | 2400 /// Add [functionElement] to the environment with provided [definition]. |
| 2387 void declareLocalFunction(LocalFunctionElement functionElement, | 2401 void declareLocalFunction(LocalFunctionElement functionElement, |
| 2388 ClosureClassElement classElement) { | 2402 ClosureClassElement classElement) { |
| 2389 ir.Primitive closure = buildFunctionExpression(classElement); | 2403 ir.Primitive closure = buildFunctionExpression(classElement); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2646 } | 2660 } |
| 2647 | 2661 |
| 2648 /// Synthetic parameter to a JavaScript factory method that takes the type | 2662 /// Synthetic parameter to a JavaScript factory method that takes the type |
| 2649 /// argument given for the type variable [variable]. | 2663 /// argument given for the type variable [variable]. |
| 2650 class TypeInformationParameter implements Local { | 2664 class TypeInformationParameter implements Local { |
| 2651 final TypeVariableElement variable; | 2665 final TypeVariableElement variable; |
| 2652 final ExecutableElement executableContext; | 2666 final ExecutableElement executableContext; |
| 2653 TypeInformationParameter(this.variable, this.executableContext); | 2667 TypeInformationParameter(this.variable, this.executableContext); |
| 2654 String get name => variable.name; | 2668 String get name => variable.name; |
| 2655 } | 2669 } |
| OLD | NEW |