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

Side by Side Diff: lib/compiler/implementation/namer.dart

Issue 10915104: Move namer into javascript backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011, 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 /**
6 * Assigns JavaScript identifiers to Dart variables, class-names and members.
7 */
8 class Namer {
9 final Compiler compiler;
10
11 static Set<String> _jsReserved = null;
12 Set<String> get jsReserved {
13 if (_jsReserved === null) {
14 _jsReserved = new Set<String>();
15 _jsReserved.addAll(JsNames.javaScriptKeywords);
16 _jsReserved.addAll(JsNames.reservedPropertySymbols);
17 }
18 return _jsReserved;
19 }
20
21 Map<Element, String> globals;
22 Map<String, int> usedGlobals;
23 Map<String, LibraryElement> shortPrivateNameOwners;
24
25 Namer(this.compiler)
26 : globals = new Map<Element, String>(),
27 usedGlobals = new Map<String, int>(),
28 shortPrivateNameOwners = new Map<String, LibraryElement>();
29
30 final String CURRENT_ISOLATE = @'$';
31 final String ISOLATE = 'Isolate';
32 final String ISOLATE_PROPERTIES = @"$isolateProperties";
33 /** Some closures must contain their name. The name is stored in
34 * [STATIC_CLOSURE_NAME_NAME]. */
35 final String STATIC_CLOSURE_NAME_NAME = @'$name';
36 static const SourceString CLOSURE_INVOCATION_NAME =
37 Compiler.CALL_OPERATOR_NAME;
38
39
40 String closureInvocationName(Selector selector) {
41 // TODO(floitsch): mangle, while not conflicting with instance names.
42 return instanceMethodInvocationName(null, CLOSURE_INVOCATION_NAME,
43 selector);
44 }
45
46 String breakLabelName(LabelElement label) {
47 return '\$${label.labelName}\$${label.target.nestingLevel}';
48 }
49
50 String implicitBreakLabelName(TargetElement target) {
51 return '\$${target.nestingLevel}';
52 }
53
54 // We sometimes handle continue targets differently from break targets,
55 // so we have special continue-only labels.
56 String continueLabelName(LabelElement label) {
57 return 'c\$${label.labelName}\$${label.target.nestingLevel}';
58 }
59
60 String implicitContinueLabelName(TargetElement target) {
61 return 'c\$${target.nestingLevel}';
62 }
63
64 /** Returns a non-unique name for the given closure element. */
65 String closureName(Element element) {
66 List<String> parts = <String>[];
67 SourceString ownName = element.name;
68 if (ownName == null || ownName.stringValue == "") {
69 parts.add("anon");
70 } else {
71 parts.add(ownName.slowToString());
72 }
73 for (Element enclosingElement = element.enclosingElement;
74 enclosingElement != null &&
75 (enclosingElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY
76 || enclosingElement.kind === ElementKind.CLASS
77 || enclosingElement.kind === ElementKind.FUNCTION
78 || enclosingElement.kind === ElementKind.GETTER
79 || enclosingElement.kind === ElementKind.SETTER);
80 enclosingElement = enclosingElement.enclosingElement) {
81 SourceString surroundingName = enclosingElement.name;
82 if (surroundingName != null) {
83 String surroundingNameString = surroundingName.slowToString();
84 if (surroundingNameString != "") parts.add(surroundingNameString);
85 }
86 }
87 // Invert the parts.
88 for (int i = 0, j = parts.length - 1; i < j; i++, j--) {
89 var tmp = parts[i];
90 parts[i] = parts[j];
91 parts[j] = tmp;
92 }
93 return safeName(Strings.join(parts, "_"));
94 }
95
96 String privateName(LibraryElement lib, SourceString name) {
97 if (name.isPrivate()) {
98 String nameString = name.slowToString();
99 // The first library asking for a short private name wins.
100 LibraryElement owner =
101 shortPrivateNameOwners.putIfAbsent(nameString, () => lib);
102 // If a private name could clash with a mangled private name we don't
103 // use the short name. For example a private name "_lib3_foo" would
104 // clash with "_foo" from "lib3".
105 if (owner === lib && !nameString.startsWith('_$LIBRARY_PREFIX')) {
106 return nameString;
107 }
108 String libName = getName(lib);
109 // If a library name does not start with the [LIBRARY_PREFIX] then our
110 // assumptions about clashing with mangled private members do not hold.
111 assert(libName.startsWith(LIBRARY_PREFIX));
112 return '_$libName$nameString';
113 } else {
114 return name.slowToString();
115 }
116 }
117
118 String instanceMethodName(LibraryElement lib, SourceString name, int arity) {
119 return '${privateName(lib, name)}\$$arity';
120 }
121
122 String instanceMethodInvocationName(LibraryElement lib, SourceString name,
123 Selector selector) {
124 // TODO(floitsch): mangle, while preserving uniqueness.
125 StringBuffer buffer = new StringBuffer();
126 List<SourceString> names = selector.getOrderedNamedArguments();
127 for (SourceString argumentName in names) {
128 buffer.add(@'$');
129 argumentName.printOn(buffer);
130 }
131 return '${privateName(lib, name)}\$${selector.argumentCount}$buffer';
132 }
133
134 String instanceFieldName(LibraryElement libraryElement, SourceString name) {
135 String proposedName = privateName(libraryElement, name);
136 return safeName(proposedName);
137 }
138
139 String shadowedFieldName(Element fieldElement) {
140 ClassElement cls = fieldElement.getEnclosingClass();
141 LibraryElement libraryElement = fieldElement.getLibrary();
142 String libName = getName(libraryElement);
143 String clsName = getName(cls);
144 String instanceName = instanceFieldName(libraryElement, fieldElement.name);
145 return safeName('$libName\$$clsName\$$instanceName');
146 }
147
148 String setterName(LibraryElement lib, SourceString name) {
149 // We dynamically create setters from the field-name. The setter name must
150 // therefore be derived from the instance field-name.
151 String fieldName = safeName(privateName(lib, name));
152 return 'set\$$fieldName';
153 }
154
155 String getterName(LibraryElement lib, SourceString name) {
156 // We dynamically create getters from the field-name. The getter name must
157 // therefore be derived from the instance field-name.
158 String fieldName = safeName(privateName(lib, name));
159 return 'get\$$fieldName';
160 }
161
162 String getFreshGlobalName(String proposedName) {
163 String name = proposedName;
164 int count = usedGlobals[name];
165 if (count !== null) {
166 // Not the first time we see this name. Append a number to make it unique.
167 do {
168 name = '$proposedName${count++}';
169 } while (usedGlobals[name] !== null);
170 // Record the count in case we see this name later. We
171 // frequently see names multiple times, as all our closures use
172 // the same name for their class.
173 usedGlobals[proposedName] = count;
174 }
175 usedGlobals[name] = 0;
176 return name;
177 }
178
179 static const String LIBRARY_PREFIX = "lib";
180
181 /**
182 * Returns a preferred JS-id for the given top-level or static element.
183 * The returned id is guaranteed to be a valid JS-id.
184 */
185 String _computeGuess(Element element) {
186 assert(!element.isInstanceMember());
187 LibraryElement lib = element.getLibrary();
188 String name;
189 if (element.isGenerativeConstructor()) {
190 if (element.name == element.getEnclosingClass().name) {
191 // Keep the class name for the class and not the factory.
192 name = "${element.name.slowToString()}\$";
193 } else {
194 name = element.name.slowToString();
195 }
196 } else if (Elements.isStaticOrTopLevel(element)) {
197 if (element.isMember()) {
198 ClassElement enclosingClass = element.getEnclosingClass();
199 name = "${enclosingClass.name.slowToString()}_"
200 "${element.name.slowToString()}";
201 } else {
202 name = element.name.slowToString();
203 }
204 } else if (element.kind === ElementKind.LIBRARY) {
205 name = LIBRARY_PREFIX;
206 } else {
207 name = element.name.slowToString();
208 }
209 // Prefix the name with '$' if it is reserved.
210 return safeName(name);
211 }
212
213 String getBailoutName(Element element) {
214 return '${getName(element)}\$bailout';
215 }
216
217 /**
218 * Returns a preferred JS-id for the given element. The returned id is
219 * guaranteed to be a valid JS-id. Globals and static fields are furthermore
220 * guaranteed to be unique.
221 *
222 * For accessing statics consider calling
223 * [isolateAccess]/[isolateBailoutAccess] or [isolatePropertyAccess] instead.
224 */
225 String getName(Element element) {
226 if (element.isInstanceMember()) {
227 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) {
228 ConstructorBodyElement bodyElement = element;
229 SourceString name = bodyElement.constructor.name;
230 return instanceMethodName(element.getLibrary(),
231 name, bodyElement.parameterCount(compiler));
232 } else if (element.kind == ElementKind.FUNCTION) {
233 FunctionElement functionElement = element;
234 return instanceMethodName(element.getLibrary(),
235 element.name,
236 functionElement.parameterCount(compiler));
237 } else if (element.kind == ElementKind.GETTER) {
238 return getterName(element.getLibrary(), element.name);
239 } else if (element.kind == ElementKind.SETTER) {
240 return setterName(element.getLibrary(), element.name);
241 } else if (element.kind == ElementKind.FIELD) {
242 return instanceFieldName(element.getLibrary(), element.name);
243 } else {
244 compiler.internalError('getName for bad kind: ${element.kind}',
245 node: element.parseNode(compiler));
246 }
247 } else {
248 // Dealing with a top-level or static element.
249 String cached = globals[element];
250 if (cached !== null) return cached;
251
252 String guess = _computeGuess(element);
253 ElementKind kind = element.kind;
254 if (kind === ElementKind.VARIABLE ||
255 kind === ElementKind.PARAMETER) {
256 // The name is not guaranteed to be unique.
257 return guess;
258 }
259 if (kind === ElementKind.GENERATIVE_CONSTRUCTOR ||
260 kind === ElementKind.FUNCTION ||
261 kind === ElementKind.CLASS ||
262 kind === ElementKind.FIELD ||
263 kind === ElementKind.GETTER ||
264 kind === ElementKind.SETTER ||
265 kind === ElementKind.TYPEDEF ||
266 kind === ElementKind.LIBRARY) {
267 String result = getFreshGlobalName(guess);
268 globals[element] = result;
269 return result;
270 }
271 compiler.internalError('getName for unknown kind: ${element.kind}',
272 node: element.parseNode(compiler));
273 }
274 }
275
276 String getLazyInitializerName(Element element) {
277 // TODO(floitsch): mangle while not conflicting with other statics.
278 assert(Elements.isStaticOrTopLevelField(element));
279 return "get\$${getName(element)}";
280 }
281
282 String isolatePropertiesAccess(Element element) {
283 return "$ISOLATE.$ISOLATE_PROPERTIES.${getName(element)}";
284 }
285
286 String isolatePropertiesAccessForConstant(String constantName) {
287 return "$ISOLATE.$ISOLATE_PROPERTIES.$constantName";
288 }
289
290 String isolateAccess(Element element) {
291 return "$CURRENT_ISOLATE.${getName(element)}";
292 }
293
294 String isolateBailoutAccess(Element element) {
295 return '${isolateAccess(element)}\$bailout';
296 }
297
298 String isolateLazyInitializerAccess(Element element) {
299 return "$CURRENT_ISOLATE.${getLazyInitializerName(element)}";
300 }
301
302 String operatorIs(Element element) {
303 return 'is\$${getName(element)}';
304 }
305
306 String safeName(String name) {
307 if (jsReserved.contains(name) || name.startsWith('\$')) {
308 name = "\$$name";
309 assert(!jsReserved.contains(name));
310 }
311 return name;
312 }
313 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698