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

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: Fix long line. Created 5 years, 10 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/code_emitter_task.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 { 7 typedef jsAst.Expression _ConstantReferenceGenerator(ConstantValue constant);
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 8
53 /** 9 /**
54 * Visitor for generating JavaScript expressions to refer to [ConstantValue]s. 10 * Generates the JavaScript expressions for constants.
55 * Do not use directly, use methods from [ConstantEmitter]. 11 *
12 * It uses a given [constantReferenceGenerator] to reference nested constants
13 * (if there are some). It is hence up to that function to decide which
14 * constants should be inlined or not.
56 */ 15 */
57 class ConstantReferenceEmitter 16 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> { 17 implements ConstantValueVisitor<jsAst.Expression, Null> {
167 18
168 // Matches blank lines, comment lines and trailing comments that can't be part 19 // Matches blank lines, comment lines and trailing comments that can't be part
169 // of a string. 20 // of a string.
170 static final RegExp COMMENT_RE = 21 static final RegExp COMMENT_RE =
171 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true); 22 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true);
172 23
173 final Compiler compiler; 24 final Compiler compiler;
174 final Namer namer; 25 final Namer namer;
26 final _ConstantReferenceGenerator constantReferenceGenerator;
175 final jsAst.Template makeConstantListTemplate; 27 final jsAst.Template makeConstantListTemplate;
176 final ConstantEmitter constantEmitter;
177 28
178 ConstantLiteralEmitter(this.compiler, 29 /**
179 this.namer, 30 * The given [constantReferenceGenerator] function must, when invoked with a
180 this.makeConstantListTemplate, 31 * constant, either return a reference or return its literal expression if it
181 this.constantEmitter); 32 * can be inlined.
33 */
34 ConstantEmitter(
35 this.compiler,
36 this.namer,
37 jsAst.Expression this.constantReferenceGenerator(ConstantValue constant),
38 this.makeConstantListTemplate);
182 39
40 /**
41 * Constructs a literal expression that evaluates to the constant. Uses a
42 * canonical name unless the constant can be emitted multiple times (as for
43 * numbers and strings).
44 */
183 jsAst.Expression generate(ConstantValue constant) { 45 jsAst.Expression generate(ConstantValue constant) {
184 return _visit(constant); 46 return _visit(constant);
185 } 47 }
186 48
187 jsAst.Expression _visit(ConstantValue constant) { 49 jsAst.Expression _visit(ConstantValue constant) {
188 return constant.accept(this, null); 50 return constant.accept(this, null);
189 } 51 }
190 52
191 @override 53 @override
192 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) { 54 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 */ 149 */
288 @override 150 @override
289 jsAst.Expression visitString(StringConstantValue constant, [_]) { 151 jsAst.Expression visitString(StringConstantValue constant, [_]) {
290 StringBuffer sb = new StringBuffer(); 152 StringBuffer sb = new StringBuffer();
291 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb); 153 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb);
292 return new jsAst.LiteralString('"$sb"'); 154 return new jsAst.LiteralString('"$sb"');
293 } 155 }
294 156
295 @override 157 @override
296 jsAst.Expression visitList(ListConstantValue constant, [_]) { 158 jsAst.Expression visitList(ListConstantValue constant, [_]) {
297 List<jsAst.Expression> elements = _array(constant.entries); 159 List<jsAst.Expression> elements = constant.entries
160 .map(constantReferenceGenerator)
161 .toList(growable: false);
298 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements); 162 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements);
299 jsAst.Expression value = makeConstantListTemplate.instantiate([array]); 163 jsAst.Expression value = makeConstantListTemplate.instantiate([array]);
300 return maybeAddTypeArguments(constant.type, value); 164 return maybeAddTypeArguments(constant.type, value);
301 } 165 }
302 166
303 @override 167 @override
304 jsAst.Expression visitMap(JavaScriptMapConstant constant, [_]) { 168 jsAst.Expression visitMap(JavaScriptMapConstant constant, [_]) {
305 jsAst.Expression jsMap() { 169 jsAst.Expression jsMap() {
306 List<jsAst.Property> properties = <jsAst.Property>[]; 170 List<jsAst.Property> properties = <jsAst.Property>[];
307 for (int i = 0; i < constant.length; i++) { 171 for (int i = 0; i < constant.length; i++) {
308 StringConstantValue key = constant.keys[i]; 172 StringConstantValue key = constant.keys[i];
309 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { 173 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) {
310 continue; 174 continue;
311 } 175 }
312 176
313 // Keys in literal maps must be emitted in place. 177 // Keys in literal maps must be emitted in place.
314 jsAst.Literal keyExpression = _visit(key); 178 jsAst.Literal keyExpression = _visit(key);
315 jsAst.Expression valueExpression = 179 jsAst.Expression valueExpression =
316 constantEmitter.reference(constant.values[i]); 180 constantReferenceGenerator(constant.values[i]);
317 properties.add(new jsAst.Property(keyExpression, valueExpression)); 181 properties.add(new jsAst.Property(keyExpression, valueExpression));
318 } 182 }
319 return new jsAst.ObjectInitializer(properties); 183 return new jsAst.ObjectInitializer(properties);
320 } 184 }
321 185
322 jsAst.Expression jsGeneralMap() { 186 jsAst.Expression jsGeneralMap() {
323 List<jsAst.Expression> data = <jsAst.Expression>[]; 187 List<jsAst.Expression> data = <jsAst.Expression>[];
324 for (int i = 0; i < constant.keys.length; i++) { 188 for (int i = 0; i < constant.keys.length; i++) {
325 jsAst.Expression keyExpression = 189 jsAst.Expression keyExpression = constantReferenceGenerator(constant.key s[i]);
326 constantEmitter.reference(constant.keys[i]);
327 jsAst.Expression valueExpression = 190 jsAst.Expression valueExpression =
328 constantEmitter.reference(constant.values[i]); 191 constantReferenceGenerator(constant.values[i]);
329 data.add(keyExpression); 192 data.add(keyExpression);
330 data.add(valueExpression); 193 data.add(valueExpression);
331 } 194 }
332 return new jsAst.ArrayInitializer(data); 195 return new jsAst.ArrayInitializer(data);
333 } 196 }
334 197
335 ClassElement classElement = constant.type.element; 198 ClassElement classElement = constant.type.element;
336 String className = classElement.name; 199 String className = classElement.name;
337 200
338 List<jsAst.Expression> arguments = <jsAst.Expression>[]; 201 List<jsAst.Expression> arguments = <jsAst.Expression>[];
339 202
340 // The arguments of the JavaScript constructor for any given Dart class 203 // The arguments of the JavaScript constructor for any given Dart class
341 // are in the same order as the members of the class element. 204 // are in the same order as the members of the class element.
342 int emittedArgumentCount = 0; 205 int emittedArgumentCount = 0;
343 classElement.implementation.forEachInstanceField( 206 classElement.implementation.forEachInstanceField(
344 (ClassElement enclosing, Element field) { 207 (ClassElement enclosing, Element field) {
345 if (field.name == JavaScriptMapConstant.LENGTH_NAME) { 208 if (field.name == JavaScriptMapConstant.LENGTH_NAME) {
346 arguments.add( 209 arguments.add(
347 new jsAst.LiteralNumber('${constant.keyList.entries.length}')); 210 new jsAst.LiteralNumber('${constant.keyList.entries.length}'));
348 } else if (field.name == JavaScriptMapConstant.JS_OBJECT_NAME) { 211 } else if (field.name == JavaScriptMapConstant.JS_OBJECT_NAME) {
349 arguments.add(jsMap()); 212 arguments.add(jsMap());
350 } else if (field.name == JavaScriptMapConstant.KEYS_NAME) { 213 } else if (field.name == JavaScriptMapConstant.KEYS_NAME) {
351 arguments.add(constantEmitter.reference(constant.keyList)); 214 arguments.add(constantReferenceGenerator(constant.keyList));
352 } else if (field.name == JavaScriptMapConstant.PROTO_VALUE) { 215 } else if (field.name == JavaScriptMapConstant.PROTO_VALUE) {
353 assert(constant.protoValue != null); 216 assert(constant.protoValue != null);
354 arguments.add(constantEmitter.reference(constant.protoValue)); 217 arguments.add(constantReferenceGenerator(constant.protoValue));
355 } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) { 218 } else if (field.name == JavaScriptMapConstant.JS_DATA_NAME) {
356 arguments.add(jsGeneralMap()); 219 arguments.add(jsGeneralMap());
357 } else { 220 } else {
358 compiler.internalError(field, 221 compiler.internalError(field,
359 "Compiler has unexpected field ${field.name} for " 222 "Compiler has unexpected field ${field.name} for "
360 "${className}."); 223 "${className}.");
361 } 224 }
362 emittedArgumentCount++; 225 emittedArgumentCount++;
363 }, 226 },
364 includeSuperAndInjectedMembers: true); 227 includeSuperAndInjectedMembers: true);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) { 271 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) {
409 Element element = constant.type.element; 272 Element element = constant.type.element;
410 if (element.isForeign(backend) 273 if (element.isForeign(backend)
411 && element.name == 'JS_CONST') { 274 && element.name == 'JS_CONST') {
412 StringConstantValue str = constant.fields[0]; 275 StringConstantValue str = constant.fields[0];
413 String value = str.primitiveValue.slowToString(); 276 String value = str.primitiveValue.slowToString();
414 return new jsAst.LiteralExpression(stripComments(value)); 277 return new jsAst.LiteralExpression(stripComments(value));
415 } 278 }
416 jsAst.Expression constructor = 279 jsAst.Expression constructor =
417 backend.emitter.constructorAccess(constant.type.element); 280 backend.emitter.constructorAccess(constant.type.element);
418 jsAst.New instantiation = 281 List<jsAst.Expression> fields =
419 new jsAst.New(constructor, _array(constant.fields)); 282 constant.fields.map(constantReferenceGenerator).toList(growable: false);
283 jsAst.New instantiation = new jsAst.New(constructor, fields);
420 return maybeAddTypeArguments(constant.type, instantiation); 284 return maybeAddTypeArguments(constant.type, instantiation);
421 } 285 }
422 286
423 String stripComments(String rawJavaScript) { 287 String stripComments(String rawJavaScript) {
424 return rawJavaScript.replaceAll(COMMENT_RE, ''); 288 return rawJavaScript.replaceAll(COMMENT_RE, '');
425 } 289 }
426 290
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, 291 jsAst.Expression maybeAddTypeArguments(InterfaceType type,
432 jsAst.Expression value) { 292 jsAst.Expression value) {
433 if (type is InterfaceType && 293 if (type is InterfaceType &&
434 !type.treatAsRaw && 294 !type.treatAsRaw &&
435 backend.classNeedsRti(type.element)) { 295 backend.classNeedsRti(type.element)) {
436 InterfaceType interface = type; 296 InterfaceType interface = type;
437 RuntimeTypes rti = backend.rti; 297 RuntimeTypes rti = backend.rti;
438 Iterable<String> arguments = interface.typeArguments 298 Iterable<String> arguments = interface.typeArguments
439 .map((DartType type) => 299 .map((DartType type) =>
440 rti.getTypeRepresentationWithHashes(type, (_){})); 300 rti.getTypeRepresentationWithHashes(type, (_){}));
441 jsAst.Expression argumentList = 301 jsAst.Expression argumentList =
442 new jsAst.LiteralString('[${arguments.join(', ')}]'); 302 new jsAst.LiteralString('[${arguments.join(', ')}]');
443 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()), 303 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()),
444 [value, argumentList]); 304 [value, argumentList]);
445 } 305 }
446 return value; 306 return value;
447 } 307 }
448 308
449 @override 309 @override
450 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) { 310 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) {
451 return constantEmitter.reference(constant.referenced); 311 return constantReferenceGenerator(constant.referenced);
452 } 312 }
453 } 313 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/code_emitter_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698