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

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

Issue 831133004: Use closure conversion in new dart2js backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 months 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 part of dart2js.ir_builder; 5 part of dart2js.ir_builder;
6 6
7 /** 7 /**
8 * This task iterates through all resolved elements and builds [ir.Node]s. The 8 * This task iterates through all resolved elements and builds [ir.Node]s. The
9 * nodes are stored in the [nodes] map and accessible through [hasIr] and 9 * nodes are stored in the [nodes] map and accessible through [hasIr] and
10 * [getIr]. 10 * [getIr].
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 101
102 /** 102 /**
103 * A tree visitor that builds [IrNodes]. The visit methods add statements using 103 * A tree visitor that builds [IrNodes]. The visit methods add statements using
104 * to the [builder] and return the last added statement for trees that represent 104 * to the [builder] and return the last added statement for trees that represent
105 * an expression. 105 * an expression.
106 */ 106 */
107 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> 107 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
108 with IrBuilderMixin<ast.Node> { 108 with IrBuilderMixin<ast.Node> {
109 final Compiler compiler; 109 final Compiler compiler;
110 final SourceFile sourceFile; 110 final SourceFile sourceFile;
111 ClosureClassMap closureMap;
111 112
112 // In SSA terms, join-point continuation parameters are the phis and the 113 // In SSA terms, join-point continuation parameters are the phis and the
113 // continuation invocation arguments are the corresponding phi inputs. To 114 // continuation invocation arguments are the corresponding phi inputs. To
114 // support name introduction and renaming for source level variables, we use 115 // support name introduction and renaming for source level variables, we use
115 // nested (delimited) visitors for constructing subparts of the IR that will 116 // nested (delimited) visitors for constructing subparts of the IR that will
116 // need renaming. Each source variable is assigned an index. 117 // need renaming. Each source variable is assigned an index.
117 // 118 //
118 // Each nested visitor maintains a list of free variable uses in the body. 119 // Each nested visitor maintains a list of free variable uses in the body.
119 // These are implemented as a list of parameters, each with their own use 120 // These are implemented as a list of parameters, each with their own use
120 // list of references. When the delimited subexpression is plugged into the 121 // list of references. When the delimited subexpression is plugged into the
121 // surrounding context, the free occurrences can be captured or become free 122 // surrounding context, the free occurrences can be captured or become free
122 // occurrences in the next outer delimited subexpression. 123 // occurrences in the next outer delimited subexpression.
123 // 124 //
124 // Each nested visitor maintains a list that maps indexes of variables 125 // Each nested visitor maintains a list that maps indexes of variables
125 // assigned in the delimited subexpression to their reaching definition --- 126 // assigned in the delimited subexpression to their reaching definition ---
126 // that is, the definition in effect at the hole in 'current'. These are 127 // that is, the definition in effect at the hole in 'current'. These are
127 // used to determine if a join-point continuation needs to be passed 128 // used to determine if a join-point continuation needs to be passed
128 // arguments, and what the arguments are. 129 // arguments, and what the arguments are.
129 130
130 /// Construct a top-level visitor. 131 /// Construct a top-level visitor.
131 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) 132 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
132 : super(elements); 133 : super(elements);
133 134
135 /// True if using the JavaScript backend; we use this to determine how
136 /// closures should be translated.
137 bool get isJavaScriptBackend => compiler.backend is JavaScriptBackend;
138
134 /** 139 /**
135 * Builds the [ir.ExecutableDefinition] for an executable element. In case the 140 * Builds the [ir.ExecutableDefinition] for an executable element. In case the
136 * function uses features that cannot be expressed in the IR, this element 141 * function uses features that cannot be expressed in the IR, this element
137 * returns `null`. 142 * returns `null`.
138 */ 143 */
139 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { 144 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
140 return nullIfGiveup(() { 145 return nullIfGiveup(() {
141 if (element is FieldElement) { 146 if (element is FieldElement) {
142 return buildField(element); 147 return buildField(element);
143 } else if (element is FunctionElement) { 148 } else if (element is FunctionElement) {
144 return buildFunction(element); 149 return buildFunction(element);
145 } else { 150 } else {
146 compiler.internalError(element, "Unexpected element type $element"); 151 compiler.internalError(element, "Unexpected element type $element");
147 } 152 }
148 }); 153 });
149 } 154 }
150 155
156 Map mapValues(Map map, dynamic fn(dynamic)) {
157 Map result = {};
158 map.forEach((key,value) {
floitsch 2015/01/08 18:29:36 indentation and missing space.
asgerf 2015/01/12 13:15:43 Done.
159 result[key] = fn(value);
160 });
161 return result;
162 }
163
164 ClosureLocation getLocation(CapturedVariable v) {
165 if (v is BoxFieldElement) {
166 return new ClosureLocation(v.box, v);
167 } else {
168 return new ClosureLocation(null, v as ClosureFieldElement);
floitsch 2015/01/08 18:29:37 It's stupid but we avoid `as`. Just create a tempo
asgerf 2015/01/12 13:15:43 Done.
169 }
170 }
171
172 ClosureEnvironment getClosureEnvironment() {
173 if (closureMap == null) return null; // dart2dart does not use closureMap
floitsch 2015/01/08 18:29:37 Finish comment with ".".
asgerf 2015/01/12 13:15:43 Done.
174 if (closureMap.closureElement == null) return null;
175 return new ClosureEnvironment(
176 closureMap.closureElement,
177 closureMap.thisLocal,
178 mapValues(closureMap.freeVariableMap, getLocation));
179 }
180
181 ClosureScope getClosureScope(ast.Node node) {
floitsch 2015/01/08 18:29:36 Add lots of documentation. I wrote the closure.dar
asgerf 2015/01/12 13:15:43 Done.
182 if (closureMap == null) return null; // dart2dart does not use closureMap
floitsch 2015/01/08 18:29:37 ditto.
asgerf 2015/01/12 13:15:43 Done.
183 closurelib.ClosureScope scope = closureMap.capturingScopes[node];
184 if (scope == null) return null;
185 return new ClosureScope(scope.boxElement,
186 mapValues(scope.capturedVariables, getLocation),
187 scope.boxedLoopVariables);
188 }
189
190 IrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
191 if (isJavaScriptBackend) {
192 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
193 element,
194 node,
195 elements);
196 return new JsIrBuilder(compiler.backend.constantSystem, element);
197 } else {
198 DetectClosureVariables closures = new DetectClosureVariables(elements);
199 if (!element.isSynthesized) {
200 closures.visit(node);
201 }
202 return new DartIrBuilder(compiler.backend.constantSystem,
203 element,
204 closures);
205 }
206 }
207
151 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. 208 /// Returns a [ir.FieldDefinition] describing the initializer of [element].
152 /// Returns `null` if [element] has no initializer. 209 /// Returns `null` if [element] has no initializer.
153 ir.FieldDefinition buildField(FieldElement element) { 210 ir.FieldDefinition buildField(FieldElement element) {
154 assert(invariant(element, element.isImplementation)); 211 assert(invariant(element, element.isImplementation));
155 ast.VariableDefinitions definitions = element.node; 212 ast.VariableDefinitions definitions = element.node;
156 ast.Node fieldDefinition = 213 ast.Node fieldDefinition =
157 definitions.definitions.nodes.first; 214 definitions.definitions.nodes.first;
158 if (definitions.modifiers.isConst) { 215 if (definitions.modifiers.isConst) {
159 // TODO(sigurdm): Just return const value. 216 // TODO(sigurdm): Just return const value.
160 } 217 }
161 assert(fieldDefinition != null); 218 assert(fieldDefinition != null);
162 assert(elements[fieldDefinition] != null); 219 assert(elements[fieldDefinition] != null);
163 DetectClosureVariables closureLocals =
164 new DetectClosureVariables(elements);
165 closureLocals.visit(fieldDefinition);
166 220
167 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, 221 IrBuilder builder = makeIRBuilder(fieldDefinition, element);
168 element, 222
169 closureLocals.usedFromClosure);
170 return withBuilder(builder, () { 223 return withBuilder(builder, () {
224 builder.beginField(closureScope: getClosureScope(fieldDefinition));
floitsch 2015/01/08 18:29:37 I would rename this call to something like buildFi
asgerf 2015/01/13 10:04:26 Everything in this class is already randomly prefi
171 ir.Primitive initializer; 225 ir.Primitive initializer;
172 if (fieldDefinition is ast.SendSet) { 226 if (fieldDefinition is ast.SendSet) {
173 ast.SendSet sendSet = fieldDefinition; 227 ast.SendSet sendSet = fieldDefinition;
174 initializer = visit(sendSet.arguments.first); 228 initializer = visit(sendSet.arguments.first);
175 } 229 }
176 return builder.makeFieldDefinition(initializer); 230 return builder.makeFieldDefinition(initializer);
177 }); 231 });
178 } 232 }
179 233
180 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, 234 ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
181 ast.FunctionExpression node) { 235 ast.FunctionExpression node) {
182 FunctionSignature signature = element.functionSignature; 236 FunctionSignature signature = element.functionSignature;
183 signature.orderedForEachParameter((ParameterElement parameterElement) { 237 List<ParameterElement> parameters = [];
184 irBuilder.createFunctionParameter(parameterElement); 238 signature.orderedForEachParameter(parameters.add);
185 }); 239
240 irBuilder.beginFunction(parameters,
floitsch 2015/01/08 18:29:37 ditto.
241 closureScope: getClosureScope(node),
242 closureEnvironment: getClosureEnvironment());
186 243
187 List<ConstantExpression> defaults = new List<ConstantExpression>(); 244 List<ConstantExpression> defaults = new List<ConstantExpression>();
188 signature.orderedOptionalParameters.forEach((ParameterElement element) { 245 signature.orderedOptionalParameters.forEach((ParameterElement element) {
189 defaults.add(getConstantForVariable(element)); 246 defaults.add(getConstantForVariable(element));
190 }); 247 });
191 248
192 List<ir.Initializer> initializers; 249 List<ir.Initializer> initializers;
193 if (element.isSynthesized) { 250 if (element.isSynthesized) {
194 assert(element is ConstructorElement); 251 assert(element is ConstructorElement);
195 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], 252 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[],
196 const <ir.Initializer>[]); 253 const <ir.Initializer>[]);
197 } else if (element.isGenerativeConstructor) { 254 } else if (element.isGenerativeConstructor) {
198 initializers = buildConstructorInitializers(node, element); 255 initializers = buildConstructorInitializers(node, element);
199 visit(node.body); 256 visit(node.body);
200 return irBuilder.makeConstructorDefinition(defaults, initializers); 257 return irBuilder.makeConstructorDefinition(defaults, initializers);
201 } else { 258 } else {
202 visit(node.body); 259 visit(node.body);
203 return irBuilder.makeFunctionDefinition(defaults); 260 return irBuilder.makeFunctionDefinition(defaults);
204 } 261 }
205 } 262 }
206 263
207 List<ir.Initializer> buildConstructorInitializers( 264 List<ir.Initializer> buildConstructorInitializers(
208 ast.FunctionExpression function, ConstructorElement element) { 265 ast.FunctionExpression function, ConstructorElement element) {
209 List<ir.Initializer> result = <ir.Initializer>[]; 266 List<ir.Initializer> result = <ir.Initializer>[];
210 FunctionSignature signature = element.functionSignature; 267 FunctionSignature signature = element.functionSignature;
211 268
212 void tryAddInitializingFormal(ParameterElement parameterElement) { 269 void tryAddInitializingFormal(ParameterElement parameterElement) {
213 if (parameterElement.isInitializingFormal) { 270 if (parameterElement.isInitializingFormal) {
214 InitializingFormalElement initializingFormal = parameterElement; 271 InitializingFormalElement initializingFormal = parameterElement;
215 withBuilder(new IrBuilder.delimited(irBuilder), () { 272 withBuilder(irBuilder.makeDelimitedBuilder(), () {
216 ir.Primitive value = irBuilder.buildLocalGet(parameterElement); 273 ir.Primitive value = irBuilder.buildLocalGet(parameterElement);
217 result.add(irBuilder.makeFieldInitializer( 274 result.add(irBuilder.makeFieldInitializer(
218 initializingFormal.fieldElement, 275 initializingFormal.fieldElement,
219 irBuilder.makeRunnableBody(value))); 276 irBuilder.makeRunnableBody(value)));
220 }); 277 });
221 } 278 }
222 } 279 }
223 280
224 // TODO(sigurdm): Preserve initializing formals as initializing formals. 281 // TODO(sigurdm): Preserve initializing formals as initializing formals.
225 signature.orderedForEachParameter(tryAddInitializingFormal); 282 signature.orderedForEachParameter(tryAddInitializingFormal);
226 283
227 if (function.initializers == null) return result; 284 if (function.initializers == null) return result;
228 bool explicitSuperInitializer = false; 285 bool explicitSuperInitializer = false;
229 for(ast.Node initializer in function.initializers) { 286 for(ast.Node initializer in function.initializers) {
230 if (initializer is ast.SendSet) { 287 if (initializer is ast.SendSet) {
231 // Field initializer. 288 // Field initializer.
232 FieldElement field = elements[initializer]; 289 FieldElement field = elements[initializer];
233 withBuilder(new IrBuilder.delimited(irBuilder), () { 290 withBuilder(irBuilder.makeDelimitedBuilder(), () {
234 ir.Primitive value = visit(initializer.arguments.head); 291 ir.Primitive value = visit(initializer.arguments.head);
235 ir.RunnableBody body = irBuilder.makeRunnableBody(value); 292 ir.RunnableBody body = irBuilder.makeRunnableBody(value);
236 result.add(irBuilder.makeFieldInitializer(field, body)); 293 result.add(irBuilder.makeFieldInitializer(field, body));
237 }); 294 });
238 } else if (initializer is ast.Send) { 295 } else if (initializer is ast.Send) {
239 // Super or this initializer. 296 // Super or this initializer.
240 if (ast.Initializers.isConstructorRedirect(initializer)) { 297 if (ast.Initializers.isConstructorRedirect(initializer)) {
241 giveup(initializer, "constructor redirect (this) initializer"); 298 giveup(initializer, "constructor redirect (this) initializer");
242 } 299 }
243 ConstructorElement constructor = elements[initializer].implementation; 300 ConstructorElement constructor = elements[initializer].implementation;
244 Selector selector = elements.getSelector(initializer); 301 Selector selector = elements.getSelector(initializer);
245 List<ir.RunnableBody> arguments = 302 List<ir.RunnableBody> arguments =
246 initializer.arguments.mapToList((ast.Node argument) { 303 initializer.arguments.mapToList((ast.Node argument) {
247 return withBuilder(new IrBuilder.delimited(irBuilder), () { 304 return withBuilder(irBuilder.makeDelimitedBuilder(), () {
248 ir.Primitive value = visit(argument); 305 ir.Primitive value = visit(argument);
249 return irBuilder.makeRunnableBody(value); 306 return irBuilder.makeRunnableBody(value);
250 }); 307 });
251 }); 308 });
252 result.add(irBuilder.makeSuperInitializer(constructor, 309 result.add(irBuilder.makeSuperInitializer(constructor,
253 arguments, 310 arguments,
254 selector)); 311 selector));
255 explicitSuperInitializer = true; 312 explicitSuperInitializer = true;
256 } else { 313 } else {
257 compiler.internalError(initializer, 314 compiler.internalError(initializer,
(...skipping 23 matching lines...) Expand all
281 } 338 }
282 339
283 ir.FunctionDefinition buildFunction(FunctionElement element) { 340 ir.FunctionDefinition buildFunction(FunctionElement element) {
284 assert(invariant(element, element.isImplementation)); 341 assert(invariant(element, element.isImplementation));
285 ast.FunctionExpression node = element.node; 342 ast.FunctionExpression node = element.node;
286 343
287 Iterable<Entity> usedFromClosure; 344 Iterable<Entity> usedFromClosure;
288 if (!element.isSynthesized) { 345 if (!element.isSynthesized) {
289 assert(node != null); 346 assert(node != null);
290 assert(elements[node] != null); 347 assert(elements[node] != null);
291
292 // TODO(karlklose): this information should be provided by resolution.
293 DetectClosureVariables closureLocals =
294 new DetectClosureVariables(elements);
295 closureLocals.visit(node);
296 usedFromClosure = closureLocals.usedFromClosure;
297 } else { 348 } else {
298 SynthesizedConstructorElementX constructor = element; 349 SynthesizedConstructorElementX constructor = element;
299 if (!constructor.isDefaultConstructor) { 350 if (!constructor.isDefaultConstructor) {
300 giveup(null, 'cannot handle synthetic forwarding constructors'); 351 giveup(null, 'cannot handle synthetic forwarding constructors');
301 } 352 }
302 353
303 usedFromClosure = <Entity>[]; 354 usedFromClosure = <Entity>[];
304 } 355 }
305 356
306 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, 357 IrBuilder builder = makeIRBuilder(node, element);
307 element,
308 usedFromClosure);
309 358
310 return withBuilder(builder, () => _makeFunctionBody(element, node)); 359 return withBuilder(builder, () => _makeFunctionBody(element, node));
311 } 360 }
312 361
313 ir.Primitive visit(ast.Node node) => node.accept(this); 362 ir.Primitive visit(ast.Node node) => node.accept(this);
314 363
315 // ==== Statements ==== 364 // ==== Statements ====
316 visitBlock(ast.Block node) { 365 visitBlock(ast.Block node) {
317 irBuilder.buildBlock(node.statements.nodes, build); 366 irBuilder.buildBlock(node.statements.nodes, build);
318 } 367 }
(...skipping 20 matching lines...) Expand all
339 388
340 // Build(ExpressionStatement(e), C) = C' 389 // Build(ExpressionStatement(e), C) = C'
341 // where (C', _) = Build(e, C) 390 // where (C', _) = Build(e, C)
342 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { 391 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
343 assert(irBuilder.isOpen); 392 assert(irBuilder.isOpen);
344 visit(node.expression); 393 visit(node.expression);
345 return null; 394 return null;
346 } 395 }
347 396
348 visitFor(ast.For node) { 397 visitFor(ast.For node) {
349 // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop. 398 // TODO(asgerf): Handle closure variables declared in a for-loop.
350 if (node.initializer is ast.VariableDefinitions) { 399 if (!isJavaScriptBackend && node.initializer is ast.VariableDefinitions) {
351 ast.VariableDefinitions definitions = node.initializer; 400 ast.VariableDefinitions definitions = node.initializer;
352 for (ast.Node definition in definitions.definitions.nodes) { 401 for (ast.Node definition in definitions.definitions.nodes) {
353 Element element = elements[definition]; 402 LocalElement element = elements[definition];
354 if (irBuilder.isClosureVariable(element)) { 403 if ((irBuilder as DartIrBuilder).isInRefCell(element)) {
floitsch 2015/01/08 18:29:36 ditto: we don't use `as`. Just assign to a tempora
355 return giveup(definition, 'Closure variable in for loop initializer'); 404 return giveup(definition, 'Closure variable in for loop initializer');
356 } 405 }
357 } 406 }
358 } 407 }
359 408
360 JumpTarget target = elements.getTargetDefinition(node); 409 JumpTarget target = elements.getTargetDefinition(node);
361 irBuilder.buildFor( 410 irBuilder.buildFor(
362 buildInitializer: subbuild(node.initializer), 411 buildInitializer: subbuild(node.initializer),
363 buildCondition: subbuild(node.condition), 412 buildCondition: subbuild(node.condition),
364 buildBody: subbuild(node.body), 413 buildBody: subbuild(node.body),
365 buildUpdate: subbuildSequence(node.update), 414 buildUpdate: subbuildSequence(node.update),
415 closureScope: getClosureScope(node),
366 target: target); 416 target: target);
367 } 417 }
368 418
369 visitIf(ast.If node) { 419 visitIf(ast.If node) {
370 irBuilder.buildIf( 420 irBuilder.buildIf(
371 build(node.condition), 421 build(node.condition),
372 subbuild(node.thenPart), 422 subbuild(node.thenPart),
373 subbuild(node.elsePart)); 423 subbuild(node.elsePart));
374 } 424 }
375 425
376 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) { 426 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) {
377 ast.Statement body = node.statement; 427 ast.Statement body = node.statement;
378 if (body is ast.Loop) return visit(body); 428 if (body is ast.Loop) return visit(body);
379 JumpTarget target = elements.getTargetDefinition(body); 429 JumpTarget target = elements.getTargetDefinition(body);
380 JumpCollector jumps = new JumpCollector(target); 430 JumpCollector jumps = new JumpCollector(target);
381 irBuilder.state.breakCollectors.add(jumps); 431 irBuilder.state.breakCollectors.add(jumps);
382 IrBuilder innerBuilder = new IrBuilder.delimited(irBuilder); 432 IrBuilder innerBuilder = irBuilder.makeDelimitedBuilder();
383 withBuilder(innerBuilder, () { 433 withBuilder(innerBuilder, () {
384 visit(body); 434 visit(body);
385 }); 435 });
386 irBuilder.state.breakCollectors.removeLast(); 436 irBuilder.state.breakCollectors.removeLast();
387 bool hasBreaks = !jumps.isEmpty; 437 bool hasBreaks = !jumps.isEmpty;
388 ir.Continuation joinContinuation; 438 ir.Continuation joinContinuation;
389 if (hasBreaks) { 439 if (hasBreaks) {
390 if (innerBuilder.isOpen) { 440 if (innerBuilder.isOpen) {
391 jumps.addJump(innerBuilder); 441 jumps.addJump(innerBuilder);
392 } 442 }
(...skipping 20 matching lines...) Expand all
413 irBuilder.environment = innerBuilder.environment; 463 irBuilder.environment = innerBuilder.environment;
414 } 464 }
415 } 465 }
416 return null; 466 return null;
417 } 467 }
418 468
419 visitWhile(ast.While node) { 469 visitWhile(ast.While node) {
420 irBuilder.buildWhile( 470 irBuilder.buildWhile(
421 buildCondition: subbuild(node.condition), 471 buildCondition: subbuild(node.condition),
422 buildBody: subbuild(node.body), 472 buildBody: subbuild(node.body),
423 target: elements.getTargetDefinition(node)); 473 target: elements.getTargetDefinition(node),
474 closureScope: getClosureScope(node));
424 } 475 }
425 476
426 visitForIn(ast.ForIn node) { 477 visitForIn(ast.ForIn node) {
427 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions] 478 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
428 // (defining a new local variable) or a send designating some existing 479 // (defining a new local variable) or a send designating some existing
429 // variable. 480 // variable.
430 ast.Node identifier = node.declaredIdentifier; 481 ast.Node identifier = node.declaredIdentifier;
431 ast.VariableDefinitions variableDeclaration = 482 ast.VariableDefinitions variableDeclaration =
432 identifier.asVariableDefinitions(); 483 identifier.asVariableDefinitions();
433 Element variableElement = elements.getForInVariable(node); 484 Element variableElement = elements.getForInVariable(node);
434 Selector selector = elements.getSelector(identifier); 485 Selector selector = elements.getSelector(identifier);
435 486
436 irBuilder.buildForIn( 487 irBuilder.buildForIn(
437 buildExpression: subbuild(node.expression), 488 buildExpression: subbuild(node.expression),
438 buildVariableDeclaration: subbuild(variableDeclaration), 489 buildVariableDeclaration: subbuild(variableDeclaration),
439 variableElement: variableElement, 490 variableElement: variableElement,
440 variableSelector: selector, 491 variableSelector: selector,
441 buildBody: subbuild(node.body), 492 buildBody: subbuild(node.body),
442 target: elements.getTargetDefinition(node)); 493 target: elements.getTargetDefinition(node),
494 closureScope: getClosureScope(node));
443 } 495 }
444 496
445 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { 497 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
446 assert(irBuilder.isOpen); 498 assert(irBuilder.isOpen);
447 if (node.modifiers.isConst) { 499 if (node.modifiers.isConst) {
448 for (ast.SendSet definition in node.definitions.nodes) { 500 for (ast.SendSet definition in node.definitions.nodes) {
449 assert(!definition.arguments.isEmpty); 501 assert(!definition.arguments.isEmpty);
450 assert(definition.arguments.tail.isEmpty); 502 assert(definition.arguments.tail.isEmpty);
451 VariableElement element = elements[definition]; 503 VariableElement element = elements[definition];
452 ConstantExpression value = getConstantForVariable(element); 504 ConstantExpression value = getConstantForVariable(element);
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after
943 } 995 }
944 996
945 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { 997 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
946 assert(irBuilder.isOpen); 998 assert(irBuilder.isOpen);
947 if (constant == null) { 999 if (constant == null) {
948 constant = getConstantForNode(node); 1000 constant = getConstantForNode(node);
949 } 1001 }
950 return irBuilder.buildConstantLiteral(constant); 1002 return irBuilder.buildConstantLiteral(constant);
951 } 1003 }
952 1004
953 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { 1005 /// Returns the backend-specific representation of an inner function.
954 FunctionElement element = elements[node]; 1006 Object makeSubFunction(ast.FunctionExpression node) {
955 assert(invariant(element, element.isImplementation)); 1007 if (isJavaScriptBackend) {
1008 ClosureClassMap innerMap =
1009 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1010 ClosureClassElement closureClass = innerMap.closureClassElement;
1011 return closureClass;
1012 } else {
1013 FunctionElement element = elements[node];
1014 assert(invariant(element, element.isImplementation));
956 1015
957 IrBuilder builder = new IrBuilder.innerFunction(irBuilder, element); 1016 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
958 1017
959 return withBuilder(builder, () => _makeFunctionBody(element, node)); 1018 return withBuilder(builder, () => _makeFunctionBody(element, node));
1019 }
960 } 1020 }
961 1021
962 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { 1022 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
963 return irBuilder.buildFunctionExpression(makeSubFunction(node)); 1023 return irBuilder.buildFunctionExpression(makeSubFunction(node));
964 } 1024 }
965 1025
966 visitFunctionDeclaration(ast.FunctionDeclaration node) { 1026 visitFunctionDeclaration(ast.FunctionDeclaration node) {
967 LocalFunctionElement element = elements[node.function]; 1027 LocalFunctionElement element = elements[node.function];
968 ir.FunctionDefinition inner = makeSubFunction(node.function); 1028 Object inner = makeSubFunction(node.function);
969 irBuilder.declareLocalFunction(element, inner); 1029 irBuilder.declareLocalFunction(element, inner);
970 } 1030 }
971 1031
972 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; 1032 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
973 1033
974 dynamic giveup(ast.Node node, [String reason]) { 1034 dynamic giveup(ast.Node node, [String reason]) {
975 throw ABORT_IRNODE_BUILDER; 1035 throw ABORT_IRNODE_BUILDER;
976 } 1036 }
977 1037
978 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { 1038 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
979 try { 1039 try {
980 return action(); 1040 return action();
981 } catch(e, tr) { 1041 } catch(e, tr) {
982 if (e == ABORT_IRNODE_BUILDER) { 1042 if (e == ABORT_IRNODE_BUILDER) {
983 return null; 1043 return null;
984 } 1044 }
985 rethrow; 1045 rethrow;
986 } 1046 }
987 } 1047 }
988 1048
989 void internalError(String reason, {ast.Node node}) { 1049 void internalError(String reason, {ast.Node node}) {
990 giveup(node); 1050 giveup(node);
991 } 1051 }
992 } 1052 }
993 1053
994 /// Classifies local variables and local functions as 'closure variables'. 1054 /// Classifies local variables and local functions as 'closure variables'.
995 /// A closure variable is one that is accessed from an inner function nested 1055 /// A closure variable is one that is accessed from an inner function nested
996 /// one or more levels inside the one that declares it. 1056 /// one or more levels inside the one that declares it.
997 class DetectClosureVariables extends ast.Visitor { 1057 class DetectClosureVariables extends ast.Visitor
1058 implements ClosureVariableInfo {
998 final TreeElements elements; 1059 final TreeElements elements;
999 DetectClosureVariables(this.elements); 1060 DetectClosureVariables(this.elements);
1000 1061
1001 FunctionElement currentFunction; 1062 FunctionElement currentFunction;
1002 bool insideInitializer = false; 1063 bool insideInitializer = false;
1003 Set<Local> usedFromClosure = new Set<Local>(); 1064 Set<Local> capturedVariables = new Set<Local>();
floitsch 2015/01/08 18:29:37 nit: maybe go directly for a Setlet ?
1004 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
1005
1006 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity);
1007 1065
1008 void markAsClosureVariable(Local local) { 1066 void markAsClosureVariable(Local local) {
1009 usedFromClosure.add(local); 1067 capturedVariables.add(local);
1010 } 1068 }
1011 1069
1012 visit(ast.Node node) => node.accept(this); 1070 visit(ast.Node node) => node.accept(this);
1013 1071
1014 visitNode(ast.Node node) { 1072 visitNode(ast.Node node) {
1015 node.visitChildren(this); 1073 node.visitChildren(this);
1016 } 1074 }
1017 1075
1018 void handleSend(ast.Send node) { 1076 void handleSend(ast.Send node) {
1019 Element element = elements[node]; 1077 Element element = elements[node];
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1054 currentFunction = elements[node]; 1112 currentFunction = elements[node];
1055 if (node.initializers != null) { 1113 if (node.initializers != null) {
1056 insideInitializer = true; 1114 insideInitializer = true;
1057 visit(node.initializers); 1115 visit(node.initializers);
1058 insideInitializer = false; 1116 insideInitializer = false;
1059 } 1117 }
1060 visit(node.body); 1118 visit(node.body);
1061 currentFunction = oldFunction; 1119 currentFunction = oldFunction;
1062 } 1120 }
1063 } 1121 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698