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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/interceptor_stub_generator.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 class InterceptorStubGenerator { 7 class InterceptorStubGenerator {
8 final Compiler compiler; 8 final Compiler compiler;
9 final Namer namer; 9 final Namer namer;
10 final JavaScriptBackend backend; 10 final JavaScriptBackend backend;
(...skipping 12 matching lines...) Expand all
23 /** 23 /**
24 * Build a JavaScrit AST node for doing a type check on 24 * Build a JavaScrit AST node for doing a type check on
25 * [cls]. [cls] must be a non-native interceptor class. 25 * [cls]. [cls] must be a non-native interceptor class.
26 */ 26 */
27 jsAst.Statement buildInterceptorCheck(ClassElement cls) { 27 jsAst.Statement buildInterceptorCheck(ClassElement cls) {
28 jsAst.Expression condition; 28 jsAst.Expression condition;
29 assert(backend.isInterceptorClass(cls)); 29 assert(backend.isInterceptorClass(cls));
30 if (cls == helpers.jsBoolClass) { 30 if (cls == helpers.jsBoolClass) {
31 condition = js('(typeof receiver) == "boolean"'); 31 condition = js('(typeof receiver) == "boolean"');
32 } else if (cls == helpers.jsIntClass || 32 } else if (cls == helpers.jsIntClass ||
33 cls == helpers.jsDoubleClass || 33 cls == helpers.jsDoubleClass ||
34 cls == helpers.jsNumberClass) { 34 cls == helpers.jsNumberClass) {
35 throw 'internal error'; 35 throw 'internal error';
36 } else if (cls == helpers.jsArrayClass || 36 } else if (cls == helpers.jsArrayClass ||
37 cls == helpers.jsMutableArrayClass || 37 cls == helpers.jsMutableArrayClass ||
38 cls == helpers.jsFixedArrayClass || 38 cls == helpers.jsFixedArrayClass ||
39 cls == helpers.jsExtendableArrayClass) { 39 cls == helpers.jsExtendableArrayClass) {
40 condition = js('receiver.constructor == Array'); 40 condition = js('receiver.constructor == Array');
41 } else if (cls == helpers.jsStringClass) { 41 } else if (cls == helpers.jsStringClass) {
42 condition = js('(typeof receiver) == "string"'); 42 condition = js('(typeof receiver) == "string"');
43 } else if (cls == helpers.jsNullClass) { 43 } else if (cls == helpers.jsNullClass) {
44 condition = js('receiver == null'); 44 condition = js('receiver == null');
45 } else { 45 } else {
46 throw 'internal error'; 46 throw 'internal error';
47 } 47 }
48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); 48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]);
49 } 49 }
50 50
51 bool hasArray = false; 51 bool hasArray = false;
52 bool hasBool = false; 52 bool hasBool = false;
53 bool hasDouble = false; 53 bool hasDouble = false;
54 bool hasInt = false; 54 bool hasInt = false;
55 bool hasNull = false; 55 bool hasNull = false;
56 bool hasNumber = false; 56 bool hasNumber = false;
57 bool hasString = false; 57 bool hasString = false;
58 bool hasNative = false; 58 bool hasNative = false;
59 bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer 59 bool anyNativeClasses =
60 .hasInstantiatedNativeClasses(); 60 compiler.enqueuer.codegen.nativeEnqueuer.hasInstantiatedNativeClasses();
61 61
62 for (ClassElement cls in classes) { 62 for (ClassElement cls in classes) {
63 if (cls == helpers.jsArrayClass || 63 if (cls == helpers.jsArrayClass ||
64 cls == helpers.jsMutableArrayClass || 64 cls == helpers.jsMutableArrayClass ||
65 cls == helpers.jsFixedArrayClass || 65 cls == helpers.jsFixedArrayClass ||
66 cls == helpers.jsExtendableArrayClass) hasArray = true; 66 cls == helpers.jsExtendableArrayClass)
67 else if (cls == helpers.jsBoolClass) hasBool = true; 67 hasArray = true;
68 else if (cls == helpers.jsDoubleClass) hasDouble = true; 68 else if (cls == helpers.jsBoolClass)
69 else if (cls == helpers.jsIntClass) hasInt = true; 69 hasBool = true;
70 else if (cls == helpers.jsNullClass) hasNull = true; 70 else if (cls == helpers.jsDoubleClass)
71 else if (cls == helpers.jsNumberClass) hasNumber = true; 71 hasDouble = true;
72 else if (cls == helpers.jsStringClass) hasString = true; 72 else if (cls == helpers.jsIntClass)
73 hasInt = true;
74 else if (cls == helpers.jsNullClass)
75 hasNull = true;
76 else if (cls == helpers.jsNumberClass)
77 hasNumber = true;
78 else if (cls == helpers.jsStringClass)
79 hasString = true;
73 else { 80 else {
74 // The set of classes includes classes mixed-in to interceptor classes 81 // The set of classes includes classes mixed-in to interceptor classes
75 // and user extensions of native classes. 82 // and user extensions of native classes.
76 // 83 //
77 // The set of classes also includes the 'primitive' interceptor 84 // The set of classes also includes the 'primitive' interceptor
78 // PlainJavaScriptObject even when it has not been resolved, since it is 85 // PlainJavaScriptObject even when it has not been resolved, since it is
79 // only resolved through the reference in getNativeInterceptor when 86 // only resolved through the reference in getNativeInterceptor when
80 // getNativeInterceptor is marked as used. Guard against probing 87 // getNativeInterceptor is marked as used. Guard against probing
81 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. 88 // unresolved PlainJavaScriptObject by testing for anyNativeClasses.
82 89
(...skipping 18 matching lines...) Expand all
101 jsAst.Statement whenNumber; 108 jsAst.Statement whenNumber;
102 109
103 /// Note: there are two number classes in play: Dart's [num], 110 /// Note: there are two number classes in play: Dart's [num],
104 /// and JavaScript's Number (typeof receiver == 'number'). This 111 /// and JavaScript's Number (typeof receiver == 'number'). This
105 /// is the fallback used when we have determined that receiver 112 /// is the fallback used when we have determined that receiver
106 /// is a JavaScript Number. 113 /// is a JavaScript Number.
107 jsAst.Expression interceptorForNumber = interceptorFor( 114 jsAst.Expression interceptorForNumber = interceptorFor(
108 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass); 115 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass);
109 116
110 if (hasInt) { 117 if (hasInt) {
111 whenNumber = js.statement('''{ 118 whenNumber = js.statement(
119 '''{
112 if (Math.floor(receiver) == receiver) return #; 120 if (Math.floor(receiver) == receiver) return #;
113 return #; 121 return #;
114 }''', [interceptorFor(helpers.jsIntClass), interceptorForNumber]); 122 }''',
123 [interceptorFor(helpers.jsIntClass), interceptorForNumber]);
115 } else { 124 } else {
116 whenNumber = js.statement('return #', interceptorForNumber); 125 whenNumber = js.statement('return #', interceptorForNumber);
117 } 126 }
118 statements.add( 127 statements
119 js.statement('if (typeof receiver == "number") #;', whenNumber)); 128 .add(js.statement('if (typeof receiver == "number") #;', whenNumber));
120 } 129 }
121 130
122 if (hasString) { 131 if (hasString) {
123 statements.add(buildInterceptorCheck(helpers.jsStringClass)); 132 statements.add(buildInterceptorCheck(helpers.jsStringClass));
124 } 133 }
125 if (hasNull) { 134 if (hasNull) {
126 statements.add(buildInterceptorCheck(helpers.jsNullClass)); 135 statements.add(buildInterceptorCheck(helpers.jsNullClass));
127 } else { 136 } else {
128 // Returning "undefined" or "null" here will provoke a JavaScript 137 // Returning "undefined" or "null" here will provoke a JavaScript
129 // TypeError which is later identified as a null-error by 138 // TypeError which is later identified as a null-error by
130 // [unwrapException] in js_helper.dart. 139 // [unwrapException] in js_helper.dart.
131 statements.add( 140 statements.add(js.statement('if (receiver == null) return receiver'));
132 js.statement('if (receiver == null) return receiver'));
133 } 141 }
134 if (hasBool) { 142 if (hasBool) {
135 statements.add(buildInterceptorCheck(helpers.jsBoolClass)); 143 statements.add(buildInterceptorCheck(helpers.jsBoolClass));
136 } 144 }
137 // TODO(ahe): It might be faster to check for Array before 145 // TODO(ahe): It might be faster to check for Array before
138 // function and bool. 146 // function and bool.
139 if (hasArray) { 147 if (hasArray) {
140 statements.add(buildInterceptorCheck(helpers.jsArrayClass)); 148 statements.add(buildInterceptorCheck(helpers.jsArrayClass));
141 } 149 }
142 150
143 if (hasNative) { 151 if (hasNative) {
144 statements.add(js.statement(r'''{ 152 statements.add(js.statement(
153 r'''{
145 if (typeof receiver != "object") { 154 if (typeof receiver != "object") {
146 if (typeof receiver == "function" ) return #; 155 if (typeof receiver == "function" ) return #;
147 return receiver; 156 return receiver;
148 } 157 }
149 if (receiver instanceof #) return receiver; 158 if (receiver instanceof #) return receiver;
150 return #(receiver); 159 return #(receiver);
151 }''', [ 160 }''',
152 interceptorFor(helpers.jsJavaScriptFunctionClass), 161 [
153 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), 162 interceptorFor(helpers.jsJavaScriptFunctionClass),
154 backend.emitter 163 backend.emitter.constructorAccess(compiler.coreClasses.objectClass),
155 .staticFunctionAccess(helpers.getNativeInterceptorMethod)])); 164 backend.emitter
156 165 .staticFunctionAccess(helpers.getNativeInterceptorMethod)
166 ]));
157 } else { 167 } else {
158 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; 168 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass;
159 if (compiler.codegenWorld 169 if (compiler.codegenWorld.directlyInstantiatedClasses
160 .directlyInstantiatedClasses.contains(jsUnknown)) { 170 .contains(jsUnknown)) {
161 statements.add( 171 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [
162 js.statement('if (!(receiver instanceof #)) return #;', 172 backend.emitter.constructorAccess(compiler.coreClasses.objectClass),
163 [backend.emitter.constructorAccess( 173 interceptorFor(jsUnknown)
164 compiler.coreClasses.objectClass), 174 ]));
165 interceptorFor(jsUnknown)]));
166 } 175 }
167 176
168 statements.add(js.statement('return receiver')); 177 statements.add(js.statement('return receiver'));
169 } 178 }
170 179
171 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); 180 return js('''function(receiver) { #; }''', new jsAst.Block(statements));
172 } 181 }
173 182
174 // Returns a statement that takes care of performance critical 183 // Returns a statement that takes care of performance critical
175 // common case for a one-shot interceptor, or null if there is no 184 // common case for a one-shot interceptor, or null if there is no
176 // fast path. 185 // fast path.
177 jsAst.Statement _fastPathForOneShotInterceptor(Selector selector, 186 jsAst.Statement _fastPathForOneShotInterceptor(
178 Set<ClassElement> classes) { 187 Selector selector, Set<ClassElement> classes) {
179
180 if (selector.isOperator) { 188 if (selector.isOperator) {
181 String name = selector.name; 189 String name = selector.name;
182 if (name == '==') { 190 if (name == '==') {
183 return js.statement('''{ 191 return js.statement('''{
184 if (receiver == null) return a0 == null; 192 if (receiver == null) return a0 == null;
185 if (typeof receiver != "object") 193 if (typeof receiver != "object")
186 return a0 != null && receiver === a0; 194 return a0 != null && receiver === a0;
187 }'''); 195 }''');
188 } 196 }
189 if (!classes.contains(helpers.jsIntClass) 197 if (!classes.contains(helpers.jsIntClass) &&
190 && !classes.contains(helpers.jsNumberClass) 198 !classes.contains(helpers.jsNumberClass) &&
191 && !classes.contains(helpers.jsDoubleClass)) { 199 !classes.contains(helpers.jsDoubleClass)) {
192 return null; 200 return null;
193 } 201 }
194 if (selector.argumentCount == 1) { 202 if (selector.argumentCount == 1) {
195 // The following operators do not map to a JavaScript operator. 203 // The following operators do not map to a JavaScript operator.
196 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { 204 if (name == '~/' || name == '<<' || name == '%' || name == '>>') {
197 return null; 205 return null;
198 } 206 }
199 jsAst.Expression result = js('receiver $name a0'); 207 jsAst.Expression result = js('receiver $name a0');
200 if (name == '&' || name == '|' || name == '^') { 208 if (name == '&' || name == '|' || name == '^') {
201 result = js('# >>> 0', result); 209 result = js('# >>> 0', result);
202 } 210 }
203 return js.statement( 211 return js.statement(
204 'if (typeof receiver == "number" && typeof a0 == "number")' 212 'if (typeof receiver == "number" && typeof a0 == "number")'
205 ' return #;', 213 ' return #;',
206 result); 214 result);
207 } else if (name == 'unary-') { 215 } else if (name == 'unary-') {
208 return js.statement( 216 return js
209 'if (typeof receiver == "number") return -receiver'); 217 .statement('if (typeof receiver == "number") return -receiver');
210 } else { 218 } else {
211 assert(name == '~'); 219 assert(name == '~');
212 return js.statement(''' 220 return js.statement('''
213 if (typeof receiver == "number" && Math.floor(receiver) == receiver) 221 if (typeof receiver == "number" && Math.floor(receiver) == receiver)
214 return (~receiver) >>> 0; 222 return (~receiver) >>> 0;
215 '''); 223 ''');
216 } 224 }
217 } else if (selector.isIndex || selector.isIndexSet) { 225 } else if (selector.isIndex || selector.isIndexSet) {
218 // For an index operation, this code generates: 226 // For an index operation, this code generates:
219 // 227 //
(...skipping 11 matching lines...) Expand all
231 // if (typeof a0 === "number") { 239 // if (typeof a0 === "number") {
232 // if (receiver.constructor == Array && !receiver.immutable$list) { 240 // if (receiver.constructor == Array && !receiver.immutable$list) {
233 // if (a0 >>> 0 === a0 && a0 < receiver.length) { 241 // if (a0 >>> 0 === a0 && a0 < receiver.length) {
234 // return receiver[a0] = a1; 242 // return receiver[a0] = a1;
235 // } 243 // }
236 // } 244 // }
237 // } 245 // }
238 bool containsArray = classes.contains(helpers.jsArrayClass); 246 bool containsArray = classes.contains(helpers.jsArrayClass);
239 bool containsString = classes.contains(helpers.jsStringClass); 247 bool containsString = classes.contains(helpers.jsStringClass);
240 bool containsJsIndexable = 248 bool containsJsIndexable =
241 helpers.jsIndexingBehaviorInterface.isResolved && classes.any((cls) { 249 helpers.jsIndexingBehaviorInterface.isResolved &&
242 return compiler.world.isSubtypeOf(cls, 250 classes.any((cls) {
243 helpers.jsIndexingBehaviorInterface); 251 return compiler.world
244 }); 252 .isSubtypeOf(cls, helpers.jsIndexingBehaviorInterface);
253 });
245 // The index set operator requires a check on its set value in 254 // The index set operator requires a check on its set value in
246 // checked mode, so we don't optimize the interceptor if the 255 // checked mode, so we don't optimize the interceptor if the
247 // compiler has type assertions enabled. 256 // compiler has type assertions enabled.
248 if (selector.isIndexSet 257 if (selector.isIndexSet &&
249 && (compiler.options.enableTypeAssertions || !containsArray)) { 258 (compiler.options.enableTypeAssertions || !containsArray)) {
250 return null; 259 return null;
251 } 260 }
252 if (!containsArray && !containsString) { 261 if (!containsArray && !containsString) {
253 return null; 262 return null;
254 } 263 }
255 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); 264 jsAst.Expression arrayCheck = js('receiver.constructor == Array');
256 jsAst.Expression indexableCheck = 265 jsAst.Expression indexableCheck =
257 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); 266 backend.generateIsJsIndexableCall(js('receiver'), js('receiver'));
258 267
259 jsAst.Expression orExp(left, right) { 268 jsAst.Expression orExp(left, right) {
260 return left == null ? right : js('# || #', [left, right]); 269 return left == null ? right : js('# || #', [left, right]);
261 } 270 }
262 271
263 if (selector.isIndex) { 272 if (selector.isIndex) {
264 jsAst.Expression typeCheck; 273 jsAst.Expression typeCheck;
265 if (containsArray) { 274 if (containsArray) {
266 typeCheck = arrayCheck; 275 typeCheck = arrayCheck;
267 } 276 }
268 277
269 if (containsString) { 278 if (containsString) {
270 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); 279 typeCheck = orExp(typeCheck, js('typeof receiver == "string"'));
271 } 280 }
272 281
273 if (containsJsIndexable) { 282 if (containsJsIndexable) {
274 typeCheck = orExp(typeCheck, indexableCheck); 283 typeCheck = orExp(typeCheck, indexableCheck);
275 } 284 }
276 285
277 return js.statement(''' 286 return js.statement(
287 '''
278 if (typeof a0 === "number") 288 if (typeof a0 === "number")
279 if (#) 289 if (#)
280 if ((a0 >>> 0) === a0 && a0 < receiver.length) 290 if ((a0 >>> 0) === a0 && a0 < receiver.length)
281 return receiver[a0]; 291 return receiver[a0];
282 ''', typeCheck); 292 ''',
293 typeCheck);
283 } else { 294 } else {
284 jsAst.Expression typeCheck; 295 jsAst.Expression typeCheck;
285 if (containsArray) { 296 if (containsArray) {
286 typeCheck = arrayCheck; 297 typeCheck = arrayCheck;
287 } 298 }
288 299
289 if (containsJsIndexable) { 300 if (containsJsIndexable) {
290 typeCheck = orExp(typeCheck, indexableCheck); 301 typeCheck = orExp(typeCheck, indexableCheck);
291 } 302 }
292 303
293 return js.statement(r''' 304 return js.statement(
305 r'''
294 if (typeof a0 === "number") 306 if (typeof a0 === "number")
295 if (# && !receiver.immutable$list && 307 if (# && !receiver.immutable$list &&
296 (a0 >>> 0) === a0 && a0 < receiver.length) 308 (a0 >>> 0) === a0 && a0 < receiver.length)
297 return receiver[a0] = a1; 309 return receiver[a0] = a1;
298 ''', typeCheck); 310 ''',
311 typeCheck);
299 } 312 }
300 } 313 }
301 return null; 314 return null;
302 } 315 }
303 316
304 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { 317 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) {
305 Selector selector = backend.oneShotInterceptors[name]; 318 Selector selector = backend.oneShotInterceptors[name];
306 Set<ClassElement> classes = 319 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector.name);
307 backend.getInterceptedClassesOn(selector.name);
308 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); 320 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes);
309 321
310 List<String> parameterNames = <String>[]; 322 List<String> parameterNames = <String>[];
311 parameterNames.add('receiver'); 323 parameterNames.add('receiver');
312 324
313 if (selector.isSetter) { 325 if (selector.isSetter) {
314 parameterNames.add('value'); 326 parameterNames.add('value');
315 } else { 327 } else {
316 for (int i = 0; i < selector.argumentCount; i++) { 328 for (int i = 0; i < selector.argumentCount; i++) {
317 parameterNames.add('a$i'); 329 parameterNames.add('a$i');
318 } 330 }
319 } 331 }
320 332
321 jsAst.Name invocationName = backend.namer.invocationName(selector); 333 jsAst.Name invocationName = backend.namer.invocationName(selector);
322 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary); 334 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary);
323 335
324 jsAst.Statement optimizedPath = 336 jsAst.Statement optimizedPath =
325 _fastPathForOneShotInterceptor(selector, classes); 337 _fastPathForOneShotInterceptor(selector, classes);
326 if (optimizedPath == null) optimizedPath = js.statement(';'); 338 if (optimizedPath == null) optimizedPath = js.statement(';');
327 339
328 return js( 340 return js('function(#) { #; return #.#(receiver).#(#) }', [
329 'function(#) { #; return #.#(receiver).#(#) }', 341 parameterNames,
330 [parameterNames, 342 optimizedPath,
331 optimizedPath, 343 globalObject,
332 globalObject, getInterceptorName, invocationName, parameterNames]); 344 getInterceptorName,
345 invocationName,
346 parameterNames
347 ]);
333 } 348 }
334 349
335 jsAst.ArrayInitializer generateTypeToInterceptorMap() { 350 jsAst.ArrayInitializer generateTypeToInterceptorMap() {
336 // TODO(sra): Perhaps inject a constant instead? 351 // TODO(sra): Perhaps inject a constant instead?
337 CustomElementsAnalysis analysis = backend.customElementsAnalysis; 352 CustomElementsAnalysis analysis = backend.customElementsAnalysis;
338 if (!analysis.needsTable) return null; 353 if (!analysis.needsTable) return null;
339 354
340 List<jsAst.Expression> elements = <jsAst.Expression>[]; 355 List<jsAst.Expression> elements = <jsAst.Expression>[];
341 JavaScriptConstantCompiler handler = backend.constants; 356 JavaScriptConstantCompiler handler = backend.constants;
342 List<ConstantValue> constants = 357 List<ConstantValue> constants =
(...skipping 19 matching lines...) Expand all
362 // A.bar() {} 377 // A.bar() {}
363 // } 378 // }
364 // 379 //
365 // Which are described by the map 380 // Which are described by the map
366 // 381 //
367 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} 382 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar}
368 // 383 //
369 // We expect most of the time the map will be a singleton. 384 // We expect most of the time the map will be a singleton.
370 var properties = []; 385 var properties = [];
371 for (Element member in analysis.constructors(classElement)) { 386 for (Element member in analysis.constructors(classElement)) {
372 properties.add( 387 properties.add(new jsAst.Property(js.string(member.name),
373 new jsAst.Property( 388 backend.emitter.staticFunctionAccess(member)));
374 js.string(member.name),
375 backend.emitter.staticFunctionAccess(member)));
376 } 389 }
377 390
378 var map = new jsAst.ObjectInitializer(properties); 391 var map = new jsAst.ObjectInitializer(properties);
379 elements.add(map); 392 elements.add(map);
380 } 393 }
381 } 394 }
382 } 395 }
383 396
384 return new jsAst.ArrayInitializer(elements); 397 return new jsAst.ArrayInitializer(elements);
385 } 398 }
386 } 399 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_emitter/headers.dart ('k') | pkg/compiler/lib/src/js_emitter/js_emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698