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

Unified Diff: sdk/lib/_internal/compiler/implementation/closure.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/closure.dart
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
deleted file mode 100644
index fc789509c25667936c296ef5b04cf27337a9061e..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ /dev/null
@@ -1,1031 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library closureToClassMapper;
-
-import "elements/elements.dart";
-import "dart2jslib.dart";
-import "dart_types.dart";
-import "js_backend/js_backend.dart" show JavaScriptBackend;
-import "scanner/scannerlib.dart" show Token;
-import "tree/tree.dart";
-import "util/util.dart";
-import "elements/modelx.dart"
- show BaseFunctionElementX,
- ClassElementX,
- ElementX,
- LocalFunctionElementX;
-import "elements/visitor.dart" show ElementVisitor;
-
-import 'universe/universe.dart' show
- Universe;
-
-class ClosureNamer {
- String getClosureVariableName(String name, int id) {
- return "${name}_$id";
- }
-
- void forgetElement(Element element) {}
-}
-
-class ClosureTask extends CompilerTask {
- Map<Node, ClosureClassMap> closureMappingCache;
- ClosureNamer namer;
- ClosureTask(Compiler compiler, this.namer)
- : closureMappingCache = new Map<Node, ClosureClassMap>(),
- super(compiler);
-
- String get name => "Closure Simplifier";
-
- ClosureClassMap computeClosureToClassMapping(Element element,
- Node node,
- TreeElements elements) {
- return measure(() {
- ClosureClassMap cached = closureMappingCache[node];
- if (cached != null) return cached;
-
- ClosureTranslator translator =
- new ClosureTranslator(compiler, elements, closureMappingCache, namer);
-
- // The translator will store the computed closure-mappings inside the
- // cache. One for given node and one for each nested closure.
- if (node is FunctionExpression) {
- translator.translateFunction(element, node);
- } else if (element.isSynthesized) {
- return new ClosureClassMap(null, null, null, new ThisLocal(element));
- } else {
- assert(element.isField);
- VariableElement field = element;
- if (field.initializer != null) {
- // The lazy initializer of a static.
- translator.translateLazyInitializer(element, node, field.initializer);
- } else {
- assert(element.isInstanceMember);
- closureMappingCache[node] =
- new ClosureClassMap(null, null, null, new ThisLocal(element));
- }
- }
- assert(closureMappingCache[node] != null);
- return closureMappingCache[node];
- });
- }
-
- ClosureClassMap getMappingForNestedFunction(FunctionExpression node) {
- return measure(() {
- ClosureClassMap nestedClosureData = closureMappingCache[node];
- if (nestedClosureData == null) {
- compiler.internalError(node, "No closure cache.");
- }
- return nestedClosureData;
- });
- }
-
- void forgetElement(var closure) {
- ClosureClassElement cls;
- if (closure is ClosureFieldElement) {
- cls = closure.closureClass;
- } else if (closure is SynthesizedCallMethodElementX) {
- cls = closure.closureClass;
- } else {
- throw new SpannableAssertionFailure(
- closure, 'Not a closure: $closure (${closure.runtimeType}).');
- }
- namer.forgetElement(cls);
- compiler.enqueuer.codegen.forgetElement(cls);
- }
-}
-
-/// Common interface for [BoxFieldElement] and [ClosureFieldElement] as
-/// non-elements.
-abstract class CapturedVariable {}
-
-// TODO(ahe): These classes continuously cause problems. We need to
-// find a more general solution.
-class ClosureFieldElement extends ElementX
- implements VariableElement, CapturedVariable {
- /// The source variable this element refers to.
- final Local local;
-
- ClosureFieldElement(String name,
- this.local,
- ClosureClassElement enclosing)
- : super(name, ElementKind.FIELD, enclosing);
-
- /// Use [closureClass] instead.
- @deprecated
- get enclosingElement => super.enclosingElement;
-
- ClosureClassElement get closureClass => super.enclosingElement;
-
- MemberElement get memberContext => closureClass.methodElement.memberContext;
-
- bool get hasNode => false;
-
- Node get node {
- throw new SpannableAssertionFailure(local,
- 'Should not access node of ClosureFieldElement.');
- }
-
- bool get hasResolvedAst => hasTreeElements;
-
- ResolvedAst get resolvedAst {
- return new ResolvedAst(this, null, treeElements);
- }
-
- Expression get initializer {
- throw new SpannableAssertionFailure(local,
- 'Should not access initializer of ClosureFieldElement.');
- }
-
- bool get isInstanceMember => true;
- bool get isAssignable => false;
-
- DartType computeType(Compiler compiler) => type;
-
- DartType get type {
- if (local is LocalElement) {
- LocalElement element = local;
- return element.type;
- }
- return const DynamicType();
- }
-
- String toString() => "ClosureFieldElement($name)";
-
- accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this);
-
- Element get analyzableElement => closureClass.methodElement.analyzableElement;
-}
-
-// TODO(ahe): These classes continuously cause problems. We need to find
-// a more general solution.
-class ClosureClassElement extends ClassElementX {
- DartType rawType;
- DartType thisType;
- FunctionType callType;
- /// Node that corresponds to this closure, used for source position.
- final FunctionExpression node;
-
- /**
- * The element for the declaration of the function expression.
- */
- final LocalFunctionElement methodElement;
-
- final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[];
-
- ClosureClassElement(this.node,
- String name,
- Compiler compiler,
- LocalFunctionElement closure)
- : this.methodElement = closure,
- super(name,
- closure.compilationUnit,
- // By assigning a fresh class-id we make sure that the hashcode
- // is unique, but also emit closure classes after all other
- // classes (since the emitter sorts classes by their id).
- compiler.getNextFreeClassId(),
- STATE_DONE) {
- JavaScriptBackend backend = compiler.backend;
- ClassElement superclass = methodElement.isInstanceMember
- ? backend.boundClosureClass
- : backend.closureClass;
- superclass.ensureResolved(compiler);
- supertype = superclass.thisType;
- interfaces = const Link<DartType>();
- thisType = rawType = new InterfaceType(this);
- allSupertypesAndSelf =
- superclass.allSupertypesAndSelf.extendClass(thisType);
- callType = methodElement.type;
- }
-
- Iterable<ClosureFieldElement> get closureFields => _closureFields;
-
- void addField(ClosureFieldElement field, DiagnosticListener listener) {
- _closureFields.add(field);
- addMember(field, listener);
- }
-
- bool get hasNode => true;
-
- bool get isClosure => true;
-
- Token get position => node.getBeginToken();
-
- Node parseNode(DiagnosticListener listener) => node;
-
- // A [ClosureClassElement] is nested inside a function or initializer in terms
- // of [enclosingElement], but still has to be treated as a top-level
- // element.
- bool get isTopLevel => true;
-
- get enclosingElement => methodElement;
-
- accept(ElementVisitor visitor) => visitor.visitClosureClassElement(this);
-}
-
-/// A local variable that contains the box object holding the [BoxFieldElement]
-/// fields.
-class BoxLocal extends Local {
- final String name;
- final ExecutableElement executableContext;
-
- BoxLocal(this.name, this.executableContext);
-}
-
-// TODO(ngeoffray, ahe): These classes continuously cause problems. We need to
-// find a more general solution.
-class BoxFieldElement extends ElementX
- implements TypedElement, CapturedVariable {
- final BoxLocal box;
-
- BoxFieldElement(String name, this.variableElement, BoxLocal box)
- : this.box = box,
- super(name, ElementKind.FIELD, box.executableContext);
-
- DartType computeType(Compiler compiler) => type;
-
- DartType get type => variableElement.type;
-
- final VariableElement variableElement;
-
- accept(ElementVisitor visitor) => visitor.visitBoxFieldElement(this);
-}
-
-/// A local variable used encode the direct (uncaptured) references to [this].
-class ThisLocal extends Local {
- final ExecutableElement executableContext;
-
- ThisLocal(this.executableContext);
-
- String get name => 'this';
-
- ClassElement get enclosingClass => executableContext.enclosingClass;
-}
-
-/// Call method of a closure class.
-class SynthesizedCallMethodElementX extends BaseFunctionElementX {
- final LocalFunctionElement expression;
-
- SynthesizedCallMethodElementX(String name,
- LocalFunctionElementX other,
- ClosureClassElement enclosing)
- : expression = other,
- super(name, other.kind, other.modifiers, enclosing, false) {
- functionSignatureCache = other.functionSignature;
- }
-
- /// Use [closureClass] instead.
- @deprecated
- get enclosingElement => super.enclosingElement;
-
- ClosureClassElement get closureClass => super.enclosingElement;
-
- MemberElement get memberContext {
- return closureClass.methodElement.memberContext;
- }
-
- bool get hasNode => expression.hasNode;
-
- FunctionExpression get node => expression.node;
-
- FunctionExpression parseNode(DiagnosticListener listener) => node;
-
- ResolvedAst get resolvedAst {
- return new ResolvedAst(this, node, treeElements);
- }
-
- Element get analyzableElement => closureClass.methodElement.analyzableElement;
-}
-
-// The box-element for a scope, and the captured variables that need to be
-// stored in the box.
-class ClosureScope {
- BoxLocal boxElement;
- Map<VariableElement, BoxFieldElement> _capturedVariableMapping;
-
- // If the scope is attached to a [For] contains the variables that are
- // declared in the initializer of the [For] and that need to be boxed.
- // Otherwise contains the empty List.
- List<VariableElement> boxedLoopVariables = const <VariableElement>[];
-
- ClosureScope(this.boxElement, this._capturedVariableMapping);
-
- bool hasBoxedLoopVariables() => !boxedLoopVariables.isEmpty;
-
- bool isCapturedVariable(VariableElement variable) {
- return _capturedVariableMapping.containsKey(variable);
- }
-
- void forEachCapturedVariable(f(LocalVariableElement variable,
- BoxFieldElement boxField)) {
- _capturedVariableMapping.forEach(f);
- }
-}
-
-class ClosureClassMap {
- // The closure's element before any translation. Will be null for methods.
- final LocalFunctionElement closureElement;
- // The closureClassElement will be null for methods that are not local
- // closures.
- final ClosureClassElement closureClassElement;
- // The callElement will be null for methods that are not local closures.
- final FunctionElement callElement;
- // The [thisElement] makes handling 'this' easier by treating it like any
- // other argument. It is only set for instance-members.
- final ThisLocal thisLocal;
-
- // Maps free locals, arguments and function elements to their captured
- // copies.
- final Map<Local, CapturedVariable> _freeVariableMapping =
- new Map<Local, CapturedVariable>();
-
- // Maps closure-fields to their captured elements. This is somehow the inverse
- // mapping of [freeVariableMapping], but whereas [freeVariableMapping] does
- // not deal with boxes, here we map instance-fields (which might represent
- // boxes) to their boxElement.
- final Map<ClosureFieldElement, Local> _closureFieldMapping =
- new Map<ClosureFieldElement, Local>();
-
- // Maps scopes ([Loop] and [FunctionExpression] nodes) to their
- // [ClosureScope] which contains their box and the
- // captured variables that are stored in the box.
- // This map will be empty if the method/closure of this [ClosureData] does not
- // contain any nested closure.
- final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>();
-
- final Set<Local> usedVariablesInTry = new Set<Local>();
-
- ClosureClassMap(this.closureElement,
- this.closureClassElement,
- this.callElement,
- this.thisLocal);
-
- void addFreeVariable(Local element) {
- assert(_freeVariableMapping[element] == null);
- _freeVariableMapping[element] = null;
- }
-
- Iterable<Local> get freeVariables => _freeVariableMapping.keys;
-
- bool isFreeVariable(Local element) {
- return _freeVariableMapping.containsKey(element);
- }
-
- CapturedVariable getFreeVariableElement(Local element) {
- return _freeVariableMapping[element];
- }
-
- /// Sets the free [variable] to be captured by the [boxField].
- void setFreeVariableBoxField(Local variable,
- BoxFieldElement boxField) {
- _freeVariableMapping[variable] = boxField;
- }
-
- /// Sets the free [variable] to be captured by the [closureField].
- void setFreeVariableClosureField(Local variable,
- ClosureFieldElement closureField) {
- _freeVariableMapping[variable] = closureField;
- }
-
-
- void forEachFreeVariable(f(Local variable,
- CapturedVariable field)) {
- _freeVariableMapping.forEach(f);
- }
-
- Local getLocalVariableForClosureField(ClosureFieldElement field) {
- return _closureFieldMapping[field];
- }
-
- void setLocalVariableForClosureField(ClosureFieldElement field,
- Local variable) {
- _closureFieldMapping[field] = variable;
- }
-
- bool get isClosure => closureElement != null;
-
- bool capturingScopesBox(Local variable) {
- return capturingScopes.values.any((scope) {
- return scope.boxedLoopVariables.contains(variable);
- });
- }
-
- bool isVariableBoxed(Local variable) {
- CapturedVariable copy = _freeVariableMapping[variable];
- if (copy is BoxFieldElement) {
- return true;
- }
- return capturingScopesBox(variable);
- }
-
- void forEachCapturedVariable(void f(Local variable,
- CapturedVariable field)) {
- _freeVariableMapping.forEach((variable, copy) {
- if (variable is BoxLocal) return;
- f(variable, copy);
- });
- capturingScopes.values.forEach((ClosureScope scope) {
- scope.forEachCapturedVariable(f);
- });
- }
-
- void forEachBoxedVariable(void f(LocalVariableElement local,
- BoxFieldElement field)) {
- _freeVariableMapping.forEach((variable, copy) {
- if (!isVariableBoxed(variable)) return;
- f(variable, copy);
- });
- capturingScopes.values.forEach((ClosureScope scope) {
- scope.forEachCapturedVariable(f);
- });
- }
-
- void removeMyselfFrom(Universe universe) {
- _freeVariableMapping.values.forEach((e) {
- universe.closurizedMembers.remove(e);
- universe.fieldSetters.remove(e);
- universe.fieldGetters.remove(e);
- });
- }
-}
-
-class ClosureTranslator extends Visitor {
- final Compiler compiler;
- final TreeElements elements;
- int closureFieldCounter = 0;
- int boxedFieldCounter = 0;
- bool inTryStatement = false;
- final Map<Node, ClosureClassMap> closureMappingCache;
-
- // Map of captured variables. Initially they will map to `null`. If
- // a variable needs to be boxed then the scope declaring the variable
- // will update this to mapping to the capturing [BoxFieldElement].
- Map<Local, BoxFieldElement> _capturedVariableMapping =
- new Map<Local, BoxFieldElement>();
-
- // List of encountered closures.
- List<Expression> closures = <Expression>[];
-
- // The local variables that have been declared in the current scope.
- List<LocalVariableElement> scopeVariables;
-
- // Keep track of the mutated local variables so that we don't need to box
- // non-mutated variables.
- Set<LocalVariableElement> mutatedVariables = new Set<LocalVariableElement>();
-
- MemberElement outermostElement;
- ExecutableElement executableContext;
-
- // The closureData of the currentFunctionElement.
- ClosureClassMap closureData;
-
- ClosureNamer namer;
-
- bool insideClosure = false;
-
- ClosureTranslator(this.compiler,
- this.elements,
- this.closureMappingCache,
- this.namer);
-
- bool isCapturedVariable(Local element) {
- return _capturedVariableMapping.containsKey(element);
- }
-
- void addCapturedVariable(Node node, Local variable) {
- if (_capturedVariableMapping[variable] != null) {
- compiler.internalError(node, 'In closure analyzer.');
- }
- _capturedVariableMapping[variable] = null;
- }
-
- void setCapturedVariableBoxField(Local variable,
- BoxFieldElement boxField) {
- assert(isCapturedVariable(variable));
- _capturedVariableMapping[variable] = boxField;
- }
-
- BoxFieldElement getCapturedVariableBoxField(Local variable) {
- return _capturedVariableMapping[variable];
- }
-
- void translateFunction(Element element, FunctionExpression node) {
- // For constructors the [element] and the [:elements[node]:] may differ.
- // The [:elements[node]:] always points to the generative-constructor
- // element, whereas the [element] might be the constructor-body element.
- visit(node); // [visitFunctionExpression] will call [visitInvokable].
- // When variables need to be boxed their [_capturedVariableMapping] is
- // updated, but we delay updating the similar freeVariableMapping in the
- // closure datas that capture these variables.
- // The closures don't have their fields (in the closure class) set, either.
- updateClosures();
- }
-
- void translateLazyInitializer(VariableElement element,
- VariableDefinitions node,
- Expression initializer) {
- visitInvokable(element, node, () { visit(initializer); });
- updateClosures();
- }
-
- // This function runs through all of the existing closures and updates their
- // free variables to the boxed value. It also adds the field-elements to the
- // class representing the closure.
- void updateClosures() {
- for (Expression closure in closures) {
- // The captured variables that need to be stored in a field of the closure
- // class.
- Set<Local> fieldCaptures = new Set<Local>();
- Set<BoxLocal> boxes = new Set<BoxLocal>();
- ClosureClassMap data = closureMappingCache[closure];
- // We get a copy of the keys and iterate over it, to avoid modifications
- // to the map while iterating over it.
- Iterable<Local> freeVariables = data.freeVariables.toList();
- freeVariables.forEach((Local fromElement) {
- assert(data.isFreeVariable(fromElement));
- assert(data.getFreeVariableElement(fromElement) == null);
- assert(isCapturedVariable(fromElement));
- BoxFieldElement boxFieldElement =
- getCapturedVariableBoxField(fromElement);
- if (boxFieldElement == null) {
- assert(fromElement is! BoxLocal);
- // The variable has not been boxed.
- fieldCaptures.add(fromElement);
- } else {
- // A boxed element.
- data.setFreeVariableBoxField(fromElement, boxFieldElement);
- boxes.add(boxFieldElement.box);
- }
- });
- ClosureClassElement closureClass = data.closureClassElement;
- assert(closureClass != null ||
- (fieldCaptures.isEmpty && boxes.isEmpty));
-
- void addClosureField(Local local, String name) {
- ClosureFieldElement closureField =
- new ClosureFieldElement(name, local, closureClass);
- closureClass.addField(closureField, compiler);
- data.setLocalVariableForClosureField(closureField, local);
- data.setFreeVariableClosureField(local, closureField);
- }
-
- // Add the box elements first so we get the same ordering.
- // TODO(sra): What is the canonical order of multiple boxes?
- for (BoxLocal capturedElement in boxes) {
- addClosureField(capturedElement, capturedElement.name);
- }
-
- /// Comparator for locals. Position boxes before elements.
- int compareLocals(a, b) {
- if (a is Element && b is Element) {
- return Elements.compareByPosition(a, b);
- } else if (a is Element) {
- return 1;
- } else if (b is Element) {
- return -1;
- } else {
- return a.name.compareTo(b.name);
- }
- }
-
- for (Local capturedLocal in fieldCaptures.toList()..sort(compareLocals)) {
- int id = closureFieldCounter++;
- String name = namer.getClosureVariableName(capturedLocal.name, id);
- addClosureField(capturedLocal, name);
- }
- closureClass.reverseBackendMembers();
- }
- }
-
- void useLocal(Local variable) {
- // If the element is not declared in the current function and the element
- // is not the closure itself we need to mark the element as free variable.
- // Note that the check on [insideClosure] is not just an
- // optimization: factories have type parameters as function
- // parameters, and type parameters are declared in the class, not
- // the factory.
- bool inCurrentContext(Local variable) {
- return variable == executableContext ||
- variable.executableContext == executableContext;
- }
-
- if (insideClosure && !inCurrentContext(variable)) {
- closureData.addFreeVariable(variable);
- } else if (inTryStatement) {
- // Don't mark the this-element or a self-reference. This would complicate
- // things in the builder.
- // Note that nested (named) functions are immutable.
- if (variable != closureData.thisLocal &&
- variable != closureData.closureElement) {
- // TODO(ngeoffray): only do this if the variable is mutated.
- closureData.usedVariablesInTry.add(variable);
- }
- }
- }
-
- void useTypeVariableAsLocal(TypeVariableType typeVariable) {
- useLocal(new TypeVariableLocal(typeVariable, outermostElement));
- }
-
- void declareLocal(LocalVariableElement element) {
- scopeVariables.add(element);
- }
-
- void registerNeedsThis() {
- if (closureData.thisLocal != null) {
- useLocal(closureData.thisLocal);
- }
- }
-
- visit(Node node) => node.accept(this);
-
- visitNode(Node node) => node.visitChildren(this);
-
- visitVariableDefinitions(VariableDefinitions node) {
- if (node.type != null) {
- visit(node.type);
- }
- for (Link<Node> link = node.definitions.nodes;
- !link.isEmpty;
- link = link.tail) {
- Node definition = link.head;
- LocalElement element = elements[definition];
- assert(element != null);
- if (!element.isInitializingFormal) {
- declareLocal(element);
- }
- // We still need to visit the right-hand sides of the init-assignments.
- // For SendSets don't visit the left again. Otherwise it would be marked
- // as mutated.
- if (definition is Send) {
- Send assignment = definition;
- Node arguments = assignment.argumentsNode;
- if (arguments != null) {
- visit(arguments);
- }
- } else {
- visit(definition);
- }
- }
- }
-
- visitTypeAnnotation(TypeAnnotation node) {
- MemberElement member = executableContext.memberContext;
- DartType type = elements.getType(node);
- // TODO(karlklose,johnniwinther): if the type is null, the annotation is
- // from a parameter which has been analyzed before the method has been
- // resolved and the result has been thrown away.
- if (compiler.enableTypeAssertions && type != null &&
- type.containsTypeVariables) {
- if (insideClosure && member.isFactoryConstructor) {
- // This is a closure in a factory constructor. Since there is no
- // [:this:], we have to mark the type arguments as free variables to
- // capture them in the closure.
- type.forEachTypeVariable((TypeVariableType variable) {
- useTypeVariableAsLocal(variable);
- });
- }
- if (member.isInstanceMember && !member.isField) {
- // In checked mode, using a type variable in a type annotation may lead
- // to a runtime type check that needs to access the type argument and
- // therefore the closure needs a this-element, if it is not in a field
- // initializer; field initatializers are evaluated in a context where
- // the type arguments are available in locals.
- registerNeedsThis();
- }
- }
- }
-
- visitIdentifier(Identifier node) {
- if (node.isThis()) {
- registerNeedsThis();
- } else {
- Element element = elements[node];
- if (element != null && element.isTypeVariable) {
- if (outermostElement.isConstructor) {
- TypeVariableElement typeVariable = element;
- useTypeVariableAsLocal(typeVariable.type);
- } else {
- registerNeedsThis();
- }
- }
- }
- node.visitChildren(this);
- }
-
- visitSend(Send node) {
- Element element = elements[node];
- if (Elements.isLocal(element)) {
- LocalElement localElement = element;
- useLocal(localElement);
- } else if (element != null && element.isTypeVariable) {
- TypeVariableElement variable = element;
- analyzeType(variable.type);
- } else if (node.receiver == null &&
- Elements.isInstanceSend(node, elements)) {
- registerNeedsThis();
- } else if (node.isSuperCall) {
- registerNeedsThis();
- } else if (node.isTypeTest || node.isTypeCast) {
- TypeAnnotation annotation = node.typeAnnotationFromIsCheckOrCast;
- DartType type = elements.getType(annotation);
- analyzeType(type);
- } else if (node.isTypeTest) {
- DartType type = elements.getType(node.typeAnnotationFromIsCheckOrCast);
- analyzeType(type);
- } else if (node.isTypeCast) {
- DartType type = elements.getType(node.arguments.head);
- analyzeType(type);
- } else if (elements.isAssert(node) && !compiler.enableUserAssertions) {
- return;
- }
- node.visitChildren(this);
- }
-
- visitSendSet(SendSet node) {
- Element element = elements[node];
- if (Elements.isLocal(element)) {
- mutatedVariables.add(element);
- if (compiler.enableTypeAssertions) {
- TypedElement typedElement = element;
- analyzeTypeVariables(typedElement.type);
- }
- }
- super.visitSendSet(node);
- }
-
- visitNewExpression(NewExpression node) {
- DartType type = elements.getType(node);
- analyzeType(type);
- node.visitChildren(this);
- }
-
- void analyzeTypeVariables(DartType type) {
- type.forEachTypeVariable((TypeVariableType typeVariable) {
- // Field initializers are inlined and access the type variable as
- // normal parameters.
- if (!outermostElement.isField &&
- !outermostElement.isConstructor) {
- registerNeedsThis();
- } else {
- useTypeVariableAsLocal(typeVariable);
- }
- });
- }
-
- void analyzeType(DartType type) {
- // TODO(johnniwinther): Find out why this can be null.
- if (type == null) return;
- if (outermostElement.isClassMember &&
- compiler.backend.classNeedsRti(outermostElement.enclosingClass)) {
- if (outermostElement.isConstructor ||
- outermostElement.isField) {
- analyzeTypeVariables(type);
- } else if (outermostElement.isInstanceMember) {
- if (type.containsTypeVariables) {
- registerNeedsThis();
- }
- }
- }
- }
-
- // If variables that are declared in the [node] scope are captured and need
- // to be boxed create a box-element and update the [capturingScopes] in the
- // current [closureData].
- // The boxed variables are updated in the [capturedVariableMapping].
- void attachCapturedScopeVariables(Node node) {
- BoxLocal box = null;
- Map<LocalVariableElement, BoxFieldElement> scopeMapping =
- new Map<LocalVariableElement, BoxFieldElement>();
-
- void boxCapturedVariable(LocalVariableElement variable) {
- if (isCapturedVariable(variable)) {
- if (box == null) {
- // TODO(floitsch): construct better box names.
- String boxName =
- namer.getClosureVariableName('box', closureFieldCounter++);
- box = new BoxLocal(boxName, executableContext);
- }
- String elementName = variable.name;
- String boxedName =
- namer.getClosureVariableName(elementName, boxedFieldCounter++);
- // TODO(kasperl): Should this be a FieldElement instead?
- BoxFieldElement boxed = new BoxFieldElement(boxedName, variable, box);
- // No need to rename the fields of a box, so we give them a native name
- // right now.
- boxed.setFixedBackendName(boxedName);
- scopeMapping[variable] = boxed;
- setCapturedVariableBoxField(variable, boxed);
- }
- }
-
- for (LocalVariableElement variable in scopeVariables) {
- // No need to box non-assignable elements.
- if (!variable.isAssignable) continue;
- if (!mutatedVariables.contains(variable)) continue;
- boxCapturedVariable(variable);
- }
- if (!scopeMapping.isEmpty) {
- ClosureScope scope = new ClosureScope(box, scopeMapping);
- closureData.capturingScopes[node] = scope;
- }
- }
-
- void inNewScope(Node node, Function action) {
- List<LocalVariableElement> oldScopeVariables = scopeVariables;
- scopeVariables = <LocalVariableElement>[];
- action();
- attachCapturedScopeVariables(node);
- mutatedVariables.removeAll(scopeVariables);
- scopeVariables = oldScopeVariables;
- }
-
- visitLoop(Loop node) {
- inNewScope(node, () {
- node.visitChildren(this);
- });
- }
-
- visitFor(For node) {
- visitLoop(node);
- // See if we have declared loop variables that need to be boxed.
- if (node.initializer == null) return;
- VariableDefinitions definitions = node.initializer.asVariableDefinitions();
- if (definitions == null) return;
- ClosureScope scopeData = closureData.capturingScopes[node];
- if (scopeData == null) return;
- List<LocalVariableElement> result = <LocalVariableElement>[];
- for (Link<Node> link = definitions.definitions.nodes;
- !link.isEmpty;
- link = link.tail) {
- Node definition = link.head;
- LocalVariableElement element = elements[definition];
- if (isCapturedVariable(element)) {
- result.add(element);
- }
- }
- scopeData.boxedLoopVariables = result;
- }
-
- /** Returns a non-unique name for the given closure element. */
- String computeClosureName(Element element) {
- Link<String> parts = const Link<String>();
- String ownName = element.name;
- if (ownName == null || ownName == "") {
- parts = parts.prepend("closure");
- } else {
- parts = parts.prepend(ownName);
- }
- for (Element enclosingElement = element.enclosingElement;
- enclosingElement != null &&
- (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY
- || enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR
- || enclosingElement.kind == ElementKind.CLASS
- || enclosingElement.kind == ElementKind.FUNCTION
- || enclosingElement.kind == ElementKind.GETTER
- || enclosingElement.kind == ElementKind.SETTER);
- enclosingElement = enclosingElement.enclosingElement) {
- // TODO(johnniwinther): Simplify computed names.
- if (enclosingElement.isGenerativeConstructor ||
- enclosingElement.isGenerativeConstructorBody ||
- enclosingElement.isFactoryConstructor) {
- parts = parts.prepend(
- Elements.reconstructConstructorName(enclosingElement));
- } else {
- String surroundingName =
- Elements.operatorNameToIdentifier(enclosingElement.name);
- parts = parts.prepend(surroundingName);
- }
- // A generative constructors's parent is the class; the class name is
- // already part of the generative constructor's name.
- if (enclosingElement.kind == ElementKind.GENERATIVE_CONSTRUCTOR) break;
- }
- StringBuffer sb = new StringBuffer();
- parts.printOn(sb, '_');
- return sb.toString();
- }
-
- JavaScriptBackend get backend => compiler.backend;
-
- ClosureClassMap globalizeClosure(FunctionExpression node,
- LocalFunctionElement element) {
- String closureName = computeClosureName(element);
- ClosureClassElement globalizedElement = new ClosureClassElement(
- node, closureName, compiler, element);
- FunctionElement callElement =
- new SynthesizedCallMethodElementX(Compiler.CALL_OPERATOR_NAME,
- element,
- globalizedElement);
- backend.maybeMarkClosureAsNeededForReflection(globalizedElement, callElement, element);
- MemberElement enclosing = element.memberContext;
- enclosing.nestedClosures.add(callElement);
- globalizedElement.addMember(callElement, compiler);
- globalizedElement.computeAllClassMembers(compiler);
- // The nested function's 'this' is the same as the one for the outer
- // function. It could be [null] if we are inside a static method.
- ThisLocal thisElement = closureData.thisLocal;
-
- return new ClosureClassMap(element, globalizedElement,
- callElement, thisElement);
- }
-
- void visitInvokable(ExecutableElement element,
- Node node,
- void visitChildren()) {
- bool oldInsideClosure = insideClosure;
- Element oldFunctionElement = executableContext;
- ClosureClassMap oldClosureData = closureData;
-
- insideClosure = outermostElement != null;
- LocalFunctionElement closure;
- executableContext = element;
- if (insideClosure) {
- closure = element;
- closures.add(node);
- closureData = globalizeClosure(node, closure);
- } else {
- outermostElement = element;
- ThisLocal thisElement = null;
- if (element.isInstanceMember || element.isGenerativeConstructor) {
- thisElement = new ThisLocal(element);
- }
- closureData = new ClosureClassMap(null, null, null, thisElement);
- }
- closureMappingCache[node] = closureData;
-
- inNewScope(node, () {
- DartType type = element.type;
- // If the method needs RTI, or checked mode is set, we need to
- // escape the potential type variables used in that closure.
- if (element is FunctionElement &&
- (compiler.backend.methodNeedsRti(element) ||
- compiler.enableTypeAssertions)) {
- analyzeTypeVariables(type);
- }
-
- visitChildren();
- });
-
-
- ClosureClassMap savedClosureData = closureData;
- bool savedInsideClosure = insideClosure;
-
- // Restore old values.
- insideClosure = oldInsideClosure;
- closureData = oldClosureData;
- executableContext = oldFunctionElement;
-
- // Mark all free variables as captured and use them in the outer function.
- Iterable<Local> freeVariables = savedClosureData.freeVariables;
- assert(freeVariables.isEmpty || savedInsideClosure);
- for (Local freeVariable in freeVariables) {
- addCapturedVariable(node, freeVariable);
- useLocal(freeVariable);
- }
- }
-
- visitFunctionExpression(FunctionExpression node) {
- Element element = elements[node];
-
- if (element.isParameter) {
- // TODO(ahe): This is a hack. This method should *not* call
- // visitChildren.
- return node.name.accept(this);
- }
-
- visitInvokable(element, node, () {
- // TODO(ahe): This is problematic. The backend should not repeat
- // the work of the resolver. It is the resolver's job to create
- // parameters, etc. Other phases should only visit statements.
- if (node.parameters != null) node.parameters.accept(this);
- if (node.initializers != null) node.initializers.accept(this);
- if (node.body != null) node.body.accept(this);
- });
- }
-
- visitTryStatement(TryStatement node) {
- // TODO(ngeoffray): implement finer grain state.
- bool oldInTryStatement = inTryStatement;
- inTryStatement = true;
- node.visitChildren(this);
- inTryStatement = oldInTryStatement;
- }
-}
-
-/// A type variable as a local variable.
-class TypeVariableLocal implements Local {
- final TypeVariableType typeVariable;
- final ExecutableElement executableContext;
-
- TypeVariableLocal(this.typeVariable, this.executableContext);
-
- String get name => typeVariable.name;
-
- int get hashCode => typeVariable.hashCode;
-
- bool operator ==(other) {
- if (other is! TypeVariableLocal) return false;
- return typeVariable == other.typeVariable;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698