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

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: 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.
ngeoffray 2013/07/17 07:35:57 Would there be a way to just produce them when we
ahe 2013/07/17 07:55:27 Yes. I hope to clean this up. However, there are,
ngeoffray 2013/07/17 08:08:42 I agree it's not trivial.
143 * See [bufferForElement].
144 */
145 final Map<Element, List<CodeBuffer>> elementBuffers =
146 new Map<Element, List<CodeBuffer>>();
147
140 void registerDynamicFunctionTypeCheck(FunctionType functionType) { 148 void registerDynamicFunctionTypeCheck(FunctionType functionType) {
141 ClassElement classElement = Types.getClassContext(functionType); 149 ClassElement classElement = Types.getClassContext(functionType);
142 if (classElement != null) { 150 if (classElement != null) {
143 checkedGenericFunctionTypes.putIfAbsent(classElement, 151 checkedGenericFunctionTypes.putIfAbsent(classElement,
144 () => new Set<FunctionType>()).add(functionType); 152 () => new Set<FunctionType>()).add(functionType);
145 } else { 153 } else {
146 checkedNonGenericFunctionTypes.add(functionType); 154 checkedNonGenericFunctionTypes.add(functionType);
147 } 155 }
148 } 156 }
149 157
(...skipping 1627 matching lines...) Expand 10 before | Expand all | Expand 10 after
1777 var metadata = buildMetadataFunction(classElement); 1785 var metadata = buildMetadataFunction(classElement);
1778 if (metadata != null) { 1786 if (metadata != null) {
1779 builder.addProperty("@", metadata); 1787 builder.addProperty("@", metadata);
1780 } 1788 }
1781 emitClassGettersSetters(classElement, builder); 1789 emitClassGettersSetters(classElement, builder);
1782 if (!classElement.isMixinApplication) { 1790 if (!classElement.isMixinApplication) {
1783 emitInstanceMembers(classElement, builder); 1791 emitInstanceMembers(classElement, builder);
1784 } 1792 }
1785 emitIsTests(classElement, builder); 1793 emitIsTests(classElement, builder);
1786 1794
1795 List<CodeBuffer> classBuffers = elementBuffers[classElement];
1796 CodeBuffer statics = new CodeBuffer();
1797 bool hasStatics = false;
1798 if (classBuffers != null) {
1799 statics.write('{$n');
1800 elementBuffers.remove(classElement);
1801 for (CodeBuffer classBuffer in classBuffers) {
1802 // TODO(ahe): What about deferred?
1803 if (classBuffer != null) {
1804 hasStatics = true;
1805 statics.addBuffer(classBuffer);
1806 }
1807 }
1808 statics.write('}$n');
1809 }
1810 if (hasStatics) {
1811 builder.addProperty('static', new jsAst.Blob(statics));
1812 }
1813
1787 // TODO(ahe): This method (generateClass) should return a jsAst.Expression. 1814 // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
1788 if (!buffer.isEmpty) { 1815 if (!buffer.isEmpty) {
1789 buffer.write(',$n$n'); 1816 buffer.write(',$n$n');
1790 } 1817 }
1791 buffer.write('$className:$_'); 1818 buffer.write('$className:$_');
1792 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler)); 1819 buffer.write(jsAst.prettyPrint(builder.toObjectInitializer(), compiler));
1793 if (backend.retainName(classElement.name)) { 1820 if (backend.retainName(classElement.name)) {
1794 buffer.write(',$n$n"+${classElement.name.slowToString()}": 0'); 1821 buffer.write(',$n$n"+${classElement.name.slowToString()}": 0');
1795 } 1822 }
1796 } 1823 }
(...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after
3382 mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n'); 3409 mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n');
3383 } 3410 }
3384 3411
3385 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); 3412 mainBuffer.add('function ${namer.isolateName}()$_{}\n');
3386 mainBuffer.add('init()$N$n'); 3413 mainBuffer.add('init()$N$n');
3387 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. 3414 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
3388 isolateProperties = namer.CURRENT_ISOLATE; 3415 isolateProperties = namer.CURRENT_ISOLATE;
3389 mainBuffer.add( 3416 mainBuffer.add(
3390 '$isolateProperties$_=$_$isolatePropertiesName$N'); 3417 '$isolateProperties$_=$_$isolatePropertiesName$N');
3391 3418
3419 emitStaticFunctions(mainBuffer);
3420
3392 if (!regularClasses.isEmpty || 3421 if (!regularClasses.isEmpty ||
3393 !deferredClasses.isEmpty || 3422 !deferredClasses.isEmpty ||
3394 !nativeClasses.isEmpty || 3423 !nativeClasses.isEmpty ||
3395 !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) { 3424 !compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty) {
3396 // Shorten the code by using "$$" as temporary. 3425 // Shorten the code by using "$$" as temporary.
3397 classesCollector = r"$$"; 3426 classesCollector = r"$$";
3398 mainBuffer.add('var $classesCollector$_=$_{}$N$n'); 3427 mainBuffer.add('var $classesCollector$_=$_{}$N$n');
3399 } 3428 }
3400 3429
3401 // As a side-effect, emitting classes will produce "bound closures" in 3430 // 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) { 3465 for (jsAst.Node node in boundClosures) {
3437 // TODO(ahe): Some of these can be deferred. 3466 // TODO(ahe): Some of these can be deferred.
3438 mainBuffer.add(jsAst.prettyPrint(node, compiler)); 3467 mainBuffer.add(jsAst.prettyPrint(node, compiler));
3439 mainBuffer.add("$N$n"); 3468 mainBuffer.add("$N$n");
3440 } 3469 }
3441 3470
3442 // After this assignment we will produce invalid JavaScript code if we use 3471 // After this assignment we will produce invalid JavaScript code if we use
3443 // the classesCollector variable. 3472 // the classesCollector variable.
3444 classesCollector = 'classesCollector should not be used from now on'; 3473 classesCollector = 'classesCollector should not be used from now on';
3445 3474
3446 emitStaticFunctions(mainBuffer); 3475 if (!elementBuffers.isEmpty) {
3447
3448 if (!libraryBuffers.isEmpty) {
3449 var oldClassesCollector = classesCollector; 3476 var oldClassesCollector = classesCollector;
3450 classesCollector = r"$$"; 3477 classesCollector = r"$$";
3451 if (compiler.enableMinification) { 3478 if (compiler.enableMinification) {
3452 mainBuffer.write(';'); 3479 mainBuffer.write(';');
3453 } 3480 }
3454 if (!mangledFieldNames.isEmpty) { 3481 if (!mangledFieldNames.isEmpty) {
3455 var keys = mangledFieldNames.keys.toList(); 3482 var keys = mangledFieldNames.keys.toList();
3456 keys.sort(); 3483 keys.sort();
3457 var properties = []; 3484 var properties = [];
3458 for (String key in keys) { 3485 for (String key in keys) {
3459 var value = js.string('${mangledFieldNames[key]}'); 3486 var value = js.string('${mangledFieldNames[key]}');
3460 properties.add(new jsAst.Property(js.string(key), value)); 3487 properties.add(new jsAst.Property(js.string(key), value));
3461 } 3488 }
3462 var map = new jsAst.ObjectInitializer(properties); 3489 var map = new jsAst.ObjectInitializer(properties);
3463 mainBuffer.write( 3490 mainBuffer.write(
3464 jsAst.prettyPrint( 3491 jsAst.prettyPrint(
3465 js('init.mangledNames = #', map).toStatement(), compiler)); 3492 js('init.mangledNames = #', map).toStatement(), compiler));
3466 if (compiler.enableMinification) { 3493 if (compiler.enableMinification) {
3467 mainBuffer.write(';'); 3494 mainBuffer.write(';');
3468 } 3495 }
3469 } 3496 }
3470 mainBuffer 3497 mainBuffer
3471 ..write(getReflectionDataParser()) 3498 ..write(getReflectionDataParser())
3472 ..write('([$n'); 3499 ..write('([$n');
3473 3500
3474 var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys); 3501 var sortedElements = Elements.sortedByPosition(elementBuffers.keys);
karlklose 2013/07/17 08:01:40 Type this variable (and also b in l. 3505)?
ahe 2013/07/17 08:31:24 Done.
3475 for (LibraryElement library in sortedLibraries) { 3502 bool hasPendingStatics = false;
3476 List<CodeBuffer> buffers = libraryBuffers[library]; 3503 for (Element element in sortedElements) {
3504 if (!element.isLibrary()) {
3505 for (var b in elementBuffers[element]) {
ngeoffray 2013/07/17 07:35:57 Add a TODO to remove this once you implement it fo
ahe 2013/07/17 07:55:27 I'm not sure this code would go away. Consider it
ngeoffray 2013/07/17 08:08:42 OK. So after reading the code again, I realize I m
ahe 2013/07/17 08:31:24 If feel that would be easier to accomplish once I
3506 if (b != null) {
3507 hasPendingStatics = true;
3508 compiler.reportInfo(
3509 element, MessageKind.GENERIC, {'text': 'Pending statics.'});
3510 print(b.getText());
3511 }
3512 }
3513 continue;
3514 }
3515 LibraryElement library = element;
3516 List<CodeBuffer> buffers = elementBuffers[library];
3477 var buffer = buffers[0]; 3517 var buffer = buffers[0];
3478 var uri = library.canonicalUri; 3518 var uri = library.canonicalUri;
3479 if (uri.scheme == 'file' && compiler.sourceMapUri != null) { 3519 if (uri.scheme == 'file' && compiler.sourceMapUri != null) {
3480 // TODO(ahe): It is a hack to use compiler.sourceMapUri 3520 // TODO(ahe): It is a hack to use compiler.sourceMapUri
3481 // here. It should be relative to the main JavaScript 3521 // here. It should be relative to the main JavaScript
3482 // output file. 3522 // output file.
3483 uri = relativize( 3523 uri = relativize(
3484 compiler.sourceMapUri, library.canonicalUri, false); 3524 compiler.sourceMapUri, library.canonicalUri, false);
3485 } 3525 }
3486 if (buffer != null) { 3526 if (buffer != null) {
(...skipping 11 matching lines...) Expand all
3498 buffer = buffers[1]; 3538 buffer = buffers[1];
3499 if (buffer != null) { 3539 if (buffer != null) {
3500 deferredLibraries 3540 deferredLibraries
3501 ..write('["${library.getLibraryOrScriptName()}",$_') 3541 ..write('["${library.getLibraryOrScriptName()}",$_')
3502 ..write('"${uri}",$_') 3542 ..write('"${uri}",$_')
3503 ..write('[],$_') 3543 ..write('[],$_')
3504 ..write('{$n') 3544 ..write('{$n')
3505 ..addBuffer(buffer) 3545 ..addBuffer(buffer)
3506 ..write('}],$n'); 3546 ..write('}],$n');
3507 } 3547 }
3508 libraryBuffers[library] = const []; 3548 elementBuffers[library] = const [];
3549 }
3550 if (hasPendingStatics) {
3551 compiler.internalError('Pending statics (see above).');
ngeoffray 2013/07/17 07:35:57 Is that an internal error, or a not yet implemente
ahe 2013/07/17 07:55:27 It is an internal error. If a static is "pending"
3509 } 3552 }
3510 mainBuffer.write('])$N'); 3553 mainBuffer.write('])$N');
3511 3554
3512 emitFinishClassesInvocationIfNecessary(mainBuffer); 3555 emitFinishClassesInvocationIfNecessary(mainBuffer);
3513 classesCollector = oldClassesCollector; 3556 classesCollector = oldClassesCollector;
3514 } 3557 }
3515 3558
3516 emitStaticFunctionGetters(mainBuffer); 3559 emitStaticFunctionGetters(mainBuffer);
3517 3560
3518 emitRuntimeTypeSupport(mainBuffer); 3561 emitRuntimeTypeSupport(mainBuffer);
(...skipping 29 matching lines...) Expand all
3548 } 3591 }
3549 compiler.assembledCode = mainBuffer.getText(); 3592 compiler.assembledCode = mainBuffer.getText();
3550 outputSourceMap(mainBuffer, compiler.assembledCode, ''); 3593 outputSourceMap(mainBuffer, compiler.assembledCode, '');
3551 3594
3552 emitDeferredCode(); 3595 emitDeferredCode();
3553 3596
3554 }); 3597 });
3555 return compiler.assembledCode; 3598 return compiler.assembledCode;
3556 } 3599 }
3557 3600
3558 final Map<LibraryElement, List<CodeBuffer>> libraryBuffers =
3559 new Map<LibraryElement, List<CodeBuffer>>();
3560
3561 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) { 3601 CodeBuffer bufferForElement(Element element, CodeBuffer eagerBuffer) {
3562 LibraryElement library = element.getLibrary(); 3602 Element owner = element.getLibrary();
3563 List<CodeBuffer> buffers = libraryBuffers.putIfAbsent( 3603 if (!element.isTopLevel() && !element.isNative()) {
3564 library, () => <CodeBuffer>[null, null]); 3604 // For static (not top level) elements, record their code in a buffer
3605 // specific to the class. For now, not supported for native classes and
3606 // native elements.
3607 ClassElement cls =
3608 element.getEnclosingClassOrCompilationUnit().declaration;
3609 if (compiler.codegenWorld.instantiatedClasses.contains(cls)
3610 && !cls.isNative()) {
3611 owner = cls;
3612 }
3613 }
3614 if (owner == null) {
ngeoffray 2013/07/17 07:35:57 This looks too defensive.
ahe 2013/07/17 07:55:27 At first sight, yes. But notice that if we don't c
3615 throw 'Bad owner of $element';
karlklose 2013/07/17 08:01:40 Could you call internalError instead?
ahe 2013/07/17 08:31:24 Done.
3616 }
3617 List<CodeBuffer> buffers = elementBuffers.putIfAbsent(
3618 owner, () => <CodeBuffer>[null, null]);
3565 bool deferred = isDeferred(element); 3619 bool deferred = isDeferred(element);
3566 int index = deferred ? 1 : 0; 3620 int index = deferred ? 1 : 0;
3567 CodeBuffer buffer = buffers[index]; 3621 CodeBuffer buffer = buffers[index];
3568 if (buffer == null) { 3622 if (buffer == null) {
3569 buffer = buffers[index] = new CodeBuffer(); 3623 buffer = buffers[index] = new CodeBuffer();
3570 } 3624 }
3571 return buffer; 3625 return buffer;
3572 } 3626 }
3573 3627
3574 /** 3628 /**
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
3675 3729
3676 // TODO(ahe): Remove this when deferred loading is fully implemented. 3730 // TODO(ahe): Remove this when deferred loading is fully implemented.
3677 void warnNotImplemented(Element element, String message) { 3731 void warnNotImplemented(Element element, String message) {
3678 compiler.reportMessage(compiler.spanFromSpannable(element), 3732 compiler.reportMessage(compiler.spanFromSpannable(element),
3679 MessageKind.GENERIC.error({'text': message}), 3733 MessageKind.GENERIC.error({'text': message}),
3680 api.Diagnostic.WARNING); 3734 api.Diagnostic.WARNING);
3681 } 3735 }
3682 3736
3683 // TODO(ahe): This code should be integrated in finishClasses. 3737 // TODO(ahe): This code should be integrated in finishClasses.
3684 String getReflectionDataParser() { 3738 String getReflectionDataParser() {
3739 String metadataField = '"${namer.metadataField}"';
3685 return ''' 3740 return '''
3686 (function (reflectionData) { 3741 (function (reflectionData) {
3687 if (!init.libraries) init.libraries = []; 3742 if (!init.libraries) init.libraries = [];
3688 if (!init.mangledNames) init.mangledNames = {}; 3743 if (!init.mangledNames) init.mangledNames = {};
3689 if (!init.mangledGlobalNames) init.mangledGlobalNames = {}; 3744 if (!init.mangledGlobalNames) init.mangledGlobalNames = {};
3745 if (!init.statics) init.statics = {};
3690 init.getterPrefix = "${namer.getterPrefix}"; 3746 init.getterPrefix = "${namer.getterPrefix}";
3691 init.setterPrefix = "${namer.setterPrefix}"; 3747 init.setterPrefix = "${namer.setterPrefix}";
3692 var libraries = init.libraries; 3748 var libraries = init.libraries;
3693 var mangledNames = init.mangledNames; 3749 var mangledNames = init.mangledNames;
3694 var mangledGlobalNames = init.mangledGlobalNames; 3750 var mangledGlobalNames = init.mangledGlobalNames;
3695 var hasOwnProperty = Object.prototype.hasOwnProperty; 3751 var hasOwnProperty = Object.prototype.hasOwnProperty;
3696 var length = reflectionData.length; 3752 var length = reflectionData.length;
3697 for (var i = 0; i < length; i++) { 3753 for (var i = 0; i < length; i++) {
3698 var data = reflectionData[i]; 3754 var data = reflectionData[i];
3699 var name = data[0]; 3755 var name = data[0];
3700 var uri = data[1]; 3756 var uri = data[1];
3701 var metadata = data[2]; 3757 var metadata = data[2];
3702 var descriptor = data[3]; 3758 var descriptor = data[3];
3703 var classes = []; 3759 var classes = [];
3704 var functions = []; 3760 var functions = [];
3705 for (var property in descriptor) { 3761 function processStatics(descriptor) {
3706 if (!hasOwnProperty.call(descriptor, property)) continue; 3762 for (var property in descriptor) {
3707 var element = descriptor[property]; 3763 if (!hasOwnProperty.call(descriptor, property)) continue;
3708 var firstChar = property.substring(0, 1); 3764 var element = descriptor[property];
3709 var previousProperty; 3765 var firstChar = property.substring(0, 1);
3710 if (firstChar == "+") { 3766 var previousProperty;
3711 mangledGlobalNames[previousProperty] = property.substring(1); 3767 if (firstChar === "+") {
3712 } else if (firstChar == "@") { 3768 mangledGlobalNames[previousProperty] = property.substring(1);
3713 property = property.substring(1); 3769 } else if (firstChar === "@") {
3714 ${namer.CURRENT_ISOLATE}[property]["${namer.metadataField}"] = element; 3770 property = property.substring(1);
3715 } else if (typeof element === "function") { 3771 ${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
3716 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element; 3772 } else if (typeof element === "function") {
3717 functions.push(property); 3773 ${namer.CURRENT_ISOLATE}[previousProperty = property] = element;
3718 } else { 3774 functions.push(property);
3719 previousProperty = property; 3775 } else {
3720 var newDesc = {}; 3776 previousProperty = property;
3721 var previousProp; 3777 var newDesc = {};
3722 for (var prop in element) { 3778 var previousProp;
3723 if (!hasOwnProperty.call(element, prop)) continue; 3779 for (var prop in element) {
3724 firstChar = prop.substring(0, 1); 3780 if (!hasOwnProperty.call(element, prop)) continue;
3725 if (firstChar == "+") { 3781 firstChar = prop.substring(0, 1);
3726 mangledNames[previousProp] = prop.substring(1); 3782 if (prop === "static") {
3727 } else if (firstChar == "@" && prop != "@") { 3783 processStatics(init.statics[property] = element[prop]);
3728 newDesc[prop.substring(1)]["${namer.metadataField}"] =''' 3784 } else if (firstChar === "+") {
3729 '''element[prop]; 3785 mangledNames[previousProp] = prop.substring(1);
3730 } else { 3786 } else if (firstChar === "@" && prop !== "@") {
3731 newDesc[previousProp = prop] = element[prop]; 3787 newDesc[prop.substring(1)][$metadataField] = element[prop];
3788 } else {
3789 newDesc[previousProp = prop] = element[prop];
3790 }
3732 } 3791 }
3792 $classesCollector[property] = newDesc;
3793 classes.push(property);
3733 } 3794 }
3734 $classesCollector[property] = newDesc;
3735 classes.push(property);
3736 } 3795 }
3737 } 3796 }
3797 processStatics(descriptor);
3738 libraries.push([name, uri, classes, functions, metadata]); 3798 libraries.push([name, uri, classes, functions, metadata]);
3739 } 3799 }
3740 })'''; 3800 })''';
3741 } 3801 }
3742 } 3802 }
3743 3803
3744 const String GENERATED_BY = """ 3804 const String GENERATED_BY = """
3745 // Generated by dart2js, the Dart to JavaScript compiler. 3805 // Generated by dart2js, the Dart to JavaScript compiler.
3746 """; 3806 """;
3747 3807
3748 const String HOOKS_API_USAGE = """ 3808 const String HOOKS_API_USAGE = """
3749 // The code supports the following hooks: 3809 // The code supports the following hooks:
3750 // dartPrint(message) - if this function is defined it is called 3810 // dartPrint(message) - if this function is defined it is called
3751 // instead of the Dart [print] method. 3811 // instead of the Dart [print] method.
3752 // dartMainRunner(main) - if this function is defined, the Dart [main] 3812 // dartMainRunner(main) - if this function is defined, the Dart [main]
3753 // method will not be invoked directly. 3813 // method will not be invoked directly.
3754 // Instead, a closure that will invoke [main] is 3814 // Instead, a closure that will invoke [main] is
3755 // passed to [dartMainRunner]. 3815 // passed to [dartMainRunner].
3756 """; 3816 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698