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

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

Issue 947333004: dart2js: simplify constant expression generation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 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
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of js_backend; 5 part of js_backend;
6 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 /** 7 /**
54 * Visitor for generating JavaScript expressions to refer to [ConstantValue]s. 8 * Generates the JavaScript expressions for constants.
55 * Do not use directly, use methods from [ConstantEmitter]. 9 *
10 * It uses a given [constantReference] to reference nested constants (if there
11 * are some). It is hence up to that function to decide which constants should
12 * be inlined or not.
56 */ 13 */
57 class ConstantReferenceEmitter 14 class ConstantEmitter
58 implements ConstantValueVisitor<jsAst.Expression, Null> {
59 final Compiler compiler;
60 final Namer namer;
61
62 final ConstantEmitter constantEmitter;
63
64 ConstantReferenceEmitter(this.compiler, this.namer, this.constantEmitter);
65
66 JavaScriptBackend get backend => compiler.backend;
67
68 jsAst.Expression generate(ConstantValue constant) {
69 return _visit(constant);
70 }
71
72 jsAst.Expression _visit(ConstantValue constant) {
73 return constant.accept(this, null);
74 }
75
76 jsAst.Expression emitCanonicalVersion(ConstantValue constant) {
77 String name = namer.constantName(constant);
78 return new jsAst.PropertyAccess.field(
79 new jsAst.VariableUse(namer.globalObjectForConstant(constant)), name);
80 }
81
82 jsAst.Expression literal(ConstantValue constant) {
83 return constantEmitter.literal(constant);
84 }
85
86 @override
87 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
88 return backend.emitter.isolateStaticClosureAccess(constant.element);
89 }
90
91 @override
92 jsAst.Expression visitNull(NullConstantValue constant, [_]) {
93 return literal(constant);
94 }
95
96 @override
97 jsAst.Expression visitInt(IntConstantValue constant, [_]) {
98 return literal(constant);
99 }
100
101 @override
102 jsAst.Expression visitDouble(DoubleConstantValue constant, [_]) {
103 return literal(constant);
104 }
105
106 @override
107 jsAst.Expression visitBool(BoolConstantValue constant, [_]) {
108 return literal(constant);
109 }
110
111 /**
112 * Write the contents of the quoted string to a [CodeBuffer] in
113 * a form that is valid as JavaScript string literal content.
114 * The string is assumed quoted by double quote characters.
115 */
116 @override
117 jsAst.Expression visitString(StringConstantValue constant, [_]) {
118 // TODO(sra): If the string is long *and repeated* (and not on a hot path)
119 // then it should be assigned to a name. We don't have reference counts (or
120 // profile information) here, so this is the wrong place.
121 return literal(constant);
122 }
123
124 @override
125 jsAst.Expression visitList(ListConstantValue constant, [_]) {
126 return emitCanonicalVersion(constant);
127 }
128
129 @override
130 jsAst.Expression visitMap(MapConstantValue constant, [_]) {
131 return emitCanonicalVersion(constant);
132 }
133
134 @override
135 jsAst.Expression visitType(TypeConstantValue constant, [_]) {
136 return emitCanonicalVersion(constant);
137 }
138
139 @override
140 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) {
141 return emitCanonicalVersion(constant);
142 }
143
144 @override
145 jsAst.Expression visitInterceptor(InterceptorConstantValue constant, [_]) {
146 return emitCanonicalVersion(constant);
147 }
148
149 @override
150 jsAst.Expression visitDummy(DummyConstantValue constant, [_]) {
151 return literal(constant);
152 }
153
154 @override
155 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) {
156 return emitCanonicalVersion(constant);
157 }
158 }
159
160 /**
161 * Visitor for generating JavaScript expressions that litterally represent
162 * [ConstantValue]s. These can be used for inlining constants or in
163 * initializers. Do not use directly, use methods from [ConstantEmitter].
164 */
165 class ConstantLiteralEmitter
166 implements ConstantValueVisitor<jsAst.Expression, Null> { 15 implements ConstantValueVisitor<jsAst.Expression, Null> {
167 16
168 // Matches blank lines, comment lines and trailing comments that can't be part 17 // Matches blank lines, comment lines and trailing comments that can't be part
169 // of a string. 18 // of a string.
170 static final RegExp COMMENT_RE = 19 static final RegExp COMMENT_RE =
171 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true); 20 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true);
172 21
173 final Compiler compiler; 22 final Compiler compiler;
174 final Namer namer; 23 final Namer namer;
24 final Function constantReference;
floitsch 2015/02/24 23:08:48 I know the function isn't typed, but I really hate
Johnni Winther 2015/02/25 11:37:02 Make a typedef like typedef jsAst.Expression Cons
floitsch 2015/02/25 16:35:18 Done.
175 final jsAst.Template makeConstantListTemplate; 25 final jsAst.Template makeConstantListTemplate;
176 final ConstantEmitter constantEmitter;
177 26
178 ConstantLiteralEmitter(this.compiler, 27 /**
179 this.namer, 28 * The given [constantReferenc] function must, when invoked with a constant,
Johnni Winther 2015/02/25 11:37:02 [constantReferenc] -> [constantReference] (if not
floitsch 2015/02/25 16:35:18 Done.
180 this.makeConstantListTemplate, 29 * either return a reference or return its literal expression if it can
181 this.constantEmitter); 30 * be inlined.
31 */
32 ConstantEmitter(
33 this.compiler,
34 this.namer,
35 jsAst.Expression this.constantReference(ConstantValue constant),
36 this.makeConstantListTemplate);
182 37
38 /**
39 * Constructs a literal expression that evaluates to the constant. Uses a
40 * canonical name unless the constant can be emitted multiple times (as for
41 * numbers and strings).
42 */
183 jsAst.Expression generate(ConstantValue constant) { 43 jsAst.Expression generate(ConstantValue constant) {
184 return _visit(constant); 44 return _visit(constant);
185 } 45 }
186 46
187 jsAst.Expression _visit(ConstantValue constant) { 47 jsAst.Expression _visit(ConstantValue constant) {
188 return constant.accept(this, null); 48 return constant.accept(this, null);
189 } 49 }
190 50
191 @override 51 @override
192 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) { 52 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 */ 147 */
288 @override 148 @override
289 jsAst.Expression visitString(StringConstantValue constant, [_]) { 149 jsAst.Expression visitString(StringConstantValue constant, [_]) {
290 StringBuffer sb = new StringBuffer(); 150 StringBuffer sb = new StringBuffer();
291 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb); 151 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb);
292 return new jsAst.LiteralString('"$sb"'); 152 return new jsAst.LiteralString('"$sb"');
293 } 153 }
294 154
295 @override 155 @override
296 jsAst.Expression visitList(ListConstantValue constant, [_]) { 156 jsAst.Expression visitList(ListConstantValue constant, [_]) {
297 List<jsAst.Expression> elements = _array(constant.entries); 157 List<jsAst.Expression> elements =
floitsch 2015/02/24 23:08:48 I initially thought that I could get away with an
158 constant.entries.map(constantReference).toList(growable: false);
298 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements); 159 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements);
299 jsAst.Expression value = makeConstantListTemplate.instantiate([array]); 160 jsAst.Expression value = makeConstantListTemplate.instantiate([array]);
300 return maybeAddTypeArguments(constant.type, value); 161 return maybeAddTypeArguments(constant.type, value);
301 } 162 }
302 163
303 @override 164 @override
304 jsAst.Expression visitMap(JavaScriptMapConstant constant, [_]) { 165 jsAst.Expression visitMap(JavaScriptMapConstant constant, [_]) {
305 jsAst.Expression jsMap() { 166 jsAst.Expression jsMap() {
306 List<jsAst.Property> properties = <jsAst.Property>[]; 167 List<jsAst.Property> properties = <jsAst.Property>[];
307 for (int i = 0; i < constant.length; i++) { 168 for (int i = 0; i < constant.length; i++) {
308 StringConstantValue key = constant.keys[i]; 169 StringConstantValue key = constant.keys[i];
309 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { 170 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) {
310 continue; 171 continue;
311 } 172 }
312 173
313 // Keys in literal maps must be emitted in place. 174 // Keys in literal maps must be emitted in place.
314 jsAst.Literal keyExpression = _visit(key); 175 jsAst.Literal keyExpression = _visit(key);
315 jsAst.Expression valueExpression = 176 jsAst.Expression valueExpression =
316 constantEmitter.reference(constant.values[i]); 177 constantReference(constant.values[i]);
317 properties.add(new jsAst.Property(keyExpression, valueExpression)); 178 properties.add(new jsAst.Property(keyExpression, valueExpression));
318 } 179 }
319 return new jsAst.ObjectInitializer(properties); 180 return new jsAst.ObjectInitializer(properties);
320 } 181 }
321 182
322 jsAst.Expression jsGeneralMap() { 183 jsAst.Expression jsGeneralMap() {
323 List<jsAst.Expression> data = <jsAst.Expression>[]; 184 List<jsAst.Expression> data = <jsAst.Expression>[];
324 for (int i = 0; i < constant.keys.length; i++) { 185 for (int i = 0; i < constant.keys.length; i++) {
325 jsAst.Expression keyExpression = 186 jsAst.Expression keyExpression = constantReference(constant.keys[i]);
326 constantEmitter.reference(constant.keys[i]);
327 jsAst.Expression valueExpression = 187 jsAst.Expression valueExpression =
328 constantEmitter.reference(constant.values[i]); 188 constantReference(constant.values[i]);
329 data.add(keyExpression); 189 data.add(keyExpression);
330 data.add(valueExpression); 190 data.add(valueExpression);
331 } 191 }
332 return new jsAst.ArrayInitializer(data); 192 return new jsAst.ArrayInitializer(data);
333 } 193 }
334 194
335 ClassElement classElement = constant.type.element; 195 ClassElement classElement = constant.type.element;
336 String className = classElement.name; 196 String className = classElement.name;
337 197
338 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 198 List<jsAst.Expression> arguments = <jsAst.Expression>[];
339 199
340 // The arguments of the JavaScript constructor for any given Dart class 200 // The arguments of the JavaScript constructor for any given Dart class
341 // are in the same order as the members of the class element. 201 // are in the same order as the members of the class element.
342 int emittedArgumentCount = 0; 202 int emittedArgumentCount = 0;
343 classElement.implementation.forEachInstanceField( 203 classElement.implementation.forEachInstanceField(
344 (ClassElement enclosing, Element field) { 204 (ClassElement enclosing, Element field) {
345 if (field.name == JavaScriptMapConstant.LENGTH_NAME) { 205 if (field.name == JavaScriptMapConstant.LENGTH_NAME) {
346 arguments.add( 206 arguments.add(
347 new jsAst.LiteralNumber('${constant.keyList.entries.length}')); 207 new jsAst.LiteralNumber('${constant.keyList.entries.length}'));
348 } else if (field.name == JavaScriptMapConstant.JS_OBJECT_NAME) { 208 } else if (field.name == JavaScriptMapConstant.JS_OBJECT_NAME) {
349 arguments.add(jsMap()); 209 arguments.add(jsMap());
350 } else if (field.name == JavaScriptMapConstant.KEYS_NAME) { 210 } else if (field.name == JavaScriptMapConstant.KEYS_NAME) {
351 arguments.add(constantEmitter.reference(constant.keyList)); 211 arguments.add(constantReference(constant.keyList));
352 } else if (field.name == JavaScriptMapConstant.PROTO_VALUE) { 212 } else if (field.name == JavaScriptMapConstant.PROTO_VALUE) {
353 assert(constant.protoValue != null); 213 assert(constant.protoValue != null);
354 arguments.add(constantEmitter.reference(constant.protoValue)); 214 arguments.add(constantReference(constant.protoValue));
355 } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) { 215 } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) {
356 arguments.add(jsGeneralMap()); 216 arguments.add(jsGeneralMap());
357 } else { 217 } else {
358 compiler.internalError(field, 218 compiler.internalError(field,
359 "Compiler has unexpected field ${field.name} for " 219 "Compiler has unexpected field ${field.name} for "
360 "${className}."); 220 "${className}.");
361 } 221 }
362 emittedArgumentCount++; 222 emittedArgumentCount++;
363 }, 223 },
364 includeSuperAndInjectedMembers: true); 224 includeSuperAndInjectedMembers: true);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) { 268 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) {
409 Element element = constant.type.element; 269 Element element = constant.type.element;
410 if (element.isForeign(backend) 270 if (element.isForeign(backend)
411 && element.name == 'JS_CONST') { 271 && element.name == 'JS_CONST') {
412 StringConstantValue str = constant.fields[0]; 272 StringConstantValue str = constant.fields[0];
413 String value = str.primitiveValue.slowToString(); 273 String value = str.primitiveValue.slowToString();
414 return new jsAst.LiteralExpression(stripComments(value)); 274 return new jsAst.LiteralExpression(stripComments(value));
415 } 275 }
416 jsAst.Expression constructor = 276 jsAst.Expression constructor =
417 backend.emitter.constructorAccess(constant.type.element); 277 backend.emitter.constructorAccess(constant.type.element);
418 jsAst.New instantiation = 278 List<jsAst.Expression> fields =
419 new jsAst.New(constructor, _array(constant.fields)); 279 constant.fields.map(constantReference).toList(growable: false);
280 jsAst.New instantiation = new jsAst.New(constructor, fields);
420 return maybeAddTypeArguments(constant.type, instantiation); 281 return maybeAddTypeArguments(constant.type, instantiation);
421 } 282 }
422 283
423 String stripComments(String rawJavaScript) { 284 String stripComments(String rawJavaScript) {
424 return rawJavaScript.replaceAll(COMMENT_RE, ''); 285 return rawJavaScript.replaceAll(COMMENT_RE, '');
425 } 286 }
426 287
427 List<jsAst.Expression> _array(List<ConstantValue> values) {
428 return values.map(constantEmitter.reference).toList(growable: false);
429 }
430
431 jsAst.Expression maybeAddTypeArguments(InterfaceType type, 288 jsAst.Expression maybeAddTypeArguments(InterfaceType type,
432 jsAst.Expression value) { 289 jsAst.Expression value) {
433 if (type is InterfaceType && 290 if (type is InterfaceType &&
434 !type.treatAsRaw && 291 !type.treatAsRaw &&
435 backend.classNeedsRti(type.element)) { 292 backend.classNeedsRti(type.element)) {
436 InterfaceType interface = type; 293 InterfaceType interface = type;
437 RuntimeTypes rti = backend.rti; 294 RuntimeTypes rti = backend.rti;
438 Iterable<String> arguments = interface.typeArguments 295 Iterable<String> arguments = interface.typeArguments
439 .map((DartType type) => 296 .map((DartType type) =>
440 rti.getTypeRepresentationWithHashes(type, (_){})); 297 rti.getTypeRepresentationWithHashes(type, (_){}));
441 jsAst.Expression argumentList = 298 jsAst.Expression argumentList =
442 new jsAst.LiteralString('[${arguments.join(', ')}]'); 299 new jsAst.LiteralString('[${arguments.join(', ')}]');
443 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()), 300 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()),
444 [value, argumentList]); 301 [value, argumentList]);
445 } 302 }
446 return value; 303 return value;
447 } 304 }
448 305
449 @override 306 @override
450 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) { 307 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) {
451 return constantEmitter.reference(constant.referenced); 308 return constantReference(constant.referenced);
452 } 309 }
453 } 310 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698