Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 library dart2js.new_js_emitter.model_emitter; | 5 library dart2js.new_js_emitter.model_emitter; |
| 6 | 6 |
| 7 import '../../dart2jslib.dart' show Compiler; | 7 import '../../dart2jslib.dart' show Compiler; |
| 8 import '../../js/js.dart' as js; | 8 import '../../js/js.dart' as js; |
| 9 import '../../js_backend/js_backend.dart' show | 9 import '../../js_backend/js_backend.dart' show |
| 10 JavaScriptBackend, | 10 JavaScriptBackend, |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 249 [ js.string(e.name), js.number(e.holder.index), emitClass(e) ]); | 249 [ js.string(e.name), js.number(e.holder.index), emitClass(e) ]); |
| 250 | 250 |
| 251 js.Expression staticArray = new js.ArrayInitializer.from(staticDescriptors); | 251 js.Expression staticArray = new js.ArrayInitializer.from(staticDescriptors); |
| 252 js.Expression classArray = new js.ArrayInitializer.from(classDescriptors); | 252 js.Expression classArray = new js.ArrayInitializer.from(classDescriptors); |
| 253 | 253 |
| 254 return new js.ArrayInitializer.from([staticArray, classArray]); | 254 return new js.ArrayInitializer.from([staticArray, classArray]); |
| 255 } | 255 } |
| 256 | 256 |
| 257 js.Expression _generateConstructor(Class cls) { | 257 js.Expression _generateConstructor(Class cls) { |
| 258 List<String> allFieldNames = <String>[]; | 258 List<String> allFieldNames = <String>[]; |
| 259 Class currentClass = cls; | 259 |
| 260 while (currentClass != null) { | 260 // If the class is not directly instantiated we only need it for inheritance |
| 261 allFieldNames.addAll( | 261 // or RTI. In either case we don't need its fields. |
| 262 currentClass.fields.map((InstanceField field) => field.name)); | 262 if (cls.isDirectlyInstantiated) { |
| 263 currentClass = currentClass.superclass; | 263 Class currentClass = cls; |
| 264 while (currentClass != null) { | |
| 265 assert(() { | |
|
kasperl
2014/11/27 09:05:14
Add a comment for the assert. What are you verifyi
floitsch
2014/11/27 12:35:16
Reduced the assert.
It is now just testing that mi
| |
| 266 if (currentClass.isMixinApplication) { | |
| 267 if (currentClass.fields.isNotEmpty) return false; | |
| 268 if (currentClass.methods.isNotEmpty) return false; | |
| 269 MixinApplication mixinApplication = currentClass; | |
| 270 if (mixinApplication.mixinClass.fields.isNotEmpty) return false; | |
| 271 } | |
| 272 return true; | |
| 273 }); | |
| 274 | |
| 275 allFieldNames.addAll( | |
| 276 currentClass.fields.map((InstanceField field) => field.name)); | |
| 277 currentClass = currentClass.superclass; | |
| 278 } | |
| 264 } | 279 } |
| 265 String name = cls.name; | 280 String name = cls.name; |
| 266 String parameters = allFieldNames.join(', '); | 281 String parameters = allFieldNames.join(', '); |
| 267 String assignments = allFieldNames | 282 String assignments = allFieldNames |
| 268 .map((String field) => "this.$field = $field;\n") | 283 .map((String field) => "this.$field = $field;\n") |
| 269 .join(); | 284 .join(); |
| 270 String code = 'function $name($parameters) { $assignments }'; | 285 String code = 'function $name($parameters) { $assignments }'; |
| 271 js.Template template = js.js.uncachedExpressionTemplate(code); | 286 js.Template template = js.js.uncachedExpressionTemplate(code); |
| 272 return template.instantiate(const []); | 287 return template.instantiate(const []); |
| 273 } | 288 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 309 .map(_generateGetter); | 324 .map(_generateGetter); |
| 310 | 325 |
| 311 Iterable<Method> setters = cls.fields | 326 Iterable<Method> setters = cls.fields |
| 312 .where((InstanceField field) => field.needsSetter) | 327 .where((InstanceField field) => field.needsSetter) |
| 313 .map(_generateSetter); | 328 .map(_generateSetter); |
| 314 | 329 |
| 315 return [getters, setters].expand((x) => x); | 330 return [getters, setters].expand((x) => x); |
| 316 } | 331 } |
| 317 | 332 |
| 318 js.Expression emitClass(Class cls) { | 333 js.Expression emitClass(Class cls) { |
| 334 if (cls.isMixinApplication) return emitMixinApplication(cls); | |
| 335 | |
| 319 List elements = [ js.string(cls.superclassName), | 336 List elements = [ js.string(cls.superclassName), |
| 320 js.number(cls.superclassHolderIndex), | 337 js.number(cls.superclassHolderIndex), |
| 321 _generateConstructor(cls) ]; | 338 _generateConstructor(cls) ]; |
| 322 Iterable<Method> methods = cls.methods; | 339 Iterable<Method> methods = cls.methods; |
| 323 Iterable<Method> gettersSetters = _generateGettersSetters(cls); | 340 Iterable<Method> gettersSetters = _generateGettersSetters(cls); |
| 324 Iterable<Method> allMethods = [methods, gettersSetters].expand((x) => x); | 341 Iterable<Method> allMethods = [methods, gettersSetters].expand((x) => x); |
| 325 elements.addAll(allMethods.expand((e) => [ js.string(e.name), e.code ])); | 342 elements.addAll(allMethods.expand((e) => [ js.string(e.name), e.code ])); |
|
sigurdm
2014/11/27 09:25:54
Space inside the '['
floitsch
2014/11/27 12:35:16
Done.
| |
| 326 return unparse(compiler, new js.ArrayInitializer.from(elements)); | 343 return unparse(compiler, new js.ArrayInitializer.from(elements)); |
| 327 } | 344 } |
| 328 | 345 |
| 346 static final String mixinFormatComment = | |
| 347 "Mixins have no constructor, but a reference to their mixin class."; | |
|
sigurdm
2014/11/27 09:25:54
Empty line between members.
floitsch
2014/11/27 12:35:16
Done.
| |
| 348 js.Expression emitMixinApplication(MixinApplication cls) { | |
| 349 List elements = [ js.string(cls.superclassName), | |
|
sigurdm
2014/11/27 09:25:54
Space inside the '['
floitsch
2014/11/27 12:35:16
Done.
| |
| 350 js.number(cls.superclassHolderIndex), | |
| 351 js.string(cls.mixinClass.name), | |
| 352 js.number(cls.mixinClass.holder.index) ]; | |
| 353 return unparse(compiler, new js.ArrayInitializer.from(elements)); | |
| 354 } | |
| 355 | |
| 329 js.Expression emitLazyInitializer(StaticField field) { | 356 js.Expression emitLazyInitializer(StaticField field) { |
| 330 assert(field.isLazy); | 357 assert(field.isLazy); |
| 331 return unparse(compiler, field.code); | 358 return unparse(compiler, field.code); |
| 332 } | 359 } |
| 333 | 360 |
| 334 js.Expression emitStaticMethod(StaticMethod method) { | 361 js.Expression emitStaticMethod(StaticMethod method) { |
| 335 return unparse(compiler, method.code); | 362 return unparse(compiler, method.code); |
| 336 } | 363 } |
| 337 } | |
| 338 | 364 |
| 339 final String boilerplate = r""" | 365 static final String boilerplate = """ |
| 340 { | 366 { |
| 341 // Declare deferred-initializer global. | 367 // Declare deferred-initializer global. |
| 342 #; | 368 #; |
| 343 | 369 |
| 344 !function(start, program) { | 370 !function(start, program) { |
| 345 | 371 |
| 346 // Initialize holder objects. | 372 // Initialize holder objects. |
| 347 #; | 373 #; |
| 348 | 374 |
| 349 function setupProgram() { | 375 function setupProgram() { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 // to resolve superclass references without constructing instances. The | 453 // to resolve superclass references without constructing instances. The |
| 428 // resolve property also serves as a marker that indicates whether or not | 454 // resolve property also serves as a marker that indicates whether or not |
| 429 // a class has been resolved yet. | 455 // a class has been resolved yet. |
| 430 patch.resolve = resolve; | 456 patch.resolve = resolve; |
| 431 holder[name] = patch; | 457 holder[name] = patch; |
| 432 } | 458 } |
| 433 | 459 |
| 434 function compileConstructor(name, descriptor) { | 460 function compileConstructor(name, descriptor) { |
| 435 descriptor = compile(name, descriptor); | 461 descriptor = compile(name, descriptor); |
| 436 var prototype = determinePrototype(descriptor); | 462 var prototype = determinePrototype(descriptor); |
| 463 // $mixinFormatComment. | |
|
floitsch
2014/11/26 17:32:09
I'm using this "marker" as a way to easily find al
sigurdm
2014/11/27 09:25:54
Perhaps also explain that in a comment in the code
floitsch
2014/11/27 12:35:16
Done.
| |
| 464 if (typeof descriptor[2] !== 'function') { | |
|
sigurdm
2014/11/27 09:25:54
Could there be a less fragile way of distinguishin
floitsch
2014/11/27 12:35:16
I don't see any, that wouldn't require bigger chan
| |
| 465 return compileMixinConstructor(name, prototype, descriptor); | |
| 466 } | |
| 437 var constructor = descriptor[2]; | 467 var constructor = descriptor[2]; |
| 438 for (var i = 3; i < descriptor.length; i += 2) { | 468 for (var i = 3; i < descriptor.length; i += 2) { |
| 439 prototype[descriptor[i]] = descriptor[i + 1]; | 469 prototype[descriptor[i]] = descriptor[i + 1]; |
| 440 } | 470 } |
| 441 constructor.prototype = prototype; | 471 constructor.prototype = prototype; |
| 442 return constructor; | 472 return constructor; |
| 443 } | 473 } |
| 444 | 474 |
| 475 function compileMixinConstructor(name, prototype, descriptor) { | |
| 476 var mixinName = descriptor[2]; | |
| 477 var mixinHolderIndex = descriptor[3]; | |
| 478 var mixin = holders[mixinHolderIndex][mixinName]; | |
| 479 if (mixin.resolve) mixin = mixin.resolve(); | |
| 480 var mixinPrototype = mixin.prototype; | |
| 481 | |
| 482 // Fill the prototype with the mixin's properties. | |
| 483 var mixinProperties = Object.keys(mixinPrototype); | |
| 484 for (var i = 0; i < mixinProperties.length; i++) { | |
| 485 var p = mixinProperties[i]; | |
| 486 prototype[p] = mixinPrototype[p]; | |
| 487 } | |
| 488 // Since this is a mixin application the constructor will actually never | |
| 489 // be invoked. We only use its prototype for the application's subclasses. | |
| 490 var constructor = function() {}; | |
| 491 constructor.prototype = prototype; | |
| 492 return constructor; | |
| 493 } | |
| 494 | |
| 445 function determinePrototype(descriptor) { | 495 function determinePrototype(descriptor) { |
| 446 var superclassName = descriptor[0]; | 496 var superclassName = descriptor[0]; |
| 447 if (!superclassName) return { }; | 497 if (!superclassName) return { }; |
| 448 | 498 |
| 449 // Look up the superclass constructor function in the right holder. | 499 // Look up the superclass constructor function in the right holder. |
| 450 var holderIndex = descriptor[1]; | 500 var holderIndex = descriptor[1]; |
| 451 var superclass = holders[holderIndex][superclassName]; | 501 var superclass = holders[holderIndex][superclassName]; |
| 452 if (superclass.resolve) superclass = superclass.resolve(); | 502 if (superclass.resolve) superclass = superclass.resolve(); |
| 453 | 503 |
| 454 // Create a new prototype object chained to the superclass prototype. | 504 // Create a new prototype object chained to the superclass prototype. |
| 455 var intermediate = function() { }; | 505 var intermediate = function() { }; |
| 456 intermediate.prototype = superclass.prototype; | 506 intermediate.prototype = superclass.prototype; |
| 457 return new intermediate(); | 507 return new intermediate(); |
| 458 } | 508 } |
| 459 | 509 |
| 460 function compile(__name__, __s__) { | 510 function compile(__name__, __s__) { |
| 461 'use strict'; | 511 'use strict'; |
| 462 // TODO(floitsch): evaluate the performance impact of the string | 512 // TODO(floitsch): evaluate the performance impact of the string |
| 463 // concatenations. | 513 // concatenations. |
| 464 return eval(__s__ + "\n//# sourceURL=" + __name__ + ".js"); | 514 return eval(__s__ + "\\n//# sourceURL=" + __name__ + ".js"); |
| 465 } | 515 } |
| 466 | 516 |
| 467 if (#) { // outputContainsConstantList | 517 if (#) { // outputContainsConstantList |
| 468 function makeConstList(list) { | 518 function makeConstList(list) { |
| 469 // By assigning a function to the properties they become part of the | 519 // By assigning a function to the properties they become part of the |
| 470 // hidden class. The actual values of the fields don't matter, since we | 520 // hidden class. The actual values of the fields don't matter, since we |
| 471 // only check if they exist. | 521 // only check if they exist. |
| 472 list.immutable$list = Array; | 522 list.immutable\$list = Array; |
| 473 list.fixed$length = Array; | 523 list.fixed\$length = Array; |
| 474 return list; | 524 return list; |
| 475 } | 525 } |
| 476 } | 526 } |
| 477 | 527 |
| 478 setupProgram(); | 528 setupProgram(); |
| 479 | 529 |
| 480 // Initialize globals. | 530 // Initialize globals. |
| 481 #; | 531 #; |
| 482 | 532 |
| 483 // Initialize constants. | 533 // Initialize constants. |
| 484 #; | 534 #; |
| 485 | 535 |
| 486 // Initialize static non-final fields. | 536 // Initialize static non-final fields. |
| 487 #; | 537 #; |
| 488 | 538 |
| 489 // Initialize eager classes. | 539 // Initialize eager classes. |
| 490 #; | 540 #; |
| 491 | 541 |
| 492 var end = Date.now(); | 542 var end = Date.now(); |
| 493 print('Setup: ' + (end - start) + ' ms.'); | 543 print('Setup: ' + (end - start) + ' ms.'); |
| 494 | 544 |
| 495 if (true) #(); // Start main. | 545 if (true) #(); // Start main. |
| 496 | 546 |
| 497 }(Date.now(), #) | 547 }(Date.now(), #) |
| 498 }"""; | 548 }"""; |
| 549 | |
| 550 } | |
| OLD | NEW |