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