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

Side by Side Diff: dart/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 19391004: Implement reflective access to static methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Address review comments Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of 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 */
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
130 * typedefs and implicitly through type annotations in checked mode. 130 * typedefs and implicitly through type annotations in checked mode.
131 */ 131 */
132 Set<FunctionType> checkedFunctionTypes; 132 Set<FunctionType> checkedFunctionTypes;
133 133
134 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes = 134 Map<ClassElement, Set<FunctionType>> checkedGenericFunctionTypes =
135 new Map<ClassElement, Set<FunctionType>>(); 135 new Map<ClassElement, Set<FunctionType>>();
136 136
137 Set<FunctionType> checkedNonGenericFunctionTypes = 137 Set<FunctionType> checkedNonGenericFunctionTypes =
138 new Set<FunctionType>(); 138 new Set<FunctionType>();
139 139
140 /**
141 * For classes and libraries, record code for static/top-level members.
142 * Later, this code is emitted when the class or library is emitted.
143 * See [bufferForElement].
144 */
145 // TODO(ahe): Generate statics with their class, and store only libraries in
146 // this map.
147 final Map<Element, List<CodeBuffer>> elementBuffers =
148 new Map<Element, List<CodeBuffer>>();
149
140 void registerDynamicFunctionTypeCheck(FunctionType functionType) { 150 void registerDynamicFunctionTypeCheck(FunctionType functionType) {
141 ClassElement classElement = Types.getClassContext(functionType); 151 ClassElement classElement = Types.getClassContext(functionType);
142 if (classElement != null) { 152 if (classElement != null) {
143 checkedGenericFunctionTypes.putIfAbsent(classElement, 153 checkedGenericFunctionTypes.putIfAbsent(classElement,
144 () => new Set<FunctionType>()).add(functionType); 154 () => new Set<FunctionType>()).add(functionType);
145 } else { 155 } else {
146 checkedNonGenericFunctionTypes.add(functionType); 156 checkedNonGenericFunctionTypes.add(functionType);
147 } 157 }
148 } 158 }
149 159
(...skipping 1627 matching lines...) Expand 10 before | Expand all | Expand 10 after
1777 var metadata = buildMetadataFunction(classElement); 1787 var metadata = buildMetadataFunction(classElement);
1778 if (metadata != null) { 1788 if (metadata != null) {
1779 builder.addProperty("@", metadata); 1789 builder.addProperty("@", metadata);
1780 } 1790 }
1781 emitClassGettersSetters(classElement, builder); 1791 emitClassGettersSetters(classElement, builder);
1782 if (!classElement.isMixinApplication) { 1792 if (!classElement.isMixinApplication) {
1783 emitInstanceMembers(classElement, builder); 1793 emitInstanceMembers(classElement, builder);
1784 } 1794 }
1785 emitIsTests(classElement, builder); 1795 emitIsTests(classElement, builder);
1786 1796
1797 List<CodeBuffer> classBuffers = elementBuffers[classElement];
1798 CodeBuffer statics = new CodeBuffer();
1799 bool hasStatics = false;
1800 if (classBuffers != null) {
1801 statics.write('{$n');
1802 elementBuffers.remove(classElement);
1803 for (CodeBuffer classBuffer in classBuffers) {
1804 // TODO(ahe): What about deferred?
1805 if (classBuffer != null) {
1806 hasStatics = true;
1807 statics.addBuffer(classBuffer);
1808 }
1809 }
1810 statics.write('}$n');
1811 }
1812 if (hasStatics) {
1813 builder.addProperty('static', new jsAst.Blob(statics));
1814 }
1815
1787 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. 1816 // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
1788 if (!buffer.isEmpty) { 1817 if (!buffer.isEmpty) {
1789 buffer.write(',$n$n'); 1818 buffer.write(',$n$n');
1790 } 1819 }
1791 buffer.write('$className:$_'); 1820 buffer.write('$className:$_');
1792 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler)); 1821 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler));
1793 if (backend.retainName(classElement.name)) { 1822 if (backend.retainName(classElement.name)) {
1794 buffer.write(',$n$n"+${classElement.name.slowToString()}": 0'); 1823 buffer.write(',$n$n"+${classElement.name.slowToString()}": 0');
1795 } 1824 }
1796 } 1825 }
(...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after
3382 mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n'); 3411 mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n');
3383 } 3412 }
3384 3413
3385 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); 3414 mainBuffer.add('function ${namer.isolateName}()$_{}\n');
3386 mainBuffer.add('init()$N$n'); 3415 mainBuffer.add('init()$N$n');
3387 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. 3416 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
3388 isolateProperties = namer.CURRENT_ISOLATE; 3417 isolateProperties = namer.CURRENT_ISOLATE;
3389 mainBuffer.add( 3418 mainBuffer.add(
3390 '$isolateProperties$_=$_$isolatePropertiesName$N'); 3419 '$isolateProperties$_=$_$isolatePropertiesName$N');
3391 3420
3421 emitStaticFunctions(mainBuffer);
3422
3392 if (!regularClasses.isEmpty || 3423 if (!regularClasses.isEmpty ||
3393 !deferredClasses.isEmpty || 3424 !deferredClasses.isEmpty ||
3394 !nativeClasses.isEmpty || 3425 !nativeClasses.isEmpty ||
3395 !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) { 3426 !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) {
3396 // Shorten the code by using "$$" as temporary. 3427 // Shorten the code by using "$$" as temporary.
3397 classesCollector = r"$$"; 3428 classesCollector = r"$$";
3398 mainBuffer.add('var $classesCollector$_=$_{}$N$n'); 3429 mainBuffer.add('var $classesCollector$_=$_{}$N$n');
3399 } 3430 }
3400 3431
3401 // As a side-effect, emitting classes will produce "bound closures" in 3432 // As a side-effect, emitting classes will produce "bound closures" in
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
3436 for (jsAst.Node node in boundClosures) { 3467 for (jsAst.Node node in boundClosures) {
3437 // TODO(ahe): Some of these can be deferred. 3468 // TODO(ahe): Some of these can be deferred.
3438 mainBuffer.add(jsAst.prettyPrint(node, compiler)); 3469 mainBuffer.add(jsAst.prettyPrint(node, compiler));
3439 mainBuffer.add("$N$n"); 3470 mainBuffer.add("$N$n");
3440 } 3471 }
3441 3472
3442 // After this assignment we will produce invalid JavaScript code if we use 3473 // After this assignment we will produce invalid JavaScript code if we use
3443 // the classesCollector variable. 3474 // the classesCollector variable.
3444 classesCollector = 'classesCollector should not be used from now on'; 3475 classesCollector = 'classesCollector should not be used from now on';
3445 3476
3446 emitStaticFunctions(mainBuffer); 3477 if (!elementBuffers.isEmpty) {
3447
3448 if (!libraryBuffers.isEmpty) {
3449 var oldClassesCollector = classesCollector; 3478 var oldClassesCollector = classesCollector;
3450 classesCollector = r"$$"; 3479 classesCollector = r"$$";
3451 if (compiler.enableMinification) { 3480 if (compiler.enableMinification) {
3452 mainBuffer.write(';'); 3481 mainBuffer.write(';');
3453 } 3482 }
3454 if (!mangledFieldNames.isEmpty) { 3483 if (!mangledFieldNames.isEmpty) {
3455 var keys = mangledFieldNames.keys.toList(); 3484 var keys = mangledFieldNames.keys.toList();
3456 keys.sort(); 3485 keys.sort();
3457 var properties = []; 3486 var properties = [];
3458 for (String key in keys) { 3487 for (String key in keys) {
3459 var value = js.string('${mangledFieldNames[key]}'); 3488 var value = js.string('${mangledFieldNames[key]}');
3460 properties.add(new jsAst.Property(js.string(key), value)); 3489 properties.add(new jsAst.Property(js.string(key), value));
3461 } 3490 }
3462 var map = new jsAst.ObjectInitializer(properties); 3491 var map = new jsAst.ObjectInitializer(properties);
3463 mainBuffer.write( 3492 mainBuffer.write(
3464 jsAst.prettyPrint( 3493 jsAst.prettyPrint(
3465 js('init.mangledNames = #', map).toStatement(), compiler)); 3494 js('init.mangledNames = #', map).toStatement(), compiler));
3466 if (compiler.enableMinification) { 3495 if (compiler.enableMinification) {
3467 mainBuffer.write(';'); 3496 mainBuffer.write(';');
3468 } 3497 }
3469 } 3498 }
3470 mainBuffer 3499 mainBuffer
3471 ..write(getReflectionDataParser()) 3500 ..write(getReflectionDataParser())
3472 ..write('([$n'); 3501 ..write('([$n');
3473 3502
3474 var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys); 3503 List<Element> sortedElements =
3475 for (LibraryElement library in sortedLibraries) { 3504 Elements.sortedByPosition(elementBuffers.keys);
3476 List<CodeBuffer> buffers = libraryBuffers[library]; 3505 bool hasPendingStatics = false;
3506 for (Element element in sortedElements) {
3507 if (!element.isLibrary()) {
3508 for (CodeBuffer b in elementBuffers[element]) {
3509 if (b != null) {
3510 hasPendingStatics = true;
3511 compiler.reportInfo(
3512 element, MessageKind.GENERIC, {'text': 'Pending statics.'});
3513 print(b.getText());
3514 }
3515 }
3516 continue;
3517 }
3518 LibraryElement library = element;
3519 List<CodeBuffer> buffers = elementBuffers[library];
3477 var buffer = buffers[0]; 3520 var buffer = buffers[0];
3478 var uri = library.canonicalUri; 3521 var uri = library.canonicalUri;
3479 if (uri.scheme == 'file' && compiler.sourceMapUri != null) { 3522 if (uri.scheme == 'file' && compiler.sourceMapUri != null) {
3480 // TODO(ahe): It is a hack to use compiler.sourceMapUri 3523 // TODO(ahe): It is a hack to use compiler.sourceMapUri
3481 // here. It should be relative to the main JavaScript 3524 // here. It should be relative to the main JavaScript
3482 // output file. 3525 // output file.
3483 uri = relativize( 3526 uri = relativize(
3484 compiler.sourceMapUri, library.canonicalUri, false); 3527 compiler.sourceMapUri, library.canonicalUri, false);
3485 } 3528 }
3486 if (buffer != null) { 3529 if (buffer != null) {
(...skipping 11 matching lines...) Expand all
3498 buffer = buffers[1]; 3541 buffer = buffers[1];
3499 if (buffer != null) { 3542 if (buffer != null) {
3500 deferredLibraries 3543 deferredLibraries
3501 ..write('["${library.getLibraryOrScriptName()}",$_') 3544 ..write('["${library.getLibraryOrScriptName()}",$_')
3502 ..write('"${uri}",$_') 3545 ..write('"${uri}",$_')
3503 ..write('[],$_') 3546 ..write('[],$_')
3504 ..write('{$n') 3547 ..write('{$n')
3505 ..addBuffer(buffer) 3548 ..addBuffer(buffer)
3506 ..write('}],$n'); 3549 ..write('}],$n');
3507 } 3550 }
3508 libraryBuffers[library] = const []; 3551 elementBuffers[library] = const [];
3552 }
3553 if (hasPendingStatics) {
3554 compiler.internalError('Pending statics (see above).');
3509 } 3555 }
3510 mainBuffer.write('])$N'); 3556 mainBuffer.write('])$N');
3511 3557
3512 emitFinishClassesInvocationIfNecessary(mainBuffer); 3558 emitFinishClassesInvocationIfNecessary(mainBuffer);
3513 classesCollector = oldClassesCollector; 3559 classesCollector = oldClassesCollector;
3514 } 3560 }
3515 3561
3516 emitStaticFunctionGetters(mainBuffer); 3562 emitStaticFunctionGetters(mainBuffer);
3517 3563
3518 emitRuntimeTypeSupport(mainBuffer); 3564 emitRuntimeTypeSupport(mainBuffer);
(...skipping 29 matching lines...) Expand all
3548 } 3594 }
3549 compiler.assembledCode = mainBuffer.getText(); 3595 compiler.assembledCode = mainBuffer.getText();
3550 outputSourceMap(mainBuffer, compiler.assembledCode, ''); 3596 outputSourceMap(mainBuffer, compiler.assembledCode, '');
3551 3597
3552 emitDeferredCode(); 3598 emitDeferredCode();
3553 3599
3554 }); 3600 });
3555 return compiler.assembledCode; 3601 return compiler.assembledCode;
3556 } 3602 }
3557 3603
3558 final Map<LibraryElement, List<CodeBuffer>> libraryBuffers =
3559 new Map<LibraryElement, List<CodeBuffer>>();
3560
3561 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { 3604 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) {
3562 LibraryElement library = element.getLibrary(); 3605 Element owner = element.getLibrary();
3563 List<CodeBuffer> buffers = libraryBuffers.putIfAbsent( 3606 if (!element.isTopLevel() && !element.isNative()) {
3564 library, () => <CodeBuffer>[null, null]); 3607 // For static (not top level) elements, record their code in a buffer
3608 // specific to the class. For now, not supported for native classes and
3609 // native elements.
3610 ClassElement cls =
3611 element.getEnclosingClassOrCompilationUnit().declaration;
3612 if (compiler.codegenWorld.instantiatedClasses.contains(cls)
3613 && !cls.isNative()) {
3614 owner = cls;
3615 }
3616 }
3617 if (owner == null) {
3618 compiler.internalErrorOnElement(element, 'Owner is null');
3619 }
3620 List<CodeBuffer> buffers = elementBuffers.putIfAbsent(
3621 owner, () => <CodeBuffer>[null, null]);
3565 bool deferred = isDeferred(element); 3622 bool deferred = isDeferred(element);
3566 int index = deferred ? 1 : 0; 3623 int index = deferred ? 1 : 0;
3567 CodeBuffer buffer = buffers[index]; 3624 CodeBuffer buffer = buffers[index];
3568 if (buffer == null) { 3625 if (buffer == null) {
3569 buffer = buffers[index] = new CodeBuffer(); 3626 buffer = buffers[index] = new CodeBuffer();
3570 } 3627 }
3571 return buffer; 3628 return buffer;
3572 } 3629 }
3573 3630
3574 /** 3631 /**
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
3675 3732
3676 // TODO(ahe): Remove this when deferred loading is fully implemented. 3733 // TODO(ahe): Remove this when deferred loading is fully implemented.
3677 void warnNotImplemented(Element element, String message) { 3734 void warnNotImplemented(Element element, String message) {
3678 compiler.reportMessage(compiler.spanFromSpannable(element), 3735 compiler.reportMessage(compiler.spanFromSpannable(element),
3679 MessageKind.GENERIC.error({'text': message}), 3736 MessageKind.GENERIC.error({'text': message}),
3680 api.Diagnostic.WARNING); 3737 api.Diagnostic.WARNING);
3681 } 3738 }
3682 3739
3683 // TODO(ahe): This code should be integrated in finishClasses. 3740 // TODO(ahe): This code should be integrated in finishClasses.
3684 String getReflectionDataParser() { 3741 String getReflectionDataParser() {
3742 String metadataField = '"${namer.metadataField}"';
3685 return ''' 3743 return '''
3686 (function (reflectionData) { 3744 (function (reflectionData) {
3687 if (!init.libraries) init.libraries = []; 3745 if (!init.libraries) init.libraries = [];
3688 if (!init.mangledNames) init.mangledNames = {}; 3746 if (!init.mangledNames) init.mangledNames = {};
3689 if (!init.mangledGlobalNames) init.mangledGlobalNames = {}; 3747 if (!init.mangledGlobalNames) init.mangledGlobalNames = {};
3748 if (!init.statics) init.statics = {};
3690 init.getterPrefix = "${namer.getterPrefix}"; 3749 init.getterPrefix = "${namer.getterPrefix}";
3691 init.setterPrefix = "${namer.setterPrefix}"; 3750 init.setterPrefix = "${namer.setterPrefix}";
3692 var libraries = init.libraries; 3751 var libraries = init.libraries;
3693 var mangledNames = init.mangledNames; 3752 var mangledNames = init.mangledNames;
3694 var mangledGlobalNames = init.mangledGlobalNames; 3753 var mangledGlobalNames = init.mangledGlobalNames;
3695 var hasOwnProperty = Object.prototype.hasOwnProperty; 3754 var hasOwnProperty = Object.prototype.hasOwnProperty;
3696 var length = reflectionData.length; 3755 var length = reflectionData.length;
3697 for (var i = 0; i < length; i++) { 3756 for (var i = 0; i < length; i++) {
3698 var data = reflectionData[i]; 3757 var data = reflectionData[i];
3699 var name = data[0]; 3758 var name = data[0];
3700 var uri = data[1]; 3759 var uri = data[1];
3701 var metadata = data[2]; 3760 var metadata = data[2];
3702 var descriptor = data[3]; 3761 var descriptor = data[3];
3703 var classes = []; 3762 var classes = [];
3704 var functions = []; 3763 var functions = [];
3705 for (var property in descriptor) { 3764 function processStatics(descriptor) {
3706 if (!hasOwnProperty.call(descriptor, property)) continue; 3765 for (var property in descriptor) {
3707 var element = descriptor[property]; 3766 if (!hasOwnProperty.call(descriptor, property)) continue;
3708 var firstChar = property.substring(0, 1); 3767 var element = descriptor[property];
3709 var previousProperty; 3768 var firstChar = property.substring(0, 1);
3710 if (firstChar == "+") { 3769 var previousProperty;
3711 mangledGlobalNames[previousProperty] = property.substring(1); 3770 if (firstChar === "+") {
3712 } else if (firstChar == "@") { 3771 mangledGlobalNames[previousProperty] = property.substring(1);
3713 property = property.substring(1); 3772 } else if (firstChar === "@") {
3714 ${namer.CURRENT_ISOLATE}[property]["${namer.metadataField}"] = element; 3773 property = property.substring(1);
3715 } else if (typeof element === "function") { 3774 ${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
3716 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; 3775 } else if (typeof element === "function") {
3717 functions.push(property); 3776 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element;
3718 } else { 3777 functions.push(property);
3719 previousProperty = property; 3778 } else {
3720 var newDesc = {}; 3779 previousProperty = property;
3721 var previousProp; 3780 var newDesc = {};
3722 for (var prop in element) { 3781 var previousProp;
3723 if (!hasOwnProperty.call(element, prop)) continue; 3782 for (var prop in element) {
3724 firstChar = prop.substring(0, 1); 3783 if (!hasOwnProperty.call(element, prop)) continue;
3725 if (firstChar == "+") { 3784 firstChar = prop.substring(0, 1);
3726 mangledNames[previousProp] = prop.substring(1); 3785 if (prop === "static") {
3727 } else if (firstChar == "@" && prop != "@") { 3786 processStatics(init.statics[property] = element[prop]);
3728 newDesc[prop.substring(1)]["${namer.metadataField}"] =''' 3787 } else if (firstChar === "+") {
3729 '''element[prop]; 3788 mangledNames[previousProp] = prop.substring(1);
3730 } else { 3789 } else if (firstChar === "@" && prop !== "@") {
3731 newDesc[previousProp = prop] = element[prop]; 3790 newDesc[prop.substring(1)][$metadataField] = element[prop];
3791 } else {
3792 newDesc[previousProp = prop] = element[prop];
3793 }
3732 } 3794 }
3795 $classesCollector[property] = newDesc;
3796 classes.push(property);
3733 } 3797 }
3734 $classesCollector[property] = newDesc;
3735 classes.push(property);
3736 } 3798 }
3737 } 3799 }
3800 processStatics(descriptor);
3738 libraries.push([name, uri, classes, functions, metadata]); 3801 libraries.push([name, uri, classes, functions, metadata]);
3739 } 3802 }
3740 })'''; 3803 })''';
3741 } 3804 }
3742 } 3805 }
3743 3806
3744 const String GENERATED_BY = """ 3807 const String GENERATED_BY = """
3745 // Generated by dart2js, the Dart to JavaScript compiler. 3808 // Generated by dart2js, the Dart to JavaScript compiler.
3746 """; 3809 """;
3747 3810
3748 const String HOOKS_API_USAGE = """ 3811 const String HOOKS_API_USAGE = """
3749 // The code supports the following hooks: 3812 // The code supports the following hooks:
3750 // dartPrint(message) - if this function is defined it is called 3813 // dartPrint(message) - if this function is defined it is called
3751 // instead of the Dart [print] method. 3814 // instead of the Dart [print] method.
3752 // dartMainRunner(main) - if this function is defined, the Dart [main] 3815 // dartMainRunner(main) - if this function is defined, the Dart [main]
3753 // method will not be invoked directly. 3816 // method will not be invoked directly.
3754 // Instead, a closure that will invoke [main] is 3817 // Instead, a closure that will invoke [main] is
3755 // passed to [dartMainRunner]. 3818 // passed to [dartMainRunner].
3756 """; 3819 """;
OLDNEW
« no previous file with comments | « dart/sdk/lib/_internal/compiler/implementation/js/printer.dart ('k') | dart/sdk/lib/_internal/lib/js_mirrors.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698