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

Side by Side Diff: pkg/compiler/lib/src/js_backend/field_naming_mixin.dart

Issue 1209973002: dart2js: Extract minified field naming into mixin. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Comments 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/js_backend.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 js_backend;
6
7 abstract class _MinifiedFieldNamer implements Namer {
8 _FieldNamingRegistry get fieldRegistry;
9
10 // Returns a minimal name for the field that is globally unique along
11 // the given element's class inheritance chain.
12 //
13 // The inheritance scope based naming might not yield a name. For instance,
14 // this could be because the field belongs to a mixin. In such a case this
15 // will return `null` and a normal field name has to be used.
16 jsAst.Name _minifiedInstanceFieldPropertyName(Element element) {
17 if (element.hasFixedBackendName) {
18 return new StringBackedName(element.fixedBackendName);
19 }
20
21 _FieldNamingScope names;
22 if (element is BoxFieldElement) {
23 names = new _FieldNamingScope.forBox(element.box, fieldRegistry);
24 } else {
25 ClassElement cls = element is ClosureFieldElement
26 ? element.closureClass
27 : element.enclosingClass;
28 names =
29 new _FieldNamingScope.forClass(cls, compiler.world, fieldRegistry);
30 }
31
32 if (names.containsField(element)) {
33 return names[element];
34 }
35 return null;
36 }
37 }
38
39 /**
40 * Encapsulates the global state of field naming.
41 *
42 * The field naming registry allocates names to be used along a path in the
43 * inheritance hierarchy of fields, starting with the object class. The actual
44 * hierarchy is encoded using instances of [_FieldNamingScope].
45 */
46 class _FieldNamingRegistry {
47 final MinifyNamer namer;
48
49 final Map<Entity, _FieldNamingScope> scopes =
50 new Map<Entity, _FieldNamingScope>();
51
52 final Map<Entity, jsAst.Name> globalNames = new Map<Entity, jsAst.Name>();
53
54 int globalCount = 0;
55
56 final List<jsAst.Name> nameStore = new List<jsAst.Name>();
57
58 _FieldNamingRegistry(this.namer);
59
60 // Returns the name to be used for a field with distance [index] from the
61 // root of the object hierarchy. The distance thereby is computed as the
62 // number of fields preceding the current field in its classes inheritance
63 // chain.
64 //
65 // The implementation assumes that names are requedsted in order, that is the
66 // name at position i+1 is requested after the name at position i was
67 // requested.
68 jsAst.Name getName(int index) {
69 if (index >= nameStore.length) {
70 // The namer usually does not use certain names as they clash with
71 // existing properties on JS objects (see [_reservedNativeProperties]).
72 // However, some of them are really short and safe to use for fields.
73 // Thus, we shortcut the namer to use those first.
74 assert(index == nameStore.length + 1);
75 if (index < MinifyNamer._reservedNativeProperties.length &&
76 MinifyNamer._reservedNativeProperties[index].length <= 2) {
77 nameStore.add(
78 new StringBackedName(MinifyNamer._reservedNativeProperties[index]));
79 } else {
80 nameStore.add(namer.getFreshName("field$index", namer.usedInstanceNames,
81 namer.suggestedInstanceNames));
82 }
83 }
84
85 return nameStore[index];
86 }
87 }
88
89 /**
90 * A [_FieldNamingScope] encodes a node in the inheritance tree of the current
91 * class hierarchy. The root node typically is the node corresponding to the
92 * `Object` class. It is used to assign a unique name to each field of a class.
93 * Unique here means unique wrt. all fields along the path back to the root.
94 * This is achieved at construction time via the [_fieldNameCounter] field that
95 * counts the number of fields on the path to the root node that have been
96 * encountered so far.
97 *
98 * Obviously, this only works if no fields are added to a parent node after its
99 * children have added their first field.
100 */
101 class _FieldNamingScope {
102 final _FieldNamingScope superScope;
103 final Entity container;
104 final Map<Element, jsAst.Name> names = new Maplet<Element, jsAst.Name>();
105 final _FieldNamingRegistry registry;
106
107 /// Naming counter used for fields of ordinary classes.
108 int _fieldNameCounter;
109
110 /// The number of fields along the superclass chain that use inheritance
111 /// based naming, including the ones allocated for this scope.
112 int get inheritanceBasedFieldNameCounter => _fieldNameCounter;
113
114 /// The number of locally used fields. Depending on the naming source
115 /// (e.g. inheritance based or globally unique for mixixns) this
116 /// might be different from [inheritanceBasedFieldNameCounter].
117 int get _localFieldNameCounter => _fieldNameCounter;
118 void set _localFieldNameCounter(int val) {
119 _fieldNameCounter = val;
120 }
121
122 factory _FieldNamingScope.forClass(
123 ClassElement cls, ClassWorld world, _FieldNamingRegistry registry) {
124 _FieldNamingScope result = registry.scopes[cls];
125 if (result != null) return result;
126
127 if (world.isUsedAsMixin(cls)) {
128 result = new _MixinFieldNamingScope.mixin(cls, registry);
129 } else {
130 if (cls.superclass == null) {
131 result = new _FieldNamingScope.rootScope(cls, registry);
132 } else {
133 _FieldNamingScope superScope =
134 new _FieldNamingScope.forClass(cls.superclass, world, registry);
135 if (cls.isMixinApplication) {
136 result =
137 new _MixinFieldNamingScope.mixedIn(cls, superScope, registry);
138 } else {
139 result = new _FieldNamingScope.inherit(cls, superScope, registry);
140 }
141 }
142 }
143
144 cls.forEachInstanceField((cls, field) => result.add(field));
145
146 registry.scopes[cls] = result;
147 return result;
148 }
149
150 factory _FieldNamingScope.forBox(Local box, _FieldNamingRegistry registry) {
151 return registry.scopes.putIfAbsent(
152 box, () => new _BoxFieldNamingScope(box, registry));
153 }
154
155 _FieldNamingScope.rootScope(this.container, this.registry)
156 : superScope = null,
157 _fieldNameCounter = 0;
158
159 _FieldNamingScope.inherit(this.container, this.superScope, this.registry) {
160 _fieldNameCounter = superScope.inheritanceBasedFieldNameCounter;
161 }
162
163 /**
164 * Checks whether [name] is already used in the current scope chain.
165 */
166 _isNameUnused(jsAst.Name name) {
167 return !names.values.contains(name) &&
168 ((superScope == null) || superScope._isNameUnused(name));
169 }
170
171 jsAst.Name _nextName() => registry.getName(_localFieldNameCounter++);
172
173 jsAst.Name operator [](Element field) {
174 jsAst.Name name = names[field];
175 if (name == null && superScope != null) return superScope[field];
176 return name;
177 }
178
179 void add(Element field) {
180 if (names.containsKey(field)) return;
181
182 jsAst.Name value = _nextName();
183 assert(invariant(field, _isNameUnused(value)));
184 names[field] = value;
185 }
186
187 bool containsField(Element field) => names.containsKey(field);
188 }
189
190 /**
191 * Field names for mixins have two constraints: They need to be unique in the
192 * hierarchy of each application of a mixin and they need to be the same for
193 * all applications of a mixin. To achieve this, we use global naming for
194 * mixins from the same name pool as fields and add a `$` at the end to ensure
195 * they do not collide with normal field names. The `$` sign is typically used
196 * as a separator between method names and argument counts and does not appear
197 * in generated names themselves.
198 */
199 class _MixinFieldNamingScope extends _FieldNamingScope {
200 int get _localFieldNameCounter => registry.globalCount;
201 void set _localFieldNameCounter(int val) {
202 registry.globalCount = val;
203 }
204
205 @override
206 Map<Entity, jsAst.Name> get names => registry.globalNames;
207
208 _MixinFieldNamingScope.mixin(ClassElement cls, _FieldNamingRegistry registry)
209 : super.rootScope(cls, registry);
210
211 _MixinFieldNamingScope.mixedIn(MixinApplicationElement container,
212 _FieldNamingScope superScope, _FieldNamingRegistry registry)
213 : super.inherit(container, superScope, registry);
214
215 jsAst.Name _nextName() {
216 jsAst.Name proposed = super._nextName();
217 return new CompoundName([proposed, Namer._literalDollar]);
218 }
219 }
220
221 /**
222 * [BoxFieldElement] fields work differently in that they do not belong to an
223 * actual class but an anonymous box associated to a [Local]. As there is no
224 * inheritance chain, we do not need to compute fields a priori but can assign
225 * names on the fly.
226 */
227 class _BoxFieldNamingScope extends _FieldNamingScope {
228 _BoxFieldNamingScope(Local box, _FieldNamingRegistry registry)
229 : super.rootScope(box, registry);
230
231 @override
232 bool containsField(_) => true;
233
234 jsAst.Name operator [](Element field) {
235 if (!names.containsKey(field)) add(field);
236 return names[field];
237 }
238 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/js_backend.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698