| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library closureToClassMapper; | 5 library closureToClassMapper; |
| 6 | 6 |
| 7 import 'common.dart'; | 7 import 'common.dart'; |
| 8 import 'common/names.dart' show | 8 import 'common/names.dart' show Identifiers; |
| 9 Identifiers; | 9 import 'common/resolution.dart' show Parsing, Resolution; |
| 10 import 'common/resolution.dart' show | 10 import 'common/tasks.dart' show CompilerTask; |
| 11 Parsing, | 11 import 'compiler.dart' show Compiler; |
| 12 Resolution; | |
| 13 import 'common/tasks.dart' show | |
| 14 CompilerTask; | |
| 15 import 'compiler.dart' show | |
| 16 Compiler; | |
| 17 import 'constants/expressions.dart'; | 12 import 'constants/expressions.dart'; |
| 18 import 'dart_types.dart'; | 13 import 'dart_types.dart'; |
| 19 import 'elements/elements.dart'; | 14 import 'elements/elements.dart'; |
| 20 import 'elements/modelx.dart' show | 15 import 'elements/modelx.dart' |
| 21 BaseFunctionElementX, | 16 show BaseFunctionElementX, ClassElementX, ElementX, LocalFunctionElementX; |
| 22 ClassElementX, | |
| 23 ElementX, | |
| 24 LocalFunctionElementX; | |
| 25 import 'elements/visitor.dart' show ElementVisitor; | 17 import 'elements/visitor.dart' show ElementVisitor; |
| 26 import 'js_backend/js_backend.dart' show JavaScriptBackend; | 18 import 'js_backend/js_backend.dart' show JavaScriptBackend; |
| 27 import 'resolution/tree_elements.dart' show TreeElements; | 19 import 'resolution/tree_elements.dart' show TreeElements; |
| 28 import 'tokens/token.dart' show Token; | 20 import 'tokens/token.dart' show Token; |
| 29 import 'tree/tree.dart'; | 21 import 'tree/tree.dart'; |
| 30 import 'util/util.dart'; | 22 import 'util/util.dart'; |
| 31 import 'universe/universe.dart' show | 23 import 'universe/universe.dart' show Universe; |
| 32 Universe; | |
| 33 | 24 |
| 34 class ClosureTask extends CompilerTask { | 25 class ClosureTask extends CompilerTask { |
| 35 Map<Node, ClosureClassMap> closureMappingCache; | 26 Map<Node, ClosureClassMap> closureMappingCache; |
| 36 ClosureTask(Compiler compiler) | 27 ClosureTask(Compiler compiler) |
| 37 : closureMappingCache = new Map<Node, ClosureClassMap>(), | 28 : closureMappingCache = new Map<Node, ClosureClassMap>(), |
| 38 super(compiler); | 29 super(compiler); |
| 39 | 30 |
| 40 String get name => "Closure Simplifier"; | 31 String get name => "Closure Simplifier"; |
| 41 | 32 |
| 42 ClosureClassMap computeClosureToClassMapping(Element element, | 33 ClosureClassMap computeClosureToClassMapping( |
| 43 Node node, | 34 Element element, Node node, TreeElements elements) { |
| 44 TreeElements elements) { | |
| 45 return measure(() { | 35 return measure(() { |
| 46 ClosureClassMap cached = closureMappingCache[node]; | 36 ClosureClassMap cached = closureMappingCache[node]; |
| 47 if (cached != null) return cached; | 37 if (cached != null) return cached; |
| 48 | 38 |
| 49 ClosureTranslator translator = | 39 ClosureTranslator translator = |
| 50 new ClosureTranslator(compiler, elements, closureMappingCache); | 40 new ClosureTranslator(compiler, elements, closureMappingCache); |
| 51 | 41 |
| 52 // The translator will store the computed closure-mappings inside the | 42 // The translator will store the computed closure-mappings inside the |
| 53 // cache. One for given node and one for each nested closure. | 43 // cache. One for given node and one for each nested closure. |
| 54 if (node is FunctionExpression) { | 44 if (node is FunctionExpression) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 100 /// non-elements. | 90 /// non-elements. |
| 101 abstract class CapturedVariable implements Element {} | 91 abstract class CapturedVariable implements Element {} |
| 102 | 92 |
| 103 // TODO(ahe): These classes continuously cause problems. We need to | 93 // TODO(ahe): These classes continuously cause problems. We need to |
| 104 // find a more general solution. | 94 // find a more general solution. |
| 105 class ClosureFieldElement extends ElementX | 95 class ClosureFieldElement extends ElementX |
| 106 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { | 96 implements FieldElement, CapturedVariable, PrivatelyNamedJSEntity { |
| 107 /// The [BoxLocal] or [LocalElement] being accessed through the field. | 97 /// The [BoxLocal] or [LocalElement] being accessed through the field. |
| 108 final Local local; | 98 final Local local; |
| 109 | 99 |
| 110 ClosureFieldElement(String name, | 100 ClosureFieldElement(String name, this.local, ClosureClassElement enclosing) |
| 111 this.local, | |
| 112 ClosureClassElement enclosing) | |
| 113 : super(name, ElementKind.FIELD, enclosing); | 101 : super(name, ElementKind.FIELD, enclosing); |
| 114 | 102 |
| 115 /// Use [closureClass] instead. | 103 /// Use [closureClass] instead. |
| 116 @deprecated | 104 @deprecated |
| 117 get enclosingElement => super.enclosingElement; | 105 get enclosingElement => super.enclosingElement; |
| 118 | 106 |
| 119 ClosureClassElement get closureClass => super.enclosingElement; | 107 ClosureClassElement get closureClass => super.enclosingElement; |
| 120 | 108 |
| 121 MemberElement get memberContext => closureClass.methodElement.memberContext; | 109 MemberElement get memberContext => closureClass.methodElement.memberContext; |
| 122 | 110 |
| 123 @override | 111 @override |
| 124 Entity get declaredEntity => local; | 112 Entity get declaredEntity => local; |
| 125 @override | 113 @override |
| 126 Entity get rootOfScope => closureClass; | 114 Entity get rootOfScope => closureClass; |
| 127 | 115 |
| 128 bool get hasNode => false; | 116 bool get hasNode => false; |
| 129 | 117 |
| 130 Node get node { | 118 Node get node { |
| 131 throw new SpannableAssertionFailure(local, | 119 throw new SpannableAssertionFailure( |
| 132 'Should not access node of ClosureFieldElement.'); | 120 local, 'Should not access node of ClosureFieldElement.'); |
| 133 } | 121 } |
| 134 | 122 |
| 135 bool get hasResolvedAst => hasTreeElements; | 123 bool get hasResolvedAst => hasTreeElements; |
| 136 | 124 |
| 137 ResolvedAst get resolvedAst { | 125 ResolvedAst get resolvedAst { |
| 138 return new ResolvedAst(this, null, treeElements); | 126 return new ResolvedAst(this, null, treeElements); |
| 139 } | 127 } |
| 140 | 128 |
| 141 Expression get initializer { | 129 Expression get initializer { |
| 142 throw new SpannableAssertionFailure(local, | 130 throw new SpannableAssertionFailure( |
| 143 'Should not access initializer of ClosureFieldElement.'); | 131 local, 'Should not access initializer of ClosureFieldElement.'); |
| 144 } | 132 } |
| 145 | 133 |
| 146 bool get isInstanceMember => true; | 134 bool get isInstanceMember => true; |
| 147 bool get isAssignable => false; | 135 bool get isAssignable => false; |
| 148 | 136 |
| 149 DartType computeType(Resolution resolution) => type; | 137 DartType computeType(Resolution resolution) => type; |
| 150 | 138 |
| 151 DartType get type { | 139 DartType get type { |
| 152 if (local is LocalElement) { | 140 if (local is LocalElement) { |
| 153 LocalElement element = local; | 141 LocalElement element = local; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 170 @override | 158 @override |
| 171 ConstantExpression get constant => null; | 159 ConstantExpression get constant => null; |
| 172 } | 160 } |
| 173 | 161 |
| 174 // TODO(ahe): These classes continuously cause problems. We need to find | 162 // TODO(ahe): These classes continuously cause problems. We need to find |
| 175 // a more general solution. | 163 // a more general solution. |
| 176 class ClosureClassElement extends ClassElementX { | 164 class ClosureClassElement extends ClassElementX { |
| 177 DartType rawType; | 165 DartType rawType; |
| 178 DartType thisType; | 166 DartType thisType; |
| 179 FunctionType callType; | 167 FunctionType callType; |
| 168 |
| 180 /// Node that corresponds to this closure, used for source position. | 169 /// Node that corresponds to this closure, used for source position. |
| 181 final FunctionExpression node; | 170 final FunctionExpression node; |
| 182 | 171 |
| 183 /** | 172 /** |
| 184 * The element for the declaration of the function expression. | 173 * The element for the declaration of the function expression. |
| 185 */ | 174 */ |
| 186 final LocalFunctionElement methodElement; | 175 final LocalFunctionElement methodElement; |
| 187 | 176 |
| 188 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; | 177 final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[]; |
| 189 | 178 |
| 190 ClosureClassElement(this.node, | 179 ClosureClassElement( |
| 191 String name, | 180 this.node, String name, Compiler compiler, LocalFunctionElement closure) |
| 192 Compiler compiler, | |
| 193 LocalFunctionElement closure) | |
| 194 : this.methodElement = closure, | 181 : this.methodElement = closure, |
| 195 super(name, | 182 super( |
| 196 closure.compilationUnit, | 183 name, |
| 197 // By assigning a fresh class-id we make sure that the hashcode | 184 closure.compilationUnit, |
| 198 // is unique, but also emit closure classes after all other | 185 // By assigning a fresh class-id we make sure that the hashcode |
| 199 // classes (since the emitter sorts classes by their id). | 186 // is unique, but also emit closure classes after all other |
| 200 compiler.getNextFreeClassId(), | 187 // classes (since the emitter sorts classes by their id). |
| 201 STATE_DONE) { | 188 compiler.getNextFreeClassId(), |
| 189 STATE_DONE) { |
| 202 JavaScriptBackend backend = compiler.backend; | 190 JavaScriptBackend backend = compiler.backend; |
| 203 ClassElement superclass = methodElement.isInstanceMember | 191 ClassElement superclass = methodElement.isInstanceMember |
| 204 ? backend.helpers.boundClosureClass | 192 ? backend.helpers.boundClosureClass |
| 205 : backend.helpers.closureClass; | 193 : backend.helpers.closureClass; |
| 206 superclass.ensureResolved(compiler.resolution); | 194 superclass.ensureResolved(compiler.resolution); |
| 207 supertype = superclass.thisType; | 195 supertype = superclass.thisType; |
| 208 interfaces = const Link<DartType>(); | 196 interfaces = const Link<DartType>(); |
| 209 thisType = rawType = new InterfaceType(this); | 197 thisType = rawType = new InterfaceType(this); |
| 210 allSupertypesAndSelf = | 198 allSupertypesAndSelf = |
| 211 superclass.allSupertypesAndSelf.extendClass(thisType); | 199 superclass.allSupertypesAndSelf.extendClass(thisType); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 class BoxLocal extends Local { | 232 class BoxLocal extends Local { |
| 245 final String name; | 233 final String name; |
| 246 final ExecutableElement executableContext; | 234 final ExecutableElement executableContext; |
| 247 | 235 |
| 248 BoxLocal(this.name, this.executableContext); | 236 BoxLocal(this.name, this.executableContext); |
| 249 } | 237 } |
| 250 | 238 |
| 251 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to | 239 // TODO(ngeoffray, ahe): These classes continuously cause problems. We need to |
| 252 // find a more general solution. | 240 // find a more general solution. |
| 253 class BoxFieldElement extends ElementX | 241 class BoxFieldElement extends ElementX |
| 254 implements TypedElement, CapturedVariable, FieldElement, | 242 implements |
| 243 TypedElement, |
| 244 CapturedVariable, |
| 245 FieldElement, |
| 255 PrivatelyNamedJSEntity { | 246 PrivatelyNamedJSEntity { |
| 256 final BoxLocal box; | 247 final BoxLocal box; |
| 257 | 248 |
| 258 BoxFieldElement(String name, this.variableElement, | 249 BoxFieldElement(String name, this.variableElement, BoxLocal box) |
| 259 BoxLocal box) | |
| 260 : this.box = box, | 250 : this.box = box, |
| 261 super(name, ElementKind.FIELD, box.executableContext); | 251 super(name, ElementKind.FIELD, box.executableContext); |
| 262 | 252 |
| 263 DartType computeType(Resolution resolution) => type; | 253 DartType computeType(Resolution resolution) => type; |
| 264 | 254 |
| 265 DartType get type => variableElement.type; | 255 DartType get type => variableElement.type; |
| 266 | 256 |
| 267 @override | 257 @override |
| 268 Entity get declaredEntity => variableElement; | 258 Entity get declaredEntity => variableElement; |
| 269 @override | 259 @override |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 String get name => 'this'; | 306 String get name => 'this'; |
| 317 | 307 |
| 318 ClassElement get enclosingClass => executableContext.enclosingClass; | 308 ClassElement get enclosingClass => executableContext.enclosingClass; |
| 319 } | 309 } |
| 320 | 310 |
| 321 /// Call method of a closure class. | 311 /// Call method of a closure class. |
| 322 class SynthesizedCallMethodElementX extends BaseFunctionElementX | 312 class SynthesizedCallMethodElementX extends BaseFunctionElementX |
| 323 implements MethodElement { | 313 implements MethodElement { |
| 324 final LocalFunctionElement expression; | 314 final LocalFunctionElement expression; |
| 325 | 315 |
| 326 SynthesizedCallMethodElementX(String name, | 316 SynthesizedCallMethodElementX( |
| 327 LocalFunctionElementX other, | 317 String name, LocalFunctionElementX other, ClosureClassElement enclosing) |
| 328 ClosureClassElement enclosing) | |
| 329 : expression = other, | 318 : expression = other, |
| 330 super(name, other.kind, other.modifiers, enclosing) { | 319 super(name, other.kind, other.modifiers, enclosing) { |
| 331 asyncMarker = other.asyncMarker; | 320 asyncMarker = other.asyncMarker; |
| 332 functionSignature = other.functionSignature; | 321 functionSignature = other.functionSignature; |
| 333 } | 322 } |
| 334 | 323 |
| 335 /// Use [closureClass] instead. | 324 /// Use [closureClass] instead. |
| 336 @deprecated | 325 @deprecated |
| 337 get enclosingElement => super.enclosingElement; | 326 get enclosingElement => super.enclosingElement; |
| 338 | 327 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 371 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; | 360 List<VariableElement> boxedLoopVariables = const <VariableElement>[]; |
| 372 | 361 |
| 373 ClosureScope(this.boxElement, this.capturedVariables); | 362 ClosureScope(this.boxElement, this.capturedVariables); |
| 374 | 363 |
| 375 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; | 364 bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty; |
| 376 | 365 |
| 377 bool isCapturedVariable(VariableElement variable) { | 366 bool isCapturedVariable(VariableElement variable) { |
| 378 return capturedVariables.containsKey(variable); | 367 return capturedVariables.containsKey(variable); |
| 379 } | 368 } |
| 380 | 369 |
| 381 void forEachCapturedVariable(f(LocalVariableElement variable, | 370 void forEachCapturedVariable( |
| 382 BoxFieldElement boxField)) { | 371 f(LocalVariableElement variable, BoxFieldElement boxField)) { |
| 383 capturedVariables.forEach(f); | 372 capturedVariables.forEach(f); |
| 384 } | 373 } |
| 385 } | 374 } |
| 386 | 375 |
| 387 class ClosureClassMap { | 376 class ClosureClassMap { |
| 388 // The closure's element before any translation. Will be null for methods. | 377 // The closure's element before any translation. Will be null for methods. |
| 389 final LocalFunctionElement closureElement; | 378 final LocalFunctionElement closureElement; |
| 390 // The closureClassElement will be null for methods that are not local | 379 // The closureClassElement will be null for methods that are not local |
| 391 // closures. | 380 // closures. |
| 392 final ClosureClassElement closureClassElement; | 381 final ClosureClassElement closureClassElement; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 409 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); | 398 final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>(); |
| 410 | 399 |
| 411 /// Variables that are used in a try must be treated as boxed because the | 400 /// Variables that are used in a try must be treated as boxed because the |
| 412 /// control flow can be non-linear. | 401 /// control flow can be non-linear. |
| 413 /// | 402 /// |
| 414 /// Also parameters to a `sync*` generator must be boxed, because of the way | 403 /// Also parameters to a `sync*` generator must be boxed, because of the way |
| 415 /// we rewrite sync* functions. See also comments in [useLocal]. | 404 /// we rewrite sync* functions. See also comments in [useLocal]. |
| 416 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. | 405 /// TODO(johnniwinter): Add variables to this only if the variable is mutated. |
| 417 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); | 406 final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>(); |
| 418 | 407 |
| 419 ClosureClassMap(this.closureElement, | 408 ClosureClassMap(this.closureElement, this.closureClassElement, |
| 420 this.closureClassElement, | 409 this.callElement, this.thisLocal); |
| 421 this.callElement, | |
| 422 this.thisLocal); | |
| 423 | 410 |
| 424 void addFreeVariable(Local element) { | 411 void addFreeVariable(Local element) { |
| 425 assert(freeVariableMap[element] == null); | 412 assert(freeVariableMap[element] == null); |
| 426 freeVariableMap[element] = null; | 413 freeVariableMap[element] = null; |
| 427 } | 414 } |
| 428 | 415 |
| 429 Iterable<Local> get freeVariables => freeVariableMap.keys; | 416 Iterable<Local> get freeVariables => freeVariableMap.keys; |
| 430 | 417 |
| 431 bool isFreeVariable(Local element) { | 418 bool isFreeVariable(Local element) { |
| 432 return freeVariableMap.containsKey(element); | 419 return freeVariableMap.containsKey(element); |
| 433 } | 420 } |
| 434 | 421 |
| 435 void forEachFreeVariable(f(Local variable, | 422 void forEachFreeVariable(f(Local variable, CapturedVariable field)) { |
| 436 CapturedVariable field)) { | |
| 437 freeVariableMap.forEach(f); | 423 freeVariableMap.forEach(f); |
| 438 } | 424 } |
| 439 | 425 |
| 440 Local getLocalVariableForClosureField(ClosureFieldElement field) { | 426 Local getLocalVariableForClosureField(ClosureFieldElement field) { |
| 441 return field.local; | 427 return field.local; |
| 442 } | 428 } |
| 443 | 429 |
| 444 bool get isClosure => closureElement != null; | 430 bool get isClosure => closureElement != null; |
| 445 | 431 |
| 446 bool capturingScopesBox(Local variable) { | 432 bool capturingScopesBox(Local variable) { |
| 447 return capturingScopes.values.any((scope) { | 433 return capturingScopes.values.any((scope) { |
| 448 return scope.boxedLoopVariables.contains(variable); | 434 return scope.boxedLoopVariables.contains(variable); |
| 449 }); | 435 }); |
| 450 } | 436 } |
| 451 | 437 |
| 452 bool isVariableBoxed(Local variable) { | 438 bool isVariableBoxed(Local variable) { |
| 453 CapturedVariable copy = freeVariableMap[variable]; | 439 CapturedVariable copy = freeVariableMap[variable]; |
| 454 if (copy is BoxFieldElement) { | 440 if (copy is BoxFieldElement) { |
| 455 return true; | 441 return true; |
| 456 } | 442 } |
| 457 return capturingScopesBox(variable); | 443 return capturingScopesBox(variable); |
| 458 } | 444 } |
| 459 | 445 |
| 460 void forEachCapturedVariable(void f(Local variable, | 446 void forEachCapturedVariable(void f(Local variable, CapturedVariable field)) { |
| 461 CapturedVariable field)) { | |
| 462 freeVariableMap.forEach((variable, copy) { | 447 freeVariableMap.forEach((variable, copy) { |
| 463 if (variable is BoxLocal) return; | 448 if (variable is BoxLocal) return; |
| 464 f(variable, copy); | 449 f(variable, copy); |
| 465 }); | 450 }); |
| 466 capturingScopes.values.forEach((ClosureScope scope) { | 451 capturingScopes.values.forEach((ClosureScope scope) { |
| 467 scope.forEachCapturedVariable(f); | 452 scope.forEachCapturedVariable(f); |
| 468 }); | 453 }); |
| 469 } | 454 } |
| 470 | 455 |
| 471 void forEachBoxedVariable(void f(LocalVariableElement local, | 456 void forEachBoxedVariable( |
| 472 BoxFieldElement field)) { | 457 void f(LocalVariableElement local, BoxFieldElement field)) { |
| 473 freeVariableMap.forEach((variable, copy) { | 458 freeVariableMap.forEach((variable, copy) { |
| 474 if (!isVariableBoxed(variable)) return; | 459 if (!isVariableBoxed(variable)) return; |
| 475 f(variable, copy); | 460 f(variable, copy); |
| 476 }); | 461 }); |
| 477 capturingScopes.values.forEach((ClosureScope scope) { | 462 capturingScopes.values.forEach((ClosureScope scope) { |
| 478 scope.forEachCapturedVariable(f); | 463 scope.forEachCapturedVariable(f); |
| 479 }); | 464 }); |
| 480 } | 465 } |
| 481 | 466 |
| 482 void removeMyselfFrom(Universe universe) { | 467 void removeMyselfFrom(Universe universe) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 514 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); | 499 Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>(); |
| 515 | 500 |
| 516 MemberElement outermostElement; | 501 MemberElement outermostElement; |
| 517 ExecutableElement executableContext; | 502 ExecutableElement executableContext; |
| 518 | 503 |
| 519 // The closureData of the currentFunctionElement. | 504 // The closureData of the currentFunctionElement. |
| 520 ClosureClassMap closureData; | 505 ClosureClassMap closureData; |
| 521 | 506 |
| 522 bool insideClosure = false; | 507 bool insideClosure = false; |
| 523 | 508 |
| 524 ClosureTranslator(this.compiler, | 509 ClosureTranslator(this.compiler, this.elements, this.closureMappingCache); |
| 525 this.elements, | |
| 526 this.closureMappingCache); | |
| 527 | 510 |
| 528 DiagnosticReporter get reporter => compiler.reporter; | 511 DiagnosticReporter get reporter => compiler.reporter; |
| 529 | 512 |
| 530 /// Generate a unique name for the [id]th closure field, with proposed name | 513 /// Generate a unique name for the [id]th closure field, with proposed name |
| 531 /// [name]. | 514 /// [name]. |
| 532 /// | 515 /// |
| 533 /// The result is used as the name of [ClosureFieldElement]s, and must | 516 /// The result is used as the name of [ClosureFieldElement]s, and must |
| 534 /// therefore be unique to avoid breaking an invariant in the element model | 517 /// therefore be unique to avoid breaking an invariant in the element model |
| 535 /// (classes cannot declare multiple fields with the same name). | 518 /// (classes cannot declare multiple fields with the same name). |
| 536 /// | 519 /// |
| (...skipping 24 matching lines...) Expand all Loading... |
| 561 return _capturedVariableMapping.containsKey(element); | 544 return _capturedVariableMapping.containsKey(element); |
| 562 } | 545 } |
| 563 | 546 |
| 564 void addCapturedVariable(Node node, Local variable) { | 547 void addCapturedVariable(Node node, Local variable) { |
| 565 if (_capturedVariableMapping[variable] != null) { | 548 if (_capturedVariableMapping[variable] != null) { |
| 566 reporter.internalError(node, 'In closure analyzer.'); | 549 reporter.internalError(node, 'In closure analyzer.'); |
| 567 } | 550 } |
| 568 _capturedVariableMapping[variable] = null; | 551 _capturedVariableMapping[variable] = null; |
| 569 } | 552 } |
| 570 | 553 |
| 571 void setCapturedVariableBoxField(Local variable, | 554 void setCapturedVariableBoxField(Local variable, BoxFieldElement boxField) { |
| 572 BoxFieldElement boxField) { | |
| 573 assert(isCapturedVariable(variable)); | 555 assert(isCapturedVariable(variable)); |
| 574 _capturedVariableMapping[variable] = boxField; | 556 _capturedVariableMapping[variable] = boxField; |
| 575 } | 557 } |
| 576 | 558 |
| 577 BoxFieldElement getCapturedVariableBoxField(Local variable) { | 559 BoxFieldElement getCapturedVariableBoxField(Local variable) { |
| 578 return _capturedVariableMapping[variable]; | 560 return _capturedVariableMapping[variable]; |
| 579 } | 561 } |
| 580 | 562 |
| 581 void translateFunction(Element element, FunctionExpression node) { | 563 void translateFunction(Element element, FunctionExpression node) { |
| 582 // For constructors the [element] and the [:elements[node]:] may differ. | 564 // For constructors the [element] and the [:elements[node]:] may differ. |
| 583 // The [:elements[node]:] always points to the generative-constructor | 565 // The [:elements[node]:] always points to the generative-constructor |
| 584 // element, whereas the [element] might be the constructor-body element. | 566 // element, whereas the [element] might be the constructor-body element. |
| 585 visit(node); // [visitFunctionExpression] will call [visitInvokable]. | 567 visit(node); // [visitFunctionExpression] will call [visitInvokable]. |
| 586 // When variables need to be boxed their [_capturedVariableMapping] is | 568 // When variables need to be boxed their [_capturedVariableMapping] is |
| 587 // updated, but we delay updating the similar freeVariableMapping in the | 569 // updated, but we delay updating the similar freeVariableMapping in the |
| 588 // closure datas that capture these variables. | 570 // closure datas that capture these variables. |
| 589 // The closures don't have their fields (in the closure class) set, either. | 571 // The closures don't have their fields (in the closure class) set, either. |
| 590 updateClosures(); | 572 updateClosures(); |
| 591 } | 573 } |
| 592 | 574 |
| 593 void translateLazyInitializer(VariableElement element, | 575 void translateLazyInitializer(VariableElement element, |
| 594 VariableDefinitions node, | 576 VariableDefinitions node, Expression initializer) { |
| 595 Expression initializer) { | 577 visitInvokable(element, node, () { |
| 596 visitInvokable(element, node, () { visit(initializer); }); | 578 visit(initializer); |
| 579 }); |
| 597 updateClosures(); | 580 updateClosures(); |
| 598 } | 581 } |
| 599 | 582 |
| 600 // This function runs through all of the existing closures and updates their | 583 // This function runs through all of the existing closures and updates their |
| 601 // free variables to the boxed value. It also adds the field-elements to the | 584 // free variables to the boxed value. It also adds the field-elements to the |
| 602 // class representing the closure. | 585 // class representing the closure. |
| 603 void updateClosures() { | 586 void updateClosures() { |
| 604 for (Expression closure in closures) { | 587 for (Expression closure in closures) { |
| 605 // The captured variables that need to be stored in a field of the closure | 588 // The captured variables that need to be stored in a field of the closure |
| 606 // class. | 589 // class. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 620 assert(fromElement is! BoxLocal); | 603 assert(fromElement is! BoxLocal); |
| 621 // The variable has not been boxed. | 604 // The variable has not been boxed. |
| 622 fieldCaptures.add(fromElement); | 605 fieldCaptures.add(fromElement); |
| 623 } else { | 606 } else { |
| 624 // A boxed element. | 607 // A boxed element. |
| 625 data.freeVariableMap[fromElement] = boxFieldElement; | 608 data.freeVariableMap[fromElement] = boxFieldElement; |
| 626 boxes.add(boxFieldElement.box); | 609 boxes.add(boxFieldElement.box); |
| 627 } | 610 } |
| 628 }); | 611 }); |
| 629 ClosureClassElement closureClass = data.closureClassElement; | 612 ClosureClassElement closureClass = data.closureClassElement; |
| 630 assert(closureClass != null || | 613 assert(closureClass != null || (fieldCaptures.isEmpty && boxes.isEmpty)); |
| 631 (fieldCaptures.isEmpty && boxes.isEmpty)); | |
| 632 | 614 |
| 633 void addClosureField(Local local, String name) { | 615 void addClosureField(Local local, String name) { |
| 634 ClosureFieldElement closureField = | 616 ClosureFieldElement closureField = |
| 635 new ClosureFieldElement(name, local, closureClass); | 617 new ClosureFieldElement(name, local, closureClass); |
| 636 closureClass.addField(closureField, reporter); | 618 closureClass.addField(closureField, reporter); |
| 637 data.freeVariableMap[local] = closureField; | 619 data.freeVariableMap[local] = closureField; |
| 638 } | 620 } |
| 639 | 621 |
| 640 // Add the box elements first so we get the same ordering. | 622 // Add the box elements first so we get the same ordering. |
| 641 // TODO(sra): What is the canonical order of multiple boxes? | 623 // TODO(sra): What is the canonical order of multiple boxes? |
| (...skipping 25 matching lines...) Expand all Loading... |
| 667 | 649 |
| 668 void useLocal(Local variable) { | 650 void useLocal(Local variable) { |
| 669 // If the element is not declared in the current function and the element | 651 // If the element is not declared in the current function and the element |
| 670 // is not the closure itself we need to mark the element as free variable. | 652 // is not the closure itself we need to mark the element as free variable. |
| 671 // Note that the check on [insideClosure] is not just an | 653 // Note that the check on [insideClosure] is not just an |
| 672 // optimization: factories have type parameters as function | 654 // optimization: factories have type parameters as function |
| 673 // parameters, and type parameters are declared in the class, not | 655 // parameters, and type parameters are declared in the class, not |
| 674 // the factory. | 656 // the factory. |
| 675 bool inCurrentContext(Local variable) { | 657 bool inCurrentContext(Local variable) { |
| 676 return variable == executableContext || | 658 return variable == executableContext || |
| 677 variable.executableContext == executableContext; | 659 variable.executableContext == executableContext; |
| 678 } | 660 } |
| 679 | 661 |
| 680 if (insideClosure && !inCurrentContext(variable)) { | 662 if (insideClosure && !inCurrentContext(variable)) { |
| 681 closureData.addFreeVariable(variable); | 663 closureData.addFreeVariable(variable); |
| 682 } else if (inTryStatement) { | 664 } else if (inTryStatement) { |
| 683 // Don't mark the this-element or a self-reference. This would complicate | 665 // Don't mark the this-element or a self-reference. This would complicate |
| 684 // things in the builder. | 666 // things in the builder. |
| 685 // Note that nested (named) functions are immutable. | 667 // Note that nested (named) functions are immutable. |
| 686 if (variable != closureData.thisLocal && | 668 if (variable != closureData.thisLocal && |
| 687 variable != closureData.closureElement && | 669 variable != closureData.closureElement && |
| (...skipping 24 matching lines...) Expand all Loading... |
| 712 | 694 |
| 713 visit(Node node) => node.accept(this); | 695 visit(Node node) => node.accept(this); |
| 714 | 696 |
| 715 visitNode(Node node) => node.visitChildren(this); | 697 visitNode(Node node) => node.visitChildren(this); |
| 716 | 698 |
| 717 visitVariableDefinitions(VariableDefinitions node) { | 699 visitVariableDefinitions(VariableDefinitions node) { |
| 718 if (node.type != null) { | 700 if (node.type != null) { |
| 719 visit(node.type); | 701 visit(node.type); |
| 720 } | 702 } |
| 721 for (Link<Node> link = node.definitions.nodes; | 703 for (Link<Node> link = node.definitions.nodes; |
| 722 !link.isEmpty; | 704 !link.isEmpty; |
| 723 link = link.tail) { | 705 link = link.tail) { |
| 724 Node definition = link.head; | 706 Node definition = link.head; |
| 725 LocalElement element = elements[definition]; | 707 LocalElement element = elements[definition]; |
| 726 assert(element != null); | 708 assert(element != null); |
| 727 if (!element.isInitializingFormal) { | 709 if (!element.isInitializingFormal) { |
| 728 declareLocal(element); | 710 declareLocal(element); |
| 729 } | 711 } |
| 730 // We still need to visit the right-hand sides of the init-assignments. | 712 // We still need to visit the right-hand sides of the init-assignments. |
| 731 // For SendSets don't visit the left again. Otherwise it would be marked | 713 // For SendSets don't visit the left again. Otherwise it would be marked |
| 732 // as mutated. | 714 // as mutated. |
| 733 if (definition is Send) { | 715 if (definition is Send) { |
| 734 Send assignment = definition; | 716 Send assignment = definition; |
| 735 Node arguments = assignment.argumentsNode; | 717 Node arguments = assignment.argumentsNode; |
| 736 if (arguments != null) { | 718 if (arguments != null) { |
| 737 visit(arguments); | 719 visit(arguments); |
| 738 } | 720 } |
| 739 } else { | 721 } else { |
| 740 visit(definition); | 722 visit(definition); |
| 741 } | 723 } |
| 742 } | 724 } |
| 743 } | 725 } |
| 744 | 726 |
| 745 visitTypeAnnotation(TypeAnnotation node) { | 727 visitTypeAnnotation(TypeAnnotation node) { |
| 746 MemberElement member = executableContext.memberContext; | 728 MemberElement member = executableContext.memberContext; |
| 747 DartType type = elements.getType(node); | 729 DartType type = elements.getType(node); |
| 748 // TODO(karlklose,johnniwinther): if the type is null, the annotation is | 730 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
| 749 // from a parameter which has been analyzed before the method has been | 731 // from a parameter which has been analyzed before the method has been |
| 750 // resolved and the result has been thrown away. | 732 // resolved and the result has been thrown away. |
| 751 if (compiler.options.enableTypeAssertions && type != null && | 733 if (compiler.options.enableTypeAssertions && |
| 734 type != null && |
| 752 type.containsTypeVariables) { | 735 type.containsTypeVariables) { |
| 753 if (insideClosure && member.isFactoryConstructor) { | 736 if (insideClosure && member.isFactoryConstructor) { |
| 754 // This is a closure in a factory constructor. Since there is no | 737 // This is a closure in a factory constructor. Since there is no |
| 755 // [:this:], we have to mark the type arguments as free variables to | 738 // [:this:], we have to mark the type arguments as free variables to |
| 756 // capture them in the closure. | 739 // capture them in the closure. |
| 757 type.forEachTypeVariable((TypeVariableType variable) { | 740 type.forEachTypeVariable((TypeVariableType variable) { |
| 758 useTypeVariableAsLocal(variable); | 741 useTypeVariableAsLocal(variable); |
| 759 }); | 742 }); |
| 760 } | 743 } |
| 761 if (member.isInstanceMember && !member.isField) { | 744 if (member.isInstanceMember && !member.isField) { |
| 762 // In checked mode, using a type variable in a type annotation may lead | 745 // In checked mode, using a type variable in a type annotation may lead |
| 763 // to a runtime type check that needs to access the type argument and | 746 // to a runtime type check that needs to access the type argument and |
| 764 // therefore the closure needs a this-element, if it is not in a field | 747 // therefore the closure needs a this-element, if it is not in a field |
| 765 // initializer; field initatializers are evaluated in a context where | 748 // initializer; field initatializers are evaluated in a context where |
| 766 // the type arguments are available in locals. | 749 // the type arguments are available in locals. |
| 767 registerNeedsThis(); | 750 registerNeedsThis(); |
| 768 } | 751 } |
| 769 } | 752 } |
| 770 } | 753 } |
| 771 | 754 |
| 772 visitIdentifier(Identifier node) { | 755 visitIdentifier(Identifier node) { |
| 773 if (node.isThis()) { | 756 if (node.isThis()) { |
| 774 registerNeedsThis(); | 757 registerNeedsThis(); |
| 775 } else { | 758 } else { |
| 776 Element element = elements[node]; | 759 Element element = elements[node]; |
| 777 if (element != null && element.isTypeVariable) { | 760 if (element != null && element.isTypeVariable) { |
| 778 if (outermostElement.isConstructor || | 761 if (outermostElement.isConstructor || outermostElement.isField) { |
| 779 outermostElement.isField) { | |
| 780 TypeVariableElement typeVariable = element; | 762 TypeVariableElement typeVariable = element; |
| 781 useTypeVariableAsLocal(typeVariable.type); | 763 useTypeVariableAsLocal(typeVariable.type); |
| 782 } else { | 764 } else { |
| 783 registerNeedsThis(); | 765 registerNeedsThis(); |
| 784 } | 766 } |
| 785 } | 767 } |
| 786 } | 768 } |
| 787 node.visitChildren(this); | 769 node.visitChildren(this); |
| 788 } | 770 } |
| 789 | 771 |
| 790 visitSend(Send node) { | 772 visitSend(Send node) { |
| 791 Element element = elements[node]; | 773 Element element = elements[node]; |
| 792 if (Elements.isLocal(element)) { | 774 if (Elements.isLocal(element)) { |
| 793 LocalElement localElement = element; | 775 LocalElement localElement = element; |
| 794 useLocal(localElement); | 776 useLocal(localElement); |
| 795 } else if (element != null && element.isTypeVariable) { | 777 } else if (element != null && element.isTypeVariable) { |
| 796 TypeVariableElement variable = element; | 778 TypeVariableElement variable = element; |
| 797 analyzeType(variable.type); | 779 analyzeType(variable.type); |
| 798 } else if (node.receiver == null && | 780 } else if (node.receiver == null && |
| 799 Elements.isInstanceSend(node, elements)) { | 781 Elements.isInstanceSend(node, elements)) { |
| 800 registerNeedsThis(); | 782 registerNeedsThis(); |
| 801 } else if (node.isSuperCall) { | 783 } else if (node.isSuperCall) { |
| 802 registerNeedsThis(); | 784 registerNeedsThis(); |
| 803 } else if (node.isTypeTest || node.isTypeCast) { | 785 } else if (node.isTypeTest || node.isTypeCast) { |
| 804 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; | 786 TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast; |
| 805 DartType type = elements.getType(annotation); | 787 DartType type = elements.getType(annotation); |
| 806 analyzeType(type); | 788 analyzeType(type); |
| 807 } else if (node.isTypeTest) { | 789 } else if (node.isTypeTest) { |
| 808 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); | 790 DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast); |
| 809 analyzeType(type); | 791 analyzeType(type); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 visitLiteralMap(LiteralMap node) { | 823 visitLiteralMap(LiteralMap node) { |
| 842 DartType type = elements.getType(node); | 824 DartType type = elements.getType(node); |
| 843 analyzeType(type); | 825 analyzeType(type); |
| 844 node.visitChildren(this); | 826 node.visitChildren(this); |
| 845 } | 827 } |
| 846 | 828 |
| 847 void analyzeTypeVariables(DartType type) { | 829 void analyzeTypeVariables(DartType type) { |
| 848 type.forEachTypeVariable((TypeVariableType typeVariable) { | 830 type.forEachTypeVariable((TypeVariableType typeVariable) { |
| 849 // Field initializers are inlined and access the type variable as | 831 // Field initializers are inlined and access the type variable as |
| 850 // normal parameters. | 832 // normal parameters. |
| 851 if (!outermostElement.isField && | 833 if (!outermostElement.isField && !outermostElement.isConstructor) { |
| 852 !outermostElement.isConstructor) { | |
| 853 registerNeedsThis(); | 834 registerNeedsThis(); |
| 854 } else { | 835 } else { |
| 855 useTypeVariableAsLocal(typeVariable); | 836 useTypeVariableAsLocal(typeVariable); |
| 856 } | 837 } |
| 857 }); | 838 }); |
| 858 } | 839 } |
| 859 | 840 |
| 860 void analyzeType(DartType type) { | 841 void analyzeType(DartType type) { |
| 861 // TODO(johnniwinther): Find out why this can be null. | 842 // TODO(johnniwinther): Find out why this can be null. |
| 862 if (type == null) return; | 843 if (type == null) return; |
| 863 if (outermostElement.isClassMember && | 844 if (outermostElement.isClassMember && |
| 864 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { | 845 compiler.backend.classNeedsRti(outermostElement.enclosingClass)) { |
| 865 if (outermostElement.isConstructor || | 846 if (outermostElement.isConstructor || outermostElement.isField) { |
| 866 outermostElement.isField) { | |
| 867 analyzeTypeVariables(type); | 847 analyzeTypeVariables(type); |
| 868 } else if (outermostElement.isInstanceMember) { | 848 } else if (outermostElement.isInstanceMember) { |
| 869 if (type.containsTypeVariables) { | 849 if (type.containsTypeVariables) { |
| 870 registerNeedsThis(); | 850 registerNeedsThis(); |
| 871 } | 851 } |
| 872 } | 852 } |
| 873 } | 853 } |
| 874 } | 854 } |
| 875 | 855 |
| 876 // If variables that are declared in the [node] scope are captured and need | 856 // If variables that are declared in the [node] scope are captured and need |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 951 // condition or body are indeed flagged as mutated. | 931 // condition or body are indeed flagged as mutated. |
| 952 if (node.conditionStatement != null) visit(node.conditionStatement); | 932 if (node.conditionStatement != null) visit(node.conditionStatement); |
| 953 if (node.body != null) visit(node.body); | 933 if (node.body != null) visit(node.body); |
| 954 | 934 |
| 955 // See if we have declared loop variables that need to be boxed. | 935 // See if we have declared loop variables that need to be boxed. |
| 956 if (node.initializer == null) return; | 936 if (node.initializer == null) return; |
| 957 VariableDefinitions definitions = | 937 VariableDefinitions definitions = |
| 958 node.initializer.asVariableDefinitions(); | 938 node.initializer.asVariableDefinitions(); |
| 959 if (definitions == null) return; | 939 if (definitions == null) return; |
| 960 for (Link<Node> link = definitions.definitions.nodes; | 940 for (Link<Node> link = definitions.definitions.nodes; |
| 961 !link.isEmpty; | 941 !link.isEmpty; |
| 962 link = link.tail) { | 942 link = link.tail) { |
| 963 Node definition = link.head; | 943 Node definition = link.head; |
| 964 LocalVariableElement element = elements[definition]; | 944 LocalVariableElement element = elements[definition]; |
| 965 // Non-mutated variables should not be boxed. The mutatedVariables set | 945 // Non-mutated variables should not be boxed. The mutatedVariables set |
| 966 // gets cleared when 'inNewScope' returns, so check it here. | 946 // gets cleared when 'inNewScope' returns, so check it here. |
| 967 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { | 947 if (isCapturedVariable(element) && mutatedVariables.contains(element)) { |
| 968 boxedLoopVariables.add(element); | 948 boxedLoopVariables.add(element); |
| 969 } | 949 } |
| 970 } | 950 } |
| 971 }); | 951 }); |
| 972 ClosureScope scopeData = closureData.capturingScopes[node]; | 952 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 973 if (scopeData == null) return; | 953 if (scopeData == null) return; |
| 974 scopeData.boxedLoopVariables = boxedLoopVariables; | 954 scopeData.boxedLoopVariables = boxedLoopVariables; |
| 975 } | 955 } |
| 976 | 956 |
| 977 /** Returns a non-unique name for the given closure element. */ | 957 /** Returns a non-unique name for the given closure element. */ |
| 978 String computeClosureName(Element element) { | 958 String computeClosureName(Element element) { |
| 979 Link<String> parts = const Link<String>(); | 959 Link<String> parts = const Link<String>(); |
| 980 String ownName = element.name; | 960 String ownName = element.name; |
| 981 if (ownName == null || ownName == "") { | 961 if (ownName == null || ownName == "") { |
| 982 parts = parts.prepend("closure"); | 962 parts = parts.prepend("closure"); |
| 983 } else { | 963 } else { |
| 984 parts = parts.prepend(ownName); | 964 parts = parts.prepend(ownName); |
| 985 } | 965 } |
| 986 for (Element enclosingElement = element.enclosingElement; | 966 for (Element enclosingElement = element.enclosingElement; |
| 987 enclosingElement != null && | 967 enclosingElement != null && |
| 988 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 968 (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || |
| 989 || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR | 969 enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR || |
| 990 || enclosingElement.kind == ElementKind.CLASS | 970 enclosingElement.kind == ElementKind.CLASS || |
| 991 || enclosingElement.kind == ElementKind.FUNCTION | 971 enclosingElement.kind == ElementKind.FUNCTION || |
| 992 || enclosingElement.kind == ElementKind.GETTER | 972 enclosingElement.kind == ElementKind.GETTER || |
| 993 || enclosingElement.kind == ElementKind.SETTER); | 973 enclosingElement.kind == ElementKind.SETTER); |
| 994 enclosingElement = enclosingElement.enclosingElement) { | 974 enclosingElement = enclosingElement.enclosingElement) { |
| 995 // TODO(johnniwinther): Simplify computed names. | 975 // TODO(johnniwinther): Simplify computed names. |
| 996 if (enclosingElement.isGenerativeConstructor || | 976 if (enclosingElement.isGenerativeConstructor || |
| 997 enclosingElement.isGenerativeConstructorBody || | 977 enclosingElement.isGenerativeConstructorBody || |
| 998 enclosingElement.isFactoryConstructor) { | 978 enclosingElement.isFactoryConstructor) { |
| 999 parts = parts.prepend( | 979 parts = parts |
| 1000 Elements.reconstructConstructorName(enclosingElement)); | 980 .prepend(Elements.reconstructConstructorName(enclosingElement)); |
| 1001 } else { | 981 } else { |
| 1002 String surroundingName = | 982 String surroundingName = |
| 1003 Elements.operatorNameToIdentifier(enclosingElement.name); | 983 Elements.operatorNameToIdentifier(enclosingElement.name); |
| 1004 parts = parts.prepend(surroundingName); | 984 parts = parts.prepend(surroundingName); |
| 1005 } | 985 } |
| 1006 // A generative constructors's parent is the class; the class name is | 986 // A generative constructors's parent is the class; the class name is |
| 1007 // already part of the generative constructor's name. | 987 // already part of the generative constructor's name. |
| 1008 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; | 988 if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break; |
| 1009 } | 989 } |
| 1010 StringBuffer sb = new StringBuffer(); | 990 StringBuffer sb = new StringBuffer(); |
| 1011 parts.printOn(sb, '_'); | 991 parts.printOn(sb, '_'); |
| 1012 return sb.toString(); | 992 return sb.toString(); |
| 1013 } | 993 } |
| 1014 | 994 |
| 1015 JavaScriptBackend get backend => compiler.backend; | 995 JavaScriptBackend get backend => compiler.backend; |
| 1016 | 996 |
| 1017 ClosureClassMap globalizeClosure(FunctionExpression node, | 997 ClosureClassMap globalizeClosure( |
| 1018 LocalFunctionElement element) { | 998 FunctionExpression node, LocalFunctionElement element) { |
| 1019 String closureName = computeClosureName(element); | 999 String closureName = computeClosureName(element); |
| 1020 ClosureClassElement globalizedElement = new ClosureClassElement( | 1000 ClosureClassElement globalizedElement = |
| 1021 node, closureName, compiler, element); | 1001 new ClosureClassElement(node, closureName, compiler, element); |
| 1022 // Extend [globalizedElement] as an instantiated class in the closed world. | 1002 // Extend [globalizedElement] as an instantiated class in the closed world. |
| 1023 compiler.world.registerClass( | 1003 compiler.world |
| 1024 globalizedElement, isDirectlyInstantiated: true); | 1004 .registerClass(globalizedElement, isDirectlyInstantiated: true); |
| 1025 FunctionElement callElement = | 1005 FunctionElement callElement = new SynthesizedCallMethodElementX( |
| 1026 new SynthesizedCallMethodElementX(Identifiers.call, | 1006 Identifiers.call, element, globalizedElement); |
| 1027 element, | |
| 1028 globalizedElement); | |
| 1029 backend.maybeMarkClosureAsNeededForReflection( | 1007 backend.maybeMarkClosureAsNeededForReflection( |
| 1030 globalizedElement, callElement, element); | 1008 globalizedElement, callElement, element); |
| 1031 MemberElement enclosing = element.memberContext; | 1009 MemberElement enclosing = element.memberContext; |
| 1032 enclosing.nestedClosures.add(callElement); | 1010 enclosing.nestedClosures.add(callElement); |
| 1033 globalizedElement.addMember(callElement, reporter); | 1011 globalizedElement.addMember(callElement, reporter); |
| 1034 globalizedElement.computeAllClassMembers(compiler); | 1012 globalizedElement.computeAllClassMembers(compiler); |
| 1035 // The nested function's 'this' is the same as the one for the outer | 1013 // The nested function's 'this' is the same as the one for the outer |
| 1036 // function. It could be [null] if we are inside a static method. | 1014 // function. It could be [null] if we are inside a static method. |
| 1037 ThisLocal thisElement = closureData.thisLocal; | 1015 ThisLocal thisElement = closureData.thisLocal; |
| 1038 | 1016 |
| 1039 return new ClosureClassMap(element, globalizedElement, | 1017 return new ClosureClassMap( |
| 1040 callElement, thisElement); | 1018 element, globalizedElement, callElement, thisElement); |
| 1041 } | 1019 } |
| 1042 | 1020 |
| 1043 void visitInvokable(ExecutableElement element, | 1021 void visitInvokable( |
| 1044 Node node, | 1022 ExecutableElement element, Node node, void visitChildren()) { |
| 1045 void visitChildren()) { | |
| 1046 bool oldInsideClosure = insideClosure; | 1023 bool oldInsideClosure = insideClosure; |
| 1047 Element oldFunctionElement = executableContext; | 1024 Element oldFunctionElement = executableContext; |
| 1048 ClosureClassMap oldClosureData = closureData; | 1025 ClosureClassMap oldClosureData = closureData; |
| 1049 | 1026 |
| 1050 insideClosure = outermostElement != null; | 1027 insideClosure = outermostElement != null; |
| 1051 LocalFunctionElement closure; | 1028 LocalFunctionElement closure; |
| 1052 executableContext = element; | 1029 executableContext = element; |
| 1053 if (insideClosure) { | 1030 if (insideClosure) { |
| 1054 closure = element; | 1031 closure = element; |
| 1055 closures.add(node); | 1032 closures.add(node); |
| 1056 closureData = globalizeClosure(node, closure); | 1033 closureData = globalizeClosure(node, closure); |
| 1057 } else { | 1034 } else { |
| 1058 outermostElement = element; | 1035 outermostElement = element; |
| 1059 ThisLocal thisElement = null; | 1036 ThisLocal thisElement = null; |
| 1060 if (element.isInstanceMember || element.isGenerativeConstructor) { | 1037 if (element.isInstanceMember || element.isGenerativeConstructor) { |
| 1061 thisElement = new ThisLocal(element); | 1038 thisElement = new ThisLocal(element); |
| 1062 } | 1039 } |
| 1063 closureData = new ClosureClassMap(null, null, null, thisElement); | 1040 closureData = new ClosureClassMap(null, null, null, thisElement); |
| 1064 } | 1041 } |
| 1065 closureMappingCache[node] = closureData; | 1042 closureMappingCache[node] = closureData; |
| 1066 | 1043 |
| 1067 inNewScope(node, () { | 1044 inNewScope(node, () { |
| 1068 DartType type = element.type; | 1045 DartType type = element.type; |
| 1069 // If the method needs RTI, or checked mode is set, we need to | 1046 // If the method needs RTI, or checked mode is set, we need to |
| 1070 // escape the potential type variables used in that closure. | 1047 // escape the potential type variables used in that closure. |
| 1071 if (element is FunctionElement && | 1048 if (element is FunctionElement && |
| 1072 (compiler.backend.methodNeedsRti(element) || | 1049 (compiler.backend.methodNeedsRti(element) || |
| 1073 compiler.options.enableTypeAssertions)) { | 1050 compiler.options.enableTypeAssertions)) { |
| 1074 analyzeTypeVariables(type); | 1051 analyzeTypeVariables(type); |
| 1075 } | 1052 } |
| 1076 | 1053 |
| 1077 visitChildren(); | 1054 visitChildren(); |
| 1078 }); | 1055 }); |
| 1079 | 1056 |
| 1080 | |
| 1081 ClosureClassMap savedClosureData = closureData; | 1057 ClosureClassMap savedClosureData = closureData; |
| 1082 bool savedInsideClosure = insideClosure; | 1058 bool savedInsideClosure = insideClosure; |
| 1083 | 1059 |
| 1084 // Restore old values. | 1060 // Restore old values. |
| 1085 insideClosure = oldInsideClosure; | 1061 insideClosure = oldInsideClosure; |
| 1086 closureData = oldClosureData; | 1062 closureData = oldClosureData; |
| 1087 executableContext = oldFunctionElement; | 1063 executableContext = oldFunctionElement; |
| 1088 | 1064 |
| 1089 // Mark all free variables as captured and use them in the outer function. | 1065 // Mark all free variables as captured and use them in the outer function. |
| 1090 Iterable<Local> freeVariables = savedClosureData.freeVariables; | 1066 Iterable<Local> freeVariables = savedClosureData.freeVariables; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1162 /// | 1138 /// |
| 1163 /// Move the below classes to a JS model eventually. | 1139 /// Move the below classes to a JS model eventually. |
| 1164 /// | 1140 /// |
| 1165 abstract class JSEntity implements Entity { | 1141 abstract class JSEntity implements Entity { |
| 1166 Entity get declaredEntity; | 1142 Entity get declaredEntity; |
| 1167 } | 1143 } |
| 1168 | 1144 |
| 1169 abstract class PrivatelyNamedJSEntity implements JSEntity { | 1145 abstract class PrivatelyNamedJSEntity implements JSEntity { |
| 1170 Entity get rootOfScope; | 1146 Entity get rootOfScope; |
| 1171 } | 1147 } |
| OLD | NEW |