| OLD | NEW |
| 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 js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
| 9 * from the given element. | 9 * from the given element. |
| 10 */ | 10 */ |
| 11 class ClosureInvocationElement extends FunctionElement { | 11 class ClosureInvocationElement extends FunctionElement { |
| 12 ClosureInvocationElement(SourceString name, | 12 ClosureInvocationElement(SourceString name, |
| 13 FunctionElement other) | 13 FunctionElement other) |
| 14 : super.from(name, other, other.enclosingElement), | 14 : super.from(name, other, other.enclosingElement), |
| 15 methodElement = other; | 15 methodElement = other; |
| 16 | 16 |
| 17 isInstanceMember() => true; | 17 isInstanceMember() => true; |
| 18 | 18 |
| 19 Element getOutermostEnclosingMemberOrTopLevel() => methodElement; | 19 Element getOutermostEnclosingMemberOrTopLevel() => methodElement; |
| 20 | 20 |
| 21 /** | 21 /** |
| 22 * The [member] this invocation refers to. | 22 * The [member] this invocation refers to. |
| 23 */ | 23 */ |
| 24 Element methodElement; | 24 Element methodElement; |
| 25 } | 25 } |
| 26 | 26 |
| 27 /** | 27 /** |
| 28 * A convenient type alias for some functions that emit keyed values. | |
| 29 */ | |
| 30 typedef void DefineStubFunction(String invocationName, js.Expression value); | |
| 31 | |
| 32 /** | |
| 33 * A data structure for collecting fragments of a class definition. | |
| 34 */ | |
| 35 class ClassBuilder { | |
| 36 final List<js.Property> properties = <js.Property>[]; | |
| 37 | |
| 38 // Has the same signature as [DefineStubFunction]. | |
| 39 void addProperty(String name, js.Expression value) { | |
| 40 properties.add(new js.Property(js.string(name), value)); | |
| 41 } | |
| 42 | |
| 43 js.Expression toObjectInitializer() => new js.ObjectInitializer(properties); | |
| 44 } | |
| 45 | |
| 46 /** | |
| 47 * Generates the code for all used classes in the program. Static fields (even | 28 * Generates the code for all used classes in the program. Static fields (even |
| 48 * in classes) are ignored, since they can be treated as non-class elements. | 29 * in classes) are ignored, since they can be treated as non-class elements. |
| 49 * | 30 * |
| 50 * The code for the containing (used) methods must exist in the [:universe:]. | 31 * The code for the containing (used) methods must exist in the [:universe:]. |
| 51 */ | 32 */ |
| 52 class CodeEmitterTask extends CompilerTask { | 33 class CodeEmitterTask extends CompilerTask { |
| 53 bool needsInheritFunction = false; | 34 bool needsInheritFunction = false; |
| 54 bool needsDefineClass = false; | 35 bool needsDefineClass = false; |
| 55 bool needsClosureClass = false; | 36 bool needsClosureClass = false; |
| 56 bool needsLazyInitializer = false; | 37 bool needsLazyInitializer = false; |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 /** | 420 /** |
| 440 * Generate stubs to handle invocation of methods with optional | 421 * Generate stubs to handle invocation of methods with optional |
| 441 * arguments. | 422 * arguments. |
| 442 * | 423 * |
| 443 * A method like [: foo([x]) :] may be invoked by the following | 424 * A method like [: foo([x]) :] may be invoked by the following |
| 444 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this | 425 * calls: [: foo(), foo(1), foo(x: 1) :]. See the sources of this |
| 445 * function for detailed examples. | 426 * function for detailed examples. |
| 446 */ | 427 */ |
| 447 void addParameterStub(FunctionElement member, | 428 void addParameterStub(FunctionElement member, |
| 448 Selector selector, | 429 Selector selector, |
| 449 DefineStubFunction defineStub, | 430 DefineMemberFunction defineInstanceMember, |
| 450 Set<String> alreadyGenerated) { | 431 Set<String> alreadyGenerated) { |
| 451 FunctionSignature parameters = member.computeSignature(compiler); | 432 FunctionSignature parameters = member.computeSignature(compiler); |
| 452 int positionalArgumentCount = selector.positionalArgumentCount; | 433 int positionalArgumentCount = selector.positionalArgumentCount; |
| 453 if (positionalArgumentCount == parameters.parameterCount) { | 434 if (positionalArgumentCount == parameters.parameterCount) { |
| 454 assert(selector.namedArgumentCount == 0); | 435 assert(selector.namedArgumentCount == 0); |
| 455 return; | 436 return; |
| 456 } | 437 } |
| 457 if (parameters.optionalParametersAreNamed | 438 if (parameters.optionalParametersAreNamed |
| 458 && selector.namedArgumentCount == parameters.optionalParameterCount) { | 439 && selector.namedArgumentCount == parameters.optionalParameterCount) { |
| 459 // If the selector has the same number of named arguments as | 440 // If the selector has the same number of named arguments as |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 } else { | 524 } else { |
| 544 body = <js.Statement>[ | 525 body = <js.Statement>[ |
| 545 new js.Return( | 526 new js.Return( |
| 546 new js.VariableUse('this') | 527 new js.VariableUse('this') |
| 547 .dot(namer.getName(member)) | 528 .dot(namer.getName(member)) |
| 548 .callWith(argumentsBuffer))]; | 529 .callWith(argumentsBuffer))]; |
| 549 } | 530 } |
| 550 | 531 |
| 551 js.Fun function = new js.Fun(parametersBuffer, new js.Block(body)); | 532 js.Fun function = new js.Fun(parametersBuffer, new js.Block(body)); |
| 552 | 533 |
| 553 defineStub(invocationName, function); | 534 CodeBuffer buffer = new CodeBuffer(); |
| 535 buffer.add(js.prettyPrint(function, compiler)); |
| 536 defineInstanceMember(invocationName, buffer); |
| 554 } | 537 } |
| 555 | 538 |
| 556 void addParameterStubs(FunctionElement member, | 539 void addParameterStubs(FunctionElement member, |
| 557 DefineStubFunction defineStub) { | 540 DefineMemberFunction defineInstanceMember) { |
| 558 // We fill the lists depending on the selector. For example, | 541 // We fill the lists depending on the selector. For example, |
| 559 // take method foo: | 542 // take method foo: |
| 560 // foo(a, b, {c, d}); | 543 // foo(a, b, {c, d}); |
| 561 // | 544 // |
| 562 // We may have multiple ways of calling foo: | 545 // We may have multiple ways of calling foo: |
| 563 // (1) foo(1, 2); | 546 // (1) foo(1, 2); |
| 564 // (2) foo(1, 2, c: 3); | 547 // (2) foo(1, 2, c: 3); |
| 565 // (3) foo(1, 2, d: 4); | 548 // (3) foo(1, 2, d: 4); |
| 566 // (4) foo(1, 2, c: 3, d: 4); | 549 // (4) foo(1, 2, c: 3, d: 4); |
| 567 // (5) foo(1, 2, d: 4, c: 3); | 550 // (5) foo(1, 2, d: 4, c: 3); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 587 Set<String> generatedStubNames = new Set<String>(); | 570 Set<String> generatedStubNames = new Set<String>(); |
| 588 if (compiler.enabledFunctionApply | 571 if (compiler.enabledFunctionApply |
| 589 && member.name == namer.closureInvocationSelectorName) { | 572 && member.name == namer.closureInvocationSelectorName) { |
| 590 // If [Function.apply] is called, we pessimistically compile all | 573 // If [Function.apply] is called, we pessimistically compile all |
| 591 // possible stubs for this closure. | 574 // possible stubs for this closure. |
| 592 FunctionSignature signature = member.computeSignature(compiler); | 575 FunctionSignature signature = member.computeSignature(compiler); |
| 593 Set<Selector> selectors = signature.optionalParametersAreNamed | 576 Set<Selector> selectors = signature.optionalParametersAreNamed |
| 594 ? computeNamedSelectors(signature, member) | 577 ? computeNamedSelectors(signature, member) |
| 595 : computeOptionalSelectors(signature, member); | 578 : computeOptionalSelectors(signature, member); |
| 596 for (Selector selector in selectors) { | 579 for (Selector selector in selectors) { |
| 597 addParameterStub(member, selector, defineStub, generatedStubNames); | 580 addParameterStub( |
| 581 member, selector, defineInstanceMember, generatedStubNames); |
| 598 } | 582 } |
| 599 } else { | 583 } else { |
| 600 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; | 584 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
| 601 if (selectors == null) return; | 585 if (selectors == null) return; |
| 602 for (Selector selector in selectors) { | 586 for (Selector selector in selectors) { |
| 603 if (!selector.applies(member, compiler)) continue; | 587 if (!selector.applies(member, compiler)) continue; |
| 604 addParameterStub(member, selector, defineStub, generatedStubNames); | 588 addParameterStub( |
| 589 member, selector, defineInstanceMember, generatedStubNames); |
| 605 } | 590 } |
| 606 } | 591 } |
| 607 } | 592 } |
| 608 | 593 |
| 609 /** | 594 /** |
| 610 * Compute the set of possible selectors in the presence of named | 595 * Compute the set of possible selectors in the presence of named |
| 611 * parameters. | 596 * parameters. |
| 612 */ | 597 */ |
| 613 Set<Selector> computeNamedSelectors(FunctionSignature signature, | 598 Set<Selector> computeNamedSelectors(FunctionSignature signature, |
| 614 FunctionElement element) { | 599 FunctionElement element) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 return member.hasFixedBackendName() | 666 return member.hasFixedBackendName() |
| 682 ? member.fixedBackendName() | 667 ? member.fixedBackendName() |
| 683 : namer.getName(member); | 668 : namer.getName(member); |
| 684 } | 669 } |
| 685 | 670 |
| 686 /** | 671 /** |
| 687 * Documentation wanted -- johnniwinther | 672 * Documentation wanted -- johnniwinther |
| 688 * | 673 * |
| 689 * Invariant: [member] must be a declaration element. | 674 * Invariant: [member] must be a declaration element. |
| 690 */ | 675 */ |
| 691 void addInstanceMember(Element member, ClassBuilder builder) { | 676 void addInstanceMember(Element member, |
| 677 DefineMemberFunction defineInstanceMember) { |
| 692 assert(invariant(member, member.isDeclaration)); | 678 assert(invariant(member, member.isDeclaration)); |
| 693 // TODO(floitsch): we don't need to deal with members of | 679 // TODO(floitsch): we don't need to deal with members of |
| 694 // uninstantiated classes, that have been overwritten by subclasses. | 680 // uninstantiated classes, that have been overwritten by subclasses. |
| 695 | 681 |
| 696 if (member.isFunction() | 682 if (member.isFunction() |
| 697 || member.isGenerativeConstructorBody() | 683 || member.isGenerativeConstructorBody() |
| 698 || member.isAccessor()) { | 684 || member.isAccessor()) { |
| 699 if (member.isAbstract(compiler)) return; | 685 if (member.isAbstract(compiler)) return; |
| 700 js.Expression code = compiler.codegenWorld.generatedCode[member]; | 686 CodeBuffer codeBuffer = compiler.codegenWorld.generatedCode[member]; |
| 701 if (code == null) return; | 687 if (codeBuffer == null) return; |
| 702 builder.addProperty(namer.getName(member), code); | 688 defineInstanceMember(namer.getName(member), codeBuffer); |
| 703 code = compiler.codegenWorld.generatedBailoutCode[member]; | 689 codeBuffer = compiler.codegenWorld.generatedBailoutCode[member]; |
| 704 if (code != null) { | 690 if (codeBuffer != null) { |
| 705 builder.addProperty(namer.getBailoutName(member), code); | 691 defineInstanceMember(namer.getBailoutName(member), codeBuffer); |
| 706 } | 692 } |
| 707 FunctionElement function = member; | 693 FunctionElement function = member; |
| 708 FunctionSignature parameters = function.computeSignature(compiler); | 694 FunctionSignature parameters = function.computeSignature(compiler); |
| 709 if (!parameters.optionalParameters.isEmpty) { | 695 if (!parameters.optionalParameters.isEmpty) { |
| 710 addParameterStubs(member, builder.addProperty); | 696 addParameterStubs(member, defineInstanceMember); |
| 711 } | 697 } |
| 712 } else if (!member.isField()) { | 698 } else if (!member.isField()) { |
| 713 compiler.internalError('unexpected kind: "${member.kind}"', | 699 compiler.internalError('unexpected kind: "${member.kind}"', |
| 714 element: member); | 700 element: member); |
| 715 } | 701 } |
| 716 emitExtraAccessors(member, builder); | 702 emitExtraAccessors(member, defineInstanceMember); |
| 717 } | 703 } |
| 718 | 704 |
| 719 /** | 705 /** |
| 720 * Documentation wanted -- johnniwinther | 706 * Documentation wanted -- johnniwinther |
| 721 * | 707 * |
| 722 * Invariant: [classElement] must be a declaration element. | 708 * Invariant: [classElement] must be a declaration element. |
| 723 */ | 709 */ |
| 724 void emitInstanceMembers(ClassElement classElement, | 710 void emitInstanceMembers(ClassElement classElement, |
| 725 ClassBuilder builder) { | 711 CodeBuffer buffer, |
| 712 bool emitLeadingComma) { |
| 726 assert(invariant(classElement, classElement.isDeclaration)); | 713 assert(invariant(classElement, classElement.isDeclaration)); |
| 714 void defineInstanceMember(String name, StringBuffer memberBuffer) { |
| 715 if (emitLeadingComma) buffer.add(','); |
| 716 emitLeadingComma = true; |
| 717 buffer.add('\n'); |
| 718 buffer.add('$_$name:$_'); |
| 719 buffer.add(memberBuffer); |
| 720 } |
| 721 |
| 727 JavaScriptBackend backend = compiler.backend; | 722 JavaScriptBackend backend = compiler.backend; |
| 728 if (classElement == backend.objectInterceptorClass) { | 723 if (classElement == backend.objectInterceptorClass) { |
| 729 emitInterceptorMethods(builder); | 724 emitInterceptorMethods(defineInstanceMember); |
| 730 // The ObjectInterceptor does not have any instance methods. | 725 // The ObjectInterceptor does not have any instance methods. |
| 731 return; | 726 return; |
| 732 } | 727 } |
| 733 | 728 |
| 734 classElement.implementation.forEachMember( | 729 classElement.implementation.forEachMember( |
| 735 (ClassElement enclosing, Element member) { | 730 (ClassElement enclosing, Element member) { |
| 736 assert(invariant(classElement, member.isDeclaration)); | 731 assert(invariant(classElement, member.isDeclaration)); |
| 737 if (member.isInstanceMember()) { | 732 if (member.isInstanceMember()) { |
| 738 addInstanceMember(member, builder); | 733 addInstanceMember(member, defineInstanceMember); |
| 739 } | 734 } |
| 740 }, | 735 }, |
| 741 includeBackendMembers: true); | 736 includeBackendMembers: true); |
| 742 | 737 |
| 743 generateIsTestsOn(classElement, (Element other) { | 738 generateIsTestsOn(classElement, (Element other) { |
| 744 js.Expression code; | 739 String code; |
| 745 if (compiler.objectClass == other) return; | 740 if (compiler.objectClass == other) return; |
| 746 if (nativeEmitter.requiresNativeIsCheck(other)) { | 741 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 747 code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); | 742 code = 'function()$_{${_}return true;$_}'; |
| 748 } else { | 743 } else { |
| 749 code = new js.LiteralBool(true); | 744 code = 'true'; |
| 750 } | 745 } |
| 751 builder.addProperty(namer.operatorIs(other), code); | 746 CodeBuffer typeTestBuffer = new CodeBuffer(); |
| 747 typeTestBuffer.add(code); |
| 748 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); |
| 752 }); | 749 }); |
| 753 | 750 |
| 754 if (identical(classElement, compiler.objectClass) | 751 if (identical(classElement, compiler.objectClass) |
| 755 && compiler.enabledNoSuchMethod) { | 752 && compiler.enabledNoSuchMethod) { |
| 756 // Emit the noSuchMethod handlers on the Object prototype now, | 753 // Emit the noSuchMethod handlers on the Object prototype now, |
| 757 // so that the code in the dynamicFunction helper can find | 754 // so that the code in the dynamicFunction helper can find |
| 758 // them. Note that this helper is invoked before analyzing the | 755 // them. Note that this helper is invoked before analyzing the |
| 759 // full JS script. | 756 // full JS script. |
| 760 if (!nativeEmitter.handleNoSuchMethod) { | 757 if (!nativeEmitter.handleNoSuchMethod) { |
| 761 emitNoSuchMethodHandlers(builder.addProperty); | 758 emitNoSuchMethodHandlers(defineInstanceMember); |
| 762 } | 759 } |
| 763 } | 760 } |
| 764 } | 761 } |
| 765 | 762 |
| 766 void emitRuntimeClassesAndTests(CodeBuffer buffer) { | 763 void emitRuntimeClassesAndTests(CodeBuffer buffer) { |
| 767 JavaScriptBackend backend = compiler.backend; | 764 JavaScriptBackend backend = compiler.backend; |
| 768 RuntimeTypeInformation rti = backend.rti; | 765 RuntimeTypeInformation rti = backend.rti; |
| 769 | 766 |
| 770 TypeChecks typeChecks = rti.computeRequiredChecks(); | 767 TypeChecks typeChecks = rti.computeRequiredChecks(); |
| 771 | 768 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 // generate the field getter/setter dynamically. Since this is only | 872 // generate the field getter/setter dynamically. Since this is only |
| 876 // allowed on fields that are in [classElement] we don't need to visit | 873 // allowed on fields that are in [classElement] we don't need to visit |
| 877 // superclasses for non-instantiated classes. | 874 // superclasses for non-instantiated classes. |
| 878 classElement.implementation.forEachInstanceField( | 875 classElement.implementation.forEachInstanceField( |
| 879 visitField, | 876 visitField, |
| 880 includeBackendMembers: true, | 877 includeBackendMembers: true, |
| 881 includeSuperMembers: isInstantiated && !classElement.isNative()); | 878 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 882 } | 879 } |
| 883 | 880 |
| 884 void generateGetter(Element member, String fieldName, String accessorName, | 881 void generateGetter(Element member, String fieldName, String accessorName, |
| 885 ClassBuilder builder) { | 882 CodeBuffer buffer) { |
| 886 String getterName = namer.getterNameFromAccessorName(accessorName); | 883 String getterName = namer.getterNameFromAccessorName(accessorName); |
| 887 builder.addProperty(getterName, | 884 buffer.add("$getterName: function() { return this.$fieldName; }"); |
| 888 js.fun([], js.block1(js.return_(js.use('this').dot(fieldName))))); | |
| 889 } | 885 } |
| 890 | 886 |
| 891 void generateSetter(Element member, String fieldName, String accessorName, | 887 void generateSetter(Element member, String fieldName, String accessorName, |
| 892 ClassBuilder builder) { | 888 CodeBuffer buffer) { |
| 893 String setterName = namer.setterNameFromAccessorName(accessorName); | 889 String setterName = namer.setterNameFromAccessorName(accessorName); |
| 894 builder.addProperty(setterName, | 890 buffer.add("$setterName: function(v) { this.$fieldName = v; }"); |
| 895 js.fun(['v'], | |
| 896 js.block1( | |
| 897 new js.ExpressionStatement( | |
| 898 js.assign(js.use('this').dot(fieldName), js.use('v')))))); | |
| 899 } | 891 } |
| 900 | 892 |
| 901 bool canGenerateCheckedSetter(Element member) { | 893 bool canGenerateCheckedSetter(Element member) { |
| 902 DartType type = member.computeType(compiler); | 894 DartType type = member.computeType(compiler); |
| 903 if (type.element.isTypeVariable() | 895 if (type.element.isTypeVariable() |
| 904 || type.element == compiler.dynamicClass | 896 || type.element == compiler.dynamicClass |
| 905 || type.element == compiler.objectClass) { | 897 || type.element == compiler.objectClass) { |
| 906 // TODO(ngeoffray): Support type checks on type parameters. | 898 // TODO(ngeoffray): Support type checks on type parameters. |
| 907 return false; | 899 return false; |
| 908 } | 900 } |
| 909 return true; | 901 return true; |
| 910 } | 902 } |
| 911 | 903 |
| 912 void generateCheckedSetter(Element member, | 904 void generateCheckedSetter(Element member, |
| 913 String fieldName, | 905 String fieldName, |
| 914 String accessorName, | 906 String accessorName, |
| 915 ClassBuilder builder) { | 907 CodeBuffer buffer) { |
| 916 assert(canGenerateCheckedSetter(member)); | 908 assert(canGenerateCheckedSetter(member)); |
| 917 DartType type = member.computeType(compiler); | 909 DartType type = member.computeType(compiler); |
| 918 SourceString helper = compiler.backend.getCheckedModeHelper(type); | 910 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 919 FunctionElement helperElement = compiler.findHelper(helper); | 911 FunctionElement helperElement = compiler.findHelper(helper); |
| 920 String helperName = namer.isolateAccess(helperElement); | 912 String helperName = namer.isolateAccess(helperElement); |
| 921 List<js.Expression> arguments = <js.Expression>[js.use('v')]; | 913 String additionalArgument = ''; |
| 922 if (helperElement.computeSignature(compiler).parameterCount != 1) { | 914 if (helperElement.computeSignature(compiler).parameterCount != 1) { |
| 923 arguments.add(js.string(namer.operatorIs(type.element))); | 915 additionalArgument = ",$_'${namer.operatorIs(type.element)}'"; |
| 924 } | 916 } |
| 925 | |
| 926 String setterName = namer.setterNameFromAccessorName(accessorName); | 917 String setterName = namer.setterNameFromAccessorName(accessorName); |
| 927 builder.addProperty(setterName, | 918 buffer.add("$setterName:${_}function(v)$_{$_" |
| 928 js.fun(['v'], | 919 "this.$fieldName$_=$_$helperName(v$additionalArgument);}"); |
| 929 js.block1( | |
| 930 new js.ExpressionStatement( | |
| 931 js.assign( | |
| 932 js.use('this').dot(fieldName), | |
| 933 js.call(js.use(helperName), arguments)))))); | |
| 934 } | 920 } |
| 935 | 921 |
| 936 void emitClassConstructor(ClassElement classElement, ClassBuilder builder) { | 922 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
| 937 /* Do nothing. */ | 923 /* Do nothing. */ |
| 938 } | 924 } |
| 939 | 925 |
| 940 void emitSuper(String superName, ClassBuilder builder) { | 926 void emitSuper(String superName, CodeBuffer buffer) { |
| 941 /* Do nothing. */ | 927 /* Do nothing. */ |
| 942 } | 928 } |
| 943 | 929 |
| 944 void emitClassFields(ClassElement classElement, | 930 void emitClassFields(ClassElement classElement, |
| 945 ClassBuilder builder, | 931 CodeBuffer buffer, |
| 932 bool emitEndingComma, |
| 946 { String superClass: "", | 933 { String superClass: "", |
| 947 bool classIsNative: false}) { | 934 bool classIsNative: false}) { |
| 948 bool isFirstField = true; | 935 bool isFirstField = true; |
| 949 StringBuffer buffer = new StringBuffer(); | 936 bool isAnythingOutput = false; |
| 950 if (!classIsNative) { | 937 if (!classIsNative) { |
| 951 buffer.add('$superClass;'); | 938 buffer.add('"":"$superClass;'); |
| 939 isAnythingOutput = true; |
| 952 } | 940 } |
| 953 visitClassFields(classElement, (Element member, | 941 visitClassFields(classElement, (Element member, |
| 954 String name, | 942 String name, |
| 955 String accessorName, | 943 String accessorName, |
| 956 bool needsGetter, | 944 bool needsGetter, |
| 957 bool needsSetter, | 945 bool needsSetter, |
| 958 bool needsCheckedSetter) { | 946 bool needsCheckedSetter) { |
| 959 // Ignore needsCheckedSetter - that is handled below. | 947 // Ignore needsCheckedSetter - that is handled below. |
| 960 bool needsAccessor = (needsGetter || needsSetter); | 948 bool needsAccessor = (needsGetter || needsSetter); |
| 961 // We need to output the fields for non-native classes so we can auto- | 949 // We need to output the fields for non-native classes so we can auto- |
| 962 // generate the constructor. For native classes there are no | 950 // generate the constructor. For native classes there are no |
| 963 // constructors, so we don't need the fields unless we are generating | 951 // constructors, so we don't need the fields unless we are generating |
| 964 // accessors at runtime. | 952 // accessors at runtime. |
| 965 if (!classIsNative || needsAccessor) { | 953 if (!classIsNative || needsAccessor) { |
| 966 // Emit correct commas. | 954 // Emit correct commas. |
| 967 if (isFirstField) { | 955 if (isFirstField) { |
| 968 isFirstField = false; | 956 isFirstField = false; |
| 957 if (!isAnythingOutput) { |
| 958 buffer.add('"":"'); |
| 959 isAnythingOutput = true; |
| 960 } |
| 969 } else { | 961 } else { |
| 970 buffer.add(','); | 962 buffer.add(","); |
| 971 } | 963 } |
| 972 int flag = 0; | 964 int flag = 0; |
| 973 if (!needsAccessor) { | 965 if (!needsAccessor) { |
| 974 // Emit field for constructor generation. | 966 // Emit field for constructor generation. |
| 975 assert(!classIsNative); | 967 assert(!classIsNative); |
| 976 buffer.add(name); | 968 buffer.add(name); |
| 977 } else { | 969 } else { |
| 978 // Emit (possibly renaming) field name so we can add accessors at | 970 // Emit (possibly renaming) field name so we can add accessors at |
| 979 // runtime. | 971 // runtime. |
| 980 buffer.add(accessorName); | 972 buffer.add(accessorName); |
| 981 if (name != accessorName) { | 973 if (name != accessorName) { |
| 982 buffer.add(':$name'); | 974 buffer.add(':$name'); |
| 983 // Only the native classes can have renaming accessors. | 975 // Only the native classes can have renaming accessors. |
| 984 assert(classIsNative); | 976 assert(classIsNative); |
| 985 flag = RENAMING_FLAG; | 977 flag = RENAMING_FLAG; |
| 986 } | 978 } |
| 987 } | 979 } |
| 988 if (needsGetter && needsSetter) { | 980 if (needsGetter && needsSetter) { |
| 989 buffer.addCharCode(GETTER_SETTER_CODE + flag); | 981 buffer.addCharCode(GETTER_SETTER_CODE + flag); |
| 990 } else if (needsGetter) { | 982 } else if (needsGetter) { |
| 991 buffer.addCharCode(GETTER_CODE + flag); | 983 buffer.addCharCode(GETTER_CODE + flag); |
| 992 } else if (needsSetter) { | 984 } else if (needsSetter) { |
| 993 buffer.addCharCode(SETTER_CODE + flag); | 985 buffer.addCharCode(SETTER_CODE + flag); |
| 994 } | 986 } |
| 995 } | 987 } |
| 996 }); | 988 }); |
| 997 | 989 if (isAnythingOutput) { |
| 998 String compactClassData = buffer.toString(); | 990 buffer.add('"'); |
| 999 if (compactClassData.length > 0) { | 991 if (emitEndingComma) { |
| 1000 builder.addProperty('', js.string(compactClassData)); | 992 buffer.add(','); |
| 993 } |
| 1001 } | 994 } |
| 1002 } | 995 } |
| 1003 | 996 |
| 997 /** Each getter/setter must be prefixed with a ",\n ". */ |
| 1004 void emitClassGettersSetters(ClassElement classElement, | 998 void emitClassGettersSetters(ClassElement classElement, |
| 1005 ClassBuilder builder) { | 999 CodeBuffer buffer, |
| 1000 bool emitLeadingComma) { |
| 1001 emitComma() { |
| 1002 if (emitLeadingComma) { |
| 1003 buffer.add(",\n$_"); |
| 1004 } else { |
| 1005 emitLeadingComma = true; |
| 1006 } |
| 1007 } |
| 1006 | 1008 |
| 1007 visitClassFields(classElement, (Element member, | 1009 visitClassFields(classElement, (Element member, |
| 1008 String name, | 1010 String name, |
| 1009 String accessorName, | 1011 String accessorName, |
| 1010 bool needsGetter, | 1012 bool needsGetter, |
| 1011 bool needsSetter, | 1013 bool needsSetter, |
| 1012 bool needsCheckedSetter) { | 1014 bool needsCheckedSetter) { |
| 1013 if (needsCheckedSetter) { | 1015 if (needsCheckedSetter) { |
| 1014 assert(!needsSetter); | 1016 assert(!needsSetter); |
| 1015 generateCheckedSetter(member, name, accessorName, builder); | 1017 emitComma(); |
| 1018 generateCheckedSetter(member, name, accessorName, buffer); |
| 1016 } | 1019 } |
| 1017 if (!getterAndSetterCanBeImplementedByFieldSpec) { | 1020 if (!getterAndSetterCanBeImplementedByFieldSpec) { |
| 1018 if (needsGetter) { | 1021 if (needsGetter) { |
| 1019 generateGetter(member, name, accessorName, builder); | 1022 emitComma(); |
| 1023 generateGetter(member, name, accessorName, buffer); |
| 1020 } | 1024 } |
| 1021 if (needsSetter) { | 1025 if (needsSetter) { |
| 1022 generateSetter(member, name, accessorName, builder); | 1026 emitComma(); |
| 1027 generateSetter(member, name, accessorName, buffer); |
| 1023 } | 1028 } |
| 1024 } | 1029 } |
| 1025 }); | 1030 }); |
| 1026 } | 1031 } |
| 1027 | 1032 |
| 1028 /** | 1033 /** |
| 1029 * Documentation wanted -- johnniwinther | 1034 * Documentation wanted -- johnniwinther |
| 1030 * | 1035 * |
| 1031 * Invariant: [classElement] must be a declaration element. | 1036 * Invariant: [classElement] must be a declaration element. |
| 1032 */ | 1037 */ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1043 } | 1048 } |
| 1044 | 1049 |
| 1045 needsDefineClass = true; | 1050 needsDefineClass = true; |
| 1046 String className = namer.getName(classElement); | 1051 String className = namer.getName(classElement); |
| 1047 ClassElement superclass = classElement.superclass; | 1052 ClassElement superclass = classElement.superclass; |
| 1048 String superName = ""; | 1053 String superName = ""; |
| 1049 if (superclass != null) { | 1054 if (superclass != null) { |
| 1050 superName = namer.getName(superclass); | 1055 superName = namer.getName(superclass); |
| 1051 } | 1056 } |
| 1052 | 1057 |
| 1053 ClassBuilder builder = new ClassBuilder(); | 1058 buffer.add('$classesCollector.$className$_=$_{'); |
| 1054 | 1059 emitClassConstructor(classElement, buffer); |
| 1055 emitClassConstructor(classElement, builder); | 1060 emitSuper(superName, buffer); |
| 1056 emitSuper(superName, builder); | 1061 emitClassFields(classElement, buffer, false, |
| 1057 emitClassFields(classElement, builder, | |
| 1058 superClass: superName, classIsNative: false); | 1062 superClass: superName, classIsNative: false); |
| 1059 emitClassGettersSetters(classElement, builder); | 1063 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
| 1060 emitInstanceMembers(classElement, builder); | 1064 // That does currently not work because the native classes have a different |
| 1061 | 1065 // syntax. |
| 1062 js.Expression init = | 1066 emitClassGettersSetters(classElement, buffer, true); |
| 1063 js.assign( | 1067 emitInstanceMembers(classElement, buffer, true); |
| 1064 js.use(classesCollector).dot(className), | 1068 buffer.add('$n}$N$n'); |
| 1065 builder.toObjectInitializer()); | |
| 1066 buffer.add(js.prettyPrint(init, compiler)); | |
| 1067 buffer.add('$N$n'); | |
| 1068 } | 1069 } |
| 1069 | 1070 |
| 1070 bool get getterAndSetterCanBeImplementedByFieldSpec => true; | 1071 bool get getterAndSetterCanBeImplementedByFieldSpec => true; |
| 1071 | 1072 |
| 1072 void emitInterceptorMethods(ClassBuilder builder) { | 1073 void emitInterceptorMethods( |
| 1074 void defineInstanceMember(String name, StringBuffer memberBuffer)) { |
| 1073 JavaScriptBackend backend = compiler.backend; | 1075 JavaScriptBackend backend = compiler.backend; |
| 1074 // Emit forwarders for the ObjectInterceptor class. We need to | 1076 // Emit forwarders for the ObjectInterceptor class. We need to |
| 1075 // emit all possible sends on intercepted methods. | 1077 // emit all possible sends on intercepted methods. |
| 1076 for (Selector selector in backend.usedInterceptors) { | 1078 for (Selector selector in backend.usedInterceptors) { |
| 1077 | 1079 |
| 1078 List<js.Parameter> parameters = <js.Parameter>[]; | 1080 List<js.Parameter> parameters = <js.Parameter>[]; |
| 1079 List<js.Expression> arguments = <js.Expression>[]; | 1081 List<js.Expression> arguments = <js.Expression>[]; |
| 1080 parameters.add(new js.Parameter('receiver')); | 1082 parameters.add(new js.Parameter('receiver')); |
| 1081 | 1083 |
| 1082 String name; | 1084 String name; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1096 } | 1098 } |
| 1097 } | 1099 } |
| 1098 js.Fun function = | 1100 js.Fun function = |
| 1099 new js.Fun(parameters, | 1101 new js.Fun(parameters, |
| 1100 new js.Block( | 1102 new js.Block( |
| 1101 <js.Statement>[ | 1103 <js.Statement>[ |
| 1102 new js.Return( | 1104 new js.Return( |
| 1103 new js.VariableUse('receiver') | 1105 new js.VariableUse('receiver') |
| 1104 .dot(name) | 1106 .dot(name) |
| 1105 .callWith(arguments))])); | 1107 .callWith(arguments))])); |
| 1106 builder.addProperty(name, function); | 1108 |
| 1109 CodeBuffer code = new CodeBuffer(); |
| 1110 code.add(js.prettyPrint(function, compiler)); |
| 1111 defineInstanceMember(name, code); |
| 1107 } | 1112 } |
| 1108 } | 1113 } |
| 1109 | 1114 |
| 1110 Collection<Element> getTypedefChecksOn(DartType type) { | 1115 Collection<Element> getTypedefChecksOn(DartType type) { |
| 1111 return checkedTypedefs.filter((TypedefElement typedef) { | 1116 return checkedTypedefs.filter((TypedefElement typedef) { |
| 1112 FunctionType typedefType = | 1117 FunctionType typedefType = |
| 1113 typedef.computeType(compiler).unalias(compiler); | 1118 typedef.computeType(compiler).unalias(compiler); |
| 1114 return compiler.types.isSubtype(type, typedefType); | 1119 return compiler.types.isSubtype(type, typedefType); |
| 1115 }); | 1120 }); |
| 1116 } | 1121 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1262 } | 1267 } |
| 1263 | 1268 |
| 1264 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { | 1269 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) { |
| 1265 if (needsDefineClass) { | 1270 if (needsDefineClass) { |
| 1266 buffer.add("$finishClassesName($classesCollector)$N"); | 1271 buffer.add("$finishClassesName($classesCollector)$N"); |
| 1267 // Reset the map. | 1272 // Reset the map. |
| 1268 buffer.add("$classesCollector$_=$_{}$N"); | 1273 buffer.add("$classesCollector$_=$_{}$N"); |
| 1269 } | 1274 } |
| 1270 } | 1275 } |
| 1271 | 1276 |
| 1272 void emitStaticFunction(CodeBuffer buffer, | 1277 void emitStaticFunctionWithNamer(CodeBuffer buffer, |
| 1273 String name, | 1278 Element element, |
| 1274 js.Expression functionExpression) { | 1279 CodeBuffer functionBuffer, |
| 1275 js.Expression assignment = | 1280 String functionNamer(Element element)) { |
| 1276 js.assign(js.use(isolateProperties).dot(name), functionExpression); | 1281 String functionName = functionNamer(element); |
| 1277 buffer.add(js.prettyPrint(assignment, compiler)); | 1282 buffer.add('$isolateProperties.$functionName$_=$_'); |
| 1283 buffer.add(functionBuffer); |
| 1278 buffer.add('$N$n'); | 1284 buffer.add('$N$n'); |
| 1279 } | 1285 } |
| 1280 | 1286 |
| 1281 void emitStaticFunctions(CodeBuffer buffer) { | 1287 void emitStaticFunctions(CodeBuffer buffer) { |
| 1282 bool isStaticFunction(Element element) => | 1288 bool isStaticFunction(Element element) => |
| 1283 !element.isInstanceMember() && !element.isField(); | 1289 !element.isInstanceMember() && !element.isField(); |
| 1284 | 1290 |
| 1285 Collection<Element> elements = | 1291 Collection<Element> elements = |
| 1286 compiler.codegenWorld.generatedCode.keys.filter(isStaticFunction); | 1292 compiler.codegenWorld.generatedCode.keys.filter(isStaticFunction); |
| 1287 Set<Element> pendingElementsWithBailouts = | 1293 Set<Element> pendingElementsWithBailouts = |
| 1288 new Set<Element>.from( | 1294 new Set<Element>.from( |
| 1289 compiler.codegenWorld.generatedBailoutCode.keys.filter( | 1295 compiler.codegenWorld.generatedBailoutCode.keys.filter( |
| 1290 isStaticFunction)); | 1296 isStaticFunction)); |
| 1291 | 1297 |
| 1292 for (Element element in Elements.sortedByPosition(elements)) { | 1298 for (Element element in Elements.sortedByPosition(elements)) { |
| 1293 js.Expression code = compiler.codegenWorld.generatedCode[element]; | 1299 CodeBuffer code = compiler.codegenWorld.generatedCode[element]; |
| 1294 emitStaticFunction(buffer, namer.getName(element), code); | 1300 emitStaticFunctionWithNamer(buffer, element, code, namer.getName); |
| 1295 js.Expression bailoutCode = | 1301 CodeBuffer bailoutCode = |
| 1296 compiler.codegenWorld.generatedBailoutCode[element]; | 1302 compiler.codegenWorld.generatedBailoutCode[element]; |
| 1297 if (bailoutCode != null) { | 1303 if (bailoutCode != null) { |
| 1298 pendingElementsWithBailouts.remove(element); | 1304 pendingElementsWithBailouts.remove(element); |
| 1299 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1305 emitStaticFunctionWithNamer( |
| 1306 buffer, element, bailoutCode, namer.getBailoutName); |
| 1300 } | 1307 } |
| 1301 } | 1308 } |
| 1302 | 1309 |
| 1303 // Is it possible the primary function was inlined but the bailout was not? | 1310 // Is it possible the primary function was inlined but the bailout was not? |
| 1304 for (Element element in | 1311 for (Element element in |
| 1305 Elements.sortedByPosition(pendingElementsWithBailouts)) { | 1312 Elements.sortedByPosition(pendingElementsWithBailouts)) { |
| 1306 CodeBuffer bailoutCode = | 1313 CodeBuffer bailoutCode = |
| 1307 compiler.codegenWorld.generatedBailoutCode[element]; | 1314 compiler.codegenWorld.generatedBailoutCode[element]; |
| 1308 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 1315 emitStaticFunctionWithNamer( |
| 1316 buffer, element, bailoutCode, namer.getBailoutName); |
| 1309 } | 1317 } |
| 1310 } | 1318 } |
| 1311 | 1319 |
| 1312 void emitStaticFunctionGetters(CodeBuffer buffer) { | 1320 void emitStaticFunctionGetters(CodeBuffer buffer) { |
| 1313 Set<FunctionElement> functionsNeedingGetter = | 1321 Set<FunctionElement> functionsNeedingGetter = |
| 1314 compiler.codegenWorld.staticFunctionsNeedingGetter; | 1322 compiler.codegenWorld.staticFunctionsNeedingGetter; |
| 1315 for (FunctionElement element in functionsNeedingGetter) { | 1323 for (FunctionElement element in |
| 1324 Elements.sortedByPosition(functionsNeedingGetter)) { |
| 1316 // The static function does not have the correct name. Since | 1325 // The static function does not have the correct name. Since |
| 1317 // [addParameterStubs] use the name to create its stubs we simply | 1326 // [addParameterStubs] use the name to create its stubs we simply |
| 1318 // create a fake element with the correct name. | 1327 // create a fake element with the correct name. |
| 1319 // Note: the callElement will not have any enclosingElement. | 1328 // Note: the callElement will not have any enclosingElement. |
| 1320 FunctionElement callElement = | 1329 FunctionElement callElement = |
| 1321 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1330 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
| 1322 element); | 1331 element); |
| 1323 String staticName = namer.getName(element); | 1332 String staticName = namer.getName(element); |
| 1324 String invocationName = namer.instanceMethodName(callElement); | 1333 String invocationName = namer.instanceMethodName(callElement); |
| 1325 String fieldAccess = '$isolateProperties.$staticName'; | 1334 String fieldAccess = '$isolateProperties.$staticName'; |
| 1326 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); | 1335 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); |
| 1327 | 1336 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 1328 addParameterStubs(callElement, (String name, js.Expression value) { | 1337 buffer.add('$fieldAccess.$name$_=$_$value$N'); |
| 1329 js.Expression assignment = | |
| 1330 js.assign( | |
| 1331 js.use(isolateProperties).dot(staticName).dot(name), | |
| 1332 value); | |
| 1333 buffer.add( | |
| 1334 js.prettyPrint(new js.ExpressionStatement(assignment), compiler)); | |
| 1335 buffer.add('$N'); | |
| 1336 }); | 1338 }); |
| 1337 | |
| 1338 // If a static function is used as a closure we need to add its name | 1339 // If a static function is used as a closure we need to add its name |
| 1339 // in case it is used in spawnFunction. | 1340 // in case it is used in spawnFunction. |
| 1340 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1341 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 1341 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 1342 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
| 1342 getTypedefChecksOn(element.computeType(compiler)).forEach( | 1343 getTypedefChecksOn(element.computeType(compiler)).forEach( |
| 1343 (Element typedef) { | 1344 (Element typedef) { |
| 1344 String operator = namer.operatorIs(typedef); | 1345 String operator = namer.operatorIs(typedef); |
| 1345 buffer.add('$fieldAccess.$operator$_=${_}true$N'); | 1346 buffer.add('$fieldAccess.$operator$_=${_}true$N'); |
| 1346 } | 1347 } |
| 1347 ); | 1348 ); |
| 1348 } | 1349 } |
| 1349 } | 1350 } |
| 1350 | 1351 |
| 1351 void emitBoundClosureClassHeader(String mangledName, | 1352 void emitBoundClosureClassHeader(String mangledName, |
| 1352 String superName, | 1353 String superName, |
| 1353 List<String> fieldNames, | 1354 List<String> fieldNames, |
| 1354 ClassBuilder builder) { | 1355 CodeBuffer buffer) { |
| 1355 builder.addProperty('', | 1356 buffer.add('$classesCollector.$mangledName$_=$_' |
| 1356 js.string("$superName;${Strings.join(fieldNames,',')}")); | 1357 '{"":"$superName;${Strings.join(fieldNames,',')}",'); |
| 1357 } | 1358 } |
| 1358 | 1359 |
| 1359 /** | 1360 /** |
| 1360 * Documentation wanted -- johnniwinther | 1361 * Documentation wanted -- johnniwinther |
| 1361 * | 1362 * |
| 1362 * Invariant: [member] must be a declaration element. | 1363 * Invariant: [member] must be a declaration element. |
| 1363 */ | 1364 */ |
| 1364 void emitDynamicFunctionGetter(FunctionElement member, | 1365 void emitDynamicFunctionGetter(FunctionElement member, |
| 1365 DefineStubFunction defineStub) { | 1366 DefineMemberFunction defineInstanceMember) { |
| 1366 assert(invariant(member, member.isDeclaration)); | 1367 assert(invariant(member, member.isDeclaration)); |
| 1367 // For every method that has the same name as a property-get we create a | 1368 // For every method that has the same name as a property-get we create a |
| 1368 // getter that returns a bound closure. Say we have a class 'A' with method | 1369 // getter that returns a bound closure. Say we have a class 'A' with method |
| 1369 // 'foo' and somewhere in the code there is a dynamic property get of | 1370 // 'foo' and somewhere in the code there is a dynamic property get of |
| 1370 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): | 1371 // 'foo'. Then we generate the following code (in pseudo Dart/JavaScript): |
| 1371 // | 1372 // |
| 1372 // class A { | 1373 // class A { |
| 1373 // foo(x, y, z) { ... } // Original function. | 1374 // foo(x, y, z) { ... } // Original function. |
| 1374 // get foo { return new BoundClosure499(this, "foo"); } | 1375 // get foo { return new BoundClosure499(this, "foo"); } |
| 1375 // } | 1376 // } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1418 // Create a new closure class. | 1419 // Create a new closure class. |
| 1419 SourceString name = const SourceString("BoundClosure"); | 1420 SourceString name = const SourceString("BoundClosure"); |
| 1420 ClassElement closureClassElement = new ClosureClassElement( | 1421 ClassElement closureClassElement = new ClosureClassElement( |
| 1421 name, compiler, member, member.getCompilationUnit()); | 1422 name, compiler, member, member.getCompilationUnit()); |
| 1422 String mangledName = namer.getName(closureClassElement); | 1423 String mangledName = namer.getName(closureClassElement); |
| 1423 String superName = namer.getName(closureClassElement.superclass); | 1424 String superName = namer.getName(closureClassElement.superclass); |
| 1424 needsClosureClass = true; | 1425 needsClosureClass = true; |
| 1425 | 1426 |
| 1426 // Define the constructor with a name so that Object.toString can | 1427 // Define the constructor with a name so that Object.toString can |
| 1427 // find the class name of the closure class. | 1428 // find the class name of the closure class. |
| 1428 ClassBuilder boundClosureBuilder = new ClassBuilder(); | |
| 1429 emitBoundClosureClassHeader( | 1429 emitBoundClosureClassHeader( |
| 1430 mangledName, superName, fieldNames, boundClosureBuilder); | 1430 mangledName, superName, fieldNames, boundClosureBuffer); |
| 1431 // Now add the methods on the closure class. The instance method does not | 1431 // Now add the methods on the closure class. The instance method does not |
| 1432 // have the correct name. Since [addParameterStubs] use the name to create | 1432 // have the correct name. Since [addParameterStubs] use the name to create |
| 1433 // its stubs we simply create a fake element with the correct name. | 1433 // its stubs we simply create a fake element with the correct name. |
| 1434 // Note: the callElement will not have any enclosingElement. | 1434 // Note: the callElement will not have any enclosingElement. |
| 1435 FunctionElement callElement = | 1435 FunctionElement callElement = |
| 1436 new ClosureInvocationElement(namer.closureInvocationSelectorName, | 1436 new ClosureInvocationElement(namer.closureInvocationSelectorName, |
| 1437 member); | 1437 member); |
| 1438 | 1438 |
| 1439 String invocationName = namer.instanceMethodName(callElement); | 1439 String invocationName = namer.instanceMethodName(callElement); |
| 1440 | 1440 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1451 | 1451 |
| 1452 js.Expression fun = | 1452 js.Expression fun = |
| 1453 new js.Fun(parameters, | 1453 new js.Fun(parameters, |
| 1454 new js.Block( | 1454 new js.Block( |
| 1455 <js.Statement>[ | 1455 <js.Statement>[ |
| 1456 new js.Return( | 1456 new js.Return( |
| 1457 new js.PropertyAccess( | 1457 new js.PropertyAccess( |
| 1458 new js.This().dot(fieldNames[0]), | 1458 new js.This().dot(fieldNames[0]), |
| 1459 new js.This().dot(fieldNames[1])) | 1459 new js.This().dot(fieldNames[1])) |
| 1460 .callWith(arguments))])); | 1460 .callWith(arguments))])); |
| 1461 boundClosureBuilder.addProperty(invocationName, fun); | |
| 1462 | 1461 |
| 1463 addParameterStubs(callElement, boundClosureBuilder.addProperty); | 1462 boundClosureBuffer.add( |
| 1463 '$_$invocationName:$_${js.prettyPrint(fun,compiler)}'); |
| 1464 |
| 1465 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { |
| 1466 boundClosureBuffer.add(',\n$_$stubName:$_$memberValue'); |
| 1467 }); |
| 1468 |
| 1464 typedefChecks.forEach((Element typedef) { | 1469 typedefChecks.forEach((Element typedef) { |
| 1465 String operator = namer.operatorIs(typedef); | 1470 String operator = namer.operatorIs(typedef); |
| 1466 boundClosureBuilder.addProperty(operator, new js.LiteralBool(true)); | 1471 boundClosureBuffer.add(',\n$_$operator$_:${_}true'); |
| 1467 }); | 1472 }); |
| 1468 | 1473 |
| 1469 js.Expression init = | 1474 boundClosureBuffer.add("$n}$N"); |
| 1470 js.assign( | |
| 1471 js.use(classesCollector).dot(mangledName), | |
| 1472 boundClosureBuilder.toObjectInitializer()); | |
| 1473 boundClosureBuffer.add(js.prettyPrint(init, compiler)); | |
| 1474 boundClosureBuffer.add("$N"); | |
| 1475 | 1475 |
| 1476 closureClass = namer.isolateAccess(closureClassElement); | 1476 closureClass = namer.isolateAccess(closureClassElement); |
| 1477 | 1477 |
| 1478 // Cache it. | 1478 // Cache it. |
| 1479 if (canBeShared) { | 1479 if (canBeShared) { |
| 1480 cache[parameterCount] = closureClass; | 1480 cache[parameterCount] = closureClass; |
| 1481 } | 1481 } |
| 1482 } | 1482 } |
| 1483 | 1483 |
| 1484 // And finally the getter. | 1484 // And finally the getter. |
| 1485 String getterName = namer.getterName(member.getLibrary(), member.name); | 1485 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 1486 String targetName = namer.instanceMethodName(member); | 1486 String targetName = namer.instanceMethodName(member); |
| 1487 | 1487 |
| 1488 List<js.Parameter> parameters = <js.Parameter>[]; | 1488 List<js.Parameter> parameters = <js.Parameter>[]; |
| 1489 List<js.Expression> arguments = <js.Expression>[]; | 1489 List<js.Expression> arguments = <js.Expression>[]; |
| 1490 arguments.add(new js.This()); | 1490 arguments.add(new js.This()); |
| 1491 arguments.add(js.string(targetName)); | 1491 arguments.add(new js.LiteralString("'$targetName'")); |
| 1492 if (inInterceptor) { | 1492 if (inInterceptor) { |
| 1493 parameters.add(new js.Parameter(extraArg)); | 1493 parameters.add(new js.Parameter(extraArg)); |
| 1494 arguments.add(new js.VariableUse(extraArg)); | 1494 arguments.add(new js.VariableUse(extraArg)); |
| 1495 } | 1495 } |
| 1496 | 1496 |
| 1497 js.Expression getterFunction = | 1497 js.Expression getterFunction = |
| 1498 new js.Fun(parameters, | 1498 new js.Fun(parameters, |
| 1499 new js.Block( | 1499 new js.Block( |
| 1500 <js.Statement>[ | 1500 <js.Statement>[ |
| 1501 new js.Return( | 1501 new js.Return( |
| 1502 new js.New( | 1502 new js.New( |
| 1503 new js.VariableUse(closureClass), | 1503 new js.VariableUse(closureClass), |
| 1504 arguments))])); | 1504 arguments))])); |
| 1505 | 1505 |
| 1506 defineStub(getterName, getterFunction); | 1506 CodeBuffer getterBuffer = new CodeBuffer(); |
| 1507 getterBuffer.add(js.prettyPrint(getterFunction, compiler)); |
| 1508 defineInstanceMember(getterName, getterBuffer); |
| 1507 } | 1509 } |
| 1508 | 1510 |
| 1509 /** | 1511 /** |
| 1510 * Documentation wanted -- johnniwinther | 1512 * Documentation wanted -- johnniwinther |
| 1511 * | 1513 * |
| 1512 * Invariant: [member] must be a declaration element. | 1514 * Invariant: [member] must be a declaration element. |
| 1513 */ | 1515 */ |
| 1514 void emitCallStubForGetter(Element member, | 1516 void emitCallStubForGetter(Element member, |
| 1515 Set<Selector> selectors, | 1517 Set<Selector> selectors, |
| 1516 DefineStubFunction defineStub) { | 1518 DefineMemberFunction defineInstanceMember) { |
| 1517 assert(invariant(member, member.isDeclaration)); | 1519 assert(invariant(member, member.isDeclaration)); |
| 1518 LibraryElement memberLibrary = member.getLibrary(); | 1520 LibraryElement memberLibrary = member.getLibrary(); |
| 1519 JavaScriptBackend backend = compiler.backend; | 1521 JavaScriptBackend backend = compiler.backend; |
| 1520 // If the class is an interceptor class, the stub gets the | 1522 // If the class is an interceptor class, the stub gets the |
| 1521 // receiver explicitely and we need to pass it to the getter call. | 1523 // receiver explicitely and we need to pass it to the getter call. |
| 1522 bool isInterceptorClass = | 1524 bool isInterceptorClass = |
| 1523 backend.isInterceptorClass(member.getEnclosingClass()); | 1525 backend.isInterceptorClass(member.getEnclosingClass()); |
| 1524 | 1526 |
| 1525 const String receiverArgumentName = r'$receiver'; | 1527 const String receiverArgumentName = r'$receiver'; |
| 1526 | 1528 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 } | 1564 } |
| 1563 | 1565 |
| 1564 js.Fun function = | 1566 js.Fun function = |
| 1565 new js.Fun(parameters, | 1567 new js.Fun(parameters, |
| 1566 new js.Block( | 1568 new js.Block( |
| 1567 <js.Statement>[ | 1569 <js.Statement>[ |
| 1568 new js.Return( | 1570 new js.Return( |
| 1569 buildGetter().dot(closureCallName) | 1571 buildGetter().dot(closureCallName) |
| 1570 .callWith(arguments))])); | 1572 .callWith(arguments))])); |
| 1571 | 1573 |
| 1572 defineStub(invocationName, function); | 1574 CodeBuffer getterBuffer = new CodeBuffer(); |
| 1575 getterBuffer.add(js.prettyPrint(function, compiler)); |
| 1576 defineInstanceMember(invocationName, getterBuffer); |
| 1573 } | 1577 } |
| 1574 } | 1578 } |
| 1575 } | 1579 } |
| 1576 | 1580 |
| 1577 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { | 1581 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { |
| 1578 ConstantHandler handler = compiler.constantHandler; | 1582 ConstantHandler handler = compiler.constantHandler; |
| 1579 List<VariableElement> staticNonFinalFields = | 1583 List<VariableElement> staticNonFinalFields = |
| 1580 handler.getStaticNonFinalFieldsForEmission(); | 1584 handler.getStaticNonFinalFieldsForEmission(); |
| 1581 for (Element element in staticNonFinalFields) { | 1585 for (Element element in staticNonFinalFields) { |
| 1582 compiler.withCurrentElement(element, () { | 1586 compiler.withCurrentElement(element, () { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1594 } | 1598 } |
| 1595 | 1599 |
| 1596 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { | 1600 void emitLazilyInitializedStaticFields(CodeBuffer buffer) { |
| 1597 ConstantHandler handler = compiler.constantHandler; | 1601 ConstantHandler handler = compiler.constantHandler; |
| 1598 List<VariableElement> lazyFields = | 1602 List<VariableElement> lazyFields = |
| 1599 handler.getLazilyInitializedFieldsForEmission(); | 1603 handler.getLazilyInitializedFieldsForEmission(); |
| 1600 if (!lazyFields.isEmpty) { | 1604 if (!lazyFields.isEmpty) { |
| 1601 needsLazyInitializer = true; | 1605 needsLazyInitializer = true; |
| 1602 for (VariableElement element in lazyFields) { | 1606 for (VariableElement element in lazyFields) { |
| 1603 assert(compiler.codegenWorld.generatedBailoutCode[element] == null); | 1607 assert(compiler.codegenWorld.generatedBailoutCode[element] == null); |
| 1604 js.Expression code = compiler.codegenWorld.generatedCode[element]; | 1608 StringBuffer code = compiler.codegenWorld.generatedCode[element]; |
| 1605 assert(code != null); | 1609 assert(code != null); |
| 1606 // The code only computes the initial value. We build the lazy-check | 1610 // The code only computes the initial value. We build the lazy-check |
| 1607 // here: | 1611 // here: |
| 1608 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); | 1612 // lazyInitializer(prototype, 'name', fieldName, getterName, initial); |
| 1609 // The name is used for error reporting. The 'initial' must be a | 1613 // The name is used for error reporting. The 'initial' must be a |
| 1610 // closure that constructs the initial value. | 1614 // closure that constructs the initial value. |
| 1611 buffer.add("$lazyInitializerName("); | 1615 buffer.add("$lazyInitializerName("); |
| 1612 buffer.add(isolateProperties); | 1616 buffer.add(isolateProperties); |
| 1613 buffer.add(",$_'"); | 1617 buffer.add(",$_'"); |
| 1614 buffer.add(element.name.slowToString()); | 1618 buffer.add(element.name.slowToString()); |
| 1615 buffer.add("',$_'"); | 1619 buffer.add("',$_'"); |
| 1616 buffer.add(namer.getName(element)); | 1620 buffer.add(namer.getName(element)); |
| 1617 buffer.add("',$_'"); | 1621 buffer.add("',$_'"); |
| 1618 buffer.add(namer.getLazyInitializerName(element)); | 1622 buffer.add(namer.getLazyInitializerName(element)); |
| 1619 buffer.add("',$_"); | 1623 buffer.add("',$_"); |
| 1620 buffer.add(js.prettyPrint(code, compiler)); | 1624 buffer.add(code); |
| 1621 emitLazyInitializedGetter(element, buffer); | 1625 emitLazyInitializedGetter(element, buffer); |
| 1622 buffer.add(")$N"); | 1626 buffer.add(")$N"); |
| 1623 } | 1627 } |
| 1624 } | 1628 } |
| 1625 } | 1629 } |
| 1626 | 1630 |
| 1627 void emitLazyInitializedGetter(VariableElement element, CodeBuffer buffer) { | 1631 void emitLazyInitializedGetter(VariableElement element, CodeBuffer buffer) { |
| 1628 // Nothing to do, the 'lazy' function will create the getter. | 1632 // Nothing to do, the 'lazy' function will create the getter. |
| 1629 } | 1633 } |
| 1630 | 1634 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1666 return list; | 1670 return list; |
| 1667 }; | 1671 }; |
| 1668 '''); | 1672 '''); |
| 1669 } | 1673 } |
| 1670 | 1674 |
| 1671 /** | 1675 /** |
| 1672 * Documentation wanted -- johnniwinther | 1676 * Documentation wanted -- johnniwinther |
| 1673 * | 1677 * |
| 1674 * Invariant: [member] must be a declaration element. | 1678 * Invariant: [member] must be a declaration element. |
| 1675 */ | 1679 */ |
| 1676 void emitExtraAccessors(Element member, ClassBuilder builder) { | 1680 void emitExtraAccessors(Element member, |
| 1681 DefineMemberFunction defineInstanceMember) { |
| 1677 assert(invariant(member, member.isDeclaration)); | 1682 assert(invariant(member, member.isDeclaration)); |
| 1678 if (member.isGetter() || member.isField()) { | 1683 if (member.isGetter() || member.isField()) { |
| 1679 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; | 1684 Set<Selector> selectors = compiler.codegenWorld.invokedNames[member.name]; |
| 1680 if (selectors != null && !selectors.isEmpty) { | 1685 if (selectors != null && !selectors.isEmpty) { |
| 1681 emitCallStubForGetter(member, selectors, builder.addProperty); | 1686 emitCallStubForGetter(member, selectors, defineInstanceMember); |
| 1682 } | 1687 } |
| 1683 } else if (member.isFunction()) { | 1688 } else if (member.isFunction()) { |
| 1684 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { | 1689 if (compiler.codegenWorld.hasInvokedGetter(member, compiler)) { |
| 1685 emitDynamicFunctionGetter(member, builder.addProperty); | 1690 emitDynamicFunctionGetter(member, defineInstanceMember); |
| 1686 } | 1691 } |
| 1687 } | 1692 } |
| 1688 } | 1693 } |
| 1689 | 1694 |
| 1690 void emitNoSuchMethodHandlers(DefineStubFunction defineStub) { | 1695 void emitNoSuchMethodHandlers(DefineMemberFunction defineInstanceMember) { |
| 1691 // Do not generate no such method handlers if there is no class. | 1696 // Do not generate no such method handlers if there is no class. |
| 1692 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; | 1697 if (compiler.codegenWorld.instantiatedClasses.isEmpty) return; |
| 1693 | 1698 |
| 1694 String noSuchMethodName = namer.publicInstanceMethodNameByArity( | 1699 String noSuchMethodName = namer.publicInstanceMethodNameByArity( |
| 1695 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); | 1700 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); |
| 1696 | 1701 |
| 1697 Element createInvocationMirrorElement = | 1702 Element createInvocationMirrorElement = |
| 1698 compiler.findHelper(const SourceString("createInvocationMirror")); | 1703 compiler.findHelper(const SourceString("createInvocationMirror")); |
| 1699 String createInvocationMirrorName = | 1704 String createInvocationMirrorName = |
| 1700 namer.getName(createInvocationMirrorElement); | 1705 namer.getName(createInvocationMirrorElement); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1726 int type = selector.invocationMirrorKind; | 1731 int type = selector.invocationMirrorKind; |
| 1727 String methodName = selector.invocationMirrorMemberName; | 1732 String methodName = selector.invocationMirrorMemberName; |
| 1728 List<js.Parameter> parameters = <js.Parameter>[]; | 1733 List<js.Parameter> parameters = <js.Parameter>[]; |
| 1729 CodeBuffer args = new CodeBuffer(); | 1734 CodeBuffer args = new CodeBuffer(); |
| 1730 for (int i = 0; i < selector.argumentCount; i++) { | 1735 for (int i = 0; i < selector.argumentCount; i++) { |
| 1731 parameters.add(new js.Parameter('\$$i')); | 1736 parameters.add(new js.Parameter('\$$i')); |
| 1732 } | 1737 } |
| 1733 | 1738 |
| 1734 List<js.Expression> argNames = | 1739 List<js.Expression> argNames = |
| 1735 selector.getOrderedNamedArguments().map((SourceString name) => | 1740 selector.getOrderedNamedArguments().map((SourceString name) => |
| 1736 js.string(name.slowToString())); | 1741 new js.LiteralString('"${name.slowToString()}"')); |
| 1737 | 1742 |
| 1738 String internalName = namer.invocationMirrorInternalName(selector); | 1743 String internalName = namer.invocationMirrorInternalName(selector); |
| 1739 | 1744 |
| 1740 String createInvocationMirror = namer.getName( | 1745 String createInvocationMirror = namer.getName( |
| 1741 compiler.createInvocationMirrorElement); | 1746 compiler.createInvocationMirrorElement); |
| 1742 | 1747 |
| 1743 js.Expression expression = | 1748 js.Expression expression = |
| 1744 new js.This() | 1749 new js.This() |
| 1745 .dot(noSuchMethodName) | 1750 .dot(noSuchMethodName) |
| 1746 .callWith( | 1751 .callWith( |
| 1747 <js.Expression>[ | 1752 <js.Expression>[ |
| 1748 new js.VariableUse(namer.CURRENT_ISOLATE) | 1753 new js.VariableUse(namer.CURRENT_ISOLATE) |
| 1749 .dot(createInvocationMirror) | 1754 .dot(createInvocationMirror) |
| 1750 .callWith( | 1755 .callWith( |
| 1751 <js.Expression>[ | 1756 <js.Expression>[ |
| 1752 js.string(methodName), | 1757 new js.LiteralString('"$methodName"'), |
| 1753 js.string(internalName), | 1758 new js.LiteralString('"$internalName"'), |
| 1754 new js.LiteralNumber('$type'), | 1759 new js.LiteralNumber('$type'), |
| 1755 new js.ArrayInitializer.from( | 1760 new js.ArrayInitializer.from( |
| 1756 parameters.map((param) => js.use(param.name))), | 1761 parameters.map((param) => |
| 1762 new js.VariableUse(param.name))), |
| 1757 new js.ArrayInitializer.from(argNames)])]); | 1763 new js.ArrayInitializer.from(argNames)])]); |
| 1758 js.Expression function = | 1764 js.Expression function = |
| 1759 new js.Fun(parameters, | 1765 new js.Fun(parameters, |
| 1760 new js.Block(<js.Statement>[new js.Return(expression)])); | 1766 new js.Block(<js.Statement>[new js.Return(expression)])); |
| 1761 return function; | 1767 return function; |
| 1762 } | 1768 } |
| 1763 | 1769 |
| 1764 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { | 1770 void addNoSuchMethodHandlers(SourceString ignore, Set<Selector> selectors) { |
| 1765 // Cache the object class and type. | 1771 // Cache the object class and type. |
| 1766 ClassElement objectClass = compiler.objectClass; | 1772 ClassElement objectClass = compiler.objectClass; |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1844 // bar through inheritance. | 1850 // bar through inheritance. |
| 1845 // | 1851 // |
| 1846 // If we're calling bar on an object of type A we do need the | 1852 // If we're calling bar on an object of type A we do need the |
| 1847 // handler because we may have to call B.noSuchMethod since B | 1853 // handler because we may have to call B.noSuchMethod since B |
| 1848 // does not implement bar. | 1854 // does not implement bar. |
| 1849 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); | 1855 Set<ClassElement> holders = noSuchMethodHoldersFor(receiverType); |
| 1850 if (holders.every(hasMatchingMember)) continue; | 1856 if (holders.every(hasMatchingMember)) continue; |
| 1851 String jsName = namer.invocationMirrorInternalName(selector); | 1857 String jsName = namer.invocationMirrorInternalName(selector); |
| 1852 if (!addedJsNames.contains(jsName)) { | 1858 if (!addedJsNames.contains(jsName)) { |
| 1853 js.Expression method = generateMethod(jsName, selector); | 1859 js.Expression method = generateMethod(jsName, selector); |
| 1854 defineStub(jsName, method); | 1860 CodeBuffer jsCode = new CodeBuffer(); |
| 1861 jsCode.add(js.prettyPrint(method, compiler)); |
| 1862 defineInstanceMember(jsName, jsCode); |
| 1855 addedJsNames.add(jsName); | 1863 addedJsNames.add(jsName); |
| 1856 } | 1864 } |
| 1857 } | 1865 } |
| 1858 } | 1866 } |
| 1859 | 1867 |
| 1860 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); | 1868 compiler.codegenWorld.invokedNames.forEach(addNoSuchMethodHandlers); |
| 1861 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); | 1869 compiler.codegenWorld.invokedGetters.forEach(addNoSuchMethodHandlers); |
| 1862 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); | 1870 compiler.codegenWorld.invokedSetters.forEach(addNoSuchMethodHandlers); |
| 1863 } | 1871 } |
| 1864 | 1872 |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2146 '${_}new ${namer.isolateName}()$N'); | 2154 '${_}new ${namer.isolateName}()$N'); |
| 2147 | 2155 |
| 2148 nativeEmitter.assembleCode(mainBuffer); | 2156 nativeEmitter.assembleCode(mainBuffer); |
| 2149 emitMain(mainBuffer); | 2157 emitMain(mainBuffer); |
| 2150 mainBuffer.add('function init()$_{\n'); | 2158 mainBuffer.add('function init()$_{\n'); |
| 2151 mainBuffer.add('$isolateProperties$_=$_{}$N'); | 2159 mainBuffer.add('$isolateProperties$_=$_{}$N'); |
| 2152 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); | 2160 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| 2153 addLazyInitializerFunctionIfNecessary(mainBuffer); | 2161 addLazyInitializerFunctionIfNecessary(mainBuffer); |
| 2154 emitFinishIsolateConstructor(mainBuffer); | 2162 emitFinishIsolateConstructor(mainBuffer); |
| 2155 mainBuffer.add('}\n'); | 2163 mainBuffer.add('}\n'); |
| 2156 compiler.assembledCode = mainBuffer.getText(); | 2164 compiler.assembledCode = mainBuffer.toString(); |
| 2157 | 2165 |
| 2158 if (generateSourceMap) { | 2166 if (generateSourceMap) { |
| 2159 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); | 2167 SourceFile compiledFile = new SourceFile(null, compiler.assembledCode); |
| 2160 String sourceMap = buildSourceMap(mainBuffer, compiledFile); | 2168 String sourceMap = buildSourceMap(mainBuffer, compiledFile); |
| 2161 // TODO(podivilov): We should find a better way to return source maps to | 2169 // TODO(podivilov): We should find a better way to return source maps to |
| 2162 // compiler. Using diagnostic handler for that purpose is a temporary | 2170 // compiler. Using diagnostic handler for that purpose is a temporary |
| 2163 // hack. | 2171 // hack. |
| 2164 compiler.reportDiagnostic( | 2172 compiler.reportDiagnostic( |
| 2165 null, sourceMap, new api.Diagnostic(-1, 'source map')); | 2173 null, sourceMap, new api.Diagnostic(-1, 'source map')); |
| 2166 } | 2174 } |
| 2167 }); | 2175 }); |
| 2168 return compiler.assembledCode; | 2176 return compiler.assembledCode; |
| 2169 } | 2177 } |
| 2170 | 2178 |
| 2171 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { | 2179 String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) { |
| 2172 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); | 2180 SourceMapBuilder sourceMapBuilder = new SourceMapBuilder(); |
| 2173 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); | 2181 buffer.forEachSourceLocation(sourceMapBuilder.addMapping); |
| 2174 return sourceMapBuilder.build(compiledFile); | 2182 return sourceMapBuilder.build(compiledFile); |
| 2175 } | 2183 } |
| 2176 } | 2184 } |
| 2177 | 2185 |
| 2186 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); |
| 2187 |
| 2178 const String GENERATED_BY = """ | 2188 const String GENERATED_BY = """ |
| 2179 // Generated by dart2js, the Dart to JavaScript compiler. | 2189 // Generated by dart2js, the Dart to JavaScript compiler. |
| 2180 """; | 2190 """; |
| 2181 const String HOOKS_API_USAGE = """ | 2191 const String HOOKS_API_USAGE = """ |
| 2182 // The code supports the following hooks: | 2192 // The code supports the following hooks: |
| 2183 // dartPrint(message) - if this function is defined it is called | 2193 // dartPrint(message) - if this function is defined it is called |
| 2184 // instead of the Dart [print] method. | 2194 // instead of the Dart [print] method. |
| 2185 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2195 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2186 // method will not be invoked directly. | 2196 // method will not be invoked directly. |
| 2187 // Instead, a closure that will invoke [main] is | 2197 // Instead, a closure that will invoke [main] is |
| 2188 // passed to [dartMainRunner]. | 2198 // passed to [dartMainRunner]. |
| 2189 """; | 2199 """; |
| OLD | NEW |