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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart

Issue 246633006: Revert "JS templates" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 | 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 dart2js.js_emitter; 5 part of dart2js.js_emitter;
6 6
7 /** 7 /**
8 * Generates the code for all used classes in the program. Static fields (even 8 * Generates the code for all used classes in the program. Static fields (even
9 * in classes) are ignored, since they can be treated as non-class elements. 9 * in classes) are ignored, since they can be treated as non-class elements.
10 * 10 *
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; 141 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); 142 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST);
143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); 143 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
144 const RANGE3_ADJUST = 144 const RANGE3_ADJUST =
145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); 145 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
146 146
147 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; 147 String receiverParamName = compiler.enableMinification ? "r" : "receiver";
148 String valueParamName = compiler.enableMinification ? "v" : "value"; 148 String valueParamName = compiler.enableMinification ? "v" : "value";
149 String reflectableField = namer.reflectableField; 149 String reflectableField = namer.reflectableField;
150 150
151 return js.statement(''' 151 // function generateAccessor(field, prototype, cls) {
152 function generateAccessor(fieldDescriptor, accessors, cls) { 152 jsAst.Fun fun = js.fun(['fieldDescriptor', 'accessors', 'cls'], [
153 var fieldInformation = fieldDescriptor.split("-"); 153 js('var fieldInformation = fieldDescriptor.split("-")'),
154 var field = fieldInformation[0]; 154 js('var field = fieldInformation[0]'),
155 var len = field.length; 155 js('var len = field.length'),
156 var code = field.charCodeAt(len - 1); 156 js('var code = field.charCodeAt(len - 1)'),
157 var reflectable; 157 js('var reflectable'),
158 if (fieldInformation.length > 1) reflectable = true; 158 js.if_('fieldInformation.length > 1', js('reflectable = true'),
159 else reflectable = false; 159 js('reflectable = false')),
160 code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST)) 160 js('code = ((code >= $RANGE1_FIRST) && (code <= $RANGE1_LAST))'
161 ? code - $RANGE1_ADJUST 161 ' ? code - $RANGE1_ADJUST'
162 : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST)) 162 ' : ((code >= $RANGE2_FIRST) && (code <= $RANGE2_LAST))'
163 ? code - $RANGE2_ADJUST 163 ' ? code - $RANGE2_ADJUST'
164 : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST)) 164 ' : ((code >= $RANGE3_FIRST) && (code <= $RANGE3_LAST))'
165 ? code - $RANGE3_ADJUST 165 ' ? code - $RANGE3_ADJUST'
166 : $NO_FIELD_CODE; 166 ' : $NO_FIELD_CODE'),
167 167
168 if (code) { // needsAccessor 168 // if (needsAccessor) {
169 var getterCode = code & 3; 169 js.if_('code', [
170 var setterCode = code >> 2; 170 js('var getterCode = code & 3'),
171 var accessorName = field = field.substring(0, len - 1); 171 js('var setterCode = code >> 2'),
172 js('var accessorName = field = field.substring(0, len - 1)'),
172 173
173 var divider = field.indexOf(":"); 174 js('var divider = field.indexOf(":")'),
174 if (divider > 0) { // Colon never in first position. 175 js.if_('divider > 0', [ // Colon never in first position.
175 accessorName = field.substring(0, divider); 176 js('accessorName = field.substring(0, divider)'),
176 field = field.substring(divider + 1); 177 js('field = field.substring(divider + 1)')
177 } 178 ]),
178 179
179 if (getterCode) { // needsGetter 180 // if (needsGetter) {
180 var args = (getterCode & 2) ? "$receiverParamName" : ""; 181 js.if_('getterCode', [
181 var receiver = (getterCode & 1) ? "this" : "$receiverParamName"; 182 js('var args = (getterCode & 2) ? "$receiverParamName" : ""'),
182 var body = "return " + receiver + "." + field; 183 js('var receiver = (getterCode & 1) ? "this" : "$receiverParamName"'),
183 var property = 184 js('var body = "return " + receiver + "." + field'),
184 cls + ".prototype.${namer.getterPrefix}" + accessorName + "="; 185 js('var property ='
185 var fn = "function(" + args + "){" + body + "}"; 186 ' cls + ".prototype.${namer.getterPrefix}" + accessorName + "="'),
186 if (reflectable) 187 js('var fn = "function(" + args + "){" + body + "}"'),
187 accessors.push(property + "\$reflectable(" + fn + ");\\n"); 188 js.if_(
188 else 189 'reflectable',
189 accessors.push(property + fn + ";\\n"); 190 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'),
190 } 191 js('accessors.push(property + fn + ";\\n")')),
192 ]),
191 193
192 if (setterCode) { // needsSetter 194 // if (needsSetter) {
193 var args = (setterCode & 2) 195 js.if_('setterCode', [
194 ? "$receiverParamName,${_}$valueParamName" 196 js('var args = (setterCode & 2)'
195 : "$valueParamName"; 197 ' ? "$receiverParamName,${_}$valueParamName"'
196 var receiver = (setterCode & 1) ? "this" : "$receiverParamName"; 198 ' : "$valueParamName"'),
197 var body = receiver + "." + field + "$_=$_$valueParamName"; 199 js('var receiver = (setterCode & 1) ? "this" : "$receiverParamName"'),
198 var property = 200 js('var body = receiver + "." + field + "$_=$_$valueParamName"'),
199 cls + ".prototype.${namer.setterPrefix}" + accessorName + "="; 201 js('var property ='
200 var fn = "function(" + args + "){" + body + "}"; 202 ' cls + ".prototype.${namer.setterPrefix}" + accessorName + "="'),
201 if (reflectable) 203 js('var fn = "function(" + args + "){" + body + "}"'),
202 accessors.push(property + "\$reflectable(" + fn + ");\\n"); 204 js.if_(
203 else 205 'reflectable',
204 accessors.push(property + fn + ";\\n"); 206 js('accessors.push(property + "\$reflectable(" + fn + ");\\n")'),
205 } 207 js('accessors.push(property + fn + ";\\n")')),
206 } 208 ]),
207 209
208 return field; 210 ]),
209 }'''); 211
212 // return field;
213 js.return_('field')
214 ]);
215
216 return new jsAst.FunctionDeclaration(
217 new jsAst.VariableDeclaration('generateAccessor'),
218 fun);
210 } 219 }
211 220
212 List get defineClassFunction { 221 List get defineClassFunction {
213 // First the class name, then the field names in an array and the members 222 // First the class name, then the field names in an array and the members
214 // (inside an Object literal). 223 // (inside an Object literal).
215 // The caller can also pass in the constructor as a function if needed. 224 // The caller can also pass in the constructor as a function if needed.
216 // 225 //
217 // Example: 226 // Example:
218 // defineClass("A", ["x", "y"], { 227 // defineClass("A", ["x", "y"], {
219 // foo$1: function(y) { 228 // foo$1: function(y) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 // - it contains all (local) members. 297 // - it contains all (local) members.
289 // - its internal prototype (__proto__) points to the superclass' 298 // - its internal prototype (__proto__) points to the superclass'
290 // prototype field. 299 // prototype field.
291 // - the prototype's constructor field points to the JavaScript 300 // - the prototype's constructor field points to the JavaScript
292 // constructor. 301 // constructor.
293 // For engines where we have access to the '__proto__' we can manipulate 302 // For engines where we have access to the '__proto__' we can manipulate
294 // the object literal directly. For other engines we have to create a new 303 // the object literal directly. For other engines we have to create a new
295 // object and copy over the members. 304 // object and copy over the members.
296 305
297 String reflectableField = namer.reflectableField; 306 String reflectableField = namer.reflectableField;
307 List<jsAst.Node> statements = [
308 js('var pendingClasses = {}'),
309 js.if_('!init.allClasses', js('init.allClasses = {}')),
310 js('var allClasses = init.allClasses'),
298 311
299 return js(''' 312 optional(
300 function(collectedClasses, isolateProperties, existingIsolateProperties) { 313 DEBUG_FAST_OBJECTS,
301 var pendingClasses = {}; 314 js('print("Number of classes: "'
302 if (!init.allClasses) init.allClasses = {}; 315 r' + Object.getOwnPropertyNames($$).length)')),
303 var allClasses = init.allClasses;
304 316
305 if (#) // DEBUG_FAST_OBJECTS 317 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
306 print("Number of classes: " +
307 Object.getOwnPropertyNames(\$\$).length);
308 318
309 var hasOwnProperty = Object.prototype.hasOwnProperty; 319 js.if_('typeof dart_precompiled == "function"',
320 [js('var constructors = dart_precompiled(collectedClasses)')],
310 321
311 if (typeof dart_precompiled == "function") { 322 [js('var combinedConstructorFunction = "function \$reflectable(fn){'
312 var constructors = dart_precompiled(collectedClasses); 323 'fn.$reflectableField=1;return fn};\\n"+ "var \$desc;\\n"'),
313 } else { 324 js('var constructorsList = []')]),
314 var combinedConstructorFunction = 325 js.forIn('cls', 'collectedClasses', [
315 "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+ 326 js.if_('hasOwnProperty.call(collectedClasses, cls)', [
316 "var \$desc;\\n"; 327 js('var desc = collectedClasses[cls]'),
317 var constructorsList = []; 328 js.if_('desc instanceof Array', js('desc = desc[1]')),
318 }
319 329
320 for (var cls in collectedClasses) { 330 /* The 'fields' are either a constructor function or a
321 if (hasOwnProperty.call(collectedClasses, cls)) { 331 * string encoding fields, constructor and superclass. Get
322 var desc = collectedClasses[cls]; 332 * the superclass and the fields in the format
323 if (desc instanceof Array) desc = desc[1]; 333 * '[name/]Super;field1,field2'
334 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
335 * The 'name/' is optional and contains the name that should be used
336 * when printing the runtime type string. It is used, for example, to
337 * print the runtime type JSInt as 'int'.
338 */
339 js('var classData = desc["${namer.classDescriptorProperty}"], '
340 'supr, name = cls, fields = classData'),
341 optional(
342 backend.hasRetainedMetadata,
343 js.if_('typeof classData == "object" && '
344 'classData instanceof Array',
345 [js('classData = fields = classData[0]')])),
324 346
325 /* The 'fields' are either a constructor function or a 347 js.if_('typeof classData == "string"', [
326 * string encoding fields, constructor and superclass. Get 348 js('var split = classData.split("/")'),
327 * the superclass and the fields in the format 349 js.if_('split.length == 2', [
328 * '[name/]Super;field1,field2' 350 js('name = split[0]'),
329 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor. 351 js('fields = split[1]')
330 * The 'name/' is optional and contains the name that should be used 352 ])
331 * when printing the runtime type string. It is used, for example, 353 ]),
332 * to print the runtime type JSInt as 'int'.
333 */
334 var classData = desc["${namer.classDescriptorProperty}"],
335 supr, name = cls, fields = classData;
336 if (#) // backend.hasRetainedMetadata
337 if (typeof classData == "object" &&
338 classData instanceof Array) {
339 classData = fields = classData[0];
340 }
341 if (typeof classData == "string") {
342 var split = classData.split("/");
343 if (split.length == 2) {
344 name = split[0];
345 fields = split[1];
346 }
347 }
348 354
349 var s = fields.split(";"); 355 js('var s = fields.split(";")'),
350 fields = s[1] == "" ? [] : s[1].split(","); 356 js('fields = s[1] == "" ? [] : s[1].split(",")'),
351 supr = s[0]; 357 js('supr = s[0]'),
352 split = supr.split(":"); 358 js('split = supr.split(":")'),
353 if (split.length == 2) { 359 js.if_('split.length == 2', [
354 supr = split[0]; 360 js('supr = split[0]'),
355 var functionSignature = split[1]; 361 js('var functionSignature = split[1]'),
356 if (functionSignature) 362 js.if_('functionSignature',
357 desc.\$signature = (function(s) { 363 js('desc.\$signature = #',
358 return function(){ return init.metadata[s]; }; 364 js.fun('s',
359 })(functionSignature); 365 js.return_(js.fun([], js.return_('init.metadata[s]'))))(
360 } 366 js('functionSignature'))))
367 ]),
361 368
362 if (#) // needsMixinSupport 369 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [
363 if (supr && supr.indexOf("+") > 0) { 370 js('s = supr.split("+")'),
364 s = supr.split("+"); 371 js('supr = s[0]'),
365 supr = s[0]; 372 js('var mixin = collectedClasses[s[1]]'),
366 var mixin = collectedClasses[s[1]]; 373 js.if_('mixin instanceof Array', js('mixin = mixin[1]')),
367 if (mixin instanceof Array) mixin = mixin[1]; 374 js.forIn('d', 'mixin', [
368 for(var d in mixin) { 375 js.if_('hasOwnProperty.call(mixin, d)'
369 if (hasOwnProperty.call(mixin, d) && 376 '&& !hasOwnProperty.call(desc, d)',
370 !hasOwnProperty.call(desc, d)) 377 js('desc[d] = mixin[d]'))
371 desc[d] = mixin[d]; 378 ]),
372 } 379 ])),
373 }
374 380
375 if (typeof dart_precompiled != "function") { 381 js.if_('typeof dart_precompiled != "function"',
376 combinedConstructorFunction += defineClass(name, cls, fields); 382 [js('combinedConstructorFunction +='
377 constructorsList.push(cls); 383 ' defineClass(name, cls, fields)'),
378 } 384 js('constructorsList.push(cls)')]),
379 if (supr) pendingClasses[cls] = supr; 385 js.if_('supr', js('pendingClasses[cls] = supr'))
380 } 386 ])
381 } 387 ]),
388 js.statement('''
389 if (typeof dart_precompiled != "function") {
390 combinedConstructorFunction +=
391 "return [\\n " + constructorsList.join(",\\n ") + "\\n]";
392 var constructors =
393 new Function("\$collectedClasses", combinedConstructorFunction)
394 (collectedClasses);
395 combinedConstructorFunction = null;
396 }'''),
397 js.for_('var i = 0', 'i < constructors.length', 'i++', [
398 js('var constructor = constructors[i]'),
399 js('var cls = constructor.name'),
400 js('var desc = collectedClasses[cls]'),
401 js('var globalObject = isolateProperties'),
402 js.if_('desc instanceof Array', [
403 js('globalObject = desc[0] || isolateProperties'),
404 js('desc = desc[1]')
405 ]),
406 optional(backend.isTreeShakingDisabled,
407 js('constructor["${namer.metadataField}"] = desc')),
408 js('allClasses[cls] = constructor'),
409 js('globalObject[cls] = constructor'),
410 ]),
411 js('constructors = null'),
382 412
383 if (typeof dart_precompiled != "function") { 413 js('var finishedClasses = {}'),
384 combinedConstructorFunction += 414 js('init.interceptorsByTag = Object.create(null)'),
385 "return [\\n " + constructorsList.join(",\\n ") + "\\n]"; 415 js('init.leafTags = {}'),
386 var constructors =
387 new Function("\$collectedClasses", combinedConstructorFunction)
388 (collectedClasses);
389 combinedConstructorFunction = null;
390 }
391 416
392 for (var i = 0; i < constructors.length; i++) { 417 buildFinishClass(),
393 var constructor = constructors[i]; 418 ];
394 var cls = constructor.name;
395 var desc = collectedClasses[cls];
396 var globalObject = isolateProperties;
397 if (desc instanceof Array) {
398 globalObject = desc[0] || isolateProperties;
399 desc = desc[1];
400 }
401 if (#) //backend.isTreeShakingDisabled,
402 constructor["${namer.metadataField}"] = desc;
403 allClasses[cls] = constructor;
404 globalObject[cls] = constructor;
405 }
406 419
407 constructors = null; 420 nsmEmitter.addTrivialNsmHandlers(statements);
408 421
409 var finishedClasses = {}; 422 statements.add(
410 init.interceptorsByTag = Object.create(null); 423 js.statement('for (var cls in pendingClasses) finishClass(cls);')
411 init.leafTags = {}; 424 );
412 425
413 #; // buildFinishClass(), 426 // function(collectedClasses,
414 427 // isolateProperties,
415 #; // buildTrivialNsmHandlers() 428 // existingIsolateProperties)
416 429 return js.fun(['collectedClasses', 'isolateProperties',
417 for (var cls in pendingClasses) finishClass(cls); 430 'existingIsolateProperties'], statements);
418 }''', [
419 DEBUG_FAST_OBJECTS,
420 backend.hasRetainedMetadata,
421 needsMixinSupport,
422 backend.isTreeShakingDisabled,
423 buildFinishClass(),
424 nsmEmitter.buildTrivialNsmHandlers()]);
425
426 } 431 }
427 432
428 jsAst.Node optional(bool condition, jsAst.Node node) { 433 jsAst.Node optional(bool condition, jsAst.Node node) {
429 return condition ? node : new jsAst.EmptyStatement(); 434 return condition ? node : new jsAst.EmptyStatement();
430 } 435 }
431 436
432 jsAst.FunctionDeclaration buildFinishClass() { 437 jsAst.FunctionDeclaration buildFinishClass() {
433 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" 438 String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
434 439
435 return js.statement(''' 440 // function finishClass(cls) {
436 function finishClass(cls) { 441 jsAst.Fun fun = js.fun(['cls'], [
437 442
438 // TODO(8540): Remove this work around. 443 // TODO(8540): Remove this work around.
439 // Opera does not support 'getOwnPropertyNames'. Therefore we use 444 /* Opera does not support 'getOwnPropertyNames'. Therefore we use
440 // hasOwnProperty instead. 445 hasOwnProperty instead. */
441 var hasOwnProperty = Object.prototype.hasOwnProperty; 446 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
442 447
443 if (hasOwnProperty.call(finishedClasses, cls)) return; 448 // if (hasOwnProperty.call(finishedClasses, cls)) return;
449 js.if_('hasOwnProperty.call(finishedClasses, cls)',
450 js.return_()),
444 451
445 finishedClasses[cls] = true; 452 js('finishedClasses[cls] = true'),
446 453
447 var superclass = pendingClasses[cls]; 454 js('var superclass = pendingClasses[cls]'),
448 455
449 // The superclass is only false (empty string) for the Dart Object 456 // The superclass is only false (empty string) for Dart's Object class.
450 // class. The minifier together with noSuchMethod can put methods on 457 // The minifier together with noSuchMethod can put methods on the
451 // the Object.prototype object, and they show through here, so we check 458 // Object.prototype object, and they show through here, so we check that
452 // that we have a string. 459 // we have a string.
453 if (!superclass || typeof superclass != "string") return; 460 js.if_('!superclass || typeof superclass != "string"', js.return_()),
454 finishClass(superclass); 461 js('finishClass(superclass)'),
455 var constructor = allClasses[cls]; 462 js('var constructor = allClasses[cls]'),
456 var superConstructor = allClasses[superclass]; 463 js('var superConstructor = allClasses[superclass]'),
457 464
458 if (!superConstructor) 465 js.if_(js('!superConstructor'),
459 superConstructor = existingIsolateProperties[superclass]; 466 js('superConstructor ='
467 'existingIsolateProperties[superclass]')),
460 468
461 var prototype = inheritFrom(constructor, superConstructor); 469 js('var prototype = inheritFrom(constructor, superConstructor)'),
462 470
463 if (#) { // !nativeClasses.isEmpty, 471 optional(!nativeClasses.isEmpty,
464 // The property looks like this: 472 // The property looks like this:
465 // 473 //
466 // HtmlElement: { 474 // HtmlElement: {
467 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton" 475 // "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton"
468 // 476 //
469 // The first two semicolon-separated parts contain dispatch tags, the 477 // The first two semicolon-separated parts contain dispatch tags, the
470 // third contains the JavaScript names for classes. 478 // third contains the JavaScript names for classes.
471 // 479 //
472 // The tags indicate that JavaScript objects with the dispatch tags 480 // The tags indicate that JavaScript objects with the dispatch tags
473 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and 481 // (usually constructor names) HTMLDivElement, HTMLAnchorElement and
474 // HTMLElement all map to the Dart native class named HtmlElement. 482 // HTMLElement all map to the Dart native class named HtmlElement.
475 // The first set is for effective leaf nodes in the hierarchy, the 483 // The first set is for effective leaf nodes in the hierarchy, the
476 // second set is non-leaf nodes. 484 // second set is non-leaf nodes.
477 // 485 //
478 // The third part contains the JavaScript names of Dart classes that 486 // The third part contains the JavaScript names of Dart classes that
479 // extend the native class. Here, FancyButton extends HtmlElement, so 487 // extend the native class. Here, FancyButton extends HtmlElement, so
480 // the runtime needs to know that window.HTMLElement.prototype is the 488 // the runtime needs to know that window.HTMLElement.prototype is the
481 // prototype that needs to be extended in creating the custom element. 489 // prototype that needs to be extended in creating the custom element.
482 // 490 //
483 // The information is used to build tables referenced by 491 // The information is used to build tables referenced by
484 // getNativeInterceptor and custom element support. 492 // getNativeInterceptor and custom element support.
485 if (hasOwnProperty.call(prototype, $specProperty)) { 493 js.if_('hasOwnProperty.call(prototype, $specProperty)', [
486 var nativeSpec = prototype[$specProperty].split(";"); 494 js('var nativeSpec = prototype[$specProperty].split(";")'),
487 if (nativeSpec[0]) { 495 js.if_('nativeSpec[0]', [
488 var tags = nativeSpec[0].split("|"); 496 js('var tags = nativeSpec[0].split("|")'),
489 for (var i = 0; i < tags.length; i++) { 497 js.for_('var i = 0', 'i < tags.length', 'i++', [
490 init.interceptorsByTag[tags[i]] = constructor; 498 js('init.interceptorsByTag[tags[i]] = constructor'),
491 init.leafTags[tags[i]] = true; 499 js('init.leafTags[tags[i]] = true')])]),
492 } 500 js.if_('nativeSpec[1]', [
493 } 501 js('tags = nativeSpec[1].split("|")'),
494 if (nativeSpec[1]) { 502 optional(true, // User subclassing of native classes?
495 tags = nativeSpec[1].split("|"); 503 js.if_('nativeSpec[2]', [
496 if (#) { // User subclassing of native classes? 504 js('var subclasses = nativeSpec[2].split("|")'),
497 if (nativeSpec[2]) { 505 js.for_('var i = 0', 'i < subclasses.length', 'i++', [
498 var subclasses = nativeSpec[2].split("|"); 506 js('var subclass = allClasses[subclasses[i]]'),
499 for (var i = 0; i < subclasses.length; i++) { 507 js('subclass.\$nativeSuperclassTag = '
500 var subclass = allClasses[subclasses[i]]; 508 'tags[0]')])])),
501 subclass.\$nativeSuperclassTag = tags[0]; 509 js.for_('i = 0', 'i < tags.length', 'i++', [
502 } 510 js('init.interceptorsByTag[tags[i]] = constructor'),
503 } 511 js('init.leafTags[tags[i]] = false')])])]))
504 for (i = 0; i < tags.length; i++) { 512 ]);
505 init.interceptorsByTag[tags[i]] = constructor; 513
506 init.leafTags[tags[i]] = false; 514 return new jsAst.FunctionDeclaration(
507 } 515 new jsAst.VariableDeclaration('finishClass'),
508 } 516 fun);
509 }
510 }
511 }
512 }''', [!nativeClasses.isEmpty, true]);
513 } 517 }
514 518
515 jsAst.Fun get finishIsolateConstructorFunction { 519 jsAst.Fun get finishIsolateConstructorFunction {
516 // We replace the old Isolate function with a new one that initializes 520 // We replace the old Isolate function with a new one that initializes
517 // all its fields with the initial (and often final) value of all globals. 521 // all its fields with the initial (and often final) value of all globals.
518 // 522 //
519 // We also copy over old values like the prototype, and the 523 // We also copy over old values like the prototype, and the
520 // isolateProperties themselves. 524 // isolateProperties themselves.
521 return js(''' 525 return js('''
522 function (oldIsolate) { 526 function (oldIsolate) {
523 var isolateProperties = oldIsolate.${namer.isolatePropertiesName}; 527 var isolateProperties = oldIsolate.${namer.isolatePropertiesName};
524 function Isolate() { 528 function Isolate() {
525 var hasOwnProperty = Object.prototype.hasOwnProperty; 529 var hasOwnProperty = Object.prototype.hasOwnProperty;
526 for (var staticName in isolateProperties) 530 for (var staticName in isolateProperties)
527 if (hasOwnProperty.call(isolateProperties, staticName)) 531 if (hasOwnProperty.call(isolateProperties, staticName))
528 this[staticName] = isolateProperties[staticName]; 532 this[staticName] = isolateProperties[staticName];
529 // Use the newly created object as prototype. In Chrome, 533 // Use the newly created object as prototype. In Chrome,
530 // this creates a hidden class for the object and makes 534 // this creates a hidden class for the object and makes
531 // sure it is fast to access. 535 // sure it is fast to access.
532 function ForceEfficientMap() {} 536 function ForceEfficientMap() {}
533 ForceEfficientMap.prototype = this; 537 ForceEfficientMap.prototype = this;
534 new ForceEfficientMap(); 538 new ForceEfficientMap();
535 } 539 }
536 Isolate.prototype = oldIsolate.prototype; 540 Isolate.prototype = oldIsolate.prototype;
537 Isolate.prototype.constructor = Isolate; 541 Isolate.prototype.constructor = Isolate;
538 Isolate.${namer.isolatePropertiesName} = isolateProperties; 542 Isolate.${namer.isolatePropertiesName} = isolateProperties;
539 if (#) 543 #
540 Isolate.$finishClassesProperty = oldIsolate.$finishClassesProperty; 544 #
541 if (#)
542 Isolate.makeConstantList = oldIsolate.makeConstantList;
543 return Isolate; 545 return Isolate;
544 }''', 546 }''',
545 [ needsDefineClass, hasMakeConstantList ]); 547 [ optional(needsDefineClass,
548 js('Isolate.$finishClassesProperty ='
549 ' oldIsolate.$finishClassesProperty')),
550 optional(hasMakeConstantList,
551 js('Isolate.makeConstantList = oldIsolate.makeConstantList'))
552 ]);
546 } 553 }
547 554
548 jsAst.Fun get lazyInitializerFunction { 555 jsAst.Fun get lazyInitializerFunction {
556 // function(prototype, staticName, fieldName, getterName, lazyValue) {
557 var parameters = <String>['prototype', 'staticName', 'fieldName',
558 'getterName', 'lazyValue'];
559 return js.fun(parameters, addLazyInitializerLogic());
560 }
561
562 List addLazyInitializerLogic() {
549 String isolate = namer.currentIsolate; 563 String isolate = namer.currentIsolate;
550 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper()); 564 String cyclicThrow = namer.isolateAccess(backend.getCyclicThrowHelper());
565 var lazies = [];
566 if (backend.rememberLazies) {
567 lazies = [
568 js.if_('!init.lazies', js('init.lazies = {}')),
569 js('init.lazies[fieldName] = getterName')];
570 }
551 571
552 return js(''' 572 return lazies..addAll([
553 function (prototype, staticName, fieldName, getterName, lazyValue) { 573 js('var sentinelUndefined = {}'),
554 if (#) { 574 js('var sentinelInProgress = {}'),
555 if (!init.lazies) init.lazies = {}; 575 js('prototype[fieldName] = sentinelUndefined'),
556 init.lazies[fieldName] = getterName;
557 }
558 576
559 var sentinelUndefined = {}; 577 // prototype[getterName] = function()
560 var sentinelInProgress = {}; 578 js('prototype[getterName] = #', js.fun([], [
561 prototype[fieldName] = sentinelUndefined; 579 js('var result = $isolate[fieldName]'),
562 580
563 prototype[getterName] = function () { 581 // try
564 var result = $isolate[fieldName]; 582 js.try_([
565 try { 583 js.if_('result === sentinelUndefined', [
566 if (result === sentinelUndefined) { 584 js('$isolate[fieldName] = sentinelInProgress'),
567 $isolate[fieldName] = sentinelInProgress;
568 585
569 try { 586 // try
570 result = $isolate[fieldName] = lazyValue(); 587 js.try_([
571 } finally { 588 js('result = $isolate[fieldName] = lazyValue()'),
572 // Use try-finally, not try-catch/throw as it destroys the
573 // stack trace.
574 if (result === sentinelUndefined)
575 if ($isolate[fieldName] === sentinelInProgress)
576 $isolate[fieldName] = null;
577 }
578 } else {
579 if (result === sentinelInProgress)
580 $cyclicThrow(staticName);
581 }
582 589
583 return result; 590 ], finallyPart: [
584 } finally { 591 // Use try-finally, not try-catch/throw as it destroys the
585 $isolate[getterName] = function() { return this[fieldName]; }; 592 // stack trace.
586 } 593
587 } 594 // if (result === sentinelUndefined)
588 } 595 js.if_('result === sentinelUndefined', [
589 ''', [backend.rememberLazies]); 596 // if ($isolate[fieldName] === sentinelInProgress)
597 js.if_('$isolate[fieldName] === sentinelInProgress', [
598 js('$isolate[fieldName] = null'),
599 ])
600 ])
601 ])
602 ], /* else */ [
603 js.if_('result === sentinelInProgress',
604 js('$cyclicThrow(staticName)')
605 )
606 ]),
607
608 // return result;
609 js.return_('result')
610
611 ], finallyPart: [
612 js('$isolate[getterName] = #',
613 js.fun([], [js.return_('this[fieldName]')]))
614 ])
615 ]))
616 ]);
590 } 617 }
591 618
592 List buildDefineClassAndFinishClassFunctionsIfNecessary() { 619 List buildDefineClassAndFinishClassFunctionsIfNecessary() {
593 if (!needsDefineClass) return []; 620 if (!needsDefineClass) return [];
594 return defineClassFunction 621 return defineClassFunction
595 ..addAll(buildInheritFrom()) 622 ..addAll(buildInheritFrom())
596 ..addAll([ 623 ..addAll([
597 js('$finishClassesName = #', finishClassesFunction) 624 js('$finishClassesName = #', finishClassesFunction)
598 ]); 625 ]);
599 } 626 }
600 627
601 List buildLazyInitializerFunctionIfNecessary() { 628 List buildLazyInitializerFunctionIfNecessary() {
602 if (!needsLazyInitializer) return []; 629 if (!needsLazyInitializer) return [];
603 630
604 return [js('# = #', [js(lazyInitializerName), lazyInitializerFunction])]; 631 return [js('$lazyInitializerName = #', lazyInitializerFunction)];
605 } 632 }
606 633
607 List buildFinishIsolateConstructor() { 634 List buildFinishIsolateConstructor() {
608 return [ 635 return [
609 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction) 636 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction)
610 ]; 637 ];
611 } 638 }
612 639
613 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 640 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
614 String isolate = namer.isolateName; 641 String isolate = namer.isolateName;
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 } 752 }
726 753
727 String namedParametersAsReflectionNames(Selector selector) { 754 String namedParametersAsReflectionNames(Selector selector) {
728 if (selector.getOrderedNamedArguments().isEmpty) return ''; 755 if (selector.getOrderedNamedArguments().isEmpty) return '';
729 String names = selector.getOrderedNamedArguments().join(':'); 756 String names = selector.getOrderedNamedArguments().join(':');
730 return ':$names'; 757 return ':$names';
731 } 758 }
732 759
733 jsAst.FunctionDeclaration buildPrecompiledFunction() { 760 jsAst.FunctionDeclaration buildPrecompiledFunction() {
734 // TODO(ahe): Compute a hash code. 761 // TODO(ahe): Compute a hash code.
735 return js.statement(''' 762 String name = 'dart_precompiled';
736 function dart_precompiled(\$collectedClasses) { 763
737 var \$desc; 764 precompiledFunction.add(
738 #; 765 js.return_(
739 return #; 766 new jsAst.ArrayInitializer.from(precompiledConstructorNames)));
740 }''', [ 767 precompiledFunction.insert(0, js(r'var $desc'));
741 precompiledFunction, 768 return new jsAst.FunctionDeclaration(
742 new jsAst.ArrayInitializer.from(precompiledConstructorNames)]); 769 new jsAst.VariableDeclaration(name),
770 js.fun([r'$collectedClasses'], precompiledFunction));
743 } 771 }
744 772
745 void generateClass(ClassElement classElement, ClassBuilder properties) { 773 void generateClass(ClassElement classElement, ClassBuilder properties) {
746 compiler.withCurrentElement(classElement, () { 774 compiler.withCurrentElement(classElement, () {
747 classEmitter.generateClass( 775 classEmitter.generateClass(
748 classElement, properties, additionalProperties[classElement]); 776 classElement, properties, additionalProperties[classElement]);
749 }); 777 });
750 } 778 }
751 779
752 /** 780 /**
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
823 Iterable<VariableElement> staticNonFinalFields = 851 Iterable<VariableElement> staticNonFinalFields =
824 handler.getStaticNonFinalFieldsForEmission(); 852 handler.getStaticNonFinalFieldsForEmission();
825 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { 853 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
826 // [:interceptedNames:] is handled in [emitInterceptedNames]. 854 // [:interceptedNames:] is handled in [emitInterceptedNames].
827 if (element == backend.interceptedNames) continue; 855 if (element == backend.interceptedNames) continue;
828 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor]. 856 // `mapTypeToInterceptor` is handled in [emitMapTypeToInterceptor].
829 if (element == backend.mapTypeToInterceptor) continue; 857 if (element == backend.mapTypeToInterceptor) continue;
830 compiler.withCurrentElement(element, () { 858 compiler.withCurrentElement(element, () {
831 Constant initialValue = handler.getInitialValueFor(element); 859 Constant initialValue = handler.getInitialValueFor(element);
832 jsAst.Expression init = 860 jsAst.Expression init =
833 js('$isolateProperties.# = #', 861 js('$isolateProperties.${namer.getNameOfGlobalField(element)} = #',
834 [namer.getNameOfGlobalField(element), 862 constantEmitter.referenceInInitializationContext(initialValue));
835 constantEmitter.referenceInInitializationContext(initialValue)]);
836 buffer.write(jsAst.prettyPrint(init, compiler)); 863 buffer.write(jsAst.prettyPrint(init, compiler));
837 buffer.write('$N'); 864 buffer.write('$N');
838 }); 865 });
839 } 866 }
840 } 867 }
841 868
842 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { 869 void emitLazilyInitializedStaticFields(CodeBuffer buffer) {
843 JavaScriptConstantCompiler handler = backend.constants; 870 JavaScriptConstantCompiler handler = backend.constants;
844 List<VariableElement> lazyFields = 871 List<VariableElement> lazyFields =
845 handler.getLazilyInitializedFieldsForEmission(); 872 handler.getLazilyInitializedFieldsForEmission();
846 if (!lazyFields.isEmpty) { 873 if (!lazyFields.isEmpty) {
847 needsLazyInitializer = true; 874 needsLazyInitializer = true;
848 for (VariableElement element in Elements.sortedByPosition(lazyFields)) { 875 for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
849 jsAst.Expression code = backend.generatedCode[element]; 876 jsAst.Expression code = backend.generatedCode[element];
850 // The code is null if we ended up not needing the lazily 877 // The code is null if we ended up not needing the lazily
851 // initialized field after all because of constant folding 878 // initialized field after all because of constant folding
852 // before code generation. 879 // before code generation.
853 if (code == null) continue; 880 if (code == null) continue;
854 // The code only computes the initial value. We build the lazy-check 881 // The code only computes the initial value. We build the lazy-check
855 // here: 882 // here:
856 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); 883 // lazyInitializer(prototype, 'name', fieldName, getterName, initial);
857 // The name is used for error reporting. The 'initial' must be a 884 // The name is used for error reporting. The 'initial' must be a
858 // closure that constructs the initial value. 885 // closure that constructs the initial value.
886 List<jsAst.Expression> arguments = <jsAst.Expression>[];
887 arguments.add(js(isolateProperties));
888 arguments.add(js.string(element.name));
889 arguments.add(js.string(namer.getNameX(element)));
890 arguments.add(js.string(namer.getLazyInitializerName(element)));
891 arguments.add(code);
859 jsAst.Expression getter = buildLazyInitializedGetter(element); 892 jsAst.Expression getter = buildLazyInitializedGetter(element);
860 jsAst.Expression init = js('#(#,#,#,#,#,#)', 893 if (getter != null) {
861 [js(lazyInitializerName), 894 arguments.add(getter);
862 js(isolateProperties), 895 }
863 js.string(element.name), 896 jsAst.Expression init = js(lazyInitializerName)(arguments);
864 js.string(namer.getNameX(element)),
865 js.string(namer.getLazyInitializerName(element)),
866 code,
867 getter == null ? [] : [getter]]);
868 buffer.write(jsAst.prettyPrint(init, compiler)); 897 buffer.write(jsAst.prettyPrint(init, compiler));
869 buffer.write("$N"); 898 buffer.write("$N");
870 } 899 }
871 } 900 }
872 } 901 }
873 902
874 jsAst.Expression buildLazyInitializedGetter(VariableElement element) { 903 jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
875 // Nothing to do, the 'lazy' function will create the getter. 904 // Nothing to do, the 'lazy' function will create the getter.
876 return null; 905 return null;
877 } 906 }
(...skipping 14 matching lines...) Expand all
892 && constantUnit == null) { 921 && constantUnit == null) {
893 // The back-end introduces some constants, like "InterceptorConstant" or 922 // The back-end introduces some constants, like "InterceptorConstant" or
894 // some list constants. They are emitted in the main output-unit, and 923 // some list constants. They are emitted in the main output-unit, and
895 // ignored otherwise. 924 // ignored otherwise.
896 // TODO(sigurdm): We should track those constants. 925 // TODO(sigurdm): We should track those constants.
897 continue; 926 continue;
898 } 927 }
899 928
900 String name = namer.constantName(constant); 929 String name = namer.constantName(constant);
901 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer); 930 if (constant.isList) emitMakeConstantListIfNotEmitted(buffer);
902 jsAst.Expression init = js('#.# = #', 931 jsAst.Expression init = js(
903 [namer.globalObjectForConstant(constant), name, 932 '${namer.globalObjectForConstant(constant)}.$name = #',
904 constantInitializerExpression(constant)]); 933 constantInitializerExpression(constant));
905 buffer.write(jsAst.prettyPrint(init, compiler)); 934 buffer.write(jsAst.prettyPrint(init, compiler));
906 buffer.write('$N'); 935 buffer.write('$N');
907 } 936 }
908 } 937 }
909 938
910 bool isConstantInlinedOrAlreadyEmitted(Constant constant) { 939 bool isConstantInlinedOrAlreadyEmitted(Constant constant) {
911 if (constant.isFunction) return true; // Already emitted. 940 if (constant.isFunction) return true; // Already emitted.
912 if (constant.isPrimitive) return true; // Inlined. 941 if (constant.isPrimitive) return true; // Inlined.
913 if (constant.isDummy) return true; // Inlined. 942 if (constant.isDummy) return true; // Inlined.
914 // The name is null when the constant is already a JS constant. 943 // The name is null when the constant is already a JS constant.
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1158 } else { 1187 } else {
1159 outputClassLists.putIfAbsent( 1188 outputClassLists.putIfAbsent(
1160 compiler.deferredLoadTask.outputUnitForElement(element), 1189 compiler.deferredLoadTask.outputUnitForElement(element),
1161 () => new List<ClassElement>()) 1190 () => new List<ClassElement>())
1162 .add(element); 1191 .add(element);
1163 } 1192 }
1164 } 1193 }
1165 } 1194 }
1166 1195
1167 void emitInitFunction(CodeBuffer buffer) { 1196 void emitInitFunction(CodeBuffer buffer) {
1168 jsAst.FunctionDeclaration decl = js.statement(''' 1197 jsAst.Fun fun = js.fun([], [
1169 function init() { 1198 js('$isolateProperties = {}'),
1170 $isolateProperties = {}; 1199 ]
1171 #; #; #; 1200 ..addAll(buildDefineClassAndFinishClassFunctionsIfNecessary())
1172 }''', [ 1201 ..addAll(buildLazyInitializerFunctionIfNecessary())
1173 buildDefineClassAndFinishClassFunctionsIfNecessary(), 1202 ..addAll(buildFinishIsolateConstructor())
1174 buildLazyInitializerFunctionIfNecessary(), 1203 );
1175 buildFinishIsolateConstructor()]); 1204 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
1176 1205 new jsAst.VariableDeclaration('init'), fun);
1177 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); 1206 buffer.write(jsAst.prettyPrint(decl, compiler).getText());
1178 if (compiler.enableMinification) buffer.write('\n'); 1207 if (compiler.enableMinification) buffer.write('\n');
1179 } 1208 }
1180 1209
1181 void emitConvertToFastObjectFunction() { 1210 void emitConvertToFastObjectFunction() {
1182 // Create an instance that uses 'properties' as prototype. This should make 1211 // Create an instance that uses 'properties' as prototype. This should make
1183 // 'properties' a fast object. 1212 // 'properties' a fast object.
1184 mainBuffer.add(r'''function convertToFastObject(properties) { 1213 mainBuffer.add(r'''function convertToFastObject(properties) {
1185 function MyClass() {}; 1214 function MyClass() {};
1186 MyClass.prototype = properties; 1215 MyClass.prototype = properties;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
1353 var keys = mangledFieldNames.keys.toList(); 1382 var keys = mangledFieldNames.keys.toList();
1354 keys.sort(); 1383 keys.sort();
1355 var properties = []; 1384 var properties = [];
1356 for (String key in keys) { 1385 for (String key in keys) {
1357 var value = js.string('${mangledFieldNames[key]}'); 1386 var value = js.string('${mangledFieldNames[key]}');
1358 properties.add(new jsAst.Property(js.string(key), value)); 1387 properties.add(new jsAst.Property(js.string(key), value));
1359 } 1388 }
1360 var map = new jsAst.ObjectInitializer(properties); 1389 var map = new jsAst.ObjectInitializer(properties);
1361 mainBuffer.write( 1390 mainBuffer.write(
1362 jsAst.prettyPrint( 1391 jsAst.prettyPrint(
1363 js.statement('init.mangledNames = #', map), compiler)); 1392 js('init.mangledNames = #', map).toStatement(), compiler));
1364 if (compiler.enableMinification) { 1393 if (compiler.enableMinification) {
1365 mainBuffer.write(';'); 1394 mainBuffer.write(';');
1366 } 1395 }
1367 } 1396 }
1368 if (!mangledGlobalFieldNames.isEmpty) { 1397 if (!mangledGlobalFieldNames.isEmpty) {
1369 var keys = mangledGlobalFieldNames.keys.toList(); 1398 var keys = mangledGlobalFieldNames.keys.toList();
1370 keys.sort(); 1399 keys.sort();
1371 var properties = []; 1400 var properties = [];
1372 for (String key in keys) { 1401 for (String key in keys) {
1373 var value = js.string('${mangledGlobalFieldNames[key]}'); 1402 var value = js.string('${mangledGlobalFieldNames[key]}');
1374 properties.add(new jsAst.Property(js.string(key), value)); 1403 properties.add(new jsAst.Property(js.string(key), value));
1375 } 1404 }
1376 var map = new jsAst.ObjectInitializer(properties); 1405 var map = new jsAst.ObjectInitializer(properties);
1377 mainBuffer.write( 1406 mainBuffer.write(
1378 jsAst.prettyPrint( 1407 jsAst.prettyPrint(
1379 js.statement('init.mangledGlobalNames = #', map), 1408 js('init.mangledGlobalNames = #', map).toStatement(),
1380 compiler)); 1409 compiler));
1381 if (compiler.enableMinification) { 1410 if (compiler.enableMinification) {
1382 mainBuffer.write(';'); 1411 mainBuffer.write(';');
1383 } 1412 }
1384 } 1413 }
1385 mainBuffer 1414 mainBuffer
1386 ..write('(') 1415 ..write('(')
1387 ..write( 1416 ..write(
1388 jsAst.prettyPrint( 1417 jsAst.prettyPrint(
1389 getReflectionDataParser(classesCollector, backend), 1418 getReflectionDataParser(classesCollector, backend),
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
1700 String sourceMap = sourceMapBuilder.build(); 1729 String sourceMap = sourceMapBuilder.build();
1701 compiler.outputProvider(name, 'js.map') 1730 compiler.outputProvider(name, 'js.map')
1702 ..add(sourceMap) 1731 ..add(sourceMap)
1703 ..close(); 1732 ..close();
1704 } 1733 }
1705 1734
1706 void registerReadTypeVariable(TypeVariableElement element) { 1735 void registerReadTypeVariable(TypeVariableElement element) {
1707 readTypeVariables.add(element); 1736 readTypeVariables.add(element);
1708 } 1737 }
1709 } 1738 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698