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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart

Issue 11415168: Revert "Emit constants using ASTs" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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 | sdk/lib/_internal/compiler/implementation/js_backend/emitter.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 class ConstantEmitter implements ConstantVisitor {
8 ConstantReferenceEmitter _referenceEmitter; 8 final Compiler compiler;
9 ConstantInitializerEmitter _initializerEmitter; 9 final Namer namer;
10 10
11 ConstantEmitter(Compiler compiler, Namer namer) { 11 CodeBuffer buffer;
12 _referenceEmitter = new ConstantReferenceEmitter(compiler, namer); 12 bool shouldEmitCanonicalVersion;
13 _initializerEmitter = new ConstantInitializerEmitter( 13
14 compiler, namer, _referenceEmitter); 14 ConstantEmitter(this.compiler, this.namer);
15
16 /**
17 * Unless the constant can be emitted multiple times (as for numbers and
18 * strings) use the canonical name.
19 */
20 void emitCanonicalVersionOfConstant(Constant constant, CodeBuffer newBuffer) {
21 shouldEmitCanonicalVersion = true;
22 buffer = newBuffer;
23 _visit(constant);
15 } 24 }
16 25
17 /** 26 /**
18 * Constructs an expression that is a reference to the constant. Uses a 27 * Emit the JavaScript code of the constant. If the constant must be
19 * canonical name unless the constant can be emitted multiple times (as for 28 * canonicalized this method emits the initialization value.
20 * numbers and strings).
21 */ 29 */
22 js.Expression reference(Constant constant) { 30 void emitJavaScriptCodeForConstant(Constant constant, CodeBuffer newBuffer) {
23 return _referenceEmitter.generate(constant); 31 shouldEmitCanonicalVersion = false;
32 buffer = newBuffer;
33 _visit(constant);
34 }
35
36 _visit(Constant constant) {
37 constant.accept(this);
38 }
39
40 void visitSentinel(SentinelConstant constant) {
41 if (shouldEmitCanonicalVersion) {
42 buffer.add(namer.CURRENT_ISOLATE);
43 } else {
44 compiler.internalError(
45 "The parameter sentinel constant does not need specific JS code");
46 }
47 }
48
49 void visitFunction(FunctionConstant constant) {
50 if (shouldEmitCanonicalVersion) {
51 buffer.add(namer.isolatePropertiesAccess(constant.element));
52 } else {
53 compiler.internalError(
54 "The function constant does not need specific JS code");
55 }
56 }
57
58 void visitNull(NullConstant constant) {
59 buffer.add("null");
60 }
61
62 void visitInt(IntConstant constant) {
63 buffer.add(constant.value.toString());
64 }
65
66 void visitDouble(DoubleConstant constant) {
67 double value = constant.value;
68 if (value.isNaN) {
69 buffer.add("(0/0)");
70 } else if (value == double.INFINITY) {
71 buffer.add("(1/0)");
72 } else if (value == -double.INFINITY) {
73 buffer.add("(-1/0)");
74 } else {
75 buffer.add("$value");
76 }
77 }
78
79 void visitTrue(TrueConstant constant) {
80 buffer.add("true");
81 }
82
83 void visitFalse(FalseConstant constant) {
84 buffer.add("false");
24 } 85 }
25 86
26 /** 87 /**
27 * Constructs an expression like [reference], but the expression is valid
28 * during isolate initialization.
29 */
30 js.Expression referenceInInitializationContext(Constant constant) {
31 return _referenceEmitter.generateInInitializationContext(constant);
32 }
33
34 /**
35 * Constructs an expression used to initialize a canonicalized constant.
36 */
37 js.Expression initializationExpression(Constant constant) {
38 return _initializerEmitter.generate(constant);
39 }
40 }
41
42 /**
43 * Visitor for generating JavaScript expressions to refer to [Constant]s.
44 * Do not use directly, use methods from [ConstantEmitter].
45 */
46 class ConstantReferenceEmitter implements ConstantVisitor<js.Expression> {
47 final Compiler compiler;
48 final Namer namer;
49 bool inIsolateInitializationContext = false;
50
51 ConstantReferenceEmitter(this.compiler, this.namer);
52
53 js.Expression generate(Constant constant) {
54 inIsolateInitializationContext = false;
55 return _visit(constant);
56 }
57
58 js.Expression generateInInitializationContext(Constant constant) {
59 inIsolateInitializationContext = true;
60 return _visit(constant);
61 }
62
63 js.Expression _visit(Constant constant) {
64 return constant.accept(this);
65 }
66
67 js.Expression visitSentinel(SentinelConstant constant) {
68 return new js.VariableUse(namer.CURRENT_ISOLATE);
69 }
70
71 js.Expression visitFunction(FunctionConstant constant) {
72 return inIsolateInitializationContext
73 ? new js.VariableUse(namer.isolatePropertiesAccess(constant.element))
74 : new js.VariableUse(namer.isolateAccess(constant.element));
75 }
76
77 js.Expression visitNull(NullConstant constant) {
78 return new js.LiteralNull();
79 }
80
81 js.Expression visitInt(IntConstant constant) {
82 return new js.LiteralNumber('${constant.value}');
83 }
84
85 js.Expression visitDouble(DoubleConstant constant) {
86 double value = constant.value;
87 if (value.isNaN) {
88 return new js.LiteralNumber("(0/0)");
89 } else if (value == double.INFINITY) {
90 return new js.LiteralNumber("(1/0)");
91 } else if (value == -double.INFINITY) {
92 return new js.LiteralNumber("(-1/0)");
93 } else {
94 return new js.LiteralNumber("$value");
95 }
96 }
97
98 js.Expression visitTrue(TrueConstant constant) {
99 if (compiler.enableMinification) {
100 // Use !0 for true.
101 return new js.Prefix("!", new js.LiteralNumber("0"));
102 } else {
103 return new js.LiteralBool(true);
104 }
105
106 }
107
108 js.Expression visitFalse(FalseConstant constant) {
109 if (compiler.enableMinification) {
110 // Use !1 for false.
111 return new js.Prefix("!", new js.LiteralNumber("1"));
112 } else {
113 return new js.LiteralBool(false);
114 }
115 }
116
117 /**
118 * Write the contents of the quoted string to a [CodeBuffer] in 88 * Write the contents of the quoted string to a [CodeBuffer] in
119 * a form that is valid as JavaScript string literal content. 89 * a form that is valid as JavaScript string literal content.
120 * The string is assumed quoted by double quote characters. 90 * The string is assumed quoted by double quote characters.
121 */ 91 */
122 js.Expression visitString(StringConstant constant) { 92 void visitString(StringConstant constant) {
123 // TODO(sra): If the string is long *and repeated* (and not on a hot path) 93 buffer.add('"');
124 // then it should be assigned to a name. We don't have reference counts (or 94 writeJsonEscapedCharsOn(constant.value.slowToString(), buffer);
125 // profile information) here, so this is the wrong place. 95 buffer.add('"');
126 StringBuffer sb = new StringBuffer();
127 writeJsonEscapedCharsOn(constant.value.slowToString(), sb);
128 return new js.LiteralString('"$sb"');
129 } 96 }
130 97
131 js.Expression emitCanonicalVersion(Constant constant) { 98 void emitCanonicalVersion(Constant constant) {
132 String name = namer.constantName(constant); 99 String name = namer.constantName(constant);
133 if (inIsolateInitializationContext) { 100 buffer.add(namer.isolatePropertiesAccessForConstant(name));
134 // $ISOLATE.$ISOLATE_PROPERTIES.$name
135 return new js.PropertyAccess.field(
136 new js.PropertyAccess.field(
137 new js.VariableUse(namer.ISOLATE),
138 namer.ISOLATE_PROPERTIES),
139 name);
140 } else {
141 return new js.PropertyAccess.field(
142 new js.VariableUse(namer.CURRENT_ISOLATE),
143 name);
144 }
145 } 101 }
146 102
147 js.Expression visitList(ListConstant constant) { 103 void visitList(ListConstant constant) {
148 return emitCanonicalVersion(constant); 104 if (shouldEmitCanonicalVersion) {
149 } 105 emitCanonicalVersion(constant);
150 106 } else {
151 js.Expression visitMap(MapConstant constant) { 107 shouldEmitCanonicalVersion = true;
152 return emitCanonicalVersion(constant); 108 buffer.add("${namer.ISOLATE}.makeConstantList");
153 } 109 buffer.add("([");
154 110 for (int i = 0; i < constant.entries.length; i++) {
155 js.Expression visitType(TypeConstant constant) { 111 if (i != 0) buffer.add(", ");
156 return emitCanonicalVersion(constant); 112 _visit(constant.entries[i]);
157 } 113 }
158 114 buffer.add("])");
159 js.Expression visitConstructed(ConstructedConstant constant) { 115 }
160 return emitCanonicalVersion(constant);
161 }
162 }
163
164 /**
165 * Visitor for generating JavaScript expressions to initialize [Constant]s.
166 * Do not use directly; use methods from [ConstantEmitter].
167 */
168 class ConstantInitializerEmitter implements ConstantVisitor<js.Expression> {
169 final Compiler compiler;
170 final Namer namer;
171 final ConstantReferenceEmitter referenceEmitter;
172
173 ConstantInitializerEmitter(this.compiler, this.namer, this.referenceEmitter);
174
175 js.Expression generate(Constant constant) {
176 return _visit(constant);
177 }
178
179 js.Expression _visit(Constant constant) {
180 return constant.accept(this);
181 }
182
183 js.Expression _reference(Constant constant) {
184 return referenceEmitter.generateInInitializationContext(constant);
185 }
186
187 js.Expression visitSentinel(SentinelConstant constant) {
188 compiler.internalError(
189 "The parameter sentinel constant does not need specific JS code");
190 }
191
192 js.Expression visitFunction(FunctionConstant constant) {
193 compiler.internalError(
194 "The function constant does not need specific JS code");
195 }
196
197 js.Expression visitNull(NullConstant constant) {
198 return _reference(constant);
199 }
200
201 js.Expression visitInt(IntConstant constant) {
202 return _reference(constant);
203 }
204
205 js.Expression visitDouble(DoubleConstant constant) {
206 return _reference(constant);
207 }
208
209 js.Expression visitTrue(TrueConstant constant) {
210 return _reference(constant);
211 }
212
213 js.Expression visitFalse(FalseConstant constant) {
214 return _reference(constant);
215 }
216
217 js.Expression visitString(StringConstant constant) {
218 // TODO(sra): Some larger strings are worth sharing.
219 return _reference(constant);
220 }
221
222 js.Expression visitList(ListConstant constant) {
223 return new js.Call(
224 new js.PropertyAccess.field(
225 new js.VariableUse(namer.ISOLATE),
226 'makeConstantList'),
227 [new js.ArrayInitializer.from(_array(constant.entries))]);
228 } 116 }
229 117
230 String getJsConstructor(ClassElement element) { 118 String getJsConstructor(ClassElement element) {
231 return namer.isolatePropertiesAccess(element); 119 return namer.isolatePropertiesAccess(element);
232 } 120 }
233 121
234 js.Expression visitMap(MapConstant constant) { 122 void visitMap(MapConstant constant) {
235 js.Expression jsMap() { 123 if (shouldEmitCanonicalVersion) {
236 List<js.Property> properties = <js.Property>[]; 124 emitCanonicalVersion(constant);
237 int valueIndex = 0; 125 } else {
238 for (int i = 0; i < constant.keys.entries.length; i++) { 126 void writeJsMap() {
239 StringConstant key = constant.keys.entries[i]; 127 buffer.add("{");
240 if (key.value == MapConstant.PROTO_PROPERTY) continue; 128 int valueIndex = 0;
129 for (int i = 0; i < constant.keys.entries.length; i++) {
130 StringConstant key = constant.keys.entries[i];
131 if (key.value == MapConstant.PROTO_PROPERTY) continue;
241 132
242 // Keys in literal maps must be emitted in place. 133 if (valueIndex != 0) buffer.add(", ");
243 js.Literal keyExpression = _visit(key); 134
244 js.Expression valueExpression = 135 // Keys in literal maps must be emitted in place.
245 _reference(constant.values[valueIndex++]); 136 emitJavaScriptCodeForConstant(key, buffer);
246 properties.add(new js.Property(keyExpression, valueExpression)); 137
138 buffer.add(": ");
139 emitCanonicalVersionOfConstant(constant.values[valueIndex++], buffer);
140 }
141 buffer.add("}");
142 if (valueIndex != constant.values.length) {
143 compiler.internalError("Bad value count.");
144 }
247 } 145 }
248 if (valueIndex != constant.values.length) { 146
249 compiler.internalError("Bad value count."); 147 void badFieldCountError() {
148 compiler.internalError(
149 "Compiler and ConstantMap disagree on number of fields.");
250 } 150 }
251 return new js.ObjectInitializer(properties); 151
152 shouldEmitCanonicalVersion = true;
153
154 ClassElement classElement = constant.type.element;
155 buffer.add("new ");
156 buffer.add(getJsConstructor(classElement));
157 buffer.add("(");
158 // The arguments of the JavaScript constructor for any given Dart class
159 // are in the same order as the members of the class element.
160 int emittedArgumentCount = 0;
161 classElement.implementation.forEachInstanceField(
162 (ClassElement enclosing, Element field) {
163 if (emittedArgumentCount != 0) buffer.add(", ");
164 if (field.name == MapConstant.LENGTH_NAME) {
165 buffer.add(constant.keys.entries.length);
166 } else if (field.name == MapConstant.JS_OBJECT_NAME) {
167 writeJsMap();
168 } else if (field.name == MapConstant.KEYS_NAME) {
169 emitCanonicalVersionOfConstant(constant.keys, buffer);
170 } else if (field.name == MapConstant.PROTO_VALUE) {
171 assert(constant.protoValue != null);
172 emitCanonicalVersionOfConstant(constant.protoValue, buffer);
173 } else {
174 badFieldCountError();
175 }
176 emittedArgumentCount++;
177 },
178 includeBackendMembers: true,
179 includeSuperMembers: true);
180 if ((constant.protoValue == null && emittedArgumentCount != 3) ||
181 (constant.protoValue != null && emittedArgumentCount != 4)) {
182 badFieldCountError();
183 }
184 buffer.add(")");
252 } 185 }
253
254 void badFieldCountError() {
255 compiler.internalError(
256 "Compiler and ConstantMap disagree on number of fields.");
257 }
258
259 ClassElement classElement = constant.type.element;
260
261 List<js.Expression> arguments = <js.Expression>[];
262
263 // The arguments of the JavaScript constructor for any given Dart class
264 // are in the same order as the members of the class element.
265 int emittedArgumentCount = 0;
266 classElement.implementation.forEachInstanceField(
267 (ClassElement enclosing, Element field) {
268 if (field.name == MapConstant.LENGTH_NAME) {
269 arguments.add(
270 new js.LiteralNumber('${constant.keys.entries.length}'));
271 } else if (field.name == MapConstant.JS_OBJECT_NAME) {
272 arguments.add(jsMap());
273 } else if (field.name == MapConstant.KEYS_NAME) {
274 arguments.add(_reference(constant.keys));
275 } else if (field.name == MapConstant.PROTO_VALUE) {
276 assert(constant.protoValue != null);
277 arguments.add(_reference(constant.protoValue));
278 } else {
279 badFieldCountError();
280 }
281 emittedArgumentCount++;
282 },
283 includeBackendMembers: true,
284 includeSuperMembers: true);
285
286 if ((constant.protoValue == null && emittedArgumentCount != 3) ||
287 (constant.protoValue != null && emittedArgumentCount != 4)) {
288 badFieldCountError();
289 }
290
291 return new js.New(
292 new js.VariableUse(getJsConstructor(classElement)),
293 arguments);
294 } 186 }
295 187
296 js.Expression visitType(TypeConstant constant) { 188 void visitType(TypeConstant constant) {
297 SourceString helperSourceName = const SourceString('createRuntimeType'); 189 if (shouldEmitCanonicalVersion) {
298 Element helper = compiler.findHelper(helperSourceName); 190 emitCanonicalVersion(constant);
299 JavaScriptBackend backend = compiler.backend;
300 String helperName = backend.namer.getName(helper);
301 DartType type = constant.representedType;
302 Element element = type.element;
303 String typeName;
304 if (type.kind == TypeKind.INTERFACE) {
305 typeName =
306 backend.rti.getStringRepresentation(type, expandRawType: true);
307 } else { 191 } else {
308 assert(type.kind == TypeKind.TYPEDEF); 192 SourceString helperSourceName =
309 typeName = element.name.slowToString(); 193 const SourceString('createRuntimeType');
194 Element helper = compiler.findHelper(helperSourceName);
195 JavaScriptBackend backend = compiler.backend;
196 String helperName = backend.namer.getName(helper);
197 DartType type = constant.representedType;
198 Element element = type.element;
199 String typeName;
200 if (type.kind == TypeKind.INTERFACE) {
201 typeName =
202 backend.rti.getStringRepresentation(type, expandRawType: true);
203 } else {
204 assert(type.kind == TypeKind.TYPEDEF);
205 typeName = element.name.slowToString();
206 }
207 buffer.add("${namer.CURRENT_ISOLATE}.$helperName('$typeName')");
310 } 208 }
311 return new js.Call(
312 new js.PropertyAccess.field(
313 new js.VariableUse(namer.CURRENT_ISOLATE),
314 helperName),
315 [new js.LiteralString("'$typeName'")]);
316 } 209 }
317 210
318 js.Expression visitConstructed(ConstructedConstant constant) { 211 void visitConstructed(ConstructedConstant constant) {
319 return new js.New( 212 if (shouldEmitCanonicalVersion) {
320 new js.VariableUse(getJsConstructor(constant.type.element)), 213 emitCanonicalVersion(constant);
321 _array(constant.fields)); 214 } else {
322 } 215 shouldEmitCanonicalVersion = true;
323 216
324 List<js.Expression> _array(List<Constant> values) { 217 buffer.add("new ");
325 List<js.Expression> valueList = <js.Expression>[]; 218 buffer.add(getJsConstructor(constant.type.element));
326 for (int i = 0; i < values.length; i++) { 219 buffer.add("(");
327 valueList.add(_reference(values[i])); 220 for (int i = 0; i < constant.fields.length; i++) {
221 if (i != 0) buffer.add(", ");
222 _visit(constant.fields[i]);
223 }
224 buffer.add(")");
328 } 225 }
329 return valueList;
330 } 226 }
331 } 227 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698