| 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) { |
| 159 result[key] = fn(value); |
| 160 }); |
| 161 return result; |
| 162 } |
| 163 |
| 164 // Converts closure.dart's CapturedVariable into a ClosureLocation. |
| 165 // There is a 1:1 corresponce between these; we do this because the IR builder |
| 166 // should not depend on synthetic elements. |
| 167 ClosureLocation getLocation(CapturedVariable v) { |
| 168 if (v is BoxFieldElement) { |
| 169 return new ClosureLocation(v.box, v); |
| 170 } else { |
| 171 ClosureFieldElement field = v; |
| 172 return new ClosureLocation(null, field); |
| 173 } |
| 174 } |
| 175 |
| 176 /// If the current function is a nested function with free variables (or a |
| 177 /// captured reference to `this`), this returns a [ClosureEnvironment] |
| 178 /// indicating how to access these. |
| 179 ClosureEnvironment getClosureEnvironment() { |
| 180 if (closureMap == null) return null; // dart2dart does not use closureMap. |
| 181 if (closureMap.closureElement == null) return null; |
| 182 return new ClosureEnvironment( |
| 183 closureMap.closureElement, |
| 184 closureMap.thisLocal, |
| 185 mapValues(closureMap.freeVariableMap, getLocation)); |
| 186 } |
| 187 |
| 188 /// If [node] has declarations for variables that should be boxed, this |
| 189 /// returns a [ClosureScope] naming a box to create, and enumerating the |
| 190 /// variables that should be stored in the box. |
| 191 /// |
| 192 /// Also see [ClosureScope]. |
| 193 ClosureScope getClosureScope(ast.Node node) { |
| 194 if (closureMap == null) return null; // dart2dart does not use closureMap. |
| 195 closurelib.ClosureScope scope = closureMap.capturingScopes[node]; |
| 196 if (scope == null) return null; |
| 197 // We translate a ClosureScope from closure.dart into IR builder's variant |
| 198 // because the IR builder should not depend on the synthetic elements |
| 199 // created in closure.dart. |
| 200 return new ClosureScope(scope.boxElement, |
| 201 mapValues(scope.capturedVariables, getLocation), |
| 202 scope.boxedLoopVariables); |
| 203 } |
| 204 |
| 205 IrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) { |
| 206 if (isJavaScriptBackend) { |
| 207 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping( |
| 208 element, |
| 209 node, |
| 210 elements); |
| 211 return new JsIrBuilder(compiler.backend.constantSystem, element); |
| 212 } else { |
| 213 DetectClosureVariables closures = new DetectClosureVariables(elements); |
| 214 if (!element.isSynthesized) { |
| 215 closures.visit(node); |
| 216 } |
| 217 return new DartIrBuilder(compiler.backend.constantSystem, |
| 218 element, |
| 219 closures); |
| 220 } |
| 221 } |
| 222 |
| 151 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. | 223 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. |
| 152 /// Returns `null` if [element] has no initializer. | |
| 153 ir.FieldDefinition buildField(FieldElement element) { | 224 ir.FieldDefinition buildField(FieldElement element) { |
| 154 assert(invariant(element, element.isImplementation)); | 225 assert(invariant(element, element.isImplementation)); |
| 155 ast.VariableDefinitions definitions = element.node; | 226 ast.VariableDefinitions definitions = element.node; |
| 156 ast.Node fieldDefinition = | 227 ast.Node fieldDefinition = |
| 157 definitions.definitions.nodes.first; | 228 definitions.definitions.nodes.first; |
| 158 if (definitions.modifiers.isConst) { | 229 if (definitions.modifiers.isConst) { |
| 159 // TODO(sigurdm): Just return const value. | 230 // TODO(sigurdm): Just return const value. |
| 160 } | 231 } |
| 161 assert(fieldDefinition != null); | 232 assert(fieldDefinition != null); |
| 162 assert(elements[fieldDefinition] != null); | 233 assert(elements[fieldDefinition] != null); |
| 163 DetectClosureVariables closureLocals = | |
| 164 new DetectClosureVariables(elements); | |
| 165 closureLocals.visit(fieldDefinition); | |
| 166 | 234 |
| 167 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, | 235 IrBuilder builder = makeIRBuilder(fieldDefinition, element); |
| 168 element, | 236 |
| 169 closureLocals.usedFromClosure); | |
| 170 return withBuilder(builder, () { | 237 return withBuilder(builder, () { |
| 238 builder.buildFieldInitializerHeader( |
| 239 closureScope: getClosureScope(fieldDefinition)); |
| 171 ir.Primitive initializer; | 240 ir.Primitive initializer; |
| 172 if (fieldDefinition is ast.SendSet) { | 241 if (fieldDefinition is ast.SendSet) { |
| 173 ast.SendSet sendSet = fieldDefinition; | 242 ast.SendSet sendSet = fieldDefinition; |
| 174 initializer = visit(sendSet.arguments.first); | 243 initializer = visit(sendSet.arguments.first); |
| 175 } | 244 } |
| 176 return builder.makeFieldDefinition(initializer); | 245 return builder.makeFieldDefinition(initializer); |
| 177 }); | 246 }); |
| 178 } | 247 } |
| 179 | 248 |
| 180 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, | 249 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, |
| 181 ast.FunctionExpression node) { | 250 ast.FunctionExpression node) { |
| 182 FunctionSignature signature = element.functionSignature; | 251 FunctionSignature signature = element.functionSignature; |
| 183 signature.orderedForEachParameter((ParameterElement parameterElement) { | 252 List<ParameterElement> parameters = []; |
| 184 irBuilder.createFunctionParameter(parameterElement); | 253 signature.orderedForEachParameter(parameters.add); |
| 185 }); | 254 |
| 255 irBuilder.buildFunctionHeader(parameters, |
| 256 closureScope: getClosureScope(node), |
| 257 closureEnvironment: getClosureEnvironment()); |
| 186 | 258 |
| 187 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 259 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 188 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 260 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 189 defaults.add(getConstantForVariable(element)); | 261 defaults.add(getConstantForVariable(element)); |
| 190 }); | 262 }); |
| 191 | 263 |
| 192 List<ir.Initializer> initializers; | 264 List<ir.Initializer> initializers; |
| 193 if (element.isSynthesized) { | 265 if (element.isSynthesized) { |
| 194 assert(element is ConstructorElement); | 266 assert(element is ConstructorElement); |
| 195 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], | 267 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], |
| 196 const <ir.Initializer>[]); | 268 const <ir.Initializer>[]); |
| 197 } else if (element.isGenerativeConstructor) { | 269 } else if (element.isGenerativeConstructor) { |
| 198 initializers = buildConstructorInitializers(node, element); | 270 initializers = buildConstructorInitializers(node, element); |
| 199 visit(node.body); | 271 visit(node.body); |
| 200 return irBuilder.makeConstructorDefinition(defaults, initializers); | 272 return irBuilder.makeConstructorDefinition(defaults, initializers); |
| 201 } else { | 273 } else { |
| 202 visit(node.body); | 274 visit(node.body); |
| 203 return irBuilder.makeFunctionDefinition(defaults); | 275 return irBuilder.makeFunctionDefinition(defaults); |
| 204 } | 276 } |
| 205 } | 277 } |
| 206 | 278 |
| 207 List<ir.Initializer> buildConstructorInitializers( | 279 List<ir.Initializer> buildConstructorInitializers( |
| 208 ast.FunctionExpression function, ConstructorElement element) { | 280 ast.FunctionExpression function, ConstructorElement element) { |
| 209 List<ir.Initializer> result = <ir.Initializer>[]; | 281 List<ir.Initializer> result = <ir.Initializer>[]; |
| 210 FunctionSignature signature = element.functionSignature; | 282 FunctionSignature signature = element.functionSignature; |
| 211 | 283 |
| 212 void tryAddInitializingFormal(ParameterElement parameterElement) { | 284 void tryAddInitializingFormal(ParameterElement parameterElement) { |
| 213 if (parameterElement.isInitializingFormal) { | 285 if (parameterElement.isInitializingFormal) { |
| 214 InitializingFormalElement initializingFormal = parameterElement; | 286 InitializingFormalElement initializingFormal = parameterElement; |
| 215 withBuilder(new IrBuilder.delimited(irBuilder), () { | 287 withBuilder(irBuilder.makeDelimitedBuilder(), () { |
| 216 ir.Primitive value = irBuilder.buildLocalGet(parameterElement); | 288 ir.Primitive value = irBuilder.buildLocalGet(parameterElement); |
| 217 result.add(irBuilder.makeFieldInitializer( | 289 result.add(irBuilder.makeFieldInitializer( |
| 218 initializingFormal.fieldElement, | 290 initializingFormal.fieldElement, |
| 219 irBuilder.makeRunnableBody(value))); | 291 irBuilder.makeRunnableBody(value))); |
| 220 }); | 292 }); |
| 221 } | 293 } |
| 222 } | 294 } |
| 223 | 295 |
| 224 // TODO(sigurdm): Preserve initializing formals as initializing formals. | 296 // TODO(sigurdm): Preserve initializing formals as initializing formals. |
| 225 signature.orderedForEachParameter(tryAddInitializingFormal); | 297 signature.orderedForEachParameter(tryAddInitializingFormal); |
| 226 | 298 |
| 227 if (function.initializers == null) return result; | 299 if (function.initializers == null) return result; |
| 228 bool explicitSuperInitializer = false; | 300 bool explicitSuperInitializer = false; |
| 229 for(ast.Node initializer in function.initializers) { | 301 for(ast.Node initializer in function.initializers) { |
| 230 if (initializer is ast.SendSet) { | 302 if (initializer is ast.SendSet) { |
| 231 // Field initializer. | 303 // Field initializer. |
| 232 FieldElement field = elements[initializer]; | 304 FieldElement field = elements[initializer]; |
| 233 withBuilder(new IrBuilder.delimited(irBuilder), () { | 305 withBuilder(irBuilder.makeDelimitedBuilder(), () { |
| 234 ir.Primitive value = visit(initializer.arguments.head); | 306 ir.Primitive value = visit(initializer.arguments.head); |
| 235 ir.RunnableBody body = irBuilder.makeRunnableBody(value); | 307 ir.RunnableBody body = irBuilder.makeRunnableBody(value); |
| 236 result.add(irBuilder.makeFieldInitializer(field, body)); | 308 result.add(irBuilder.makeFieldInitializer(field, body)); |
| 237 }); | 309 }); |
| 238 } else if (initializer is ast.Send) { | 310 } else if (initializer is ast.Send) { |
| 239 // Super or this initializer. | 311 // Super or this initializer. |
| 240 if (ast.Initializers.isConstructorRedirect(initializer)) { | 312 if (ast.Initializers.isConstructorRedirect(initializer)) { |
| 241 giveup(initializer, "constructor redirect (this) initializer"); | 313 giveup(initializer, "constructor redirect (this) initializer"); |
| 242 } | 314 } |
| 243 ConstructorElement constructor = elements[initializer].implementation; | 315 ConstructorElement constructor = elements[initializer].implementation; |
| 244 Selector selector = elements.getSelector(initializer); | 316 Selector selector = elements.getSelector(initializer); |
| 245 List<ir.RunnableBody> arguments = | 317 List<ir.RunnableBody> arguments = |
| 246 initializer.arguments.mapToList((ast.Node argument) { | 318 initializer.arguments.mapToList((ast.Node argument) { |
| 247 return withBuilder(new IrBuilder.delimited(irBuilder), () { | 319 return withBuilder(irBuilder.makeDelimitedBuilder(), () { |
| 248 ir.Primitive value = visit(argument); | 320 ir.Primitive value = visit(argument); |
| 249 return irBuilder.makeRunnableBody(value); | 321 return irBuilder.makeRunnableBody(value); |
| 250 }); | 322 }); |
| 251 }); | 323 }); |
| 252 result.add(irBuilder.makeSuperInitializer(constructor, | 324 result.add(irBuilder.makeSuperInitializer(constructor, |
| 253 arguments, | 325 arguments, |
| 254 selector)); | 326 selector)); |
| 255 explicitSuperInitializer = true; | 327 explicitSuperInitializer = true; |
| 256 } else { | 328 } else { |
| 257 compiler.internalError(initializer, | 329 compiler.internalError(initializer, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 281 } | 353 } |
| 282 | 354 |
| 283 ir.FunctionDefinition buildFunction(FunctionElement element) { | 355 ir.FunctionDefinition buildFunction(FunctionElement element) { |
| 284 assert(invariant(element, element.isImplementation)); | 356 assert(invariant(element, element.isImplementation)); |
| 285 ast.FunctionExpression node = element.node; | 357 ast.FunctionExpression node = element.node; |
| 286 | 358 |
| 287 Iterable<Entity> usedFromClosure; | 359 Iterable<Entity> usedFromClosure; |
| 288 if (!element.isSynthesized) { | 360 if (!element.isSynthesized) { |
| 289 assert(node != null); | 361 assert(node != null); |
| 290 assert(elements[node] != null); | 362 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 { | 363 } else { |
| 298 SynthesizedConstructorElementX constructor = element; | 364 SynthesizedConstructorElementX constructor = element; |
| 299 if (!constructor.isDefaultConstructor) { | 365 if (!constructor.isDefaultConstructor) { |
| 300 giveup(null, 'cannot handle synthetic forwarding constructors'); | 366 giveup(null, 'cannot handle synthetic forwarding constructors'); |
| 301 } | 367 } |
| 302 | 368 |
| 303 usedFromClosure = <Entity>[]; | 369 usedFromClosure = <Entity>[]; |
| 304 } | 370 } |
| 305 | 371 |
| 306 IrBuilder builder = new IrBuilder(compiler.backend.constantSystem, | 372 IrBuilder builder = makeIRBuilder(node, element); |
| 307 element, | |
| 308 usedFromClosure); | |
| 309 | 373 |
| 310 return withBuilder(builder, () => _makeFunctionBody(element, node)); | 374 return withBuilder(builder, () => _makeFunctionBody(element, node)); |
| 311 } | 375 } |
| 312 | 376 |
| 313 ir.Primitive visit(ast.Node node) => node.accept(this); | 377 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 314 | 378 |
| 315 // ==== Statements ==== | 379 // ==== Statements ==== |
| 316 visitBlock(ast.Block node) { | 380 visitBlock(ast.Block node) { |
| 317 irBuilder.buildBlock(node.statements.nodes, build); | 381 irBuilder.buildBlock(node.statements.nodes, build); |
| 318 } | 382 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 339 | 403 |
| 340 // Build(ExpressionStatement(e), C) = C' | 404 // Build(ExpressionStatement(e), C) = C' |
| 341 // where (C', _) = Build(e, C) | 405 // where (C', _) = Build(e, C) |
| 342 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { | 406 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { |
| 343 assert(irBuilder.isOpen); | 407 assert(irBuilder.isOpen); |
| 344 visit(node.expression); | 408 visit(node.expression); |
| 345 return null; | 409 return null; |
| 346 } | 410 } |
| 347 | 411 |
| 348 visitFor(ast.For node) { | 412 visitFor(ast.For node) { |
| 349 // TODO(kmillikin,sigurdm): Handle closure variables declared in a for-loop. | 413 // TODO(asgerf): Handle closure variables declared in a for-loop. |
| 350 if (node.initializer is ast.VariableDefinitions) { | 414 if (!isJavaScriptBackend && node.initializer is ast.VariableDefinitions) { |
| 351 ast.VariableDefinitions definitions = node.initializer; | 415 ast.VariableDefinitions definitions = node.initializer; |
| 352 for (ast.Node definition in definitions.definitions.nodes) { | 416 for (ast.Node definition in definitions.definitions.nodes) { |
| 353 Element element = elements[definition]; | 417 LocalElement element = elements[definition]; |
| 354 if (irBuilder.isClosureVariable(element)) { | 418 DartIrBuilder dartIrBuilder = irBuilder; |
| 419 if (dartIrBuilder.isInClosureVariable(element)) { |
| 355 return giveup(definition, 'Closure variable in for loop initializer'); | 420 return giveup(definition, 'Closure variable in for loop initializer'); |
| 356 } | 421 } |
| 357 } | 422 } |
| 358 } | 423 } |
| 359 | 424 |
| 360 JumpTarget target = elements.getTargetDefinition(node); | 425 JumpTarget target = elements.getTargetDefinition(node); |
| 361 irBuilder.buildFor( | 426 irBuilder.buildFor( |
| 362 buildInitializer: subbuild(node.initializer), | 427 buildInitializer: subbuild(node.initializer), |
| 363 buildCondition: subbuild(node.condition), | 428 buildCondition: subbuild(node.condition), |
| 364 buildBody: subbuild(node.body), | 429 buildBody: subbuild(node.body), |
| 365 buildUpdate: subbuildSequence(node.update), | 430 buildUpdate: subbuildSequence(node.update), |
| 431 closureScope: getClosureScope(node), |
| 366 target: target); | 432 target: target); |
| 367 } | 433 } |
| 368 | 434 |
| 369 visitIf(ast.If node) { | 435 visitIf(ast.If node) { |
| 370 irBuilder.buildIf( | 436 irBuilder.buildIf( |
| 371 build(node.condition), | 437 build(node.condition), |
| 372 subbuild(node.thenPart), | 438 subbuild(node.thenPart), |
| 373 subbuild(node.elsePart)); | 439 subbuild(node.elsePart)); |
| 374 } | 440 } |
| 375 | 441 |
| 376 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) { | 442 ir.Primitive visitLabeledStatement(ast.LabeledStatement node) { |
| 377 ast.Statement body = node.statement; | 443 ast.Statement body = node.statement; |
| 378 if (body is ast.Loop) return visit(body); | 444 if (body is ast.Loop) return visit(body); |
| 379 JumpTarget target = elements.getTargetDefinition(body); | 445 JumpTarget target = elements.getTargetDefinition(body); |
| 380 JumpCollector jumps = new JumpCollector(target); | 446 JumpCollector jumps = new JumpCollector(target); |
| 381 irBuilder.state.breakCollectors.add(jumps); | 447 irBuilder.state.breakCollectors.add(jumps); |
| 382 IrBuilder innerBuilder = new IrBuilder.delimited(irBuilder); | 448 IrBuilder innerBuilder = irBuilder.makeDelimitedBuilder(); |
| 383 withBuilder(innerBuilder, () { | 449 withBuilder(innerBuilder, () { |
| 384 visit(body); | 450 visit(body); |
| 385 }); | 451 }); |
| 386 irBuilder.state.breakCollectors.removeLast(); | 452 irBuilder.state.breakCollectors.removeLast(); |
| 387 bool hasBreaks = !jumps.isEmpty; | 453 bool hasBreaks = !jumps.isEmpty; |
| 388 ir.Continuation joinContinuation; | 454 ir.Continuation joinContinuation; |
| 389 if (hasBreaks) { | 455 if (hasBreaks) { |
| 390 if (innerBuilder.isOpen) { | 456 if (innerBuilder.isOpen) { |
| 391 jumps.addJump(innerBuilder); | 457 jumps.addJump(innerBuilder); |
| 392 } | 458 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 413 irBuilder.environment = innerBuilder.environment; | 479 irBuilder.environment = innerBuilder.environment; |
| 414 } | 480 } |
| 415 } | 481 } |
| 416 return null; | 482 return null; |
| 417 } | 483 } |
| 418 | 484 |
| 419 visitWhile(ast.While node) { | 485 visitWhile(ast.While node) { |
| 420 irBuilder.buildWhile( | 486 irBuilder.buildWhile( |
| 421 buildCondition: subbuild(node.condition), | 487 buildCondition: subbuild(node.condition), |
| 422 buildBody: subbuild(node.body), | 488 buildBody: subbuild(node.body), |
| 423 target: elements.getTargetDefinition(node)); | 489 target: elements.getTargetDefinition(node), |
| 490 closureScope: getClosureScope(node)); |
| 424 } | 491 } |
| 425 | 492 |
| 426 visitForIn(ast.ForIn node) { | 493 visitForIn(ast.ForIn node) { |
| 427 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions] | 494 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions] |
| 428 // (defining a new local variable) or a send designating some existing | 495 // (defining a new local variable) or a send designating some existing |
| 429 // variable. | 496 // variable. |
| 430 ast.Node identifier = node.declaredIdentifier; | 497 ast.Node identifier = node.declaredIdentifier; |
| 431 ast.VariableDefinitions variableDeclaration = | 498 ast.VariableDefinitions variableDeclaration = |
| 432 identifier.asVariableDefinitions(); | 499 identifier.asVariableDefinitions(); |
| 433 Element variableElement = elements.getForInVariable(node); | 500 Element variableElement = elements.getForInVariable(node); |
| 434 Selector selector = elements.getSelector(identifier); | 501 Selector selector = elements.getSelector(identifier); |
| 435 | 502 |
| 436 irBuilder.buildForIn( | 503 irBuilder.buildForIn( |
| 437 buildExpression: subbuild(node.expression), | 504 buildExpression: subbuild(node.expression), |
| 438 buildVariableDeclaration: subbuild(variableDeclaration), | 505 buildVariableDeclaration: subbuild(variableDeclaration), |
| 439 variableElement: variableElement, | 506 variableElement: variableElement, |
| 440 variableSelector: selector, | 507 variableSelector: selector, |
| 441 buildBody: subbuild(node.body), | 508 buildBody: subbuild(node.body), |
| 442 target: elements.getTargetDefinition(node)); | 509 target: elements.getTargetDefinition(node), |
| 510 closureScope: getClosureScope(node)); |
| 443 } | 511 } |
| 444 | 512 |
| 445 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 513 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 446 assert(irBuilder.isOpen); | 514 assert(irBuilder.isOpen); |
| 447 if (node.modifiers.isConst) { | 515 if (node.modifiers.isConst) { |
| 448 for (ast.SendSet definition in node.definitions.nodes) { | 516 for (ast.SendSet definition in node.definitions.nodes) { |
| 449 assert(!definition.arguments.isEmpty); | 517 assert(!definition.arguments.isEmpty); |
| 450 assert(definition.arguments.tail.isEmpty); | 518 assert(definition.arguments.tail.isEmpty); |
| 451 VariableElement element = elements[definition]; | 519 VariableElement element = elements[definition]; |
| 452 ConstantExpression value = getConstantForVariable(element); | 520 ConstantExpression value = getConstantForVariable(element); |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 } | 1011 } |
| 944 | 1012 |
| 945 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { | 1013 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { |
| 946 assert(irBuilder.isOpen); | 1014 assert(irBuilder.isOpen); |
| 947 if (constant == null) { | 1015 if (constant == null) { |
| 948 constant = getConstantForNode(node); | 1016 constant = getConstantForNode(node); |
| 949 } | 1017 } |
| 950 return irBuilder.buildConstantLiteral(constant); | 1018 return irBuilder.buildConstantLiteral(constant); |
| 951 } | 1019 } |
| 952 | 1020 |
| 953 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { | 1021 /// Returns the backend-specific representation of an inner function. |
| 954 FunctionElement element = elements[node]; | 1022 Object makeSubFunction(ast.FunctionExpression node) { |
| 955 assert(invariant(element, element.isImplementation)); | 1023 if (isJavaScriptBackend) { |
| 1024 ClosureClassMap innerMap = |
| 1025 compiler.closureToClassMapper.getMappingForNestedFunction(node); |
| 1026 ClosureClassElement closureClass = innerMap.closureClassElement; |
| 1027 return closureClass; |
| 1028 } else { |
| 1029 FunctionElement element = elements[node]; |
| 1030 assert(invariant(element, element.isImplementation)); |
| 956 | 1031 |
| 957 IrBuilder builder = new IrBuilder.innerFunction(irBuilder, element); | 1032 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element); |
| 958 | 1033 |
| 959 return withBuilder(builder, () => _makeFunctionBody(element, node)); | 1034 return withBuilder(builder, () => _makeFunctionBody(element, node)); |
| 1035 } |
| 960 } | 1036 } |
| 961 | 1037 |
| 962 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | 1038 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 963 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | 1039 return irBuilder.buildFunctionExpression(makeSubFunction(node)); |
| 964 } | 1040 } |
| 965 | 1041 |
| 966 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 1042 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 967 LocalFunctionElement element = elements[node.function]; | 1043 LocalFunctionElement element = elements[node.function]; |
| 968 ir.FunctionDefinition inner = makeSubFunction(node.function); | 1044 Object inner = makeSubFunction(node.function); |
| 969 irBuilder.declareLocalFunction(element, inner); | 1045 irBuilder.declareLocalFunction(element, inner); |
| 970 } | 1046 } |
| 971 | 1047 |
| 972 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 1048 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 973 | 1049 |
| 974 dynamic giveup(ast.Node node, [String reason]) { | 1050 dynamic giveup(ast.Node node, [String reason]) { |
| 975 throw ABORT_IRNODE_BUILDER; | 1051 throw ABORT_IRNODE_BUILDER; |
| 976 } | 1052 } |
| 977 | 1053 |
| 978 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { | 1054 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { |
| 979 try { | 1055 try { |
| 980 return action(); | 1056 return action(); |
| 981 } catch(e, tr) { | 1057 } catch(e, tr) { |
| 982 if (e == ABORT_IRNODE_BUILDER) { | 1058 if (e == ABORT_IRNODE_BUILDER) { |
| 983 return null; | 1059 return null; |
| 984 } | 1060 } |
| 985 rethrow; | 1061 rethrow; |
| 986 } | 1062 } |
| 987 } | 1063 } |
| 988 | 1064 |
| 989 void internalError(String reason, {ast.Node node}) { | 1065 void internalError(String reason, {ast.Node node}) { |
| 990 giveup(node); | 1066 giveup(node); |
| 991 } | 1067 } |
| 992 } | 1068 } |
| 993 | 1069 |
| 994 /// Classifies local variables and local functions as 'closure variables'. | 1070 /// Classifies local variables and local functions as 'closure variables'. |
| 995 /// A closure variable is one that is accessed from an inner function nested | 1071 /// A closure variable is one that is accessed from an inner function nested |
| 996 /// one or more levels inside the one that declares it. | 1072 /// one or more levels inside the one that declares it. |
| 997 class DetectClosureVariables extends ast.Visitor { | 1073 class DetectClosureVariables extends ast.Visitor |
| 1074 implements ClosureVariableInfo { |
| 998 final TreeElements elements; | 1075 final TreeElements elements; |
| 999 DetectClosureVariables(this.elements); | 1076 DetectClosureVariables(this.elements); |
| 1000 | 1077 |
| 1001 FunctionElement currentFunction; | 1078 FunctionElement currentFunction; |
| 1002 bool insideInitializer = false; | 1079 bool insideInitializer = false; |
| 1003 Set<Local> usedFromClosure = new Set<Local>(); | 1080 Set<Local> capturedVariables = new Set<Local>(); |
| 1004 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); | |
| 1005 | |
| 1006 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity); | |
| 1007 | 1081 |
| 1008 void markAsClosureVariable(Local local) { | 1082 void markAsClosureVariable(Local local) { |
| 1009 usedFromClosure.add(local); | 1083 capturedVariables.add(local); |
| 1010 } | 1084 } |
| 1011 | 1085 |
| 1012 visit(ast.Node node) => node.accept(this); | 1086 visit(ast.Node node) => node.accept(this); |
| 1013 | 1087 |
| 1014 visitNode(ast.Node node) { | 1088 visitNode(ast.Node node) { |
| 1015 node.visitChildren(this); | 1089 node.visitChildren(this); |
| 1016 } | 1090 } |
| 1017 | 1091 |
| 1018 void handleSend(ast.Send node) { | 1092 void handleSend(ast.Send node) { |
| 1019 Element element = elements[node]; | 1093 Element element = elements[node]; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1054 currentFunction = elements[node]; | 1128 currentFunction = elements[node]; |
| 1055 if (node.initializers != null) { | 1129 if (node.initializers != null) { |
| 1056 insideInitializer = true; | 1130 insideInitializer = true; |
| 1057 visit(node.initializers); | 1131 visit(node.initializers); |
| 1058 insideInitializer = false; | 1132 insideInitializer = false; |
| 1059 } | 1133 } |
| 1060 visit(node.body); | 1134 visit(node.body); |
| 1061 currentFunction = oldFunction; | 1135 currentFunction = oldFunction; |
| 1062 } | 1136 } |
| 1063 } | 1137 } |
| OLD | NEW |