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_backend/dart_backend.dart' show DartBackend; | 9 import '../dart_backend/dart_backend.dart' show DartBackend; |
10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 /// [nodes] in its context using [build]. | 170 /// [nodes] in its context using [build]. |
171 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses | 171 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses |
172 // `List` instead of `Link`. | 172 // `List` instead of `Link`. |
173 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { | 173 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { |
174 return (IrBuilder builder) { | 174 return (IrBuilder builder) { |
175 return withBuilder(builder, () => builder.buildSequence(nodes, build)); | 175 return withBuilder(builder, () => builder.buildSequence(nodes, build)); |
176 }; | 176 }; |
177 } | 177 } |
178 } | 178 } |
179 | 179 |
180 /// Shared state between nested builders. | 180 /// Shared state between IrBuilders of nested functions. |
| 181 class IrBuilderClosureState { |
| 182 final Iterable<Entity> closureLocals; |
| 183 |
| 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 IrBuilderClosureState(this.closureLocals) { |
| 198 for (Local local in closureLocals) { |
| 199 ExecutableElement context = local.executableContext; |
| 200 ir.ClosureVariable variable = new ir.ClosureVariable(context, local); |
| 201 local2closure[local] = variable; |
| 202 getClosureList(context).add(variable); |
| 203 } |
| 204 } |
| 205 } |
| 206 |
| 207 /// Shared state between delimited IrBuilders within the same function. |
181 class IrBuilderSharedState { | 208 class IrBuilderSharedState { |
182 final ConstantSystem constantSystem; | 209 final ConstantSystem constantSystem; |
183 | 210 |
184 /// A stack of collectors for breaks. | 211 /// A stack of collectors for breaks. |
185 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 212 final List<JumpCollector> breakCollectors = <JumpCollector>[]; |
186 | 213 |
187 /// A stack of collectors for continues. | 214 /// A stack of collectors for continues. |
188 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 215 final List<JumpCollector> continueCollectors = <JumpCollector>[]; |
189 | 216 |
190 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; | 217 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; |
191 | 218 |
192 final Iterable<Entity> closureLocals; | |
193 | |
194 final ExecutableElement currentElement; | 219 final ExecutableElement currentElement; |
195 | 220 |
196 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 221 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
197 | 222 |
198 IrBuilderSharedState(this.constantSystem, | 223 final List<ir.Definition> functionParameters = <ir.Definition>[]; |
199 this.currentElement, | 224 |
200 this.closureLocals); | 225 IrBuilderSharedState(this.constantSystem, this.currentElement); |
201 } | 226 } |
202 | 227 |
203 /// A factory for building the cps IR. | 228 /// A factory for building the cps IR. |
204 class IrBuilder { | 229 class IrBuilder { |
205 // TODO(johnniwinther): Make these field final and remove the default values | 230 // TODO(johnniwinther): Make these field final and remove the default values |
206 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. | 231 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. |
207 | 232 |
208 final List<ir.Parameter> _parameters = <ir.Parameter>[]; | 233 final List<ir.Parameter> _parameters = <ir.Parameter>[]; |
209 | 234 |
210 final IrBuilderSharedState state; | 235 final IrBuilderSharedState state; |
211 | 236 |
| 237 final IrBuilderClosureState closure; |
| 238 |
212 /// A map from variable indexes to their values. | 239 /// A map from variable indexes to their values. |
213 Environment environment; | 240 Environment environment; |
214 | 241 |
215 // The IR builder maintains a context, which is an expression with a hole in | 242 // The IR builder maintains a context, which is an expression with a hole in |
216 // it. The hole represents the focus where new expressions can be added. | 243 // it. The hole represents the focus where new expressions can be added. |
217 // The context is implemented by 'root' which is the root of the expression | 244 // The context is implemented by 'root' which is the root of the expression |
218 // and 'current' which is the expression that immediately contains the hole. | 245 // and 'current' which is the expression that immediately contains the hole. |
219 // Not all expressions have a hole (e.g., invocations, which always occur in | 246 // Not all expressions have a hole (e.g., invocations, which always occur in |
220 // tail position, do not have a hole). Expressions with a hole have a plug | 247 // tail position, do not have a hole). Expressions with a hole have a plug |
221 // method. | 248 // method. |
(...skipping 13 matching lines...) Expand all Loading... |
235 // current context (root, current) as the visitor state and mutate current. | 262 // current context (root, current) as the visitor state and mutate current. |
236 // Visiting a statement returns null; visiting an expression returns the | 263 // Visiting a statement returns null; visiting an expression returns the |
237 // primitive denoting its value. | 264 // primitive denoting its value. |
238 | 265 |
239 ir.Expression _root = null; | 266 ir.Expression _root = null; |
240 ir.Expression _current = null; | 267 ir.Expression _current = null; |
241 | 268 |
242 IrBuilder(ConstantSystem constantSystem, | 269 IrBuilder(ConstantSystem constantSystem, |
243 ExecutableElement currentElement, | 270 ExecutableElement currentElement, |
244 Iterable<Entity> closureLocals) | 271 Iterable<Entity> closureLocals) |
245 : this.state = new IrBuilderSharedState( | 272 : this.state = new IrBuilderSharedState(constantSystem, currentElement), |
246 constantSystem, currentElement, closureLocals), | 273 this.closure = new IrBuilderClosureState(closureLocals), |
247 this.environment = new Environment.empty(); | 274 this.environment = new Environment.empty(); |
248 | 275 |
249 /// Construct a delimited visitor for visiting a subtree. | 276 /// Construct a delimited visitor for visiting a subtree. |
250 /// | 277 /// |
251 /// The delimited visitor has its own compile-time environment mapping | 278 /// The delimited visitor has its own compile-time environment mapping |
252 /// local variables to their values, which is initially a copy of the parent | 279 /// local variables to their values, which is initially a copy of the parent |
253 /// environment. It has its own context for building an IR expression, so | 280 /// environment. It has its own context for building an IR expression, so |
254 /// the built expression is not plugged into the parent's context. | 281 /// the built expression is not plugged into the parent's context. |
255 IrBuilder.delimited(IrBuilder parent) | 282 IrBuilder.delimited(IrBuilder parent) |
256 : this.state = parent.state, | 283 : this.state = parent.state, |
| 284 this.closure = parent.closure, |
257 this.environment = new Environment.from(parent.environment); | 285 this.environment = new Environment.from(parent.environment); |
258 | 286 |
259 /// Construct a visitor for a recursive continuation. | 287 /// Construct a visitor for a recursive continuation. |
260 /// | 288 /// |
261 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) | 289 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) |
262 /// for all the local variables in the parent, because the invocation sites | 290 /// for all the local variables in the parent, because the invocation sites |
263 /// of the continuation are not all known when the builder is created. The | 291 /// of the continuation are not all known when the builder is created. The |
264 /// recursive invocations will be passed values for all the local variables, | 292 /// recursive invocations will be passed values for all the local variables, |
265 /// which may be eliminated later if they are redundant---if they take on | 293 /// which may be eliminated later if they are redundant---if they take on |
266 /// the same value at all invocation sites. | 294 /// the same value at all invocation sites. |
267 IrBuilder.recursive(IrBuilder parent) | 295 IrBuilder.recursive(IrBuilder parent) |
268 : this.state = parent.state, | 296 : this.state = parent.state, |
| 297 this.closure = parent.closure, |
269 this.environment = new Environment.empty() { | 298 this.environment = new Environment.empty() { |
270 parent.environment.index2variable.forEach(createParameter); | 299 parent.environment.index2variable.forEach(createLocalParameter); |
271 } | 300 } |
272 | 301 |
| 302 /// Construct a builder for an inner function. |
| 303 IrBuilder.innerFunction(IrBuilder parent, |
| 304 ExecutableElement currentElement) |
| 305 : this.state = new IrBuilderSharedState(parent.state.constantSystem, |
| 306 currentElement), |
| 307 this.closure = parent.closure, |
| 308 this.environment = new Environment.empty(); |
| 309 |
273 | 310 |
274 bool get isOpen => _root == null || _current != null; | 311 bool get isOpen => _root == null || _current != null; |
275 | 312 |
276 /// True if [element] is a local variable, local function, or parameter that | 313 /// True if [element] is a local variable, local function, or parameter that |
277 /// is accessed from an inner function. Recursive self-references in a local | 314 /// is accessed from an inner function. Recursive self-references in a local |
278 /// function count as closure accesses. | 315 /// function count as closure accesses. |
279 /// | 316 /// |
280 /// If `true`, [element] is a [LocalElement]. | 317 /// If `true`, [element] is a [LocalElement]. |
281 bool isClosureVariable(Element element) { | 318 bool isClosureVariable(Element element) { |
282 return state.closureLocals.contains(element); | 319 return closure.closureLocals.contains(element); |
| 320 } |
| 321 |
| 322 /// Returns the [ClosureVariable] corresponding to the given variable. |
| 323 /// Returns `null` for non-closure variables. |
| 324 ir.ClosureVariable getClosureVariable(LocalElement element) { |
| 325 return closure.local2closure[element]; |
| 326 } |
| 327 |
| 328 /// Adds the given parameter to the function currently being built. |
| 329 void createFunctionParameter(ParameterElement parameterElement) { |
| 330 if (isClosureVariable(parameterElement)) { |
| 331 state.functionParameters.add(getClosureVariable(parameterElement)); |
| 332 } else { |
| 333 state.functionParameters.add(createLocalParameter(parameterElement)); |
| 334 } |
283 } | 335 } |
284 | 336 |
285 /// Create a parameter for [parameterElement] and add it to the current | 337 /// Create a parameter for [parameterElement] and add it to the current |
286 /// environment. | 338 /// environment. |
287 /// | 339 ir.Parameter createLocalParameter(LocalElement parameterElement) { |
288 /// [isClosureVariable] marks whether [parameterElement] is accessed from an | |
289 /// inner function. | |
290 void createParameter(LocalElement parameterElement) { | |
291 ir.Parameter parameter = new ir.Parameter(parameterElement); | 340 ir.Parameter parameter = new ir.Parameter(parameterElement); |
292 _parameters.add(parameter); | 341 _parameters.add(parameter); |
293 if (isClosureVariable(parameterElement)) { | 342 environment.extend(parameterElement, parameter); |
294 add(new ir.SetClosureVariable(parameterElement, parameter)); | 343 return parameter; |
295 } else { | |
296 environment.extend(parameterElement, parameter); | |
297 } | |
298 } | 344 } |
299 | 345 |
300 /// Add the constant [variableElement] to the environment with [value] as its | 346 /// Add the constant [variableElement] to the environment with [value] as its |
301 /// constant value. | 347 /// constant value. |
302 void declareLocalConstant(LocalVariableElement variableElement, | 348 void declareLocalConstant(LocalVariableElement variableElement, |
303 ConstantExpression value) { | 349 ConstantExpression value) { |
304 state.localConstants.add(new ConstDeclaration(variableElement, value)); | 350 state.localConstants.add(new ConstDeclaration(variableElement, value)); |
305 } | 351 } |
306 | 352 |
307 /// Add [variableElement] to the environment with [initialValue] as its | 353 /// Add [variableElement] to the environment with [initialValue] as its |
308 /// initial value. | 354 /// initial value. |
309 void declareLocalVariable(LocalVariableElement variableElement, | 355 void declareLocalVariable(LocalVariableElement variableElement, |
310 {ir.Primitive initialValue}) { | 356 {ir.Primitive initialValue}) { |
311 assert(isOpen); | 357 assert(isOpen); |
312 if (initialValue == null) { | 358 if (initialValue == null) { |
313 // TODO(kmillikin): Consider pooling constants. | 359 // TODO(kmillikin): Consider pooling constants. |
314 // The initial value is null. | 360 // The initial value is null. |
315 initialValue = buildNullLiteral(); | 361 initialValue = buildNullLiteral(); |
316 } | 362 } |
317 if (isClosureVariable(variableElement)) { | 363 if (isClosureVariable(variableElement)) { |
318 add(new ir.SetClosureVariable(variableElement, | 364 add(new ir.SetClosureVariable(getClosureVariable(variableElement), |
319 initialValue, | 365 initialValue, |
320 isDeclaration: true)); | 366 isDeclaration: true)); |
321 } else { | 367 } else { |
322 // In case a primitive was introduced for the initializer expression, | 368 // In case a primitive was introduced for the initializer expression, |
323 // use this variable element to help derive a good name for it. | 369 // use this variable element to help derive a good name for it. |
324 initialValue.useElementAsHint(variableElement); | 370 initialValue.useElementAsHint(variableElement); |
325 environment.extend(variableElement, initialValue); | 371 environment.extend(variableElement, initialValue); |
326 } | 372 } |
327 } | 373 } |
328 | 374 |
329 /// Add [functionElement] to the environment with provided [definition]. | 375 /// Add [functionElement] to the environment with provided [definition]. |
330 void declareLocalFunction(LocalFunctionElement functionElement, | 376 void declareLocalFunction(LocalFunctionElement functionElement, |
331 ir.FunctionDefinition definition) { | 377 ir.FunctionDefinition definition) { |
332 assert(isOpen); | 378 assert(isOpen); |
333 if (isClosureVariable(functionElement)) { | 379 if (isClosureVariable(functionElement)) { |
334 add(new ir.DeclareFunction(functionElement, definition)); | 380 ir.ClosureVariable variable = getClosureVariable(functionElement); |
| 381 add(new ir.DeclareFunction(variable, definition)); |
335 } else { | 382 } else { |
336 ir.CreateFunction prim = new ir.CreateFunction(definition); | 383 ir.CreateFunction prim = new ir.CreateFunction(definition); |
337 add(new ir.LetPrim(prim)); | 384 add(new ir.LetPrim(prim)); |
338 environment.extend(functionElement, prim); | 385 environment.extend(functionElement, prim); |
339 prim.useElementAsHint(functionElement); | 386 prim.useElementAsHint(functionElement); |
340 } | 387 } |
341 } | 388 } |
342 | 389 |
343 // Plug an expression into the 'hole' in the context being accumulated. The | 390 // Plug an expression into the 'hole' in the context being accumulated. The |
344 // empty context (just a hole) is represented by root (and current) being | 391 // empty context (just a hole) is represented by root (and current) being |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 buildReturn(initializer); | 589 buildReturn(initializer); |
543 return new ir.FieldDefinition(state.currentElement, | 590 return new ir.FieldDefinition(state.currentElement, |
544 state.returnContinuation, | 591 state.returnContinuation, |
545 _root); | 592 _root); |
546 } | 593 } |
547 } | 594 } |
548 | 595 |
549 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. | 596 /// Create a [ir.FunctionDefinition] for [element] using [_root] as the body. |
550 /// | 597 /// |
551 /// Parameters must be created before the construction of the body using | 598 /// Parameters must be created before the construction of the body using |
552 /// [createParameter]. | 599 /// [createFunctionParameter]. |
553 ir.FunctionDefinition makeFunctionDefinition( | 600 ir.FunctionDefinition makeFunctionDefinition( |
554 List<ConstantExpression> defaults) { | 601 List<ConstantExpression> defaults) { |
555 FunctionElement element = state.currentElement; | 602 FunctionElement element = state.currentElement; |
556 if (element.isAbstract || element.isExternal) { | 603 if (element.isAbstract || element.isExternal) { |
557 assert(invariant(element, _root == null, | 604 assert(invariant(element, _root == null, |
558 message: "Non-empty body for abstract method $element: $_root")); | 605 message: "Non-empty body for abstract method $element: $_root")); |
559 assert(invariant(element, state.localConstants.isEmpty, | 606 assert(invariant(element, state.localConstants.isEmpty, |
560 message: "Local constants for abstract method $element: " | 607 message: "Local constants for abstract method $element: " |
561 "${state.localConstants}")); | 608 "${state.localConstants}")); |
562 return new ir.FunctionDefinition.abstract( | 609 return new ir.FunctionDefinition.abstract( |
563 element, _parameters, defaults); | 610 element, state.functionParameters, defaults); |
564 } else { | 611 } else { |
565 _ensureReturn(); | 612 _ensureReturn(); |
566 return new ir.FunctionDefinition( | 613 return new ir.FunctionDefinition( |
567 element, state.returnContinuation, _parameters, _root, | 614 element, state.returnContinuation, state.functionParameters, _root, |
568 state.localConstants, defaults); | 615 state.localConstants, defaults, closure.getClosureList(element)); |
569 } | 616 } |
570 } | 617 } |
571 | 618 |
572 /// Create a super invocation where the method name and the argument structure | 619 /// Create a super invocation where the method name and the argument structure |
573 /// are defined by [selector] and the argument values are defined by | 620 /// are defined by [selector] and the argument values are defined by |
574 /// [arguments]. | 621 /// [arguments]. |
575 ir.Primitive buildSuperInvocation(Selector selector, | 622 ir.Primitive buildSuperInvocation(Selector selector, |
576 List<ir.Primitive> arguments) { | 623 List<ir.Primitive> arguments) { |
577 return _buildInvokeSuper(selector, arguments); | 624 return _buildInvokeSuper(selector, arguments); |
578 } | 625 } |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { | 724 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { |
678 assert(isOpen); | 725 assert(isOpen); |
679 return _continueWithExpression( | 726 return _continueWithExpression( |
680 (k) => new ir.ConcatenateStrings(k, arguments)); | 727 (k) => new ir.ConcatenateStrings(k, arguments)); |
681 } | 728 } |
682 | 729 |
683 /// Create a read access of [local]. | 730 /// Create a read access of [local]. |
684 ir.Primitive buildLocalGet(LocalElement local) { | 731 ir.Primitive buildLocalGet(LocalElement local) { |
685 assert(isOpen); | 732 assert(isOpen); |
686 if (isClosureVariable(local)) { | 733 if (isClosureVariable(local)) { |
687 ir.Primitive result = new ir.GetClosureVariable(local); | 734 ir.Primitive result = |
| 735 new ir.GetClosureVariable(getClosureVariable(local)); |
688 add(new ir.LetPrim(result)); | 736 add(new ir.LetPrim(result)); |
689 return result; | 737 return result; |
690 } else { | 738 } else { |
691 return environment.lookup(local); | 739 return environment.lookup(local); |
692 } | 740 } |
693 } | 741 } |
694 | 742 |
695 /// Create a write access to [local] with the provided [value]. | 743 /// Create a write access to [local] with the provided [value]. |
696 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) { | 744 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) { |
697 assert(isOpen); | 745 assert(isOpen); |
698 if (isClosureVariable(local)) { | 746 if (isClosureVariable(local)) { |
699 add(new ir.SetClosureVariable(local, value)); | 747 add(new ir.SetClosureVariable(getClosureVariable(local), value)); |
700 } else { | 748 } else { |
701 value.useElementAsHint(local); | 749 value.useElementAsHint(local); |
702 environment.update(local, value); | 750 environment.update(local, value); |
703 } | 751 } |
704 return value; | 752 return value; |
705 } | 753 } |
706 | 754 |
707 /// Create an invocation of [local] where the argument structure is defined | 755 /// Create an invocation of [local] where the argument structure is defined |
708 /// by [selector] and the argument values are defined by [arguments]. | 756 /// by [selector] and the argument values are defined by [arguments]. |
709 ir.Primitive buildLocalInvocation(LocalElement local, | 757 ir.Primitive buildLocalInvocation(LocalElement local, |
710 Selector selector, | 758 Selector selector, |
711 List<ir.Definition> arguments) { | 759 List<ir.Definition> arguments) { |
712 ir.Primitive receiver; | 760 ir.Primitive receiver; |
713 if (isClosureVariable(local)) { | 761 if (isClosureVariable(local)) { |
714 receiver = new ir.GetClosureVariable(local); | 762 receiver = new ir.GetClosureVariable(getClosureVariable(local)); |
715 add(new ir.LetPrim(receiver)); | 763 add(new ir.LetPrim(receiver)); |
716 } else { | 764 } else { |
717 receiver = environment.lookup(local); | 765 receiver = environment.lookup(local); |
718 } | 766 } |
719 return _buildInvokeCall(receiver, selector, arguments); | 767 return _buildInvokeCall(receiver, selector, arguments); |
720 } | 768 } |
721 | 769 |
722 /// Create an invocation of the [functionExpression] where the argument | 770 /// Create an invocation of the [functionExpression] where the argument |
723 /// structure are defined by [selector] and the argument values are defined by | 771 /// structure are defined by [selector] and the argument values are defined by |
724 /// [arguments]. | 772 /// [arguments]. |
(...skipping 742 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1467 index = 0; | 1515 index = 0; |
1468 for (int i = 0; i < environment.length; ++i) { | 1516 for (int i = 0; i < environment.length; ++i) { |
1469 if (common[i] == null) { | 1517 if (common[i] == null) { |
1470 environment.index2value[i] = parameters[index++]; | 1518 environment.index2value[i] = parameters[index++]; |
1471 } | 1519 } |
1472 } | 1520 } |
1473 | 1521 |
1474 return join; | 1522 return join; |
1475 } | 1523 } |
1476 } | 1524 } |
OLD | NEW |