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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart

Issue 1221333015: dart2js: Move field-visiting code to the program-builder. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Change order. Created 5 years, 5 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of dart2js.js_emitter.program_builder;
floitsch 2015/07/08 11:09:46 This file has practically no new code. (Except for
6
7 /**
8 * [member] is a field (instance, static, or top level).
9 *
10 * [name] is the field name that the [Namer] has picked for this field's
11 * storage, that is, the JavaScript property name.
12 *
13 * [accessorName] is the name of the accessor. For instance fields this is
14 * mostly the same as [name] except when [member] is shadowing a field in its
15 * superclass. For other fields, they are rarely the same.
16 *
17 * [needsGetter] and [needsSetter] represent if a getter or a setter
18 * respectively is needed. There are many factors in this, for example, if the
19 * accessor can be inlined.
20 *
21 * [needsCheckedSetter] indicates that a checked getter is needed, and in this
22 * case, [needsSetter] is always false. [needsCheckedSetter] is only true when
23 * type assertions are enabled (checked mode).
24 */
25 typedef void AcceptField(VariableElement member,
26 js.Name name,
27 js.Name accessorName,
28 bool needsGetter,
29 bool needsSetter,
30 bool needsCheckedSetter);
31
32
33 class FieldVisitor {
34 final Compiler compiler;
35 final Namer namer;
36
37 JavaScriptBackend get backend => compiler.backend;
38
39 FieldVisitor(this.compiler, this.namer);
40
41 /**
42 * Invokes [f] for each of the fields of [element].
43 *
44 * [element] must be a [ClassElement] or a [LibraryElement].
45 *
46 * If [element] is a [ClassElement], the static fields of the class are
47 * visited if [visitStatics] is true and the instance fields are visited if
48 * [visitStatics] is false.
49 *
50 * If [element] is a [LibraryElement], [visitStatics] must be true.
51 *
52 * When visiting the instance fields of a class, the fields of its superclass
53 * are also visited if the class is instantiated.
54 *
55 * Invariant: [element] must be a declaration element.
56 */
57 void visitFields(Element element, bool visitStatics, AcceptField f) {
58 assert(invariant(element, element.isDeclaration));
59
60 bool isClass = false;
61 bool isLibrary = false;
62 if (element.isClass) {
63 isClass = true;
64 } else if (element.isLibrary) {
65 isLibrary = true;
66 assert(invariant(element, visitStatics));
67 } else {
68 throw new SpannableAssertionFailure(
69 element, 'Expected a ClassElement or a LibraryElement.');
70 }
71
72 // If the class is never instantiated we still need to set it up for
73 // inheritance purposes, but we can simplify its JavaScript constructor.
74 bool isInstantiated =
75 compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
76
77 void visitField(Element holder, FieldElement field) {
78 assert(invariant(element, field.isDeclaration));
79
80 // Keep track of whether or not we're dealing with a field mixin
81 // into a native class.
82 bool isMixinNativeField =
83 isClass && element.isNative && holder.isMixinApplication;
84
85 // See if we can dynamically create getters and setters.
86 // We can only generate getters and setters for [element] since
87 // the fields of super classes could be overwritten with getters or
88 // setters.
89 bool needsGetter = false;
90 bool needsSetter = false;
91 if (isLibrary || isMixinNativeField || holder == element) {
92 needsGetter = fieldNeedsGetter(field);
93 needsSetter = fieldNeedsSetter(field);
94 }
95
96 if ((isInstantiated && !holder.isNative)
97 || needsGetter
98 || needsSetter) {
99 js.Name accessorName = namer.fieldAccessorName(field);
100 js.Name fieldName = namer.fieldPropertyName(field);
101 bool needsCheckedSetter = false;
102 if (compiler.enableTypeAssertions
103 && needsSetter
104 && !canAvoidGeneratedCheckedSetter(field)) {
105 needsCheckedSetter = true;
106 needsSetter = false;
107 }
108 // Getters and setters with suffixes will be generated dynamically.
109 f(field, fieldName, accessorName, needsGetter, needsSetter,
110 needsCheckedSetter);
111 }
112 }
113
114 if (isLibrary) {
115 LibraryElement library = element;
116 library.implementation.forEachLocalMember((Element member) {
117 if (member.isField) visitField(library, member);
118 });
119 } else if (visitStatics) {
120 ClassElement cls = element;
121 cls.implementation.forEachStaticField(visitField);
122 } else {
123 ClassElement cls = element;
124 // TODO(kasperl): We should make sure to only emit one version of
125 // overridden fields. Right now, we rely on the ordering so the
126 // fields pulled in from mixins are replaced with the fields from
127 // the class definition.
128
129 // If a class is not instantiated then we add the field just so we can
130 // generate the field getter/setter dynamically. Since this is only
131 // allowed on fields that are in [element] we don't need to visit
132 // superclasses for non-instantiated classes.
133 cls.implementation.forEachInstanceField(
134 visitField, includeSuperAndInjectedMembers: isInstantiated);
135 }
136 }
137
138 bool fieldNeedsGetter(VariableElement field) {
139 assert(field.isField);
140 if (fieldAccessNeverThrows(field)) return false;
141 if (backend.shouldRetainGetter(field)) return true;
142 return field.isClassMember &&
143 compiler.codegenWorld.hasInvokedGetter(field, compiler.world);
144 }
145
146 bool fieldNeedsSetter(VariableElement field) {
147 assert(field.isField);
148 if (fieldAccessNeverThrows(field)) return false;
149 if (field.isFinal || field.isConst) return false;
150 if (backend.shouldRetainSetter(field)) return true;
151 return field.isClassMember &&
152 compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
153 }
154
155 static bool fieldAccessNeverThrows(VariableElement field) {
156 return
157 // We never access a field in a closure (a captured variable) without
158 // knowing that it is there. Therefore we don't need to use a getter
159 // (that will throw if the getter method is missing), but can always
160 // access the field directly.
161 field is ClosureFieldElement;
162 }
163
164 bool canAvoidGeneratedCheckedSetter(VariableElement member) {
165 // We never generate accessors for top-level/static fields.
166 if (!member.isInstanceMember) return true;
167 DartType type = member.type;
168 return type.treatAsDynamic || (type.element == compiler.objectClass);
169 }
170 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698