Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 class _FieldNamingRegistry { | |
| 43 final MinifyNamer namer; | |
| 44 | |
| 45 final Map<Entity, _FieldNamingScope> scopes = | |
| 46 new Map<Entity, _FieldNamingScope>(); | |
| 47 | |
| 48 final Map<Entity, jsAst.Name> globalNames = new Map<Entity, jsAst.Name>(); | |
| 49 | |
| 50 int globalCount = 0; | |
| 51 | |
| 52 final List<jsAst.Name> nameStore = new List<jsAst.Name>(); | |
| 53 | |
| 54 _FieldNamingRegistry(this.namer); | |
| 55 | |
| 56 jsAst.Name getName(int count) { | |
|
Johnni Winther
2015/06/26 10:03:35
Document the significance of [count]. Maybe rename
herhut
2015/06/29 12:19:31
Done.
| |
| 57 if (count >= nameStore.length) { | |
| 58 // The namer usually does not use certain names as they clash with | |
| 59 // existing properties on JS objects (see [_reservedNativeProperties]). | |
| 60 // However, some of them are really short and safe to use for fields. | |
| 61 // Thus, we shortcut the namer to use those first. | |
| 62 if (count < MinifyNamer._reservedNativeProperties.length && | |
| 63 MinifyNamer._reservedNativeProperties[count].length <= 2) { | |
| 64 nameStore.add( | |
| 65 new StringBackedName(MinifyNamer._reservedNativeProperties[count])); | |
| 66 } else { | |
| 67 nameStore.add(namer.getFreshName("field$count", namer.usedInstanceNames, | |
| 68 namer.suggestedInstanceNames)); | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 return nameStore[count]; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 /** | |
| 77 * A [_FieldNamingScope] encodes a node in the inheritance tree of the current | |
| 78 * class hierarchy. The root node typically is the node corresponding to the | |
| 79 * `Object` class. It is used to assign a unique name to each field of a class. | |
| 80 * Unique here means unique wrt. all fields along the path back to the root. | |
| 81 * This is achieved at construction time via the [_fieldNameCounter] field that | |
| 82 * counts the number of fields on the path to the root node that have been | |
| 83 * encountered so far. | |
| 84 * | |
| 85 * Obviously, this only works if no fields are added to a parent node after its | |
| 86 * children have added their first field. | |
| 87 */ | |
| 88 class _FieldNamingScope { | |
| 89 final _FieldNamingScope superScope; | |
| 90 final Entity container; | |
| 91 final Map<Element, jsAst.Name> names = new Maplet<Element, jsAst.Name>(); | |
| 92 final _FieldNamingRegistry registry; | |
| 93 | |
| 94 /// Naming counter used for fields of ordinary classes. | |
| 95 int _fieldNameCounter; | |
| 96 | |
| 97 /// The number of fields along the superclass chain that use inheritance | |
| 98 /// based naming, including the ones allocated for this scope. | |
| 99 int get inheritanceBasedFieldNameCounter => _fieldNameCounter; | |
| 100 | |
| 101 /// The number of locally used fields. Depending on the naming source | |
| 102 /// (e.g. inheritance based or globally unique for mixixns) this | |
| 103 /// might be different from [inheritanceBasedFieldNameCounter]. | |
| 104 int get _localFieldNameCounter => _fieldNameCounter; | |
| 105 void set _localFieldNameCounter(int val) { | |
| 106 _fieldNameCounter = val; | |
| 107 } | |
| 108 | |
| 109 factory _FieldNamingScope.forClass( | |
| 110 ClassElement cls, ClassWorld world, _FieldNamingRegistry registry) { | |
| 111 _FieldNamingScope result = registry.scopes[cls]; | |
| 112 if (result != null) return result; | |
| 113 | |
| 114 if (world.isUsedAsMixin(cls)) { | |
| 115 result = new _MixinFieldNamingScope.mixin(cls, registry); | |
| 116 } else { | |
| 117 if (cls.superclass == null) { | |
| 118 result = new _FieldNamingScope.rootScope(cls, registry); | |
| 119 } else { | |
| 120 _FieldNamingScope superScope = | |
| 121 new _FieldNamingScope.forClass(cls.superclass, world, registry); | |
| 122 if (cls.isMixinApplication) { | |
| 123 result = | |
| 124 new _MixinFieldNamingScope.mixedIn(cls, superScope, registry); | |
| 125 } else { | |
| 126 result = new _FieldNamingScope.inherit(cls, superScope, registry); | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 cls.forEachInstanceField((cls, field) => result.add(field)); | |
| 132 | |
| 133 registry.scopes[cls] = result; | |
| 134 return result; | |
| 135 } | |
| 136 | |
| 137 factory _FieldNamingScope.forBox(Local box, _FieldNamingRegistry registry) { | |
| 138 return registry.scopes.putIfAbsent( | |
| 139 box, () => new _BoxFieldNamingScope(box, registry)); | |
| 140 } | |
| 141 | |
| 142 _FieldNamingScope.rootScope(this.container, this.registry) | |
| 143 : superScope = null, | |
| 144 _fieldNameCounter = 0; | |
| 145 | |
| 146 _FieldNamingScope.inherit(this.container, this.superScope, this.registry) { | |
| 147 _fieldNameCounter = superScope.inheritanceBasedFieldNameCounter; | |
| 148 } | |
| 149 | |
| 150 /** | |
| 151 * Checks whether [name] is already used in the current scope chain. | |
| 152 */ | |
| 153 _isNameUnused(jsAst.Name name) { | |
| 154 return !names.values.contains(name) && | |
| 155 ((superScope == null) || superScope._isNameUnused(name)); | |
| 156 } | |
| 157 | |
| 158 jsAst.Name _nextName() => registry.getName(_localFieldNameCounter++); | |
| 159 | |
| 160 jsAst.Name operator [](Element field) { | |
| 161 jsAst.Name name = names[field]; | |
| 162 if (name == null && superScope != null) return superScope[field]; | |
| 163 return name; | |
| 164 } | |
| 165 | |
| 166 void add(Element field) { | |
| 167 if (names.containsKey(field)) return; | |
| 168 | |
| 169 jsAst.Name value = _nextName(); | |
| 170 assert(invariant(field, _isNameUnused(value))); | |
| 171 names[field] = value; | |
| 172 } | |
| 173 | |
| 174 bool containsField(Element field) => names.containsKey(field); | |
| 175 } | |
| 176 | |
| 177 /** | |
| 178 * Field names for mixins have two constraints: They need to be unique in the | |
| 179 * hierarchy of each application of a mixin and they need to be the same for | |
| 180 * all applications of a mixin. To achieve this, we use global naming for | |
| 181 * mixins from the same name pool as fields and add a `$` at the end to ensure | |
| 182 * they do not collide with normal field names. The `$` sign is typically used | |
| 183 * as a separator between method names and argument counts and does not appear | |
| 184 * in generated names themselves. | |
| 185 */ | |
| 186 class _MixinFieldNamingScope extends _FieldNamingScope { | |
| 187 int get _localFieldNameCounter => registry.globalCount; | |
| 188 void set _localFieldNameCounter(int val) { | |
| 189 registry.globalCount = val; | |
| 190 } | |
| 191 | |
| 192 @override | |
| 193 Map<Entity, jsAst.Name> get names => registry.globalNames; | |
| 194 | |
| 195 _MixinFieldNamingScope.mixin(ClassElement cls, _FieldNamingRegistry registry) | |
| 196 : super.rootScope(cls, registry); | |
| 197 | |
| 198 _MixinFieldNamingScope.mixedIn(MixinApplicationElement container, | |
| 199 _FieldNamingScope superScope, _FieldNamingRegistry registry) | |
| 200 : super.inherit(container, superScope, registry); | |
| 201 | |
| 202 jsAst.Name _nextName() { | |
| 203 jsAst.Name proposed = super._nextName(); | |
| 204 return new CompoundName([proposed, Namer._literalDollar]); | |
| 205 } | |
| 206 } | |
| 207 | |
| 208 /** | |
| 209 * [BoxFieldElement] fields work differently in that they do not belong to an | |
| 210 * actual class but an anonymous box associated to a [Local]. As there is no | |
| 211 * inheritance chain, we do not need to compute fields a priori but can assign | |
| 212 * names on the fly. | |
| 213 */ | |
| 214 class _BoxFieldNamingScope extends _FieldNamingScope { | |
| 215 _BoxFieldNamingScope(Local box, _FieldNamingRegistry registry) | |
| 216 : super.rootScope(box, registry); | |
| 217 | |
| 218 @override | |
| 219 bool containsField(_) => true; | |
| 220 | |
| 221 jsAst.Name operator [](Element field) { | |
| 222 if (!names.containsKey(field)) add(field); | |
| 223 return names[field]; | |
| 224 } | |
| 225 } | |
| OLD | NEW |