Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 756383004: Refactored treatment of closure variables in dart2js CPS. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698