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 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |