| 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 '../../dart_types.dart' show DartType; |
| 8 import '../../js/js.dart' as js; | 9 import '../../js/js.dart' as js; |
| 9 import '../../js_backend/js_backend.dart' show | 10 import '../../js_backend/js_backend.dart' show |
| 10 JavaScriptBackend, | 11 JavaScriptBackend, |
| 11 Namer, | 12 Namer, |
| 12 ConstantEmitter; | 13 ConstantEmitter; |
| 13 | 14 |
| 14 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show | 15 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show |
| 15 DEFERRED_LIBRARY_URIS, | 16 DEFERRED_LIBRARY_URIS, |
| 16 DEFERRED_LIBRARY_HASHES, | 17 DEFERRED_LIBRARY_HASHES, |
| 17 GET_TYPE_FROM_NAME, | 18 GET_TYPE_FROM_NAME, |
| 18 INITIALIZE_LOADED_HUNK, | 19 INITIALIZE_LOADED_HUNK, |
| 19 IS_HUNK_INITIALIZED, | 20 IS_HUNK_INITIALIZED, |
| 20 IS_HUNK_LOADED, | 21 IS_HUNK_LOADED, |
| 21 MANGLED_GLOBAL_NAMES, | 22 MANGLED_GLOBAL_NAMES, |
| 22 METADATA, | 23 METADATA, |
| 23 TYPE_TO_INTERCEPTOR_MAP; | 24 TYPE_TO_INTERCEPTOR_MAP; |
| 24 | 25 |
| 25 import '../js_emitter.dart' show NativeGenerator; | 26 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode; |
| 26 import '../model.dart'; | 27 import '../model.dart'; |
| 27 | 28 |
| 29 |
| 28 class ModelEmitter { | 30 class ModelEmitter { |
| 29 final Compiler compiler; | 31 final Compiler compiler; |
| 30 final Namer namer; | 32 final Namer namer; |
| 31 final ConstantEmitter constantEmitter; | 33 final ConstantEmitter constantEmitter; |
| 32 | 34 |
| 33 JavaScriptBackend get backend => compiler.backend; | 35 JavaScriptBackend get backend => compiler.backend; |
| 34 | 36 |
| 35 /// For deferred loading we communicate the initializers via this global var. | 37 /// For deferred loading we communicate the initializers via this global var. |
| 36 static const String deferredInitializersGlobal = | 38 static const String deferredInitializersGlobal = |
| 37 r"$__dart_deferred_initializers__"; | 39 r"$__dart_deferred_initializers__"; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 } else { | 103 } else { |
| 102 nativeBoilerplate = js.js.statement(";"); | 104 nativeBoilerplate = js.js.statement(";"); |
| 103 } | 105 } |
| 104 | 106 |
| 105 js.Expression code = new js.ArrayInitializer(elements); | 107 js.Expression code = new js.ArrayInitializer(elements); |
| 106 | 108 |
| 107 return js.js.statement( | 109 return js.js.statement( |
| 108 boilerplate, | 110 boilerplate, |
| 109 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 111 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 110 'holders': emitHolders(fragment.holders), | 112 'holders': emitHolders(fragment.holders), |
| 113 'tearOff': buildTearOffCode(backend), |
| 114 'parseFunctionDescriptor': |
| 115 js.js.statement(parseFunctionDescriptorBoilerplate), |
| 111 'cyclicThrow': | 116 'cyclicThrow': |
| 112 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), | 117 backend.emitter.staticFunctionAccess(backend.getCyclicThrowHelper()), |
| 113 'outputContainsConstantList': program.outputContainsConstantList, | 118 'outputContainsConstantList': program.outputContainsConstantList, |
| 114 'embeddedGlobals': emitEmbeddedGlobals(program), | 119 'embeddedGlobals': emitEmbeddedGlobals(program), |
| 115 'constants': emitConstants(fragment.constants), | 120 'constants': emitConstants(fragment.constants), |
| 116 'staticNonFinals': | 121 'staticNonFinals': |
| 117 emitStaticNonFinalFields(fragment.staticNonFinalFields), | 122 emitStaticNonFinalFields(fragment.staticNonFinalFields), |
| 118 'nativeBoilerplate': nativeBoilerplate, | 123 'nativeBoilerplate': nativeBoilerplate, |
| 119 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 124 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 120 'eagerClasses': emitEagerClassInitializations(fragment.libraries), | 125 'eagerClasses': emitEagerClassInitializations(fragment.libraries), |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 List elements = [js.string(cls.superclassName), | 393 List elements = [js.string(cls.superclassName), |
| 389 js.number(cls.superclassHolderIndex)]; | 394 js.number(cls.superclassHolderIndex)]; |
| 390 | 395 |
| 391 if (cls.isMixinApplication) { | 396 if (cls.isMixinApplication) { |
| 392 MixinApplication mixin = cls; | 397 MixinApplication mixin = cls; |
| 393 elements.add(js.string(mixin.mixinClass.name)); | 398 elements.add(js.string(mixin.mixinClass.name)); |
| 394 elements.add(js.number(mixin.mixinClass.holder.index)); | 399 elements.add(js.number(mixin.mixinClass.holder.index)); |
| 395 } else { | 400 } else { |
| 396 elements.add(_generateConstructor(cls)); | 401 elements.add(_generateConstructor(cls)); |
| 397 } | 402 } |
| 398 Iterable<Method> methods = cls.methods.expand((Method method) { | 403 Iterable<Method> methods = cls.methods; |
| 399 // TODO(floitsch): can there be anything else than a DartMethod? | |
| 400 if (method is DartMethod) { | |
| 401 return [method]..addAll(method.parameterStubs); | |
| 402 } else { | |
| 403 return [method]; | |
| 404 } | |
| 405 }); | |
| 406 Iterable<Method> isChecks = cls.isChecks; | 404 Iterable<Method> isChecks = cls.isChecks; |
| 407 Iterable<Method> callStubs = cls.callStubs; | 405 Iterable<Method> callStubs = cls.callStubs; |
| 408 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; | 406 Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs; |
| 409 Iterable<Method> gettersSetters = _generateGettersSetters(cls); | 407 Iterable<Method> gettersSetters = _generateGettersSetters(cls); |
| 410 Iterable<Method> allMethods = | 408 Iterable<Method> allMethods = |
| 411 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters] | 409 [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters] |
| 412 .expand((x) => x); | 410 .expand((x) => x); |
| 413 elements.addAll(allMethods.expand((e) => [js.string(e.name), e.code])); | 411 elements.addAll(allMethods.expand(emitInstanceMethod)); |
| 412 |
| 414 return unparse(compiler, new js.ArrayInitializer(elements)); | 413 return unparse(compiler, new js.ArrayInitializer(elements)); |
| 415 } | 414 } |
| 416 | 415 |
| 417 js.Expression emitLazyInitializer(StaticField field) { | 416 js.Expression emitLazyInitializer(StaticField field) { |
| 418 assert(field.isLazy); | 417 assert(field.isLazy); |
| 419 return unparse(compiler, field.code); | 418 return unparse(compiler, field.code); |
| 420 } | 419 } |
| 421 | 420 |
| 421 /// JavaScript code template that implements parsing of a function descriptor. |
| 422 /// Descriptors are used in place of the actual JavaScript function |
| 423 /// definition in the output if additional information needs to be passed to |
| 424 /// facilitate the generation of tearOffs at runtime. The format is an array |
| 425 /// with the following fields: |
| 426 /// |
| 427 /// [Method.code] |
| 428 /// [DartMethod.callName] |
| 429 /// [DartMethod.tearOffName] |
| 430 /// [JavaScriptBackend.isInterceptedMethod] |
| 431 /// functionType |
| 432 /// |
| 433 /// followed by |
| 434 /// |
| 435 /// [ParameterStubMethod.name] |
| 436 /// [ParameterStubMethod.code] |
| 437 /// |
| 438 /// for each stub in [DartMethod.parameterStubs]. |
| 439 |
| 440 static final String parseFunctionDescriptorBoilerplate = r""" |
| 441 function parseFunctionDescriptor(proto, name, descriptor) { |
| 442 if (descriptor instanceof Array) { |
| 443 proto[name] = descriptor[0]; |
| 444 var funs = [descriptor[0]]; |
| 445 funs[0].$callName = descriptor[1]; |
| 446 for (var pos = 5; pos < descriptor.length; pos += 3) { |
| 447 var stub = descriptor[pos + 2]; |
| 448 stub.$callName = descriptor[pos + 1]; |
| 449 proto[descriptor[pos]] = stub; |
| 450 funs.push(stub); |
| 451 } |
| 452 if (descriptor[2] != null) { |
| 453 var isIntercepted = descriptor[3]; |
| 454 var reflectionInfo = descriptor[4]; |
| 455 proto[descriptor[2]] = |
| 456 tearOff(funs, reflectionInfo, false, name, isIntercepted); |
| 457 } |
| 458 } else { |
| 459 proto[name] = descriptor; |
| 460 } |
| 461 } |
| 462 """; |
| 463 |
| 464 js.Expression _generateFunctionType(DartType memberType) { |
| 465 if (memberType.containsTypeVariables) { |
| 466 js.Expression thisAccess = js.js(r'this.$receiver'); |
| 467 return backend.rti.getSignatureEncoding(memberType, thisAccess); |
| 468 } else { |
| 469 return js.number(backend.emitter.metadataCollector.reifyType(memberType)); |
| 470 } |
| 471 } |
| 472 |
| 473 Iterable<js.Expression> emitInstanceMethod(Method method) { |
| 474 |
| 475 List<js.Expression> makeNameCodePair(Method method) { |
| 476 return [js.string(method.name), method.code]; |
| 477 } |
| 478 |
| 479 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { |
| 480 js.Expression callName = stub.callName == null |
| 481 ? new js.LiteralNull() |
| 482 : js.string(stub.callName); |
| 483 return [js.string(stub.name), callName, stub.code]; |
| 484 } |
| 485 |
| 486 if (method is DartMethod) { |
| 487 if (method.needsTearOff) { |
| 488 /// See [parseFunctionDescriptorBoilerplate] for a full description of |
| 489 /// the format. |
| 490 // [name, [function, callName, tearOffName, isIntercepted, functionType, |
| 491 // stub1_name, stub1_callName, stub1_code, ...] |
| 492 bool isIntercepted = backend.isInterceptedMethod(method.element); |
| 493 var data = [method.code]; |
| 494 data.add(js.string(method.callName)); |
| 495 data.add(js.string(method.tearOffName)); |
| 496 data.add(new js.LiteralBool(isIntercepted)); |
| 497 data.add(_generateFunctionType(method.type)); |
| 498 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
| 499 return [js.string(method.name), new js.ArrayInitializer(data)]; |
| 500 } else { |
| 501 // TODO(floitsch): not the most efficient way... |
| 502 return ([method]..addAll(method.parameterStubs)) |
| 503 .expand(makeNameCodePair); |
| 504 } |
| 505 } else { |
| 506 return makeNameCodePair(method); |
| 507 } |
| 508 } |
| 509 |
| 422 Iterable<js.Expression> emitStaticMethod(StaticMethod method) { | 510 Iterable<js.Expression> emitStaticMethod(StaticMethod method) { |
| 423 js.Expression holderIndex = js.number(method.holder.index); | 511 js.Expression holderIndex = js.number(method.holder.index); |
| 424 List<js.Expression> output = <js.Expression>[]; | 512 List<js.Expression> output = <js.Expression>[]; |
| 425 | 513 |
| 426 void _addMethod(Method method) { | 514 void _addMethod(Method method) { |
| 427 js.Expression unparsed = unparse(compiler, method.code); | 515 js.Expression unparsed = unparse(compiler, method.code); |
| 428 output.add(js.string(method.name)); | 516 output.add(js.string(method.name)); |
| 429 output.add(holderIndex); | 517 output.add(holderIndex); |
| 430 output.add(unparsed); | 518 output.add(unparsed); |
| 431 } | 519 } |
| 432 | 520 |
| 521 List<js.Expression> makeNameCallNameCodeTriplet(ParameterStubMethod stub) { |
| 522 js.Expression callName = stub.callName == null |
| 523 ? new js.LiteralNull() |
| 524 : js.string(stub.callName); |
| 525 return [js.string(stub.name), callName, unparse(compiler, stub.code)]; |
| 526 } |
| 527 |
| 433 _addMethod(method); | 528 _addMethod(method); |
| 434 // TODO(floitsch): can there be anything else than a StaticDartMethod? | 529 // TODO(floitsch): can there be anything else than a StaticDartMethod? |
| 435 if (method is StaticDartMethod) { | 530 if (method is StaticDartMethod) { |
| 436 method.parameterStubs.forEach(_addMethod); | 531 if (method.needsTearOff) { |
| 532 /// The format emitted is the same as for the parser specified at |
| 533 /// [parseFunctionDescriptorBoilerplate] except for the missing |
| 534 /// field whether the method is intercepted. |
| 535 // [name, [function, callName, tearOffName, functionType, |
| 536 // stub1_name, stub1_callName, stub1_code, ...] |
| 537 var data = [unparse(compiler, method.code)]; |
| 538 data.add(js.string(method.callName)); |
| 539 data.add(js.string(method.tearOffName)); |
| 540 data.add(_generateFunctionType(method.type)); |
| 541 data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet)); |
| 542 return [js.string(method.name), holderIndex, |
| 543 new js.ArrayInitializer(data)]; |
| 544 } else { |
| 545 method.parameterStubs.forEach(_addMethod); |
| 546 } |
| 437 } | 547 } |
| 438 return output; | 548 return output; |
| 439 } | 549 } |
| 440 | 550 |
| 441 static final String boilerplate = """ | 551 static final String boilerplate = """ |
| 442 { | 552 { |
| 443 // Declare deferred-initializer global. | 553 // Declare deferred-initializer global. |
| 444 #deferredInitializer; | 554 #deferredInitializer; |
| 445 | 555 |
| 446 !function(start, program) { | 556 !function(start, program) { |
| 447 | |
| 448 // Initialize holder objects. | 557 // Initialize holder objects. |
| 449 #holders; | 558 #holders; |
| 450 | 559 |
| 560 // Counter to generate unique names for tear offs. |
| 561 var functionCounter = 0; |
| 562 |
| 451 function setupProgram() { | 563 function setupProgram() { |
| 452 for (var i = 0; i < program.length - 1; i++) { | 564 for (var i = 0; i < program.length - 1; i++) { |
| 453 setupLibrary(program[i]); | 565 setupLibrary(program[i]); |
| 454 } | 566 } |
| 455 setupLazyStatics(program[i]); | 567 setupLazyStatics(program[i]); |
| 456 } | 568 } |
| 457 | 569 |
| 458 function setupLibrary(library) { | 570 function setupLibrary(library) { |
| 459 var statics = library[0]; | 571 var statics = library[0]; |
| 460 for (var i = 0; i < statics.length; i += 3) { | 572 for (var i = 0; i < statics.length; i += 3) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 474 for (var i = 0; i < statics.length; i += 4) { | 586 for (var i = 0; i < statics.length; i += 4) { |
| 475 var name = statics[i]; | 587 var name = statics[i]; |
| 476 var getterName = statics[i + 1]; | 588 var getterName = statics[i + 1]; |
| 477 var holderIndex = statics[i + 2]; | 589 var holderIndex = statics[i + 2]; |
| 478 var initializer = statics[i + 3]; | 590 var initializer = statics[i + 3]; |
| 479 setupLazyStatic(name, getterName, holders[holderIndex], initializer); | 591 setupLazyStatic(name, getterName, holders[holderIndex], initializer); |
| 480 } | 592 } |
| 481 } | 593 } |
| 482 | 594 |
| 483 function setupStatic(name, holder, descriptor) { | 595 function setupStatic(name, holder, descriptor) { |
| 484 holder[name] = function() { | 596 if (typeof descriptor == 'string') { |
| 485 var method = compile(name, descriptor); | 597 holder[name] = function() { |
| 486 holder[name] = method; | 598 var method = compile(name, descriptor); |
| 487 return method.apply(this, arguments); | 599 holder[name] = method; |
| 488 }; | 600 return method.apply(this, arguments); |
| 601 }; |
| 602 } else { |
| 603 // Parse the tear off information and generate compile handlers. |
| 604 // TODO(herhut): Share parser with instance methods. |
| 605 function compileAllStubs() { |
| 606 var funs; |
| 607 var fun = compile(name, descriptor[0]); |
| 608 fun.\$callName = descriptor[1]; |
| 609 holder[name] = fun; |
| 610 funs = [fun]; |
| 611 for (var pos = 4; pos < descriptor.length; pos += 3) { |
| 612 var stubName = descriptor[pos]; |
| 613 fun = compile(stubName, descriptor[pos + 2]); |
| 614 fun.\$callName = descriptor[pos + 1]; |
| 615 holder[stubName] = fun; |
| 616 funs.push(fun); |
| 617 } |
| 618 if (descriptor[2] != null) { // tear-off name. |
| 619 // functions, reflectionInfo, isStatic, name, isIntercepted. |
| 620 holder[descriptor[2]] = |
| 621 tearOff(funs, descriptor[3], true, name, false); |
| 622 } |
| 623 } |
| 624 |
| 625 function setupCompileAllAndDelegateStub(name) { |
| 626 holder[name] = function() { |
| 627 compileAllStubs(); |
| 628 return holder[name].apply(this, arguments); |
| 629 }; |
| 630 } |
| 631 |
| 632 setupCompileAllAndDelegateStub(name); |
| 633 for (var pos = 4; pos < descriptor.length; pos += 3) { |
| 634 setupCompileAllAndDelegateStub(descriptor[pos]); |
| 635 } |
| 636 if (descriptor[2] != null) { // tear-off name. |
| 637 setupCompileAllAndDelegateStub(descriptor[2]) |
| 638 } |
| 639 } |
| 489 } | 640 } |
| 490 | 641 |
| 491 function setupLazyStatic(name, getterName, holder, descriptor) { | 642 function setupLazyStatic(name, getterName, holder, descriptor) { |
| 492 holder[name] = null; | 643 holder[name] = null; |
| 493 holder[getterName] = function() { | 644 holder[getterName] = function() { |
| 494 var initializer = compile(name, descriptor); | 645 var initializer = compile(name, descriptor); |
| 495 holder[getterName] = function() { #cyclicThrow(name) }; | 646 holder[getterName] = function() { #cyclicThrow(name) }; |
| 496 var result; | 647 var result; |
| 497 var sentinelInProgress = descriptor; | 648 var sentinelInProgress = descriptor; |
| 498 try { | 649 try { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 526 constructor.apply(object, arguments); | 677 constructor.apply(object, arguments); |
| 527 return object; | 678 return object; |
| 528 }; | 679 }; |
| 529 | 680 |
| 530 // We store the ensureResolved function on the patch function to make it | 681 // We store the ensureResolved function on the patch function to make it |
| 531 // possible to resolve superclass references without constructing instances. | 682 // possible to resolve superclass references without constructing instances. |
| 532 patch.ensureResolved = ensureResolved; | 683 patch.ensureResolved = ensureResolved; |
| 533 holder[name] = patch; | 684 holder[name] = patch; |
| 534 } | 685 } |
| 535 | 686 |
| 687 #tearOff; |
| 688 |
| 689 #parseFunctionDescriptor; |
| 690 |
| 536 function compileConstructor(name, descriptor) { | 691 function compileConstructor(name, descriptor) { |
| 537 descriptor = compile(name, descriptor); | 692 descriptor = compile(name, descriptor); |
| 538 var prototype = determinePrototype(descriptor); | 693 var prototype = determinePrototype(descriptor); |
| 539 var constructor; | 694 var constructor; |
| 540 // $mixinFormatDescription. | 695 // $mixinFormatDescription. |
| 541 if (typeof descriptor[2] !== 'function') { | 696 if (typeof descriptor[2] !== 'function') { |
| 542 constructor = compileMixinConstructor(name, prototype, descriptor); | 697 constructor = compileMixinConstructor(name, prototype, descriptor); |
| 543 for (var i = 4; i < descriptor.length; i += 2) { | 698 for (var i = 4; i < descriptor.length; i += 2) { |
| 544 prototype[descriptor[i]] = descriptor[i + 1]; | 699 parseFunctionDescriptor(prototype, descriptor, descriptor[i + 1]); |
| 545 } | 700 } |
| 546 } else { | 701 } else { |
| 547 constructor = descriptor[2]; | 702 constructor = descriptor[2]; |
| 548 for (var i = 3; i < descriptor.length; i += 2) { | 703 for (var i = 3; i < descriptor.length; i += 2) { |
| 549 prototype[descriptor[i]] = descriptor[i + 1]; | 704 parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]); |
| 550 } | 705 } |
| 551 } | 706 } |
| 552 constructor.builtin\$cls = name; // Needed for RTI. | 707 constructor.builtin\$cls = name; // Needed for RTI. |
| 553 constructor.prototype = prototype; | 708 constructor.prototype = prototype; |
| 554 prototype[#operatorIsPrefix + name] = constructor; | 709 prototype[#operatorIsPrefix + name] = constructor; |
| 555 prototype.constructor = constructor; | 710 prototype.constructor = constructor; |
| 556 return constructor; | 711 return constructor; |
| 557 } | 712 } |
| 558 | 713 |
| 559 function compileMixinConstructor(name, prototype, descriptor) { | 714 function compileMixinConstructor(name, prototype, descriptor) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 | 781 |
| 627 var end = Date.now(); | 782 var end = Date.now(); |
| 628 print('Setup: ' + (end - start) + ' ms.'); | 783 print('Setup: ' + (end - start) + ' ms.'); |
| 629 | 784 |
| 630 #main(); // Start main. | 785 #main(); // Start main. |
| 631 | 786 |
| 632 }(Date.now(), #code) | 787 }(Date.now(), #code) |
| 633 }"""; | 788 }"""; |
| 634 | 789 |
| 635 } | 790 } |
| OLD | NEW |