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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 class ConstantEmitter {
8 ConstantReferenceEmitter _referenceEmitter;
9 ConstantLiteralEmitter _literalEmitter;
10
11 ConstantEmitter(Compiler compiler,
12 Namer namer,
13 jsAst.Template makeConstantListTemplate) {
14 _literalEmitter = new ConstantLiteralEmitter(
15 compiler, namer, makeConstantListTemplate, this);
16 _referenceEmitter = new ConstantReferenceEmitter(compiler, namer, this);
17 }
18
19 /**
20 * Constructs an expression that is a reference to the constant. Uses a
21 * canonical name unless the constant can be emitted multiple times (as for
22 * numbers and strings).
23 */
24 jsAst.Expression reference(ConstantValue constant) {
25 return _referenceEmitter.generate(constant);
26 }
27
28 /**
29 * Constructs a literal expression that evaluates to the constant. Uses a
30 * canonical name unless the constant can be emitted multiple times (as for
31 * numbers and strings).
32 */
33 jsAst.Expression literal(ConstantValue constant) {
34 return _literalEmitter.generate(constant);
35 }
36
37 /**
38 * Constructs an expression like [reference], but the expression is valid
39 * during isolate initialization.
40 */
41 jsAst.Expression referenceInInitializationContext(ConstantValue constant) {
42 return _referenceEmitter.generate(constant);
43 }
44
45 /**
46 * Constructs an expression used to initialize a canonicalized constant.
47 */
48 jsAst.Expression initializationExpression(ConstantValue constant) {
49 return _literalEmitter.generate(constant);
50 }
51 }
52
53 /**
54 * Visitor for generating JavaScript expressions to refer to [ConstantValue]s.
55 * Do not use directly, use methods from [ConstantEmitter].
56 */
57 class ConstantReferenceEmitter
58 implements ConstantValueVisitor<jsAst.Expression> {
59 final Compiler compiler;
60 final Namer namer;
61
62 final ConstantEmitter constantEmitter;
63
64 ConstantReferenceEmitter(this.compiler, this.namer, this.constantEmitter);
65
66 jsAst.Expression generate(ConstantValue constant) {
67 return _visit(constant);
68 }
69
70 jsAst.Expression _visit(ConstantValue constant) {
71 return constant.accept(this);
72 }
73
74 jsAst.Expression emitCanonicalVersion(ConstantValue constant) {
75 String name = namer.constantName(constant);
76 return new jsAst.PropertyAccess.field(
77 new jsAst.VariableUse(namer.globalObjectForConstant(constant)), name);
78 }
79
80 jsAst.Expression literal(ConstantValue constant) {
81 return constantEmitter.literal(constant);
82 }
83
84 jsAst.Expression visitFunction(FunctionConstantValue constant) {
85 return namer.isolateStaticClosureAccess(constant.element);
86 }
87
88 jsAst.Expression visitNull(NullConstantValue constant) {
89 return literal(constant);
90 }
91
92 jsAst.Expression visitInt(IntConstantValue constant) {
93 return literal(constant);
94 }
95
96 jsAst.Expression visitDouble(DoubleConstantValue constant) {
97 return literal(constant);
98 }
99
100 jsAst.Expression visitTrue(TrueConstantValue constant) {
101 return literal(constant);
102 }
103
104 jsAst.Expression visitFalse(FalseConstantValue constant) {
105 return literal(constant);
106 }
107
108 /**
109 * Write the contents of the quoted string to a [CodeBuffer] in
110 * a form that is valid as JavaScript string literal content.
111 * The string is assumed quoted by double quote characters.
112 */
113 jsAst.Expression visitString(StringConstantValue constant) {
114 // TODO(sra): If the string is long *and repeated* (and not on a hot path)
115 // then it should be assigned to a name. We don't have reference counts (or
116 // profile information) here, so this is the wrong place.
117 return literal(constant);
118 }
119
120 jsAst.Expression visitList(ListConstantValue constant) {
121 return emitCanonicalVersion(constant);
122 }
123
124 jsAst.Expression visitMap(MapConstantValue constant) {
125 return emitCanonicalVersion(constant);
126 }
127
128 jsAst.Expression visitType(TypeConstantValue constant) {
129 return emitCanonicalVersion(constant);
130 }
131
132 jsAst.Expression visitConstructed(ConstructedConstantValue constant) {
133 return emitCanonicalVersion(constant);
134 }
135
136 jsAst.Expression visitInterceptor(InterceptorConstantValue constant) {
137 return emitCanonicalVersion(constant);
138 }
139
140 jsAst.Expression visitDummy(DummyConstantValue constant) {
141 return literal(constant);
142 }
143
144 jsAst.Expression visitDeferred(DeferredConstantValue constant) {
145 return emitCanonicalVersion(constant);
146 }
147 }
148
149 /**
150 * Visitor for generating JavaScript expressions that litterally represent
151 * [ConstantValue]s. These can be used for inlining constants or in
152 * initializers. Do not use directly, use methods from [ConstantEmitter].
153 */
154 class ConstantLiteralEmitter implements ConstantValueVisitor<jsAst.Expression> {
155
156 // Matches blank lines, comment lines and trailing comments that can't be part
157 // of a string.
158 static final RegExp COMMENT_RE =
159 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true);
160
161 final Compiler compiler;
162 final Namer namer;
163 final jsAst.Template makeConstantListTemplate;
164 final ConstantEmitter constantEmitter;
165
166 ConstantLiteralEmitter(this.compiler,
167 this.namer,
168 this.makeConstantListTemplate,
169 this.constantEmitter);
170
171 jsAst.Expression generate(ConstantValue constant) {
172 return _visit(constant);
173 }
174
175 jsAst.Expression _visit(ConstantValue constant) {
176 return constant.accept(this);
177 }
178
179 jsAst.Expression visitFunction(FunctionConstantValue constant) {
180 compiler.internalError(NO_LOCATION_SPANNABLE,
181 "The function constant does not need specific JS code.");
182 return null;
183 }
184
185 jsAst.Expression visitNull(NullConstantValue constant) {
186 return new jsAst.LiteralNull();
187 }
188
189 jsAst.Expression visitInt(IntConstantValue constant) {
190 return new jsAst.LiteralNumber('${constant.primitiveValue}');
191 }
192
193 jsAst.Expression visitDouble(DoubleConstantValue constant) {
194 double value = constant.primitiveValue;
195 if (value.isNaN) {
196 return js("0/0");
197 } else if (value == double.INFINITY) {
198 return js("1/0");
199 } else if (value == -double.INFINITY) {
200 return js("-1/0");
201 } else {
202 return new jsAst.LiteralNumber("$value");
203 }
204 }
205
206 jsAst.Expression visitTrue(TrueConstantValue constant) {
207 if (compiler.enableMinification) {
208 // Use !0 for true.
209 return js("!0");
210 } else {
211 return js('true');
212 }
213 }
214
215 jsAst.Expression visitFalse(FalseConstantValue constant) {
216 if (compiler.enableMinification) {
217 // Use !1 for false.
218 return js("!1");
219 } else {
220 return js('false');
221 }
222 }
223
224 /**
225 * Write the contents of the quoted string to a [CodeBuffer] in
226 * a form that is valid as JavaScript string literal content.
227 * The string is assumed quoted by double quote characters.
228 */
229 jsAst.Expression visitString(StringConstantValue constant) {
230 StringBuffer sb = new StringBuffer();
231 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb);
232 return new jsAst.LiteralString('"$sb"');
233 }
234
235 jsAst.Expression visitList(ListConstantValue constant) {
236 List<jsAst.Expression> elements = _array(constant.entries);
237 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements);
238 jsAst.Expression value = makeConstantListTemplate.instantiate([array]);
239 return maybeAddTypeArguments(constant.type, value);
240 }
241
242 jsAst.Expression getJsConstructor(ClassElement element) {
243 return namer.elementAccess(element);
244 }
245
246 jsAst.Expression visitMap(JavaScriptMapConstant constant) {
247 jsAst.Expression jsMap() {
248 List<jsAst.Property> properties = <jsAst.Property>[];
249 for (int i = 0; i < constant.length; i++) {
250 StringConstantValue key = constant.keys[i];
251 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) {
252 continue;
253 }
254
255 // Keys in literal maps must be emitted in place.
256 jsAst.Literal keyExpression = _visit(key);
257 jsAst.Expression valueExpression =
258 constantEmitter.reference(constant.values[i]);
259 properties.add(new jsAst.Property(keyExpression, valueExpression));
260 }
261 return new jsAst.ObjectInitializer(properties);
262 }
263
264 jsAst.Expression jsGeneralMap() {
265 List<jsAst.Expression> data = <jsAst.Expression>[];
266 for (int i = 0; i < constant.keys.length; i++) {
267 jsAst.Expression keyExpression =
268 constantEmitter.reference(constant.keys[i]);
269 jsAst.Expression valueExpression =
270 constantEmitter.reference(constant.values[i]);
271 data.add(keyExpression);
272 data.add(valueExpression);
273 }
274 return new jsAst.ArrayInitializer.from(data);
275 }
276
277 ClassElement classElement = constant.type.element;
278 String className = classElement.name;
279
280 List<jsAst.Expression> arguments = <jsAst.Expression>[];
281
282 // The arguments of the JavaScript constructor for any given Dart class
283 // are in the same order as the members of the class element.
284 int emittedArgumentCount = 0;
285 classElement.implementation.forEachInstanceField(
286 (ClassElement enclosing, Element field) {
287 if (field.name == JavaScriptMapConstant.LENGTH_NAME) {
288 arguments.add(
289 new jsAst.LiteralNumber('${constant.keyList.entries.length}'));
290 } else if (field.name == JavaScriptMapConstant.JS_OBJECT_NAME) {
291 arguments.add(jsMap());
292 } else if (field.name == JavaScriptMapConstant.KEYS_NAME) {
293 arguments.add(constantEmitter.reference(constant.keyList));
294 } else if (field.name == JavaScriptMapConstant.PROTO_VALUE) {
295 assert(constant.protoValue != null);
296 arguments.add(constantEmitter.reference(constant.protoValue));
297 } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) {
298 arguments.add(jsGeneralMap());
299 } else {
300 compiler.internalError(field,
301 "Compiler has unexpected field ${field.name} for "
302 "${className}.");
303 }
304 emittedArgumentCount++;
305 },
306 includeSuperAndInjectedMembers: true);
307 if ((className == JavaScriptMapConstant.DART_STRING_CLASS &&
308 emittedArgumentCount != 3) ||
309 (className == JavaScriptMapConstant.DART_PROTO_CLASS &&
310 emittedArgumentCount != 4) ||
311 (className == JavaScriptMapConstant.DART_GENERAL_CLASS &&
312 emittedArgumentCount != 1)) {
313 compiler.internalError(classElement,
314 "Compiler and ${className} disagree on number of fields.");
315 }
316
317 jsAst.Expression value =
318 new jsAst.New(getJsConstructor(classElement), arguments);
319 return maybeAddTypeArguments(constant.type, value);
320 }
321
322 JavaScriptBackend get backend => compiler.backend;
323
324 jsAst.PropertyAccess getHelperProperty(Element helper) {
325 return backend.namer.elementAccess(helper);
326 }
327
328 jsAst.Expression visitType(TypeConstantValue constant) {
329 DartType type = constant.representedType;
330 String name = namer.getRuntimeTypeName(type.element);
331 jsAst.Expression typeName = new jsAst.LiteralString("'$name'");
332 return new jsAst.Call(getHelperProperty(backend.getCreateRuntimeType()),
333 [typeName]);
334 }
335
336 jsAst.Expression visitInterceptor(InterceptorConstantValue constant) {
337 return new jsAst.PropertyAccess.field(
338 getJsConstructor(constant.dispatchedType.element),
339 'prototype');
340 }
341
342 jsAst.Expression visitDummy(DummyConstantValue constant) {
343 return new jsAst.LiteralNumber('0');
344 }
345
346 jsAst.Expression visitConstructed(ConstructedConstantValue constant) {
347 Element element = constant.type.element;
348 if (element.isForeign(backend)
349 && element.name == 'JS_CONST') {
350 StringConstantValue str = constant.fields[0];
351 String value = str.primitiveValue.slowToString();
352 return new jsAst.LiteralExpression(stripComments(value));
353 }
354 jsAst.New instantiation = new jsAst.New(
355 getJsConstructor(constant.type.element),
356 _array(constant.fields));
357 return maybeAddTypeArguments(constant.type, instantiation);
358 }
359
360 String stripComments(String rawJavaScript) {
361 return rawJavaScript.replaceAll(COMMENT_RE, '');
362 }
363
364 List<jsAst.Expression> _array(List<ConstantValue> values) {
365 List<jsAst.Expression> valueList = <jsAst.Expression>[];
366 for (int i = 0; i < values.length; i++) {
367 valueList.add(constantEmitter.reference(values[i]));
368 }
369 return valueList;
370 }
371
372 jsAst.Expression maybeAddTypeArguments(InterfaceType type,
373 jsAst.Expression value) {
374 if (type is InterfaceType &&
375 !type.treatAsRaw &&
376 backend.classNeedsRti(type.element)) {
377 InterfaceType interface = type;
378 RuntimeTypes rti = backend.rti;
379 Iterable<String> arguments = interface.typeArguments
380 .map((DartType type) =>
381 rti.getTypeRepresentationWithHashes(type, (_){}));
382 jsAst.Expression argumentList =
383 new jsAst.LiteralString('[${arguments.join(', ')}]');
384 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()),
385 [value, argumentList]);
386 }
387 return value;
388 }
389
390 jsAst.Expression visitDeferred(DeferredConstantValue constant) {
391 return constantEmitter.reference(constant.referenced);
392 }
393 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698