| 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/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_types.dart'; | 9 import '../dart_types.dart'; |
| 10 import '../dart2jslib.dart'; | 10 import '../dart2jslib.dart'; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 /// [nodes] in its context using [build]. | 172 /// [nodes] in its context using [build]. |
| 173 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses | 173 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses |
| 174 // `List` instead of `Link`. | 174 // `List` instead of `Link`. |
| 175 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { | 175 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { |
| 176 return (IrBuilder builder) { | 176 return (IrBuilder builder) { |
| 177 return withBuilder(builder, () => builder.buildSequence(nodes, build)); | 177 return withBuilder(builder, () => builder.buildSequence(nodes, build)); |
| 178 }; | 178 }; |
| 179 } | 179 } |
| 180 } | 180 } |
| 181 | 181 |
| 182 /// Shared state between IrBuilders of nested functions. | |
| 183 class IrBuilderClosureState { | |
| 184 /// Maps local variables to their corresponding [ClosureVariable] object. | |
| 185 final Map<Local, ir.ClosureVariable> local2closure = | |
| 186 <Local, ir.ClosureVariable>{}; | |
| 187 | |
| 188 /// Maps functions to the list of closure variables declared in that function. | |
| 189 final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures = | |
| 190 <ExecutableElement, List<ir.ClosureVariable>>{}; | |
| 191 | |
| 192 /// Returns the closure variables declared in the given function. | |
| 193 List<ir.ClosureVariable> getClosureList(ExecutableElement element) { | |
| 194 return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]); | |
| 195 } | |
| 196 | |
| 197 /// Creates a closure variable for the given local. | |
| 198 void makeClosureVariable(Local local) { | |
| 199 ir.ClosureVariable variable = | |
| 200 new ir.ClosureVariable(local.executableContext, local); | |
| 201 local2closure[local] = variable; | |
| 202 getClosureList(local.executableContext).add(variable); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 /// Shared state between delimited IrBuilders within the same function. | 182 /// Shared state between delimited IrBuilders within the same function. |
| 207 class IrBuilderSharedState { | 183 class IrBuilderDelimitedState { |
| 208 final ConstantSystem constantSystem; | 184 final ConstantSystem constantSystem; |
| 209 | 185 |
| 210 /// A stack of collectors for breaks. | 186 /// A stack of collectors for breaks. |
| 211 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 187 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 212 | 188 |
| 213 /// A stack of collectors for continues. | 189 /// A stack of collectors for continues. |
| 214 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 190 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 215 | 191 |
| 216 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 192 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
| 217 | 193 |
| 218 final ExecutableElement currentElement; | 194 final ExecutableElement currentElement; |
| 219 | 195 |
| 220 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 196 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 221 | 197 |
| 222 final List<ir.Definition> functionParameters = <ir.Definition>[]; | 198 final List<ir.Definition> functionParameters = <ir.Definition>[]; |
| 223 | 199 |
| 224 /// Maps boxed locals to their location. These locals are not part of | 200 IrBuilderDelimitedState(this.constantSystem, this.currentElement); |
| 225 /// the environment. | |
| 226 final Map<Local, ClosureLocation> boxedVariables = {}; | |
| 227 | |
| 228 /// If non-null, this refers to the receiver (`this`) in the enclosing method. | |
| 229 ir.Primitive receiver; | |
| 230 | |
| 231 IrBuilderSharedState(this.constantSystem, this.currentElement); | |
| 232 } | 201 } |
| 233 | 202 |
| 234 /// A factory for building the cps IR. | 203 /// A factory for building the cps IR. |
| 235 /// | 204 /// |
| 236 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured | 205 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured |
| 237 /// variables in different ways. | 206 /// variables in different ways. |
| 238 abstract class IrBuilder { | 207 abstract class IrBuilder { |
| 239 IrBuilder _makeInstance(); | 208 IrBuilder _makeInstance(); |
| 240 | 209 |
| 241 void declareLocalVariable(LocalVariableElement element, | 210 void declareLocalVariable(LocalVariableElement element, |
| 242 {ir.Primitive initialValue}); | 211 {ir.Primitive initialValue}); |
| 243 void declareLocalFunction(LocalFunctionElement element, Object function); | 212 void declareLocalFunction(LocalFunctionElement element, Object function); |
| 244 ir.Primitive buildFunctionExpression(Object function); | 213 ir.Primitive buildFunctionExpression(Object function); |
| 245 ir.Primitive buildLocalGet(LocalElement element); | 214 ir.Primitive buildLocalGet(LocalElement element); |
| 246 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value); | 215 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value); |
| 247 | 216 |
| 248 /// Called when entering a nested function with free variables. | 217 /// Called when entering a nested function with free variables. |
| 249 /// The free variables should subsequently be accessible using [buildLocalGet] | 218 /// |
| 219 /// The free variables must subsequently be accessible using [buildLocalGet] |
| 250 /// and [buildLocalSet]. | 220 /// and [buildLocalSet]. |
| 251 void _buildClosureEnvironmentSetup(ClosureEnvironment env); | 221 void _enterClosureEnvironment(ClosureEnvironment env); |
| 252 | 222 |
| 253 /// Enter a scope that declares boxed variables. The boxed variables must | 223 /// Called when entering a function body or loop body. |
| 254 /// subsequently be accessible using [buildLocalGet], [buildLocalSet], etc. | 224 /// |
| 255 void _buildClosureScopeSetup(ClosureScope scope); | 225 /// This is not called for for-loops, which instead use the methods |
| 226 /// [_enterForLoopInitializer], [_enterForLoopBody], and [_enterForLoopUpdate] |
| 227 /// due to their special scoping rules. |
| 228 /// |
| 229 /// The boxed variables declared in this scope must subsequently be available |
| 230 /// using [buildLocalGet], [buildLocalSet], etc. |
| 231 void _enterScope(ClosureScope scope); |
| 232 |
| 233 /// Called before building the initializer of a for-loop. |
| 234 /// |
| 235 /// The loop variables will subsequently be declared using |
| 236 /// [declareLocalVariable]. |
| 237 void _enterForLoopInitializer(ClosureScope scope, |
| 238 List<LocalElement> loopVariables); |
| 239 |
| 240 /// Called before building the body of a for-loop. |
| 241 void _enterForLoopBody(ClosureScope scope, |
| 242 List<LocalElement> loopVariables); |
| 243 |
| 244 /// Called before building the update of a for-loop. |
| 245 void _enterForLoopUpdate(ClosureScope scope, |
| 246 List<LocalElement> loopVariables); |
| 256 | 247 |
| 257 /// Add the given function parameter to the IR, and bind it in the environment | 248 /// Add the given function parameter to the IR, and bind it in the environment |
| 258 /// or put it in its box, if necessary. | 249 /// or put it in its box, if necessary. |
| 259 void _createFunctionParameter(ParameterElement parameterElement); | 250 void _createFunctionParameter(ParameterElement parameterElement); |
| 260 | 251 |
| 261 /// Called before the update expression of a for-loop. A new box should be | 252 /// Returns the list of closure variables declared in the given function or |
| 262 /// created for [scope] and the values from the old box should be copied over. | 253 /// field initializer. |
| 263 void _migrateLoopVariables(ClosureScope scope); | 254 List<ir.ClosureVariable> _getDeclaredClosureVariables(ExecutableElement elm); |
| 255 |
| 256 /// Creates an access to the receiver from the current (or enclosing) method. |
| 257 /// |
| 258 /// If inside a closure class, [buildThis] will redirect access through |
| 259 /// closure fields in order to access the receiver from the enclosing method. |
| 260 ir.Primitive buildThis(); |
| 264 | 261 |
| 265 // TODO(johnniwinther): Make these field final and remove the default values | 262 // TODO(johnniwinther): Make these field final and remove the default values |
| 266 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | 263 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. |
| 267 | 264 |
| 268 final List<ir.Parameter> _parameters = <ir.Parameter>[]; | 265 final List<ir.Parameter> _parameters = <ir.Parameter>[]; |
| 269 | 266 |
| 270 IrBuilderSharedState state; | 267 IrBuilderDelimitedState state; |
| 271 | |
| 272 IrBuilderClosureState closure; | |
| 273 | 268 |
| 274 /// A map from variable indexes to their values. | 269 /// A map from variable indexes to their values. |
| 275 /// | 270 /// |
| 276 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not | 271 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not |
| 277 /// in the map; look up their [BoxLocal] instead. | 272 /// in the map; look up their [BoxLocal] instead. |
| 278 Environment environment; | 273 Environment environment; |
| 279 | 274 |
| 280 // The IR builder maintains a context, which is an expression with a hole in | 275 // The IR builder maintains a context, which is an expression with a hole in |
| 281 // it. The hole represents the focus where new expressions can be added. | 276 // it. The hole represents the focus where new expressions can be added. |
| 282 // The context is implemented by 'root' which is the root of the expression | 277 // The context is implemented by 'root' which is the root of the expression |
| (...skipping 16 matching lines...) Expand all Loading... |
| 299 // We do not pass contexts as arguments or return them. Rather we use the | 294 // We do not pass contexts as arguments or return them. Rather we use the |
| 300 // current context (root, current) as the visitor state and mutate current. | 295 // current context (root, current) as the visitor state and mutate current. |
| 301 // Visiting a statement returns null; visiting an expression returns the | 296 // Visiting a statement returns null; visiting an expression returns the |
| 302 // primitive denoting its value. | 297 // primitive denoting its value. |
| 303 | 298 |
| 304 ir.Expression _root = null; | 299 ir.Expression _root = null; |
| 305 ir.Expression _current = null; | 300 ir.Expression _current = null; |
| 306 | 301 |
| 307 /// Initialize a new top-level IR builder. | 302 /// Initialize a new top-level IR builder. |
| 308 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { | 303 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { |
| 309 state = new IrBuilderSharedState(constantSystem, currentElement); | 304 state = new IrBuilderDelimitedState(constantSystem, currentElement); |
| 310 closure = new IrBuilderClosureState(); | |
| 311 environment = new Environment.empty(); | 305 environment = new Environment.empty(); |
| 312 } | 306 } |
| 313 | 307 |
| 314 /// Construct a delimited visitor for visiting a subtree. | 308 /// Construct a delimited visitor for visiting a subtree. |
| 315 /// | 309 /// |
| 316 /// The delimited visitor has its own compile-time environment mapping | 310 /// The delimited visitor has its own compile-time environment mapping |
| 317 /// local variables to their values, which is initially a copy of the parent | 311 /// local variables to their values, which is initially a copy of the parent |
| 318 /// environment. It has its own context for building an IR expression, so | 312 /// environment. It has its own context for building an IR expression, so |
| 319 /// the built expression is not plugged into the parent's context. | 313 /// the built expression is not plugged into the parent's context. |
| 320 IrBuilder makeDelimitedBuilder() { | 314 IrBuilder makeDelimitedBuilder() { |
| 321 return _makeInstance() | 315 return _makeInstance() |
| 322 ..state = state | 316 ..state = state |
| 323 ..closure = closure | |
| 324 ..environment = new Environment.from(environment); | 317 ..environment = new Environment.from(environment); |
| 325 } | 318 } |
| 326 | 319 |
| 327 /// Construct a visitor for a recursive continuation. | 320 /// Construct a visitor for a recursive continuation. |
| 328 /// | 321 /// |
| 329 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) | 322 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) |
| 330 /// for all the local variables in the parent, because the invocation sites | 323 /// for all the local variables in the parent, because the invocation sites |
| 331 /// of the continuation are not all known when the builder is created. The | 324 /// of the continuation are not all known when the builder is created. The |
| 332 /// recursive invocations will be passed values for all the local variables, | 325 /// recursive invocations will be passed values for all the local variables, |
| 333 /// which may be eliminated later if they are redundant---if they take on | 326 /// which may be eliminated later if they are redundant---if they take on |
| 334 /// the same value at all invocation sites. | 327 /// the same value at all invocation sites. |
| 335 IrBuilder makeRecursiveBuilder() { | 328 IrBuilder makeRecursiveBuilder() { |
| 336 IrBuilder inner = _makeInstance() | 329 IrBuilder inner = _makeInstance() |
| 337 ..state = state | 330 ..state = state |
| 338 ..closure = closure | |
| 339 ..environment = new Environment.empty(); | 331 ..environment = new Environment.empty(); |
| 340 environment.index2variable.forEach(inner.createLocalParameter); | 332 environment.index2variable.forEach(inner.createLocalParameter); |
| 341 return inner; | 333 return inner; |
| 342 } | 334 } |
| 343 | 335 |
| 344 /// Construct a builder for an inner function. | 336 /// Construct a builder for an inner function. |
| 345 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { | 337 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { |
| 346 return _makeInstance() | 338 return _makeInstance() |
| 347 ..state = new IrBuilderSharedState(state.constantSystem, currentElement) | 339 ..state = new IrBuilderDelimitedState(state.constantSystem, currentEleme
nt) |
| 348 ..closure = closure | |
| 349 ..environment = new Environment.empty(); | 340 ..environment = new Environment.empty(); |
| 350 } | 341 } |
| 351 | 342 |
| 352 bool get isOpen => _root == null || _current != null; | 343 bool get isOpen => _root == null || _current != null; |
| 353 | 344 |
| 354 | 345 |
| 355 void buildFieldInitializerHeader({ClosureScope closureScope}) { | 346 void buildFieldInitializerHeader({ClosureScope closureScope}) { |
| 356 _buildClosureScopeSetup(closureScope); | 347 _enterScope(closureScope); |
| 357 } | 348 } |
| 358 | 349 |
| 359 void buildFunctionHeader(Iterable<ParameterElement> parameters, | 350 void buildFunctionHeader(Iterable<ParameterElement> parameters, |
| 360 {ClosureScope closureScope, | 351 {ClosureScope closureScope, |
| 361 ClosureEnvironment closureEnvironment}) { | 352 ClosureEnvironment closureEnvironment}) { |
| 362 _buildClosureEnvironmentSetup(closureEnvironment); | 353 _enterClosureEnvironment(closureEnvironment); |
| 363 _buildClosureScopeSetup(closureScope); | 354 _enterScope(closureScope); |
| 364 parameters.forEach(_createFunctionParameter); | 355 parameters.forEach(_createFunctionParameter); |
| 365 } | 356 } |
| 366 | 357 |
| 367 /// Creates a parameter for [local] and adds it to the current environment. | 358 /// Creates a parameter for [local] and adds it to the current environment. |
| 368 ir.Parameter createLocalParameter(Local local) { | 359 ir.Parameter createLocalParameter(Local local) { |
| 369 ir.Parameter parameter = new ir.Parameter(local); | 360 ir.Parameter parameter = new ir.Parameter(local); |
| 370 _parameters.add(parameter); | 361 _parameters.add(parameter); |
| 371 environment.extend(local, parameter); | 362 environment.extend(local, parameter); |
| 372 return parameter; | 363 return parameter; |
| 373 } | 364 } |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 608 message: "Non-empty body for abstract method $element: $_root")); | 599 message: "Non-empty body for abstract method $element: $_root")); |
| 609 assert(invariant(element, state.localConstants.isEmpty, | 600 assert(invariant(element, state.localConstants.isEmpty, |
| 610 message: "Local constants for abstract method $element: " | 601 message: "Local constants for abstract method $element: " |
| 611 "${state.localConstants}")); | 602 "${state.localConstants}")); |
| 612 return new ir.FunctionDefinition.abstract( | 603 return new ir.FunctionDefinition.abstract( |
| 613 element, state.functionParameters, defaults); | 604 element, state.functionParameters, defaults); |
| 614 } else { | 605 } else { |
| 615 ir.RunnableBody body = makeRunnableBody(); | 606 ir.RunnableBody body = makeRunnableBody(); |
| 616 return new ir.FunctionDefinition( | 607 return new ir.FunctionDefinition( |
| 617 element, state.functionParameters, body, | 608 element, state.functionParameters, body, |
| 618 state.localConstants, defaults, closure.getClosureList(element)); | 609 state.localConstants, defaults, |
| 610 _getDeclaredClosureVariables(element)); |
| 619 } | 611 } |
| 620 } | 612 } |
| 621 | 613 |
| 622 ir.ConstructorDefinition makeConstructorDefinition( | 614 ir.ConstructorDefinition makeConstructorDefinition( |
| 623 List<ConstantExpression> defaults, List<ir.Initializer> initializers) { | 615 List<ConstantExpression> defaults, List<ir.Initializer> initializers) { |
| 624 FunctionElement element = state.currentElement; | 616 FunctionElement element = state.currentElement; |
| 625 if (element.isExternal) { | 617 if (element.isExternal) { |
| 626 assert(invariant(element, _root == null, | 618 assert(invariant(element, _root == null, |
| 627 message: "Non-empty body for external constructor $element: $_root")); | 619 message: "Non-empty body for external constructor $element: $_root")); |
| 628 assert(invariant(element, state.localConstants.isEmpty, | 620 assert(invariant(element, state.localConstants.isEmpty, |
| 629 message: "Local constants for external constructor $element: " | 621 message: "Local constants for external constructor $element: " |
| 630 "${state.localConstants}")); | 622 "${state.localConstants}")); |
| 631 return new ir.ConstructorDefinition.abstract( | 623 return new ir.ConstructorDefinition.abstract( |
| 632 element, state.functionParameters, defaults); | 624 element, state.functionParameters, defaults); |
| 633 } | 625 } |
| 634 ir.RunnableBody body = makeRunnableBody(); | 626 ir.RunnableBody body = makeRunnableBody(); |
| 635 return new ir.ConstructorDefinition( | 627 return new ir.ConstructorDefinition( |
| 636 element, state.functionParameters, body, initializers, | 628 element, state.functionParameters, body, initializers, |
| 637 state.localConstants, defaults, | 629 state.localConstants, defaults, |
| 638 closure.getClosureList(element)); | 630 _getDeclaredClosureVariables(element)); |
| 639 } | 631 } |
| 640 | 632 |
| 641 /// Create a super invocation where the method name and the argument structure | 633 /// Create a super invocation where the method name and the argument structure |
| 642 /// are defined by [selector] and the argument values are defined by | 634 /// are defined by [selector] and the argument values are defined by |
| 643 /// [arguments]. | 635 /// [arguments]. |
| 644 ir.Primitive buildSuperInvocation(Selector selector, | 636 ir.Primitive buildSuperInvocation(Selector selector, |
| 645 List<ir.Primitive> arguments) { | 637 List<ir.Primitive> arguments) { |
| 646 return _buildInvokeSuper(selector, arguments); | 638 return _buildInvokeSuper(selector, arguments); |
| 647 } | 639 } |
| 648 | 640 |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 /// Creates a for loop in which the initializer, condition, body, update are | 855 /// Creates a for loop in which the initializer, condition, body, update are |
| 864 /// created by [buildInitializer], [buildCondition], [buildBody] and | 856 /// created by [buildInitializer], [buildCondition], [buildBody] and |
| 865 /// [buildUpdate], respectively. | 857 /// [buildUpdate], respectively. |
| 866 /// | 858 /// |
| 867 /// The jump [target] is used to identify which `break` and `continue` | 859 /// The jump [target] is used to identify which `break` and `continue` |
| 868 /// statements that have this `for` statement as their target. | 860 /// statements that have this `for` statement as their target. |
| 869 /// | 861 /// |
| 870 /// The [closureScope] identifies variables that should be boxed in this loop. | 862 /// The [closureScope] identifies variables that should be boxed in this loop. |
| 871 /// This includes variables declared inside the body of the loop as well as | 863 /// This includes variables declared inside the body of the loop as well as |
| 872 /// in the for-loop initializer. | 864 /// in the for-loop initializer. |
| 865 /// |
| 866 /// [loopVariables] is the list of variables declared in the for-loop |
| 867 /// initializer. |
| 873 void buildFor({SubbuildFunction buildInitializer, | 868 void buildFor({SubbuildFunction buildInitializer, |
| 874 SubbuildFunction buildCondition, | 869 SubbuildFunction buildCondition, |
| 875 SubbuildFunction buildBody, | 870 SubbuildFunction buildBody, |
| 876 SubbuildFunction buildUpdate, | 871 SubbuildFunction buildUpdate, |
| 877 JumpTarget target, | 872 JumpTarget target, |
| 878 ClosureScope closureScope}) { | 873 ClosureScope closureScope, |
| 874 List<LocalElement> loopVariables}) { |
| 879 assert(isOpen); | 875 assert(isOpen); |
| 880 | 876 |
| 881 // For loops use four named continuations: the entry to the condition, | 877 // For loops use four named continuations: the entry to the condition, |
| 882 // the entry to the body, the loop exit, and the loop successor (break). | 878 // the entry to the body, the loop exit, and the loop successor (break). |
| 883 // The CPS translation of | 879 // The CPS translation of |
| 884 // [[for (initializer; condition; update) body; successor]] is: | 880 // [[for (initializer; condition; update) body; successor]] is: |
| 885 // | 881 // |
| 886 // [[initializer]]; | 882 // [[initializer]]; |
| 887 // let cont loop(x, ...) = | 883 // let cont loop(x, ...) = |
| 888 // let prim cond = [[condition]] in | 884 // let prim cond = [[condition]] in |
| 889 // let cont break() = [[successor]] in | 885 // let cont break() = [[successor]] in |
| 890 // let cont exit() = break(v, ...) in | 886 // let cont exit() = break(v, ...) in |
| 891 // let cont body() = | 887 // let cont body() = |
| 892 // let cont continue(x, ...) = [[update]]; loop(v, ...) in | 888 // let cont continue(x, ...) = [[update]]; loop(v, ...) in |
| 893 // [[body]]; continue(v, ...) in | 889 // [[body]]; continue(v, ...) in |
| 894 // branch cond (body, exit) in | 890 // branch cond (body, exit) in |
| 895 // loop(v, ...) | 891 // loop(v, ...) |
| 896 // | 892 // |
| 897 // If there are no breaks in the body, the break continuation is inlined | 893 // If there are no breaks in the body, the break continuation is inlined |
| 898 // in the exit continuation (i.e., the translation of the successor | 894 // in the exit continuation (i.e., the translation of the successor |
| 899 // statement occurs in the exit continuation). If there is only one | 895 // statement occurs in the exit continuation). If there is only one |
| 900 // invocation of the continue continuation (i.e., no continues in the | 896 // invocation of the continue continuation (i.e., no continues in the |
| 901 // body), the continue continuation is inlined in the body. | 897 // body), the continue continuation is inlined in the body. |
| 902 | 898 |
| 903 // If the variables declared in the initializer must be boxed, we must | 899 _enterForLoopInitializer(closureScope, loopVariables); |
| 904 // create the box before entering the loop and renew the box at the end | |
| 905 // of the loop. | |
| 906 bool hasBoxedLoopVariables = closureScope != null && | |
| 907 !closureScope.boxedLoopVariables.isEmpty; | |
| 908 | |
| 909 // If a variable declared in the initializer must be boxed, we should | |
| 910 // create the box before initializing these variables. | |
| 911 // Otherwise, it is best to create the box inside the body so we don't have | |
| 912 // to create a box before the loop AND at the end of the loop. | |
| 913 if (hasBoxedLoopVariables) { | |
| 914 _buildClosureScopeSetup(closureScope); | |
| 915 } | |
| 916 | 900 |
| 917 buildInitializer(this); | 901 buildInitializer(this); |
| 918 | 902 |
| 919 IrBuilder condBuilder = makeRecursiveBuilder(); | 903 IrBuilder condBuilder = makeRecursiveBuilder(); |
| 920 ir.Primitive condition = buildCondition(condBuilder); | 904 ir.Primitive condition = buildCondition(condBuilder); |
| 921 if (condition == null) { | 905 if (condition == null) { |
| 922 // If the condition is empty then the body is entered unconditionally. | 906 // If the condition is empty then the body is entered unconditionally. |
| 923 condition = condBuilder.buildBooleanLiteral(true); | 907 condition = condBuilder.buildBooleanLiteral(true); |
| 924 } | 908 } |
| 925 | 909 |
| 926 JumpCollector breakCollector = new JumpCollector(target); | 910 JumpCollector breakCollector = new JumpCollector(target); |
| 927 JumpCollector continueCollector = new JumpCollector(target); | 911 JumpCollector continueCollector = new JumpCollector(target); |
| 928 state.breakCollectors.add(breakCollector); | 912 state.breakCollectors.add(breakCollector); |
| 929 state.continueCollectors.add(continueCollector); | 913 state.continueCollectors.add(continueCollector); |
| 930 | 914 |
| 931 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); | 915 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); |
| 932 | 916 |
| 933 // If we did not yet create a box for the boxed variables, we must create it | 917 bodyBuilder._enterForLoopBody(closureScope, loopVariables); |
| 934 // here. This saves us from | |
| 935 if (!hasBoxedLoopVariables) { | |
| 936 bodyBuilder._buildClosureScopeSetup(closureScope); | |
| 937 } | |
| 938 | 918 |
| 939 buildBody(bodyBuilder); | 919 buildBody(bodyBuilder); |
| 940 assert(state.breakCollectors.last == breakCollector); | 920 assert(state.breakCollectors.last == breakCollector); |
| 941 assert(state.continueCollectors.last == continueCollector); | 921 assert(state.continueCollectors.last == continueCollector); |
| 942 state.breakCollectors.removeLast(); | 922 state.breakCollectors.removeLast(); |
| 943 state.continueCollectors.removeLast(); | 923 state.continueCollectors.removeLast(); |
| 944 | 924 |
| 945 // The binding of the continue continuation should occur as late as | 925 // The binding of the continue continuation should occur as late as |
| 946 // possible, that is, at the nearest common ancestor of all the continue | 926 // possible, that is, at the nearest common ancestor of all the continue |
| 947 // sites in the body. However, that is difficult to compute here, so it | 927 // sites in the body. However, that is difficult to compute here, so it |
| 948 // is instead placed just outside the body of the body continuation. | 928 // is instead placed just outside the body of the body continuation. |
| 949 bool hasContinues = !continueCollector.isEmpty; | 929 bool hasContinues = !continueCollector.isEmpty; |
| 950 IrBuilder updateBuilder = hasContinues | 930 IrBuilder updateBuilder = hasContinues |
| 951 ? condBuilder.makeRecursiveBuilder() | 931 ? condBuilder.makeRecursiveBuilder() |
| 952 : bodyBuilder; | 932 : bodyBuilder; |
| 953 if (hasBoxedLoopVariables) { | 933 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); |
| 954 updateBuilder._migrateLoopVariables(closureScope); | |
| 955 } | |
| 956 buildUpdate(updateBuilder); | 934 buildUpdate(updateBuilder); |
| 957 | 935 |
| 958 // Create body entry and loop exit continuations and a branch to them. | 936 // Create body entry and loop exit continuations and a branch to them. |
| 959 ir.Continuation bodyContinuation = new ir.Continuation([]); | 937 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 960 ir.Continuation exitContinuation = new ir.Continuation([]); | 938 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 961 ir.LetCont branch = | 939 ir.LetCont branch = |
| 962 new ir.LetCont(exitContinuation, | 940 new ir.LetCont(exitContinuation, |
| 963 new ir.LetCont(bodyContinuation, | 941 new ir.LetCont(bodyContinuation, |
| 964 new ir.Branch(new ir.IsTrue(condition), | 942 new ir.Branch(new ir.IsTrue(condition), |
| 965 bodyContinuation, | 943 bodyContinuation, |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1071 new ir.InvokeMethod(iterator, | 1049 new ir.InvokeMethod(iterator, |
| 1072 new Selector.call("moveNext", null, 0), | 1050 new Selector.call("moveNext", null, 0), |
| 1073 moveNextInvoked, emptyArguments))); | 1051 moveNextInvoked, emptyArguments))); |
| 1074 | 1052 |
| 1075 JumpCollector breakCollector = new JumpCollector(target); | 1053 JumpCollector breakCollector = new JumpCollector(target); |
| 1076 JumpCollector continueCollector = new JumpCollector(target); | 1054 JumpCollector continueCollector = new JumpCollector(target); |
| 1077 state.breakCollectors.add(breakCollector); | 1055 state.breakCollectors.add(breakCollector); |
| 1078 state.continueCollectors.add(continueCollector); | 1056 state.continueCollectors.add(continueCollector); |
| 1079 | 1057 |
| 1080 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); | 1058 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); |
| 1081 bodyBuilder._buildClosureScopeSetup(closureScope); | 1059 bodyBuilder._enterScope(closureScope); |
| 1082 if (buildVariableDeclaration != null) { | 1060 if (buildVariableDeclaration != null) { |
| 1083 buildVariableDeclaration(bodyBuilder); | 1061 buildVariableDeclaration(bodyBuilder); |
| 1084 } | 1062 } |
| 1085 | 1063 |
| 1086 ir.Parameter currentValue = new ir.Parameter(null); | 1064 ir.Parameter currentValue = new ir.Parameter(null); |
| 1087 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); | 1065 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); |
| 1088 bodyBuilder.add(new ir.LetCont(currentInvoked, | 1066 bodyBuilder.add(new ir.LetCont(currentInvoked, |
| 1089 new ir.InvokeMethod(iterator, new Selector.getter("current", null), | 1067 new ir.InvokeMethod(iterator, new Selector.getter("current", null), |
| 1090 currentInvoked, emptyArguments))); | 1068 currentInvoked, emptyArguments))); |
| 1091 if (Elements.isLocal(variableElement)) { | 1069 if (Elements.isLocal(variableElement)) { |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1176 // The condition and body are delimited. | 1154 // The condition and body are delimited. |
| 1177 IrBuilder condBuilder = makeRecursiveBuilder(); | 1155 IrBuilder condBuilder = makeRecursiveBuilder(); |
| 1178 ir.Primitive condition = buildCondition(condBuilder); | 1156 ir.Primitive condition = buildCondition(condBuilder); |
| 1179 | 1157 |
| 1180 JumpCollector breakCollector = new JumpCollector(target); | 1158 JumpCollector breakCollector = new JumpCollector(target); |
| 1181 JumpCollector continueCollector = new JumpCollector(target); | 1159 JumpCollector continueCollector = new JumpCollector(target); |
| 1182 state.breakCollectors.add(breakCollector); | 1160 state.breakCollectors.add(breakCollector); |
| 1183 state.continueCollectors.add(continueCollector); | 1161 state.continueCollectors.add(continueCollector); |
| 1184 | 1162 |
| 1185 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); | 1163 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); |
| 1186 bodyBuilder._buildClosureScopeSetup(closureScope); | 1164 bodyBuilder._enterScope(closureScope); |
| 1187 buildBody(bodyBuilder); | 1165 buildBody(bodyBuilder); |
| 1188 assert(state.breakCollectors.last == breakCollector); | 1166 assert(state.breakCollectors.last == breakCollector); |
| 1189 assert(state.continueCollectors.last == continueCollector); | 1167 assert(state.continueCollectors.last == continueCollector); |
| 1190 state.breakCollectors.removeLast(); | 1168 state.breakCollectors.removeLast(); |
| 1191 state.continueCollectors.removeLast(); | 1169 state.continueCollectors.removeLast(); |
| 1192 | 1170 |
| 1193 // Create body entry and loop exit continuations and a branch to them. | 1171 // Create body entry and loop exit continuations and a branch to them. |
| 1194 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1172 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1195 ir.Continuation exitContinuation = new ir.Continuation([]); | 1173 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1196 ir.LetCont branch = | 1174 ir.LetCont branch = |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1427 new ir.LetCont(leftTrueContinuation, | 1405 new ir.LetCont(leftTrueContinuation, |
| 1428 new ir.LetCont(leftFalseContinuation, | 1406 new ir.LetCont(leftFalseContinuation, |
| 1429 new ir.Branch(new ir.IsTrue(leftValue), | 1407 new ir.Branch(new ir.IsTrue(leftValue), |
| 1430 leftTrueContinuation, | 1408 leftTrueContinuation, |
| 1431 leftFalseContinuation))))); | 1409 leftFalseContinuation))))); |
| 1432 // There is always a join parameter for the result value, because it | 1410 // There is always a join parameter for the result value, because it |
| 1433 // is different on at least two paths. | 1411 // is different on at least two paths. |
| 1434 return joinContinuation.parameters.last; | 1412 return joinContinuation.parameters.last; |
| 1435 } | 1413 } |
| 1436 | 1414 |
| 1437 /// Creates an access to the receiver from the current (or enclosing) method. | |
| 1438 /// | |
| 1439 /// If inside a closure class, [buildThis] will redirect access through | |
| 1440 /// closure fields in order to access the receiver from the enclosing method. | |
| 1441 ir.Primitive buildThis() { | |
| 1442 if (state.receiver != null) return state.receiver; | |
| 1443 ir.Primitive thisPrim = new ir.This(); | |
| 1444 add(new ir.LetPrim(thisPrim)); | |
| 1445 return thisPrim; | |
| 1446 } | |
| 1447 | |
| 1448 /// Create a non-recursive join-point continuation. | 1415 /// Create a non-recursive join-point continuation. |
| 1449 /// | 1416 /// |
| 1450 /// Given the environment length at the join point and a list of | 1417 /// Given the environment length at the join point and a list of |
| 1451 /// jumps that should reach the join point, create a join-point | 1418 /// jumps that should reach the join point, create a join-point |
| 1452 /// continuation. The join-point continuation has a parameter for each | 1419 /// continuation. The join-point continuation has a parameter for each |
| 1453 /// variable that has different values reaching on different paths. | 1420 /// variable that has different values reaching on different paths. |
| 1454 /// | 1421 /// |
| 1455 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. | 1422 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. |
| 1456 /// They are filled in with the target continuation and appropriate | 1423 /// They are filled in with the target continuation and appropriate |
| 1457 /// arguments. | 1424 /// arguments. |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1544 for (int i = 0; i < environment.length; ++i) { | 1511 for (int i = 0; i < environment.length; ++i) { |
| 1545 if (common[i] == null) { | 1512 if (common[i] == null) { |
| 1546 environment.index2value[i] = parameters[index++]; | 1513 environment.index2value[i] = parameters[index++]; |
| 1547 } | 1514 } |
| 1548 } | 1515 } |
| 1549 | 1516 |
| 1550 return join; | 1517 return join; |
| 1551 } | 1518 } |
| 1552 } | 1519 } |
| 1553 | 1520 |
| 1521 /// Shared state between DartIrBuilders within the same method. |
| 1522 class DartIrBuilderSharedState { |
| 1523 /// Maps local variables to their corresponding [ClosureVariable] object. |
| 1524 final Map<Local, ir.ClosureVariable> local2closure = |
| 1525 <Local, ir.ClosureVariable>{}; |
| 1526 |
| 1527 /// Maps functions to the list of closure variables declared in that function. |
| 1528 final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures = |
| 1529 <ExecutableElement, List<ir.ClosureVariable>>{}; |
| 1530 |
| 1531 final ClosureVariableInfo closureVariables; |
| 1532 |
| 1533 /// Returns the closure variables declared in the given function. |
| 1534 List<ir.ClosureVariable> getClosureList(ExecutableElement element) { |
| 1535 return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]); |
| 1536 } |
| 1537 |
| 1538 /// Creates a closure variable for the given local. |
| 1539 void makeClosureVariable(Local local) { |
| 1540 ir.ClosureVariable variable = |
| 1541 new ir.ClosureVariable(local.executableContext, local); |
| 1542 local2closure[local] = variable; |
| 1543 getClosureList(local.executableContext).add(variable); |
| 1544 } |
| 1545 |
| 1546 /// Closure variables that should temporarily be treated as registers. |
| 1547 final Set<Local> registerizedClosureVariables = new Set<Local>(); |
| 1548 |
| 1549 DartIrBuilderSharedState(this.closureVariables) { |
| 1550 closureVariables.capturedVariables.forEach(makeClosureVariable); |
| 1551 } |
| 1552 } |
| 1553 |
| 1554 /// Dart-specific subclass of [IrBuilder]. | 1554 /// Dart-specific subclass of [IrBuilder]. |
| 1555 /// | 1555 /// |
| 1556 /// Inner functions are represented by a [FunctionDefinition] with the | 1556 /// Inner functions are represented by a [FunctionDefinition] with the |
| 1557 /// IR for the inner function nested inside. | 1557 /// IR for the inner function nested inside. |
| 1558 /// | 1558 /// |
| 1559 /// Captured variables are translated to ref cells (see [ClosureVariable]) | 1559 /// Captured variables are translated to ref cells (see [ClosureVariable]) |
| 1560 /// using [GetClosureVariable] and [SetClosureVariable]. | 1560 /// using [GetClosureVariable] and [SetClosureVariable]. |
| 1561 class DartIrBuilder extends IrBuilder { | 1561 class DartIrBuilder extends IrBuilder { |
| 1562 ClosureVariableInfo closureVariables; | 1562 final DartIrBuilderSharedState dartState; |
| 1563 | 1563 |
| 1564 IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables); | 1564 IrBuilder _makeInstance() => new DartIrBuilder._blank(dartState); |
| 1565 DartIrBuilder._blank(this.closureVariables); | 1565 DartIrBuilder._blank(this.dartState); |
| 1566 | 1566 |
| 1567 DartIrBuilder(ConstantSystem constantSystem, | 1567 DartIrBuilder(ConstantSystem constantSystem, |
| 1568 ExecutableElement currentElement, | 1568 ExecutableElement currentElement, |
| 1569 this.closureVariables) { | 1569 ClosureVariableInfo closureVariables) |
| 1570 : dartState = new DartIrBuilderSharedState(closureVariables) { |
| 1570 _init(constantSystem, currentElement); | 1571 _init(constantSystem, currentElement); |
| 1571 closureVariables.capturedVariables.forEach(closure.makeClosureVariable); | |
| 1572 } | 1572 } |
| 1573 | 1573 |
| 1574 /// True if [local] is stored in a [ClosureVariable]. | 1574 /// True if [local] should currently be accessed from a [ClosureVariable]. |
| 1575 bool isInClosureVariable(Local local) { | 1575 bool isInClosureVariable(Local local) { |
| 1576 return closure.local2closure.containsKey(local); | 1576 return dartState.local2closure.containsKey(local) && |
| 1577 !dartState.registerizedClosureVariables.contains(local); |
| 1577 } | 1578 } |
| 1578 | 1579 |
| 1579 /// Gets the [ClosureVariable] containing the value of [local]. | 1580 /// Gets the [ClosureVariable] containing the value of [local]. |
| 1580 ir.ClosureVariable getClosureVariable(Local local) { | 1581 ir.ClosureVariable getClosureVariable(Local local) { |
| 1581 return closure.local2closure[local]; | 1582 return dartState.local2closure[local]; |
| 1582 } | 1583 } |
| 1583 | 1584 |
| 1584 void _buildClosureScopeSetup(ClosureScope scope) { | 1585 void _enterScope(ClosureScope scope) { |
| 1585 assert(scope == null); | 1586 assert(scope == null); |
| 1586 } | 1587 } |
| 1587 | 1588 |
| 1588 void _buildClosureEnvironmentSetup(ClosureEnvironment env) { | 1589 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 1589 assert(env == null); | 1590 assert(env == null); |
| 1590 } | 1591 } |
| 1591 | 1592 |
| 1592 void _migrateLoopVariables(ClosureScope scope) { | 1593 void _enterForLoopInitializer(ClosureScope scope, |
| 1594 List<LocalElement> loopVariables) { |
| 1593 assert(scope == null); | 1595 assert(scope == null); |
| 1596 for (LocalElement loopVariable in loopVariables) { |
| 1597 if (dartState.local2closure.containsKey(loopVariable)) { |
| 1598 // Temporarily keep the loop variable in a primitive. |
| 1599 // The loop variable will be added to environment when |
| 1600 // [declareLocalVariable] is called. |
| 1601 dartState.registerizedClosureVariables.add(loopVariable); |
| 1602 } |
| 1603 } |
| 1604 } |
| 1605 |
| 1606 void _enterForLoopBody(ClosureScope scope, |
| 1607 List<LocalElement> loopVariables) { |
| 1608 assert(scope == null); |
| 1609 for (LocalElement loopVariable in loopVariables) { |
| 1610 if (dartState.local2closure.containsKey(loopVariable)) { |
| 1611 // Move from primitive into ClosureVariable. |
| 1612 dartState.registerizedClosureVariables.remove(loopVariable); |
| 1613 add(new ir.SetClosureVariable(getClosureVariable(loopVariable), |
| 1614 environment.lookup(loopVariable), |
| 1615 isDeclaration: true)); |
| 1616 } |
| 1617 } |
| 1618 } |
| 1619 |
| 1620 void _enterForLoopUpdate(ClosureScope scope, |
| 1621 List<LocalElement> loopVariables) { |
| 1622 assert(scope == null); |
| 1623 // Move captured loop variables back into the local environment. |
| 1624 // The update expression will use the values we put in the environment, |
| 1625 // and then the environments for the initializer and update will be |
| 1626 // joined at the head of the body. |
| 1627 for (LocalElement loopVariable in loopVariables) { |
| 1628 if (isInClosureVariable(loopVariable)) { |
| 1629 ir.ClosureVariable closureVariable = getClosureVariable(loopVariable); |
| 1630 ir.Primitive get = new ir.GetClosureVariable(closureVariable); |
| 1631 add(new ir.LetPrim(get)); |
| 1632 environment.update(loopVariable, get); |
| 1633 dartState.registerizedClosureVariables.add(loopVariable); |
| 1634 } |
| 1635 } |
| 1594 } | 1636 } |
| 1595 | 1637 |
| 1596 void _createFunctionParameter(ParameterElement parameterElement) { | 1638 void _createFunctionParameter(ParameterElement parameterElement) { |
| 1597 ir.Parameter parameter = new ir.Parameter(parameterElement); | 1639 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 1598 _parameters.add(parameter); | 1640 _parameters.add(parameter); |
| 1599 if (isInClosureVariable(parameterElement)) { | 1641 if (isInClosureVariable(parameterElement)) { |
| 1600 state.functionParameters.add(getClosureVariable(parameterElement)); | 1642 state.functionParameters.add(getClosureVariable(parameterElement)); |
| 1601 } else { | 1643 } else { |
| 1602 state.functionParameters.add(parameter); | 1644 state.functionParameters.add(parameter); |
| 1603 environment.extend(parameterElement, parameter); | 1645 environment.extend(parameterElement, parameter); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1662 assert(isOpen); | 1704 assert(isOpen); |
| 1663 if (isInClosureVariable(local)) { | 1705 if (isInClosureVariable(local)) { |
| 1664 add(new ir.SetClosureVariable(getClosureVariable(local), value)); | 1706 add(new ir.SetClosureVariable(getClosureVariable(local), value)); |
| 1665 } else { | 1707 } else { |
| 1666 value.useElementAsHint(local); | 1708 value.useElementAsHint(local); |
| 1667 environment.update(local, value); | 1709 environment.update(local, value); |
| 1668 } | 1710 } |
| 1669 return value; | 1711 return value; |
| 1670 } | 1712 } |
| 1671 | 1713 |
| 1714 List<ir.ClosureVariable> _getDeclaredClosureVariables( |
| 1715 ExecutableElement element) { |
| 1716 return dartState.getClosureList(element); |
| 1717 } |
| 1718 |
| 1719 ir.Primitive buildThis() { |
| 1720 ir.Primitive thisPrim = new ir.This(); |
| 1721 add(new ir.LetPrim(thisPrim)); |
| 1722 return thisPrim; |
| 1723 } |
| 1672 | 1724 |
| 1673 } | 1725 } |
| 1674 | 1726 |
| 1727 /// State shared between JsIrBuilders within the same function. |
| 1728 /// |
| 1729 /// Note that this is not shared between builders of nested functions. |
| 1730 class JsIrBuilderSharedState { |
| 1731 /// Maps boxed locals to their location. These locals are not part of |
| 1732 /// the environment. |
| 1733 final Map<Local, ClosureLocation> boxedVariables = {}; |
| 1734 |
| 1735 /// If non-null, this refers to the receiver (`this`) in the enclosing method. |
| 1736 ir.Primitive receiver; |
| 1737 } |
| 1738 |
| 1675 /// JS-specific subclass of [IrBuilder]. | 1739 /// JS-specific subclass of [IrBuilder]. |
| 1676 /// | 1740 /// |
| 1677 /// Inner functions are represented by a [ClosureClassElement], and captured | 1741 /// Inner functions are represented by a [ClosureClassElement], and captured |
| 1678 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField]. | 1742 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField]. |
| 1679 class JsIrBuilder extends IrBuilder { | 1743 class JsIrBuilder extends IrBuilder { |
| 1680 IrBuilder _makeInstance() => new JsIrBuilder._blank(); | 1744 final JsIrBuilderSharedState jsState; |
| 1681 JsIrBuilder._blank(); | |
| 1682 | 1745 |
| 1683 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) { | 1746 IrBuilder _makeInstance() => new JsIrBuilder._blank(jsState); |
| 1747 JsIrBuilder._blank(this.jsState); |
| 1748 |
| 1749 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) |
| 1750 : jsState = new JsIrBuilderSharedState() { |
| 1684 _init(constantSystem, currentElement); | 1751 _init(constantSystem, currentElement); |
| 1685 } | 1752 } |
| 1686 | 1753 |
| 1687 void _buildClosureEnvironmentSetup(ClosureEnvironment env) { | 1754 void _enterClosureEnvironment(ClosureEnvironment env) { |
| 1688 if (env == null) return; | 1755 if (env == null) return; |
| 1689 | 1756 |
| 1690 // Obtain a reference to the function object (this). | 1757 // Obtain a reference to the function object (this). |
| 1691 ir.Primitive thisPrim = new ir.This(); | 1758 ir.Primitive thisPrim = new ir.This(); |
| 1692 add(new ir.LetPrim(thisPrim)); | 1759 add(new ir.LetPrim(thisPrim)); |
| 1693 | 1760 |
| 1694 // Obtain access to the free variables. | 1761 // Obtain access to the free variables. |
| 1695 env.freeVariables.forEach((Local local, ClosureLocation location) { | 1762 env.freeVariables.forEach((Local local, ClosureLocation location) { |
| 1696 if (location.isBox) { | 1763 if (location.isBox) { |
| 1697 // Boxed variables are loaded from their box on-demand. | 1764 // Boxed variables are loaded from their box on-demand. |
| 1698 state.boxedVariables[local] = location; | 1765 jsState.boxedVariables[local] = location; |
| 1699 } else { | 1766 } else { |
| 1700 // Unboxed variables are loaded from the function object immediately. | 1767 // Unboxed variables are loaded from the function object immediately. |
| 1701 // This includes BoxLocals which are themselves unboxed variables. | 1768 // This includes BoxLocals which are themselves unboxed variables. |
| 1702 ir.Primitive load = new ir.GetField(thisPrim, location.field); | 1769 ir.Primitive load = new ir.GetField(thisPrim, location.field); |
| 1703 add(new ir.LetPrim(load)); | 1770 add(new ir.LetPrim(load)); |
| 1704 environment.extend(local, load); | 1771 environment.extend(local, load); |
| 1705 } | 1772 } |
| 1706 }); | 1773 }); |
| 1707 | 1774 |
| 1708 // If the function captures a reference to the receiver from the | 1775 // If the function captures a reference to the receiver from the |
| 1709 // enclosing method, remember which primitive refers to the receiver object. | 1776 // enclosing method, remember which primitive refers to the receiver object. |
| 1710 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { | 1777 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) { |
| 1711 state.receiver = environment.lookup(env.thisLocal); | 1778 jsState.receiver = environment.lookup(env.thisLocal); |
| 1712 } | 1779 } |
| 1713 | 1780 |
| 1714 // If the function has a self-reference, use the value of `this`. | 1781 // If the function has a self-reference, use the value of `this`. |
| 1715 if (env.selfReference != null) { | 1782 if (env.selfReference != null) { |
| 1716 environment.extend(env.selfReference, thisPrim); | 1783 environment.extend(env.selfReference, thisPrim); |
| 1717 } | 1784 } |
| 1718 } | 1785 } |
| 1719 | 1786 |
| 1720 void _buildClosureScopeSetup(ClosureScope scope) { | 1787 void _enterScope(ClosureScope scope) { |
| 1721 if (scope == null) return; | 1788 if (scope == null) return; |
| 1722 ir.CreateBox boxPrim = new ir.CreateBox(); | 1789 ir.CreateBox boxPrim = new ir.CreateBox(); |
| 1723 add(new ir.LetPrim(boxPrim)); | 1790 add(new ir.LetPrim(boxPrim)); |
| 1724 environment.extend(scope.box, boxPrim); | 1791 environment.extend(scope.box, boxPrim); |
| 1725 boxPrim.useElementAsHint(scope.box); | 1792 boxPrim.useElementAsHint(scope.box); |
| 1726 scope.capturedVariables.forEach((Local local, ClosureLocation location) { | 1793 scope.capturedVariables.forEach((Local local, ClosureLocation location) { |
| 1727 assert(!state.boxedVariables.containsKey(local)); | 1794 assert(!jsState.boxedVariables.containsKey(local)); |
| 1728 if (location.isBox) { | 1795 if (location.isBox) { |
| 1729 state.boxedVariables[local] = location; | 1796 jsState.boxedVariables[local] = location; |
| 1730 } | 1797 } |
| 1731 }); | 1798 }); |
| 1732 } | 1799 } |
| 1733 | 1800 |
| 1734 void _createFunctionParameter(ParameterElement parameterElement) { | 1801 void _createFunctionParameter(ParameterElement parameterElement) { |
| 1735 ir.Parameter parameter = new ir.Parameter(parameterElement); | 1802 ir.Parameter parameter = new ir.Parameter(parameterElement); |
| 1736 _parameters.add(parameter); | 1803 _parameters.add(parameter); |
| 1737 state.functionParameters.add(parameter); | 1804 state.functionParameters.add(parameter); |
| 1738 ClosureLocation location = state.boxedVariables[parameterElement]; | 1805 ClosureLocation location = jsState.boxedVariables[parameterElement]; |
| 1739 if (location != null) { | 1806 if (location != null) { |
| 1740 add(new ir.SetField(environment.lookup(location.box), | 1807 add(new ir.SetField(environment.lookup(location.box), |
| 1741 location.field, | 1808 location.field, |
| 1742 parameter)); | 1809 parameter)); |
| 1743 } else { | 1810 } else { |
| 1744 environment.extend(parameterElement, parameter); | 1811 environment.extend(parameterElement, parameter); |
| 1745 } | 1812 } |
| 1746 } | 1813 } |
| 1747 | 1814 |
| 1748 void declareLocalVariable(LocalElement variableElement, | 1815 void declareLocalVariable(LocalElement variableElement, |
| 1749 {ir.Primitive initialValue}) { | 1816 {ir.Primitive initialValue}) { |
| 1750 assert(isOpen); | 1817 assert(isOpen); |
| 1751 if (initialValue == null) { | 1818 if (initialValue == null) { |
| 1752 initialValue = buildNullLiteral(); | 1819 initialValue = buildNullLiteral(); |
| 1753 } | 1820 } |
| 1754 ClosureLocation location = state.boxedVariables[variableElement]; | 1821 ClosureLocation location = jsState.boxedVariables[variableElement]; |
| 1755 if (location != null) { | 1822 if (location != null) { |
| 1756 add(new ir.SetField(environment.lookup(location.box), | 1823 add(new ir.SetField(environment.lookup(location.box), |
| 1757 location.field, | 1824 location.field, |
| 1758 initialValue)); | 1825 initialValue)); |
| 1759 } else { | 1826 } else { |
| 1760 initialValue.useElementAsHint(variableElement); | 1827 initialValue.useElementAsHint(variableElement); |
| 1761 environment.extend(variableElement, initialValue); | 1828 environment.extend(variableElement, initialValue); |
| 1762 } | 1829 } |
| 1763 } | 1830 } |
| 1764 | 1831 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1775 arguments.add(environment.lookup(field.local)); | 1842 arguments.add(environment.lookup(field.local)); |
| 1776 } | 1843 } |
| 1777 ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments); | 1844 ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments); |
| 1778 add(new ir.LetPrim(closure)); | 1845 add(new ir.LetPrim(closure)); |
| 1779 return closure; | 1846 return closure; |
| 1780 } | 1847 } |
| 1781 | 1848 |
| 1782 /// Create a read access of [local]. | 1849 /// Create a read access of [local]. |
| 1783 ir.Primitive buildLocalGet(LocalElement local) { | 1850 ir.Primitive buildLocalGet(LocalElement local) { |
| 1784 assert(isOpen); | 1851 assert(isOpen); |
| 1785 ClosureLocation location = state.boxedVariables[local]; | 1852 ClosureLocation location = jsState.boxedVariables[local]; |
| 1786 if (location != null) { | 1853 if (location != null) { |
| 1787 ir.Primitive result = new ir.GetField(environment.lookup(location.box), | 1854 ir.Primitive result = new ir.GetField(environment.lookup(location.box), |
| 1788 location.field); | 1855 location.field); |
| 1789 result.useElementAsHint(local); | 1856 result.useElementAsHint(local); |
| 1790 add(new ir.LetPrim(result)); | 1857 add(new ir.LetPrim(result)); |
| 1791 return result; | 1858 return result; |
| 1792 } else { | 1859 } else { |
| 1793 return environment.lookup(local); | 1860 return environment.lookup(local); |
| 1794 } | 1861 } |
| 1795 } | 1862 } |
| 1796 | 1863 |
| 1797 /// Create a write access to [local] with the provided [value]. | 1864 /// Create a write access to [local] with the provided [value]. |
| 1798 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) { | 1865 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) { |
| 1799 assert(isOpen); | 1866 assert(isOpen); |
| 1800 ClosureLocation location = state.boxedVariables[local]; | 1867 ClosureLocation location = jsState.boxedVariables[local]; |
| 1801 if (location != null) { | 1868 if (location != null) { |
| 1802 add(new ir.SetField(environment.lookup(location.box), | 1869 add(new ir.SetField(environment.lookup(location.box), |
| 1803 location.field, | 1870 location.field, |
| 1804 value)); | 1871 value)); |
| 1805 } else { | 1872 } else { |
| 1806 value.useElementAsHint(local); | 1873 value.useElementAsHint(local); |
| 1807 environment.update(local, value); | 1874 environment.update(local, value); |
| 1808 } | 1875 } |
| 1809 return value; | 1876 return value; |
| 1810 } | 1877 } |
| 1811 | 1878 |
| 1812 void _migrateLoopVariables(ClosureScope scope) { | 1879 void _enterForLoopInitializer(ClosureScope scope, |
| 1880 List<LocalElement> loopVariables) { |
| 1813 if (scope == null) return; | 1881 if (scope == null) return; |
| 1882 // If there are no boxed loop variables, don't create the box here, let |
| 1883 // it be created inside the body instead. |
| 1884 if (scope.boxedLoopVariables.isEmpty) return; |
| 1885 _enterScope(scope); |
| 1886 } |
| 1887 |
| 1888 void _enterForLoopBody(ClosureScope scope, |
| 1889 List<LocalElement> loopVariables) { |
| 1890 if (scope == null) return; |
| 1891 // If there are boxed loop variables, the box has already been created |
| 1892 // at the initializer. |
| 1893 if (!scope.boxedLoopVariables.isEmpty) return; |
| 1894 _enterScope(scope); |
| 1895 } |
| 1896 |
| 1897 void _enterForLoopUpdate(ClosureScope scope, |
| 1898 List<LocalElement> loopVariables) { |
| 1899 if (scope == null) return; |
| 1900 // If there are no boxed loop variables, then the box is created inside the |
| 1901 // body, so there is no need to explicitly renew it. |
| 1902 if (scope.boxedLoopVariables.isEmpty) return; |
| 1814 ir.Primitive box = environment.lookup(scope.box); | 1903 ir.Primitive box = environment.lookup(scope.box); |
| 1815 ir.Primitive newBox = new ir.CreateBox(); | 1904 ir.Primitive newBox = new ir.CreateBox(); |
| 1816 newBox.useElementAsHint(scope.box); | 1905 newBox.useElementAsHint(scope.box); |
| 1817 add(new ir.LetPrim(newBox)); | 1906 add(new ir.LetPrim(newBox)); |
| 1818 for (VariableElement loopVar in scope.boxedLoopVariables) { | 1907 for (VariableElement loopVar in scope.boxedLoopVariables) { |
| 1819 ClosureLocation location = scope.capturedVariables[loopVar]; | 1908 ClosureLocation location = scope.capturedVariables[loopVar]; |
| 1820 ir.Primitive get = new ir.GetField(box, location.field); | 1909 ir.Primitive get = new ir.GetField(box, location.field); |
| 1821 add(new ir.LetPrim(get)); | 1910 add(new ir.LetPrim(get)); |
| 1822 add(new ir.SetField(newBox, location.field, get)); | 1911 add(new ir.SetField(newBox, location.field, get)); |
| 1823 } | 1912 } |
| 1824 environment.update(scope.box, newBox); | 1913 environment.update(scope.box, newBox); |
| 1825 } | 1914 } |
| 1826 | 1915 |
| 1916 List<ir.ClosureVariable> _getDeclaredClosureVariables( |
| 1917 ExecutableElement element) { |
| 1918 return <ir.ClosureVariable>[]; |
| 1919 } |
| 1920 |
| 1921 ir.Primitive buildThis() { |
| 1922 if (jsState.receiver != null) return jsState.receiver; |
| 1923 ir.Primitive thisPrim = new ir.This(); |
| 1924 add(new ir.LetPrim(thisPrim)); |
| 1925 return thisPrim; |
| 1926 } |
| 1827 } | 1927 } |
| 1828 | 1928 |
| 1829 | 1929 |
| 1830 /// Location of a variable relative to a given closure. | 1930 /// Location of a variable relative to a given closure. |
| 1831 class ClosureLocation { | 1931 class ClosureLocation { |
| 1832 /// If not `null`, this location is [box].[field]. | 1932 /// If not `null`, this location is [box].[field]. |
| 1833 /// The location of [box] can be obtained separately from an | 1933 /// The location of [box] can be obtained separately from an |
| 1834 /// enclosing [ClosureEnvironment] or [ClosureScope]. | 1934 /// enclosing [ClosureEnvironment] or [ClosureScope]. |
| 1835 /// If `null`, then the location is [field] on the enclosing function object. | 1935 /// If `null`, then the location is [field] on the enclosing function object. |
| 1836 final BoxLocal box; | 1936 final BoxLocal box; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1873 /// to find the captured value of `this`. | 1973 /// to find the captured value of `this`. |
| 1874 final ThisLocal thisLocal; | 1974 final ThisLocal thisLocal; |
| 1875 | 1975 |
| 1876 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location. | 1976 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location. |
| 1877 final Map<Local, ClosureLocation> freeVariables; | 1977 final Map<Local, ClosureLocation> freeVariables; |
| 1878 | 1978 |
| 1879 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); | 1979 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); |
| 1880 } | 1980 } |
| 1881 | 1981 |
| 1882 /// Information about which variables are captured in a closure. | 1982 /// Information about which variables are captured in a closure. |
| 1983 /// |
| 1883 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and | 1984 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and |
| 1884 /// [ClosureEnvironment]. | 1985 /// [ClosureEnvironment]. |
| 1885 abstract class ClosureVariableInfo { | 1986 abstract class ClosureVariableInfo { |
| 1886 Iterable<Local> get capturedVariables; | 1987 Iterable<Local> get capturedVariables; |
| 1887 } | 1988 } |
| OLD | NEW |