Chromium Code Reviews| 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 24 matching lines...) Expand all Loading... | |
| 35 return nodes[element.implementation]; | 35 return nodes[element.implementation]; |
| 36 } | 36 } |
| 37 | 37 |
| 38 ir.ExecutableDefinition buildNode(AstElement element) { | 38 ir.ExecutableDefinition buildNode(AstElement element) { |
| 39 if (!canBuild(element)) return null; | 39 if (!canBuild(element)) return null; |
| 40 TreeElements elementsMapping = element.resolvedAst.elements; | 40 TreeElements elementsMapping = element.resolvedAst.elements; |
| 41 element = element.implementation; | 41 element = element.implementation; |
| 42 return compiler.withCurrentElement(element, () { | 42 return compiler.withCurrentElement(element, () { |
| 43 SourceFile sourceFile = elementSourceFile(element); | 43 SourceFile sourceFile = elementSourceFile(element); |
| 44 IrBuilderVisitor builder = | 44 IrBuilderVisitor builder = |
| 45 new IrBuilderVisitor(elementsMapping, compiler, sourceFile); | 45 compiler.backend is JavaScriptBackend |
| 46 ? new JsIrBuilderVisitor(elementsMapping, compiler, sourceFile) | |
| 47 : new DartIrBuilderVisitor(elementsMapping, compiler, sourceFile); | |
| 46 return builder.buildExecutable(element); | 48 return builder.buildExecutable(element); |
| 47 }); | 49 }); |
| 48 } | 50 } |
| 49 | 51 |
| 50 void buildNodes() { | 52 void buildNodes() { |
| 51 measure(() { | 53 measure(() { |
| 52 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements; | 54 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements; |
| 53 resolved.forEach((AstElement element) { | 55 resolved.forEach((AstElement element) { |
| 54 ir.ExecutableDefinition definition = buildNode(element); | 56 ir.ExecutableDefinition definition = buildNode(element); |
| 55 if (definition != null) { | 57 if (definition != null) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 75 } | 77 } |
| 76 return compiler.backend.shouldOutput(element); | 78 return compiler.backend.shouldOutput(element); |
| 77 } | 79 } |
| 78 | 80 |
| 79 bool get inCheckedMode { | 81 bool get inCheckedMode { |
| 80 bool result = false; | 82 bool result = false; |
| 81 assert((result = true)); | 83 assert((result = true)); |
| 82 return result; | 84 return result; |
| 83 } | 85 } |
| 84 | 86 |
| 85 SourceFile elementSourceFile(Element element) { | 87 } |
| 86 if (element is FunctionElement) { | 88 |
| 87 FunctionElement functionElement = element; | 89 SourceFile elementSourceFile(Element element) { |
| 88 if (functionElement.patch != null) element = functionElement.patch; | 90 if (element is FunctionElement) { |
| 89 } | 91 FunctionElement functionElement = element; |
| 90 return element.compilationUnit.script.file; | 92 if (functionElement.patch != null) element = functionElement.patch; |
| 91 } | 93 } |
| 94 return element.compilationUnit.script.file; | |
| 92 } | 95 } |
| 93 | 96 |
| 94 class _GetterElements { | 97 class _GetterElements { |
| 95 ir.Primitive result; | 98 ir.Primitive result; |
| 96 ir.Primitive index; | 99 ir.Primitive index; |
| 97 ir.Primitive receiver; | 100 ir.Primitive receiver; |
| 98 | 101 |
| 99 _GetterElements({this.result, this.index, this.receiver}) ; | 102 _GetterElements({this.result, this.index, this.receiver}) ; |
| 100 } | 103 } |
| 101 | 104 |
| 102 /** | 105 /** |
| 103 * A tree visitor that builds [IrNodes]. The visit methods add statements using | 106 * 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 | 107 * to the [builder] and return the last added statement for trees that represent |
| 105 * an expression. | 108 * an expression. |
| 106 */ | 109 */ |
| 107 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> | 110 abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> |
| 108 with IrBuilderMixin<ast.Node> { | 111 with IrBuilderMixin<ast.Node> { |
| 109 final Compiler compiler; | 112 final Compiler compiler; |
| 110 final SourceFile sourceFile; | 113 final SourceFile sourceFile; |
| 111 ClosureClassMap closureMap; | |
| 112 | 114 |
| 113 // In SSA terms, join-point continuation parameters are the phis and the | 115 // In SSA terms, join-point continuation parameters are the phis and the |
| 114 // continuation invocation arguments are the corresponding phi inputs. To | 116 // continuation invocation arguments are the corresponding phi inputs. To |
| 115 // support name introduction and renaming for source level variables, we use | 117 // support name introduction and renaming for source level variables, we use |
| 116 // nested (delimited) visitors for constructing subparts of the IR that will | 118 // nested (delimited) visitors for constructing subparts of the IR that will |
| 117 // need renaming. Each source variable is assigned an index. | 119 // need renaming. Each source variable is assigned an index. |
| 118 // | 120 // |
| 119 // Each nested visitor maintains a list of free variable uses in the body. | 121 // Each nested visitor maintains a list of free variable uses in the body. |
| 120 // These are implemented as a list of parameters, each with their own use | 122 // These are implemented as a list of parameters, each with their own use |
| 121 // list of references. When the delimited subexpression is plugged into the | 123 // list of references. When the delimited subexpression is plugged into the |
| 122 // surrounding context, the free occurrences can be captured or become free | 124 // surrounding context, the free occurrences can be captured or become free |
| 123 // occurrences in the next outer delimited subexpression. | 125 // occurrences in the next outer delimited subexpression. |
| 124 // | 126 // |
| 125 // Each nested visitor maintains a list that maps indexes of variables | 127 // Each nested visitor maintains a list that maps indexes of variables |
| 126 // assigned in the delimited subexpression to their reaching definition --- | 128 // assigned in the delimited subexpression to their reaching definition --- |
| 127 // that is, the definition in effect at the hole in 'current'. These are | 129 // that is, the definition in effect at the hole in 'current'. These are |
| 128 // used to determine if a join-point continuation needs to be passed | 130 // used to determine if a join-point continuation needs to be passed |
| 129 // arguments, and what the arguments are. | 131 // arguments, and what the arguments are. |
| 130 | 132 |
| 131 /// Construct a top-level visitor. | 133 /// Construct a top-level visitor. |
| 132 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) | 134 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) |
| 133 : super(elements); | 135 : super(elements); |
| 134 | 136 |
| 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 | |
| 139 /** | 137 /** |
| 140 * Builds the [ir.ExecutableDefinition] for an executable element. In case the | 138 * Builds the [ir.ExecutableDefinition] for an executable element. In case the |
| 141 * function uses features that cannot be expressed in the IR, this element | 139 * function uses features that cannot be expressed in the IR, this element |
| 142 * returns `null`. | 140 * returns `null`. |
| 143 */ | 141 */ |
| 144 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { | 142 ir.ExecutableDefinition buildExecutable(ExecutableElement element); |
| 145 return nullIfGiveup(() { | |
| 146 if (element is FieldElement) { | |
| 147 return buildField(element); | |
| 148 } else if (element is FunctionElement) { | |
| 149 return buildFunction(element); | |
| 150 } else { | |
| 151 compiler.internalError(element, "Unexpected element type $element"); | |
| 152 } | |
| 153 }); | |
| 154 } | |
| 155 | 143 |
| 156 Map mapValues(Map map, dynamic fn(dynamic)) { | 144 ClosureScope getClosureScopeForNode(ast.Node node); |
| 157 Map result = {}; | 145 ClosureEnvironment getClosureEnvironment(); |
| 158 map.forEach((key,value) { | |
| 159 result[key] = fn(value); | |
| 160 }); | |
| 161 return result; | |
| 162 } | |
| 163 | 146 |
| 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 | 147 |
| 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 | |
| 223 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. | |
| 224 ir.FieldDefinition buildField(FieldElement element) { | |
| 225 assert(invariant(element, element.isImplementation)); | |
| 226 ast.VariableDefinitions definitions = element.node; | |
| 227 ast.Node fieldDefinition = | |
| 228 definitions.definitions.nodes.first; | |
| 229 if (definitions.modifiers.isConst) { | |
| 230 // TODO(sigurdm): Just return const value. | |
| 231 } | |
| 232 assert(fieldDefinition != null); | |
| 233 assert(elements[fieldDefinition] != null); | |
| 234 | |
| 235 IrBuilder builder = makeIRBuilder(fieldDefinition, element); | |
| 236 | |
| 237 return withBuilder(builder, () { | |
| 238 builder.buildFieldInitializerHeader( | |
| 239 closureScope: getClosureScope(fieldDefinition)); | |
| 240 ir.Primitive initializer; | |
| 241 if (fieldDefinition is ast.SendSet) { | |
| 242 ast.SendSet sendSet = fieldDefinition; | |
| 243 initializer = visit(sendSet.arguments.first); | |
| 244 } | |
| 245 return builder.makeFieldDefinition(initializer); | |
| 246 }); | |
| 247 } | |
| 248 | 148 |
| 249 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, | 149 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, |
| 250 ast.FunctionExpression node) { | 150 ast.FunctionExpression node) { |
| 251 FunctionSignature signature = element.functionSignature; | 151 FunctionSignature signature = element.functionSignature; |
| 252 List<ParameterElement> parameters = []; | 152 List<ParameterElement> parameters = []; |
| 253 signature.orderedForEachParameter(parameters.add); | 153 signature.orderedForEachParameter(parameters.add); |
| 254 | 154 |
| 255 irBuilder.buildFunctionHeader(parameters, | 155 irBuilder.buildFunctionHeader(parameters, |
| 256 closureScope: getClosureScope(node), | 156 closureScope: getClosureScopeForNode(node), |
| 257 closureEnvironment: getClosureEnvironment()); | 157 env: getClosureEnvironment()); |
| 258 | 158 |
| 259 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 159 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 260 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 160 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 261 defaults.add(getConstantForVariable(element)); | 161 defaults.add(getConstantForVariable(element)); |
| 262 }); | 162 }); |
| 263 | 163 |
| 264 List<ir.Initializer> initializers; | 164 List<ir.Initializer> initializers; |
| 265 if (element.isSynthesized) { | 165 if (element.isSynthesized) { |
| 266 assert(element is ConstructorElement); | 166 assert(element is ConstructorElement); |
| 267 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], | 167 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 "No default constructor available."); | 245 "No default constructor available."); |
| 346 } | 246 } |
| 347 result.add(irBuilder.makeSuperInitializer(target, | 247 result.add(irBuilder.makeSuperInitializer(target, |
| 348 <ir.RunnableBody>[], | 248 <ir.RunnableBody>[], |
| 349 selector)); | 249 selector)); |
| 350 } | 250 } |
| 351 } | 251 } |
| 352 return result; | 252 return result; |
| 353 } | 253 } |
| 354 | 254 |
| 355 ir.FunctionDefinition buildFunction(FunctionElement element) { | |
| 356 assert(invariant(element, element.isImplementation)); | |
| 357 ast.FunctionExpression node = element.node; | |
| 358 | |
| 359 Iterable<Entity> usedFromClosure; | |
| 360 if (!element.isSynthesized) { | |
| 361 assert(node != null); | |
| 362 assert(elements[node] != null); | |
| 363 } else { | |
| 364 SynthesizedConstructorElementX constructor = element; | |
| 365 if (!constructor.isDefaultConstructor) { | |
| 366 giveup(null, 'cannot handle synthetic forwarding constructors'); | |
| 367 } | |
| 368 | |
| 369 usedFromClosure = <Entity>[]; | |
| 370 } | |
| 371 | |
| 372 IrBuilder builder = makeIRBuilder(node, element); | |
| 373 | |
| 374 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 375 } | |
| 376 | |
| 377 ir.Primitive visit(ast.Node node) => node.accept(this); | 255 ir.Primitive visit(ast.Node node) => node.accept(this); |
| 378 | 256 |
| 379 // ==== Statements ==== | 257 // ==== Statements ==== |
| 380 visitBlock(ast.Block node) { | 258 visitBlock(ast.Block node) { |
| 381 irBuilder.buildBlock(node.statements.nodes, build); | 259 irBuilder.buildBlock(node.statements.nodes, build); |
| 382 } | 260 } |
| 383 | 261 |
| 384 ir.Primitive visitBreakStatement(ast.BreakStatement node) { | 262 ir.Primitive visitBreakStatement(ast.BreakStatement node) { |
| 385 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { | 263 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { |
| 386 compiler.internalError(node, "'break' target not found"); | 264 compiler.internalError(node, "'break' target not found"); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 418 loopVariables.add(loopVariable); | 296 loopVariables.add(loopVariable); |
| 419 } | 297 } |
| 420 } | 298 } |
| 421 | 299 |
| 422 JumpTarget target = elements.getTargetDefinition(node); | 300 JumpTarget target = elements.getTargetDefinition(node); |
| 423 irBuilder.buildFor( | 301 irBuilder.buildFor( |
| 424 buildInitializer: subbuild(node.initializer), | 302 buildInitializer: subbuild(node.initializer), |
| 425 buildCondition: subbuild(node.condition), | 303 buildCondition: subbuild(node.condition), |
| 426 buildBody: subbuild(node.body), | 304 buildBody: subbuild(node.body), |
| 427 buildUpdate: subbuildSequence(node.update), | 305 buildUpdate: subbuildSequence(node.update), |
| 428 closureScope: getClosureScope(node), | 306 closureScope: getClosureScopeForNode(node), |
| 429 loopVariables: loopVariables, | 307 loopVariables: loopVariables, |
| 430 target: target); | 308 target: target); |
| 431 } | 309 } |
| 432 | 310 |
| 433 visitIf(ast.If node) { | 311 visitIf(ast.If node) { |
| 434 irBuilder.buildIf( | 312 irBuilder.buildIf( |
| 435 build(node.condition), | 313 build(node.condition), |
| 436 subbuild(node.thenPart), | 314 subbuild(node.thenPart), |
| 437 subbuild(node.elsePart)); | 315 subbuild(node.elsePart)); |
| 438 } | 316 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 } | 357 } |
| 480 } | 358 } |
| 481 return null; | 359 return null; |
| 482 } | 360 } |
| 483 | 361 |
| 484 visitWhile(ast.While node) { | 362 visitWhile(ast.While node) { |
| 485 irBuilder.buildWhile( | 363 irBuilder.buildWhile( |
| 486 buildCondition: subbuild(node.condition), | 364 buildCondition: subbuild(node.condition), |
| 487 buildBody: subbuild(node.body), | 365 buildBody: subbuild(node.body), |
| 488 target: elements.getTargetDefinition(node), | 366 target: elements.getTargetDefinition(node), |
| 489 closureScope: getClosureScope(node)); | 367 closureScope: getClosureScopeForNode(node)); |
| 490 } | 368 } |
| 491 | 369 |
| 492 visitForIn(ast.ForIn node) { | 370 visitForIn(ast.ForIn node) { |
| 493 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions] | 371 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions] |
| 494 // (defining a new local variable) or a send designating some existing | 372 // (defining a new local variable) or a send designating some existing |
| 495 // variable. | 373 // variable. |
| 496 ast.Node identifier = node.declaredIdentifier; | 374 ast.Node identifier = node.declaredIdentifier; |
| 497 ast.VariableDefinitions variableDeclaration = | 375 ast.VariableDefinitions variableDeclaration = |
| 498 identifier.asVariableDefinitions(); | 376 identifier.asVariableDefinitions(); |
| 499 Element variableElement = elements.getForInVariable(node); | 377 Element variableElement = elements.getForInVariable(node); |
| 500 Selector selector = elements.getSelector(identifier); | 378 Selector selector = elements.getSelector(identifier); |
| 501 | 379 |
| 502 irBuilder.buildForIn( | 380 irBuilder.buildForIn( |
| 503 buildExpression: subbuild(node.expression), | 381 buildExpression: subbuild(node.expression), |
| 504 buildVariableDeclaration: subbuild(variableDeclaration), | 382 buildVariableDeclaration: subbuild(variableDeclaration), |
| 505 variableElement: variableElement, | 383 variableElement: variableElement, |
| 506 variableSelector: selector, | 384 variableSelector: selector, |
| 507 buildBody: subbuild(node.body), | 385 buildBody: subbuild(node.body), |
| 508 target: elements.getTargetDefinition(node), | 386 target: elements.getTargetDefinition(node), |
| 509 closureScope: getClosureScope(node)); | 387 closureScope: getClosureScopeForNode(node)); |
| 510 } | 388 } |
| 511 | 389 |
| 512 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { | 390 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { |
| 513 assert(irBuilder.isOpen); | 391 assert(irBuilder.isOpen); |
| 514 if (node.modifiers.isConst) { | 392 if (node.modifiers.isConst) { |
| 515 for (ast.SendSet definition in node.definitions.nodes) { | 393 for (ast.SendSet definition in node.definitions.nodes) { |
| 516 assert(!definition.arguments.isEmpty); | 394 assert(!definition.arguments.isEmpty); |
| 517 assert(definition.arguments.tail.isEmpty); | 395 assert(definition.arguments.tail.isEmpty); |
| 518 VariableElement element = elements[definition]; | 396 VariableElement element = elements[definition]; |
| 519 ConstantExpression value = getConstantForVariable(element); | 397 ConstantExpression value = getConstantForVariable(element); |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1011 } | 889 } |
| 1012 | 890 |
| 1013 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { | 891 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { |
| 1014 assert(irBuilder.isOpen); | 892 assert(irBuilder.isOpen); |
| 1015 if (constant == null) { | 893 if (constant == null) { |
| 1016 constant = getConstantForNode(node); | 894 constant = getConstantForNode(node); |
| 1017 } | 895 } |
| 1018 return irBuilder.buildConstantLiteral(constant); | 896 return irBuilder.buildConstantLiteral(constant); |
| 1019 } | 897 } |
| 1020 | 898 |
| 1021 /// Returns the backend-specific representation of an inner function. | |
| 1022 Object makeSubFunction(ast.FunctionExpression node) { | |
| 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)); | |
| 1031 | |
| 1032 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element); | |
| 1033 | |
| 1034 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 1035 } | |
| 1036 } | |
| 1037 | |
| 1038 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | |
| 1039 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | |
| 1040 } | |
| 1041 | |
| 1042 visitFunctionDeclaration(ast.FunctionDeclaration node) { | |
| 1043 LocalFunctionElement element = elements[node.function]; | |
| 1044 Object inner = makeSubFunction(node.function); | |
| 1045 irBuilder.declareLocalFunction(element, inner); | |
| 1046 } | |
| 1047 | |
| 1048 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { | 899 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { |
| 1049 try { | 900 try { |
| 1050 return action(); | 901 return action(); |
| 1051 } catch(e, tr) { | 902 } catch(e, tr) { |
| 1052 if (e == ABORT_IRNODE_BUILDER) { | 903 if (e == ABORT_IRNODE_BUILDER) { |
| 1053 return null; | 904 return null; |
| 1054 } | 905 } |
| 1055 rethrow; | 906 rethrow; |
| 1056 } | 907 } |
| 1057 } | 908 } |
| 1058 | 909 |
| 1059 void internalError(String reason, {ast.Node node}) { | 910 void internalError(String reason, {ast.Node node}) { |
| 1060 giveup(node); | 911 giveup(node); |
| 1061 } | 912 } |
| 1062 } | 913 } |
| 1063 | 914 |
| 1064 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 915 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1065 | 916 |
| 1066 dynamic giveup(ast.Node node, [String reason]) { | 917 dynamic giveup(ast.Node node, [String reason]) { |
| 1067 throw ABORT_IRNODE_BUILDER; | 918 throw ABORT_IRNODE_BUILDER; |
| 1068 } | 919 } |
| 1069 | 920 |
| 1070 /// Classifies local variables and local functions as captured, if they | 921 /// Classifies local variables and local functions as captured, if they |
| 1071 /// are accessed from within a nested function. | 922 /// are accessed from within a nested function. |
| 1072 /// | 923 /// |
| 1073 /// This class is specific to the [DartIrBuilder], in that it gives up if it | 924 /// This class is specific to the [DartIrBuilder], in that it gives up if it |
| 1074 /// sees a feature that is currently unsupport by that builder. In particular, | 925 /// sees a feature that is currently unsupport by that builder. In particular, |
| 1075 /// loop variables captured in a for-loop initializer, condition, or update | 926 /// loop variables captured in a for-loop initializer, condition, or update |
| 1076 /// expression are unsupported. | 927 /// expression are unsupported. |
| 1077 class DetectClosureVariables extends ast.Visitor | 928 class DartCapturedVariables extends ast.Visitor |
| 1078 implements ClosureVariableInfo { | 929 implements DartCapturedVariableInfo { |
| 1079 final TreeElements elements; | 930 final TreeElements elements; |
| 1080 DetectClosureVariables(this.elements); | 931 DartCapturedVariables(this.elements); |
| 1081 | 932 |
| 1082 FunctionElement currentFunction; | 933 FunctionElement currentFunction; |
| 1083 bool insideInitializer = false; | 934 bool insideInitializer = false; |
| 1084 Set<Local> capturedVariables = new Set<Local>(); | 935 Set<Local> capturedVariables = new Set<Local>(); |
| 1085 | 936 |
| 1086 void markAsClosureVariable(Local local) { | 937 void markAsCaptured(Local local) { |
| 1087 capturedVariables.add(local); | 938 capturedVariables.add(local); |
| 1088 } | 939 } |
| 1089 | 940 |
| 1090 visit(ast.Node node) => node.accept(this); | 941 visit(ast.Node node) => node.accept(this); |
| 1091 | 942 |
| 1092 visitNode(ast.Node node) { | 943 visitNode(ast.Node node) { |
| 1093 node.visitChildren(this); | 944 node.visitChildren(this); |
| 1094 } | 945 } |
| 1095 | 946 |
| 1096 visitFor(ast.For node) { | 947 visitFor(ast.For node) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1111 | 962 |
| 1112 if (node.body != null) visit(node.body); | 963 if (node.body != null) visit(node.body); |
| 1113 } | 964 } |
| 1114 | 965 |
| 1115 void handleSend(ast.Send node) { | 966 void handleSend(ast.Send node) { |
| 1116 Element element = elements[node]; | 967 Element element = elements[node]; |
| 1117 if (Elements.isLocal(element) && | 968 if (Elements.isLocal(element) && |
| 1118 !element.isConst && | 969 !element.isConst && |
| 1119 element.enclosingElement != currentFunction) { | 970 element.enclosingElement != currentFunction) { |
| 1120 LocalElement local = element; | 971 LocalElement local = element; |
| 1121 markAsClosureVariable(local); | 972 markAsCaptured(local); |
| 1122 } | 973 } |
| 1123 } | 974 } |
| 1124 | 975 |
| 1125 visitSend(ast.Send node) { | 976 visitSend(ast.Send node) { |
| 1126 handleSend(node); | 977 handleSend(node); |
| 1127 node.visitChildren(this); | 978 node.visitChildren(this); |
| 1128 } | 979 } |
| 1129 | 980 |
| 1130 visitSendSet(ast.SendSet node) { | 981 visitSendSet(ast.SendSet node) { |
| 1131 handleSend(node); | 982 handleSend(node); |
| 1132 Element element = elements[node]; | 983 Element element = elements[node]; |
| 1133 // Initializers in an initializer-list can communicate via parameters. | 984 // Initializers in an initializer-list can communicate via parameters. |
| 1134 // If a parameter is stored in an initializer list we box it. | 985 // If a parameter is stored in an initializer list we box it. |
| 1135 if (insideInitializer && | 986 if (insideInitializer && |
| 1136 Elements.isLocal(element) && | 987 Elements.isLocal(element) && |
| 1137 element.isParameter) { | 988 element.isParameter) { |
| 1138 LocalElement local = element; | 989 LocalElement local = element; |
| 1139 // TODO(sigurdm): Fix this. | 990 // TODO(sigurdm): Fix this. |
| 1140 // Though these variables do not outlive the activation of the function, | 991 // Though these variables do not outlive the activation of the function, |
| 1141 // they still need to be boxed. As a simplification, we treat them as if | 992 // they still need to be boxed. As a simplification, we treat them as if |
| 1142 // they are captured by a closure (i.e., they do outlive the activation of | 993 // they are captured by a closure (i.e., they do outlive the activation of |
| 1143 // the function). | 994 // the function). |
| 1144 markAsClosureVariable(local); | 995 markAsCaptured(local); |
| 1145 } | 996 } |
| 1146 node.visitChildren(this); | 997 node.visitChildren(this); |
| 1147 } | 998 } |
| 1148 | 999 |
| 1149 visitFunctionExpression(ast.FunctionExpression node) { | 1000 visitFunctionExpression(ast.FunctionExpression node) { |
| 1150 FunctionElement oldFunction = currentFunction; | 1001 FunctionElement oldFunction = currentFunction; |
| 1151 currentFunction = elements[node]; | 1002 currentFunction = elements[node]; |
| 1152 if (node.initializers != null) { | 1003 if (node.initializers != null) { |
| 1153 insideInitializer = true; | 1004 insideInitializer = true; |
| 1154 visit(node.initializers); | 1005 visit(node.initializers); |
| 1155 insideInitializer = false; | 1006 insideInitializer = false; |
| 1156 } | 1007 } |
| 1157 visit(node.body); | 1008 visit(node.body); |
| 1158 currentFunction = oldFunction; | 1009 currentFunction = oldFunction; |
| 1159 } | 1010 } |
| 1160 } | 1011 } |
| 1012 | |
| 1013 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder]. | |
| 1014 class DartIrBuilderVisitor extends IrBuilderVisitor { | |
| 1015 /// Promote the type of [irBuilder] to [DartIrBuilder]. | |
| 1016 DartIrBuilder get irBuilder => super.irBuilder; | |
| 1017 | |
| 1018 DartIrBuilderVisitor(TreeElements elements, | |
| 1019 Compiler compiler, | |
| 1020 SourceFile sourceFile) | |
| 1021 : super(elements, compiler, sourceFile); | |
| 1022 | |
| 1023 DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) { | |
| 1024 DartCapturedVariables closures = new DartCapturedVariables(elements); | |
| 1025 if (!element.isSynthesized) { | |
| 1026 closures.visit(node); | |
| 1027 } | |
| 1028 return new DartIrBuilder(compiler.backend.constantSystem, | |
| 1029 element, | |
| 1030 closures); | |
| 1031 } | |
| 1032 | |
| 1033 /// Recursively builds the IR for the given nested function. | |
| 1034 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { | |
| 1035 FunctionElement element = elements[node]; | |
| 1036 assert(invariant(element, element.isImplementation)); | |
| 1037 | |
| 1038 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element); | |
| 1039 | |
| 1040 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 1041 } | |
| 1042 | |
| 1043 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | |
| 1044 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | |
| 1045 } | |
| 1046 | |
| 1047 visitFunctionDeclaration(ast.FunctionDeclaration node) { | |
| 1048 LocalFunctionElement element = elements[node.function]; | |
| 1049 Object inner = makeSubFunction(node.function); | |
| 1050 irBuilder.declareLocalFunction(element, inner); | |
| 1051 } | |
| 1052 | |
| 1053 ClosureScope getClosureScopeForNode(ast.Node node) => null; | |
| 1054 ClosureEnvironment getClosureEnvironment() => null; | |
| 1055 | |
| 1056 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { | |
| 1057 return nullIfGiveup(() { | |
| 1058 if (element is FieldElement) { | |
| 1059 return buildField(element); | |
| 1060 } else if (element is FunctionElement) { | |
| 1061 return buildFunction(element); | |
| 1062 } else { | |
| 1063 compiler.internalError(element, "Unexpected element type $element"); | |
| 1064 } | |
| 1065 }); | |
| 1066 } | |
| 1067 | |
| 1068 /// Returns a [ir.FieldDefinition] describing the initializer of [element]. | |
| 1069 ir.FieldDefinition buildField(FieldElement element) { | |
| 1070 assert(invariant(element, element.isImplementation)); | |
| 1071 ast.VariableDefinitions definitions = element.node; | |
| 1072 ast.Node fieldDefinition = definitions.definitions.nodes.first; | |
| 1073 if (definitions.modifiers.isConst) { | |
| 1074 // TODO(sigurdm): Just return const value. | |
| 1075 } | |
| 1076 assert(fieldDefinition != null); | |
| 1077 assert(elements[fieldDefinition] != null); | |
| 1078 | |
| 1079 IrBuilder builder = makeIRBuilder(fieldDefinition, element); | |
| 1080 | |
| 1081 return withBuilder(builder, () { | |
| 1082 builder.buildFieldInitializerHeader( | |
| 1083 closureScope: getClosureScopeForNode(fieldDefinition)); | |
| 1084 ir.Primitive initializer; | |
| 1085 if (fieldDefinition is ast.SendSet) { | |
| 1086 ast.SendSet sendSet = fieldDefinition; | |
| 1087 initializer = visit(sendSet.arguments.first); | |
| 1088 } | |
| 1089 return builder.makeFieldDefinition(initializer); | |
| 1090 }); | |
| 1091 } | |
| 1092 | |
| 1093 ir.FunctionDefinition buildFunction(FunctionElement element) { | |
| 1094 assert(invariant(element, element.isImplementation)); | |
| 1095 ast.FunctionExpression node = element.node; | |
| 1096 | |
| 1097 if (!element.isSynthesized) { | |
| 1098 assert(node != null); | |
| 1099 assert(elements[node] != null); | |
| 1100 } else { | |
| 1101 SynthesizedConstructorElementX constructor = element; | |
| 1102 if (!constructor.isDefaultConstructor) { | |
| 1103 giveup(null, 'cannot handle synthetic forwarding constructors'); | |
| 1104 } | |
| 1105 } | |
| 1106 | |
| 1107 IrBuilder builder = makeIRBuilder(node, element); | |
| 1108 | |
| 1109 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 1110 } | |
| 1111 } | |
| 1112 | |
| 1113 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder]. | |
| 1114 class JsIrBuilderVisitor extends IrBuilderVisitor { | |
| 1115 /// Promote the type of [irBuilder] to [JsIrBuilder]. | |
| 1116 JsIrBuilder get irBuilder => super.irBuilder; | |
| 1117 ClosureClassMap closureMap; | |
|
floitsch
2015/01/22 10:36:01
Add a small comment what this is and where it come
asgerf
2015/01/22 10:58:29
Done.
| |
| 1118 | |
| 1119 /// During construction of a constructor factory, [fieldValues] maps fields | |
| 1120 /// to the primitive containing their initial value. | |
| 1121 Map<FieldElement, ir.Primitive> fieldValues = <FieldElement, ir.Primitive>{}; | |
| 1122 | |
| 1123 JsIrBuilderVisitor(TreeElements elements, | |
| 1124 Compiler compiler, | |
| 1125 SourceFile sourceFile) | |
| 1126 : super(elements, compiler, sourceFile); | |
| 1127 | |
| 1128 /// Builds the IR for creating an instance of the closure class corresponding | |
| 1129 /// to the given nested function. | |
| 1130 ClosureClassElement makeSubFunction(ast.FunctionExpression node) { | |
| 1131 ClosureClassMap innerMap = | |
| 1132 compiler.closureToClassMapper.getMappingForNestedFunction(node); | |
| 1133 ClosureClassElement closureClass = innerMap.closureClassElement; | |
| 1134 return closureClass; | |
| 1135 } | |
| 1136 | |
| 1137 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | |
| 1138 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | |
| 1139 } | |
| 1140 | |
| 1141 visitFunctionDeclaration(ast.FunctionDeclaration node) { | |
| 1142 LocalFunctionElement element = elements[node.function]; | |
| 1143 Object inner = makeSubFunction(node.function); | |
| 1144 irBuilder.declareLocalFunction(element, inner); | |
| 1145 } | |
| 1146 | |
| 1147 Map mapValues(Map map, dynamic fn(dynamic)) { | |
| 1148 Map result = {}; | |
| 1149 map.forEach((key, value) { | |
| 1150 result[key] = fn(value); | |
| 1151 }); | |
| 1152 return result; | |
| 1153 } | |
| 1154 | |
| 1155 /// Converts closure.dart's CapturedVariable into a ClosureLocation. | |
| 1156 /// There is a 1:1 corresponce between these; we do this because the | |
| 1157 /// IR builder should not depend on synthetic elements. | |
| 1158 ClosureLocation getLocation(CapturedVariable v) { | |
| 1159 if (v is BoxFieldElement) { | |
| 1160 return new ClosureLocation(v.box, v); | |
| 1161 } else { | |
| 1162 ClosureFieldElement field = v; | |
| 1163 return new ClosureLocation(null, field); | |
| 1164 } | |
| 1165 } | |
| 1166 | |
| 1167 /// If the current function is a nested function with free variables (or a | |
| 1168 /// captured reference to `this`), returns a [ClosureEnvironment] | |
| 1169 /// indicating how to access these. | |
| 1170 ClosureEnvironment getClosureEnvironment() { | |
| 1171 if (closureMap.closureElement == null) return null; | |
| 1172 return new ClosureEnvironment( | |
| 1173 closureMap.closureElement, | |
| 1174 closureMap.thisLocal, | |
| 1175 mapValues(closureMap.freeVariableMap, getLocation)); | |
| 1176 } | |
| 1177 | |
| 1178 /// If [node] has declarations for variables that should be boxed, | |
| 1179 /// returns a [ClosureScope] naming a box to create, and enumerating the | |
| 1180 /// variables that should be stored in the box. | |
| 1181 /// | |
| 1182 /// Also see [ClosureScope]. | |
| 1183 ClosureScope getClosureScopeForNode(ast.Node node) { | |
| 1184 closurelib.ClosureScope scope = closureMap.capturingScopes[node]; | |
| 1185 if (scope == null) return null; | |
| 1186 // We translate a ClosureScope from closure.dart into IR builder's variant | |
| 1187 // because the IR builder should not depend on the synthetic elements | |
| 1188 // created in closure.dart. | |
| 1189 return new ClosureScope(scope.boxElement, | |
| 1190 mapValues(scope.capturedVariables, getLocation), | |
| 1191 scope.boxedLoopVariables); | |
| 1192 } | |
| 1193 | |
| 1194 /// Returns the [ClosureScope] for any function, possibly different from the | |
| 1195 /// one currently being built. | |
| 1196 ClosureScope getClosureScopeForFunction(FunctionElement function) { | |
| 1197 ClosureClassMap map = | |
| 1198 compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 1199 function, | |
| 1200 function.node, | |
| 1201 elements); | |
| 1202 closurelib.ClosureScope scope = map.capturingScopes[function.node]; | |
| 1203 if (scope == null) return null; | |
| 1204 return new ClosureScope(scope.boxElement, | |
| 1205 mapValues(scope.capturedVariables, getLocation), | |
| 1206 scope.boxedLoopVariables); | |
| 1207 } | |
| 1208 | |
| 1209 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { | |
| 1210 return nullIfGiveup(() { | |
| 1211 switch (element.kind) { | |
| 1212 case ElementKind.GENERATIVE_CONSTRUCTOR: | |
| 1213 return buildConstructor(element); | |
| 1214 | |
| 1215 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY: | |
| 1216 return buildConstructorBody(element); | |
| 1217 | |
| 1218 case ElementKind.FUNCTION: | |
| 1219 case ElementKind.GETTER: | |
| 1220 case ElementKind.SETTER: | |
| 1221 return buildFunction(element); | |
| 1222 | |
| 1223 default: | |
| 1224 compiler.internalError(element, "Unexpected element type $element"); | |
| 1225 } | |
| 1226 }); | |
| 1227 } | |
| 1228 | |
| 1229 /// Builds the IR for an [expression] taken from a different [context]. | |
| 1230 /// | |
| 1231 /// Such expressions need to be compiled with a different [sourceFile] and | |
| 1232 /// [elements] mapping. | |
| 1233 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) { | |
| 1234 JsIrBuilderVisitor visitor = new JsIrBuilderVisitor( | |
| 1235 context.resolvedAst.elements, | |
| 1236 compiler, | |
| 1237 elementSourceFile(context)); | |
| 1238 return visitor.withBuilder(irBuilder, () => visitor.visit(expression)); | |
| 1239 } | |
| 1240 | |
| 1241 /// Builds the IR for a given constructor. | |
| 1242 /// | |
| 1243 /// 1. Evaluates all own or inherited field initializers. | |
| 1244 /// 2. Creates the object and assigns its fields. | |
| 1245 /// 3. Calls constructor body and super constructor bodies. | |
| 1246 /// 4. Returns the created object. | |
| 1247 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) { | |
| 1248 constructor = constructor.implementation; | |
| 1249 ClassElement classElement = constructor.enclosingClass.implementation; | |
| 1250 | |
| 1251 JsIrBuilder builder = | |
| 1252 new JsIrBuilder(compiler.backend.constantSystem, constructor); | |
| 1253 | |
| 1254 return withBuilder(builder, () { | |
| 1255 // Setup parameters and create a box if anything is captured. | |
| 1256 List<ParameterElement> parameters = []; | |
| 1257 constructor.functionSignature.orderedForEachParameter(parameters.add); | |
| 1258 builder.buildFunctionHeader(parameters, | |
| 1259 closureScope: getClosureScopeForFunction(constructor)); | |
| 1260 | |
| 1261 // -- Step 1: evaluate field initializers --- | |
| 1262 // Evaluate field initializers in constructor and super constructors. | |
| 1263 List<ConstructorElement> constructorList = <ConstructorElement>[]; | |
| 1264 evaluateConstructorFieldInitializers(constructor, constructorList); | |
| 1265 | |
| 1266 // All parameters in all constructors are now bound in the environment. | |
| 1267 // BoxLocals for captured parameters are also in the environment. | |
| 1268 // The initial value of all fields are now bound in [fieldValues]. | |
| 1269 | |
| 1270 // --- Step 2: create the object --- | |
| 1271 // Get the initial field values in the canonical order. | |
| 1272 List<ir.Primitive> instanceArguments = <ir.Primitive>[]; | |
| 1273 classElement.forEachInstanceField((ClassElement c, FieldElement field) { | |
| 1274 ir.Primitive value = fieldValues[field]; | |
| 1275 if (value != null) { | |
| 1276 instanceArguments.add(fieldValues[field]); | |
| 1277 } else { | |
| 1278 assert(Elements.isNativeOrExtendsNative(c)); | |
| 1279 // Native fields are initialized elsewhere. | |
| 1280 } | |
| 1281 }, includeSuperAndInjectedMembers: true); | |
| 1282 ir.Primitive instance = | |
| 1283 new ir.CreateInstance(classElement, instanceArguments); | |
| 1284 irBuilder.add(new ir.LetPrim(instance)); | |
| 1285 | |
| 1286 // --- Step 3: call constructor bodies --- | |
| 1287 for (ConstructorElement target in constructorList) { | |
| 1288 ConstructorBodyElement bodyElement = getConstructorBody(target); | |
| 1289 if (bodyElement == null) continue; // Skip if constructor has no body. | |
| 1290 List<ir.Primitive> bodyArguments = <ir.Primitive>[]; | |
| 1291 for (Local param in getConstructorBodyParameters(bodyElement)) { | |
| 1292 bodyArguments.add(irBuilder.environment.lookup(param)); | |
| 1293 } | |
| 1294 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments); | |
| 1295 } | |
| 1296 | |
| 1297 // --- step 4: return the created object ---- | |
| 1298 irBuilder.buildReturn(instance); | |
| 1299 | |
| 1300 return irBuilder.makeFunctionDefinition([]); | |
| 1301 }); | |
| 1302 } | |
| 1303 | |
| 1304 /// Evaluates all field initializers on [constructor] and all constructors | |
| 1305 /// invoked through `this()` or `super()` ("superconstructors"). | |
| 1306 /// | |
| 1307 /// The resulting field values will be available in [fieldValues]. The values | |
| 1308 /// are not stored in any fields. | |
| 1309 /// | |
| 1310 /// This procedure assumes that the parameters to [constructor] are available | |
| 1311 /// in the IR builder's environment. | |
| 1312 /// | |
| 1313 /// The parameters to superconstructors are, however, assumed *not* to be in | |
| 1314 /// the environment, but will be put there by this procedure. | |
| 1315 /// | |
| 1316 /// All constructors will be added to [supers], with superconstructors first. | |
| 1317 void evaluateConstructorFieldInitializers(ConstructorElement constructor, | |
| 1318 List<ConstructorElement> supers) { | |
| 1319 // Evaluate declaration-site field initializers. | |
| 1320 ClassElement enclosingClass = constructor.enclosingClass.implementation; | |
| 1321 enclosingClass.forEachInstanceField((ClassElement _, FieldElement field) { | |
| 1322 if (field.initializer != null) { | |
| 1323 fieldValues[field] = inlineExpression(field, field.initializer); | |
| 1324 } else { | |
| 1325 if (Elements.isNativeOrExtendsNative(enclosingClass)) { | |
| 1326 // Native field is initialized elsewhere. | |
| 1327 } else { | |
| 1328 // Fields without an initializer default to null. | |
| 1329 // This value will be overwritten below if an initializer is found. | |
| 1330 fieldValues[field] = irBuilder.buildNullLiteral(); | |
| 1331 } | |
| 1332 } | |
| 1333 }); | |
| 1334 // Evaluate initializing parameters, e.g. `Foo(this.x)`. | |
| 1335 constructor.functionSignature.orderedForEachParameter( | |
| 1336 (ParameterElement parameter) { | |
| 1337 if (parameter.isInitializingFormal) { | |
| 1338 InitializingFormalElement fieldParameter = parameter; | |
| 1339 fieldValues[fieldParameter.fieldElement] = | |
| 1340 irBuilder.buildLocalGet(parameter); | |
| 1341 } | |
| 1342 }); | |
| 1343 // Evaluate constructor initializers, e.g. `Foo() : x = 50`. | |
| 1344 ast.FunctionExpression node = constructor.node; | |
| 1345 bool hasConstructorCall = false; // Has this() or super() initializer? | |
| 1346 if (node != null && node.initializers != null) { | |
| 1347 for(ast.Node initializer in node.initializers) { | |
| 1348 if (initializer is ast.SendSet) { | |
| 1349 // Field initializer. | |
| 1350 FieldElement field = elements[initializer]; | |
| 1351 fieldValues[field] = | |
| 1352 inlineExpression(constructor, initializer.arguments.head); | |
| 1353 } else if (initializer is ast.Send) { | |
| 1354 // Super or this initializer. | |
| 1355 ConstructorElement target = elements[initializer].implementation; | |
| 1356 Selector selector = elements.getSelector(initializer); | |
| 1357 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit); | |
| 1358 loadArguments(target, selector, arguments); | |
| 1359 evaluateConstructorFieldInitializers(target, supers); | |
| 1360 hasConstructorCall = true; | |
| 1361 } else { | |
| 1362 compiler.internalError(initializer, | |
| 1363 "Unexpected initializer type $initializer"); | |
| 1364 } | |
| 1365 } | |
| 1366 } | |
| 1367 // If no super() or this() was found, also call default superconstructor. | |
| 1368 if (!hasConstructorCall && !enclosingClass.isObject) { | |
| 1369 ClassElement superClass = enclosingClass.superclass; | |
| 1370 Selector selector = | |
| 1371 new Selector.callDefaultConstructor(enclosingClass.library); | |
| 1372 FunctionElement target = superClass.lookupConstructor(selector); | |
| 1373 if (target == null) { | |
| 1374 compiler.internalError(superClass, "No default constructor available."); | |
| 1375 } | |
| 1376 evaluateConstructorFieldInitializers(target, supers); | |
| 1377 } | |
| 1378 // Add this constructor after the superconstructors. | |
| 1379 supers.add(constructor); | |
| 1380 } | |
| 1381 | |
| 1382 /// In preparation of inlining (part of) [target], the [arguments] are moved | |
| 1383 /// into the environment bindings for the corresponding parameters. | |
| 1384 /// | |
| 1385 /// Defaults for optional arguments are evaluated in order to ensure | |
| 1386 /// all parameters are available in the environment. | |
| 1387 void loadArguments(FunctionElement target, | |
| 1388 Selector selector, | |
| 1389 List<ir.Primitive> arguments) { | |
| 1390 target = target.implementation; | |
| 1391 FunctionSignature signature = target.functionSignature; | |
| 1392 | |
| 1393 // Establish a scope in case parameters are captured. | |
| 1394 ClosureScope scope = getClosureScopeForFunction(target); | |
| 1395 irBuilder._enterScope(scope); | |
| 1396 | |
| 1397 // Load required parameters | |
| 1398 int index = 0; | |
| 1399 signature.forEachRequiredParameter((ParameterElement param) { | |
| 1400 irBuilder.declareLocalVariable(param, initialValue: arguments[index]); | |
| 1401 index++; | |
| 1402 }); | |
| 1403 | |
| 1404 // Load optional parameters, evaluating default values for omitted ones. | |
| 1405 signature.forEachOptionalParameter((ParameterElement param) { | |
| 1406 ir.Primitive value; | |
| 1407 // Load argument if provided. | |
| 1408 if (signature.optionalParametersAreNamed) { | |
| 1409 int translatedIndex = selector.namedArguments.indexOf(param.name); | |
| 1410 if (translatedIndex != -1) { | |
| 1411 value = arguments[translatedIndex]; | |
| 1412 } | |
| 1413 } else if (index < arguments.length) { | |
| 1414 value = arguments[index]; | |
| 1415 } | |
| 1416 // Load default if argument was not provided. | |
| 1417 if (value == null) { | |
| 1418 if (param.initializer != null) { | |
| 1419 value = visit(param.initializer); | |
| 1420 } else { | |
| 1421 value = irBuilder.buildNullLiteral(); | |
| 1422 } | |
| 1423 } | |
| 1424 irBuilder.declareLocalVariable(param, initialValue: value); | |
| 1425 index++; | |
| 1426 }); | |
| 1427 } | |
| 1428 | |
| 1429 /** | |
| 1430 * Returns the constructor body associated with the given constructor or | |
| 1431 * creates a new constructor body, if none can be found. | |
| 1432 * | |
| 1433 * Returns `null` if the constructor does not have a body. | |
| 1434 */ | |
| 1435 ConstructorBodyElement getConstructorBody(FunctionElement constructor) { | |
| 1436 // TODO(asgerf): This is largely inherited from the SSA builder. | |
| 1437 // The ConstructorBodyElement has an invalid function signature, but we | |
| 1438 // cannot add a BoxLocal as parameter, because BoxLocal is not an element. | |
| 1439 // Instead of forging ParameterElements to forge a FunctionSignature, we | |
| 1440 // need a way to create backend methods without creating more fake elements. | |
| 1441 | |
| 1442 assert(constructor.isGenerativeConstructor); | |
| 1443 assert(invariant(constructor, constructor.isImplementation)); | |
| 1444 if (constructor.isSynthesized) return null; | |
| 1445 ast.FunctionExpression node = constructor.node; | |
| 1446 // If we know the body doesn't have any code, we don't generate it. | |
| 1447 if (!node.hasBody()) return null; | |
| 1448 if (node.hasEmptyBody()) return null; | |
| 1449 ClassElement classElement = constructor.enclosingClass; | |
| 1450 ConstructorBodyElement bodyElement; | |
| 1451 classElement.forEachBackendMember((Element backendMember) { | |
| 1452 if (backendMember.isGenerativeConstructorBody) { | |
| 1453 ConstructorBodyElement body = backendMember; | |
| 1454 if (body.constructor == constructor) { | |
| 1455 bodyElement = backendMember; | |
| 1456 } | |
| 1457 } | |
| 1458 }); | |
| 1459 if (bodyElement == null) { | |
| 1460 bodyElement = new ConstructorBodyElementX(constructor); | |
| 1461 classElement.addBackendMember(bodyElement); | |
| 1462 | |
| 1463 if (constructor.isPatch) { | |
| 1464 // Create origin body element for patched constructors. | |
| 1465 ConstructorBodyElementX patch = bodyElement; | |
| 1466 ConstructorBodyElementX origin = | |
| 1467 new ConstructorBodyElementX(constructor.origin); | |
| 1468 origin.applyPatch(patch); | |
| 1469 classElement.origin.addBackendMember(bodyElement.origin); | |
| 1470 } | |
| 1471 } | |
| 1472 assert(bodyElement.isGenerativeConstructorBody); | |
| 1473 return bodyElement; | |
| 1474 } | |
| 1475 | |
| 1476 /// The list of parameters to send from the generative constructor | |
| 1477 /// to the generative constructor body. | |
| 1478 /// | |
| 1479 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed | |
| 1480 /// containing the boxed parameters. | |
| 1481 /// | |
| 1482 /// For example, given the following constructor, | |
| 1483 /// | |
| 1484 /// Foo(x, y) : field = (() => ++x) { print(x + y) } | |
| 1485 /// | |
| 1486 /// the argument `x` would be replaced by a [BoxLocal]: | |
| 1487 /// | |
| 1488 /// Foo_body(box0, y) { print(box0.x + y) } | |
| 1489 /// | |
| 1490 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) { | |
| 1491 List<Local> parameters = <Local>[]; | |
| 1492 ClosureScope scope = getClosureScopeForFunction(body.constructor); | |
| 1493 if (scope != null) { | |
| 1494 parameters.add(scope.box); | |
| 1495 } | |
| 1496 body.functionSignature.orderedForEachParameter((ParameterElement param) { | |
| 1497 if (scope != null && scope.capturedVariables.containsKey(param)) { | |
| 1498 // Do not pass this parameter; the box will carry its value. | |
| 1499 } else { | |
| 1500 parameters.add(param); | |
| 1501 } | |
| 1502 }); | |
| 1503 return parameters; | |
| 1504 } | |
| 1505 | |
| 1506 /// Builds the IR for the body of a constructor. | |
| 1507 /// | |
| 1508 /// This function is invoked from one or more "factory" constructors built by | |
| 1509 /// [buildConstructor]. | |
| 1510 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) { | |
| 1511 ConstructorElement constructor = body.constructor; | |
| 1512 ast.FunctionExpression node = constructor.node; | |
| 1513 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 1514 constructor, | |
| 1515 node, | |
| 1516 elements); | |
| 1517 | |
| 1518 JsIrBuilder builder = | |
| 1519 new JsIrBuilder(compiler.backend.constantSystem, body); | |
| 1520 | |
| 1521 return withBuilder(builder, () { | |
| 1522 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body), | |
| 1523 getClosureScopeForNode(node)); | |
| 1524 visit(node.body); | |
| 1525 return irBuilder.makeFunctionDefinition([]); | |
| 1526 }); | |
| 1527 } | |
| 1528 | |
| 1529 ir.FunctionDefinition buildFunction(FunctionElement element) { | |
| 1530 assert(invariant(element, element.isImplementation)); | |
| 1531 ast.FunctionExpression node = element.node; | |
| 1532 | |
| 1533 assert(!element.isSynthesized); | |
| 1534 assert(node != null); | |
| 1535 assert(elements[node] != null); | |
| 1536 | |
| 1537 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping( | |
| 1538 element, | |
| 1539 node, | |
| 1540 elements); | |
| 1541 IrBuilder builder = | |
| 1542 new JsIrBuilder(compiler.backend.constantSystem, element); | |
| 1543 return withBuilder(builder, () => _makeFunctionBody(element, node)); | |
| 1544 } | |
| 1545 | |
| 1546 } | |
| 1547 | |
| OLD | NEW |