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

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

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

Powered by Google App Engine
This is Rietveld 408576698