| 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 // Mixins are not allowed to inject fields. |
| 266 assert(!currentClass.isMixinApplication || |
| 267 (currentClass as MixinApplication).mixinClass.fields.isEmpty); |
| 268 |
| 269 allFieldNames.addAll( |
| 270 currentClass.fields.map((InstanceField field) => field.name)); |
| 271 currentClass = currentClass.superclass; |
| 272 } |
| 264 } | 273 } |
| 265 String name = cls.name; | 274 String name = cls.name; |
| 266 String parameters = allFieldNames.join(', '); | 275 String parameters = allFieldNames.join(', '); |
| 267 String assignments = allFieldNames | 276 String assignments = allFieldNames |
| 268 .map((String field) => "this.$field = $field;\n") | 277 .map((String field) => "this.$field = $field;\n") |
| 269 .join(); | 278 .join(); |
| 270 String code = 'function $name($parameters) { $assignments }'; | 279 String code = 'function $name($parameters) { $assignments }'; |
| 271 js.Template template = js.js.uncachedExpressionTemplate(code); | 280 js.Template template = js.js.uncachedExpressionTemplate(code); |
| 272 return template.instantiate(const []); | 281 return template.instantiate(const []); |
| 273 } | 282 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 .map(_generateGetter); | 318 .map(_generateGetter); |
| 310 | 319 |
| 311 Iterable<Method> setters = cls.fields | 320 Iterable<Method> setters = cls.fields |
| 312 .where((InstanceField field) => field.needsSetter) | 321 .where((InstanceField field) => field.needsSetter) |
| 313 .map(_generateSetter); | 322 .map(_generateSetter); |
| 314 | 323 |
| 315 return [getters, setters].expand((x) => x); | 324 return [getters, setters].expand((x) => x); |
| 316 } | 325 } |
| 317 | 326 |
| 318 js.Expression emitClass(Class cls) { | 327 js.Expression emitClass(Class cls) { |
| 319 List elements = [ js.string(cls.superclassName), | 328 if (cls.isMixinApplication) return emitMixinApplication(cls); |
| 320 js.number(cls.superclassHolderIndex), | 329 |
| 321 _generateConstructor(cls) ]; | 330 List elements = [js.string(cls.superclassName), |
| 331 js.number(cls.superclassHolderIndex), |
| 332 _generateConstructor(cls)]; |
| 322 Iterable<Method> methods = cls.methods; | 333 Iterable<Method> methods = cls.methods; |
| 323 Iterable<Method> gettersSetters = _generateGettersSetters(cls); | 334 Iterable<Method> gettersSetters = _generateGettersSetters(cls); |
| 324 Iterable<Method> allMethods = [methods, gettersSetters].expand((x) => x); | 335 Iterable<Method> allMethods = [methods, gettersSetters].expand((x) => x); |
| 325 elements.addAll(allMethods.expand((e) => [ js.string(e.name), e.code ])); | 336 elements.addAll(allMethods.expand((e) => [js.string(e.name), e.code])); |
| 326 return unparse(compiler, new js.ArrayInitializer.from(elements)); | 337 return unparse(compiler, new js.ArrayInitializer.from(elements)); |
| 327 } | 338 } |
| 328 | 339 |
| 340 // This string should be referenced wherever JavaScript code makes assumptions |
| 341 // on the mixin format. |
| 342 static final String mixinFormatDescription = |
| 343 "Mixins have no constructor, but a reference to their mixin class."; |
| 344 |
| 345 js.Expression emitMixinApplication(MixinApplication cls) { |
| 346 List elements = [js.string(cls.superclassName), |
| 347 js.number(cls.superclassHolderIndex), |
| 348 js.string(cls.mixinClass.name), |
| 349 js.number(cls.mixinClass.holder.index)]; |
| 350 return unparse(compiler, new js.ArrayInitializer.from(elements)); |
| 351 } |
| 352 |
| 329 js.Expression emitLazyInitializer(StaticField field) { | 353 js.Expression emitLazyInitializer(StaticField field) { |
| 330 assert(field.isLazy); | 354 assert(field.isLazy); |
| 331 return unparse(compiler, field.code); | 355 return unparse(compiler, field.code); |
| 332 } | 356 } |
| 333 | 357 |
| 334 js.Expression emitStaticMethod(StaticMethod method) { | 358 js.Expression emitStaticMethod(StaticMethod method) { |
| 335 return unparse(compiler, method.code); | 359 return unparse(compiler, method.code); |
| 336 } | 360 } |
| 337 } | |
| 338 | 361 |
| 339 final String boilerplate = r""" | 362 static final String boilerplate = """ |
| 340 { | 363 { |
| 341 // Declare deferred-initializer global. | 364 // Declare deferred-initializer global. |
| 342 #; | 365 #; |
| 343 | 366 |
| 344 !function(start, program) { | 367 !function(start, program) { |
| 345 | 368 |
| 346 // Initialize holder objects. | 369 // Initialize holder objects. |
| 347 #; | 370 #; |
| 348 | 371 |
| 349 function setupProgram() { | 372 function setupProgram() { |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 427 // to resolve superclass references without constructing instances. The | 450 // to resolve superclass references without constructing instances. The |
| 428 // resolve property also serves as a marker that indicates whether or not | 451 // resolve property also serves as a marker that indicates whether or not |
| 429 // a class has been resolved yet. | 452 // a class has been resolved yet. |
| 430 patch.resolve = resolve; | 453 patch.resolve = resolve; |
| 431 holder[name] = patch; | 454 holder[name] = patch; |
| 432 } | 455 } |
| 433 | 456 |
| 434 function compileConstructor(name, descriptor) { | 457 function compileConstructor(name, descriptor) { |
| 435 descriptor = compile(name, descriptor); | 458 descriptor = compile(name, descriptor); |
| 436 var prototype = determinePrototype(descriptor); | 459 var prototype = determinePrototype(descriptor); |
| 460 // $mixinFormatDescription. |
| 461 if (typeof descriptor[2] !== 'function') { |
| 462 return compileMixinConstructor(name, prototype, descriptor); |
| 463 } |
| 437 var constructor = descriptor[2]; | 464 var constructor = descriptor[2]; |
| 438 for (var i = 3; i < descriptor.length; i += 2) { | 465 for (var i = 3; i < descriptor.length; i += 2) { |
| 439 prototype[descriptor[i]] = descriptor[i + 1]; | 466 prototype[descriptor[i]] = descriptor[i + 1]; |
| 440 } | 467 } |
| 441 constructor.prototype = prototype; | 468 constructor.prototype = prototype; |
| 442 return constructor; | 469 return constructor; |
| 443 } | 470 } |
| 444 | 471 |
| 472 function compileMixinConstructor(name, prototype, descriptor) { |
| 473 // $mixinFormatDescription. |
| 474 var mixinName = descriptor[2]; |
| 475 var mixinHolderIndex = descriptor[3]; |
| 476 var mixin = holders[mixinHolderIndex][mixinName]; |
| 477 if (mixin.resolve) mixin = mixin.resolve(); |
| 478 var mixinPrototype = mixin.prototype; |
| 479 |
| 480 // Fill the prototype with the mixin's properties. |
| 481 var mixinProperties = Object.keys(mixinPrototype); |
| 482 for (var i = 0; i < mixinProperties.length; i++) { |
| 483 var p = mixinProperties[i]; |
| 484 prototype[p] = mixinPrototype[p]; |
| 485 } |
| 486 // Since this is a mixin application the constructor will actually never |
| 487 // be invoked. We only use its prototype for the application's subclasses. |
| 488 var constructor = function() {}; |
| 489 constructor.prototype = prototype; |
| 490 return constructor; |
| 491 } |
| 492 |
| 445 function determinePrototype(descriptor) { | 493 function determinePrototype(descriptor) { |
| 446 var superclassName = descriptor[0]; | 494 var superclassName = descriptor[0]; |
| 447 if (!superclassName) return { }; | 495 if (!superclassName) return { }; |
| 448 | 496 |
| 449 // Look up the superclass constructor function in the right holder. | 497 // Look up the superclass constructor function in the right holder. |
| 450 var holderIndex = descriptor[1]; | 498 var holderIndex = descriptor[1]; |
| 451 var superclass = holders[holderIndex][superclassName]; | 499 var superclass = holders[holderIndex][superclassName]; |
| 452 if (superclass.resolve) superclass = superclass.resolve(); | 500 if (superclass.resolve) superclass = superclass.resolve(); |
| 453 | 501 |
| 454 // Create a new prototype object chained to the superclass prototype. | 502 // Create a new prototype object chained to the superclass prototype. |
| 455 var intermediate = function() { }; | 503 var intermediate = function() { }; |
| 456 intermediate.prototype = superclass.prototype; | 504 intermediate.prototype = superclass.prototype; |
| 457 return new intermediate(); | 505 return new intermediate(); |
| 458 } | 506 } |
| 459 | 507 |
| 460 function compile(__name__, __s__) { | 508 function compile(__name__, __s__) { |
| 461 'use strict'; | 509 'use strict'; |
| 462 // TODO(floitsch): evaluate the performance impact of the string | 510 // TODO(floitsch): evaluate the performance impact of the string |
| 463 // concatenations. | 511 // concatenations. |
| 464 return eval(__s__ + "\n//# sourceURL=" + __name__ + ".js"); | 512 return eval(__s__ + "\\n//# sourceURL=" + __name__ + ".js"); |
| 465 } | 513 } |
| 466 | 514 |
| 467 if (#) { // outputContainsConstantList | 515 if (#) { // outputContainsConstantList |
| 468 function makeConstList(list) { | 516 function makeConstList(list) { |
| 469 // By assigning a function to the properties they become part of the | 517 // 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 | 518 // hidden class. The actual values of the fields don't matter, since we |
| 471 // only check if they exist. | 519 // only check if they exist. |
| 472 list.immutable$list = Array; | 520 list.immutable\$list = Array; |
| 473 list.fixed$length = Array; | 521 list.fixed\$length = Array; |
| 474 return list; | 522 return list; |
| 475 } | 523 } |
| 476 } | 524 } |
| 477 | 525 |
| 478 setupProgram(); | 526 setupProgram(); |
| 479 | 527 |
| 480 // Initialize globals. | 528 // Initialize globals. |
| 481 #; | 529 #; |
| 482 | 530 |
| 483 // Initialize constants. | 531 // Initialize constants. |
| 484 #; | 532 #; |
| 485 | 533 |
| 486 // Initialize static non-final fields. | 534 // Initialize static non-final fields. |
| 487 #; | 535 #; |
| 488 | 536 |
| 489 // Initialize eager classes. | 537 // Initialize eager classes. |
| 490 #; | 538 #; |
| 491 | 539 |
| 492 var end = Date.now(); | 540 var end = Date.now(); |
| 493 print('Setup: ' + (end - start) + ' ms.'); | 541 print('Setup: ' + (end - start) + ' ms.'); |
| 494 | 542 |
| 495 if (true) #(); // Start main. | 543 if (true) #(); // Start main. |
| 496 | 544 |
| 497 }(Date.now(), #) | 545 }(Date.now(), #) |
| 498 }"""; | 546 }"""; |
| 547 |
| 548 } |
| OLD | NEW |