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

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: Comments 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 /// 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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/constant_propagation.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698