Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dart2js.js_emitter.startup_emitter.model_emitter; | 5 part of dart2js.js_emitter.startup_emitter.model_emitter; |
| 6 | 6 |
| 7 const String deferredExtension = "part.js"; | 7 const String deferredExtension = "part.js"; |
| 8 /// For deferred loading we communicate the initializers via this global var. | 8 /// For deferred loading we communicate the initializers via this global var. |
| 9 const String deferredInitializersGlobal = r"$__dart_deferred_initializers__"; | 9 const String deferredInitializersGlobal = r"$__dart_deferred_initializers__"; |
| 10 | 10 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 // The runtime ensures that const-lists cannot be modified. | 109 // The runtime ensures that const-lists cannot be modified. |
| 110 function makeConstList(list) { | 110 function makeConstList(list) { |
| 111 // By assigning a function to the properties they become part of the | 111 // By assigning a function to the properties they become part of the |
| 112 // hidden class. The actual values of the fields don't matter, since we | 112 // hidden class. The actual values of the fields don't matter, since we |
| 113 // only check if they exist. | 113 // only check if they exist. |
| 114 list.immutable\$list = Array; | 114 list.immutable\$list = Array; |
| 115 list.fixed\$length = Array; | 115 list.fixed\$length = Array; |
| 116 return list; | 116 return list; |
| 117 } | 117 } |
| 118 | 118 |
| 119 // TODO(floitsch): provide code for tear-offs. | 119 // This variable is used by the tearOffCode to guarantee unique functions per |
| 120 // tear-offs. | |
| 121 var functionCounter = 0; | |
| 122 #tearOffCode; | |
| 123 | |
| 124 // Each deferred hunk comes with its own types which are added to the end | |
| 125 // of the types-array. | |
| 126 // The `funTypes` passed to the `installTearOff` function below is relative to | |
| 127 // the hunk the function comes from. The `typesOffset` variable encodes the | |
| 128 // offset at which the new types will be added. | |
| 129 var typesOffset = 0; | |
| 130 | |
| 131 // Adapts the stored data, so it's suitable for a tearOff call. | |
| 132 // TODO(floitsch): Change tearOffCode to accept the data directly, or create a | |
| 133 // different tearOffCode? | |
| 134 function installTearOff(container, getterName, | |
| 135 isStatic, isIntercepted, requiredParameterCount, | |
|
Siggi Cherem (dart-lang)
2015/07/22 20:51:28
missing 1 space of indentation (FWIW, I don't thin
floitsch
2015/07/29 17:27:15
Done.
| |
| 136 optionalParameterDefaultValues, | |
| 137 callNames, funNames, funType) { | |
| 138 var funs = []; | |
| 139 for (var i = 0; i < funNames.length; i++) { | |
| 140 var fun = container[funNames[i]]; | |
| 141 fun.#callName = callNames[i]; | |
| 142 funs.push(fun); | |
| 143 } | |
| 144 | |
| 145 funs[0][#argumentCount] = requiredParameterCount; | |
| 146 funs[0][#defaultArgumentValues] = optionalParameterDefaultValues; | |
| 147 var reflectionInfo = funType; | |
| 148 if (typeof reflectionInfo == "number") { | |
| 149 // The reflectionInfo can either be a function, or a pointer into the types | |
| 150 // table. If it points into the types-table we need to update the index, | |
| 151 // in case the tear-off is part of a deferred hunk. | |
| 152 reflectionInfo = reflectionInfo + typesOffset; | |
| 153 } | |
| 154 var name = funNames[0]; | |
| 155 container[getterName] = | |
| 156 tearOff(funs, reflectionInfo, isStatic, name, isIntercepted); | |
| 157 } | |
| 120 | 158 |
| 121 // Instead of setting the interceptor tags directly we use this update | 159 // Instead of setting the interceptor tags directly we use this update |
| 122 // function. This makes it easier for deferred fragments to contribute to the | 160 // function. This makes it easier for deferred fragments to contribute to the |
| 123 // embedded global. | 161 // embedded global. |
| 124 function setOrUpdateInterceptorsByTag(newTags) { | 162 function setOrUpdateInterceptorsByTag(newTags) { |
| 125 var tags = #embeddedInterceptorTags; | 163 var tags = #embeddedInterceptorTags; |
| 126 if (!tags) { | 164 if (!tags) { |
| 127 #embeddedInterceptorTags = newTags; | 165 #embeddedInterceptorTags = newTags; |
| 128 return; | 166 return; |
| 129 } | 167 } |
| 130 copyProperties(newTags, tags); | 168 copyProperties(newTags, tags); |
| 131 } | 169 } |
| 132 | 170 |
| 133 // Instead of setting the leaf tags directly we use this update | 171 // Instead of setting the leaf tags directly we use this update |
| 134 // function. This makes it easier for deferred fragments to contribute to the | 172 // function. This makes it easier for deferred fragments to contribute to the |
| 135 // embedded global. | 173 // embedded global. |
| 136 function setOrUpdateLeafTags(newTags) { | 174 function setOrUpdateLeafTags(newTags) { |
| 137 var tags = #embeddedLeafTags; | 175 var tags = #embeddedLeafTags; |
| 138 if (!tags) { | 176 if (!tags) { |
| 139 #embeddedLeafTags = newTags; | 177 #embeddedLeafTags = newTags; |
| 140 return; | 178 return; |
| 141 } | 179 } |
| 142 copyProperties(newTags, tags); | 180 copyProperties(newTags, tags); |
| 143 } | 181 } |
| 144 | 182 |
| 145 // Updates the types embedded global. | 183 // Updates the types embedded global. |
| 146 function updateTypes(newTypes) { | 184 function updateTypes(newTypes) { |
| 147 var types = #embeddedTypes; | 185 var types = #embeddedTypes; |
| 148 types.push.apply(types, newTypes); | 186 types.push.apply(types, newTypes); |
| 187 // This relies on the fact that types are added *after* the tear-offs have | |
|
Siggi Cherem (dart-lang)
2015/07/22 20:51:28
nit: move the comment above the push call?
floitsch
2015/07/29 17:27:15
Done. and added more comments.
| |
| 188 // been installed. | |
| 149 } | 189 } |
| 150 | 190 |
| 151 // Updates the given holder with the properties of the [newHolder]. | 191 // Updates the given holder with the properties of the [newHolder]. |
| 152 // This function is used when a deferred fragment is initialized. | 192 // This function is used when a deferred fragment is initialized. |
| 153 function updateHolder(holder, newHolder) { | 193 function updateHolder(holder, newHolder) { |
| 154 // TODO(floitsch): updating the prototype (instead of copying) is | 194 // TODO(floitsch): updating the prototype (instead of copying) is |
| 155 // *horribly* inefficient in Firefox. There we should just copy the | 195 // *horribly* inefficient in Firefox. There we should just copy the |
| 156 // properties. | 196 // properties. |
| 157 var oldPrototype = holder.__proto__; | 197 var oldPrototype = holder.__proto__; |
| 158 newHolder.__proto__ = oldPrototype; | 198 newHolder.__proto__ = oldPrototype; |
| 159 holder.__proto__ = newHolder; | 199 holder.__proto__ = newHolder; |
| 160 return holder; | 200 return holder; |
| 161 } | 201 } |
| 162 | 202 |
| 163 // Every deferred hunk (i.e. fragment) is a function that we can invoke to | 203 // Every deferred hunk (i.e. fragment) is a function that we can invoke to |
| 164 // initialize it. At this moment it contributes its data to the main hunk. | 204 // initialize it. At this moment it contributes its data to the main hunk. |
| 165 function initializeDeferredHunk(hunk) { | 205 function initializeDeferredHunk(hunk) { |
| 206 // Update the typesOffset for the next deferred library. | |
| 207 typesOffset = #embeddedTypes.length; | |
| 208 | |
| 166 // TODO(floitsch): extend natives. | 209 // TODO(floitsch): extend natives. |
| 167 hunk(inherit, mixin, lazy, makeConstList, installTearOff, | 210 hunk(inherit, mixin, lazy, makeConstList, installTearOff, |
| 168 updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags, | 211 updateHolder, updateTypes, updateInterceptorsByTag, updateLeafTags, |
| 169 #embeddedGlobalsObject, #holdersList, #staticState); | 212 #embeddedGlobalsObject, #holdersList, #staticState); |
| 170 } | 213 } |
| 171 | 214 |
| 172 // Creates the holders. | 215 // Creates the holders. |
| 173 #holders; | 216 #holders; |
| 174 // TODO(floitsch): if name is not set (for example in IE), run through all | 217 // TODO(floitsch): if name is not set (for example in IE), run through all |
| 175 // functions and set the name. | 218 // functions and set the name. |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 | 326 |
| 284 js.Statement emitMainFragment(Program program) { | 327 js.Statement emitMainFragment(Program program) { |
| 285 MainFragment fragment = program.fragments.first; | 328 MainFragment fragment = program.fragments.first; |
| 286 | 329 |
| 287 return js.js.statement(mainBoilerplate, | 330 return js.js.statement(mainBoilerplate, |
| 288 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 331 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 289 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), | 332 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), |
| 290 'cyclicThrow': backend.emitter.staticFunctionAccess( | 333 'cyclicThrow': backend.emitter.staticFunctionAccess( |
| 291 backend.getCyclicThrowHelper()), | 334 backend.getCyclicThrowHelper()), |
| 292 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 335 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 336 'tearOffCode': new js.Block(buildTearOffCode(backend)), | |
| 293 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | 337 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), |
| 294 'embeddedInterceptorTags': | 338 'embeddedInterceptorTags': |
| 295 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), | 339 generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG), |
| 296 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), | 340 'embeddedLeafTags': generateEmbeddedGlobalAccess(LEAF_TAGS), |
| 297 'embeddedGlobalsObject': js.js("init"), | 341 'embeddedGlobalsObject': js.js("init"), |
| 298 'holdersList': new js.ArrayInitializer(program.holders.map((holder) { | 342 'holdersList': new js.ArrayInitializer(program.holders.map((holder) { |
| 299 return js.js("#", holder.name); | 343 return js.js("#", holder.name); |
| 300 }).toList()), | 344 }).toList()), |
| 301 'staticStateDeclaration': new js.VariableDeclaration( | 345 'staticStateDeclaration': new js.VariableDeclaration( |
| 302 namer.staticStateHolder, allowRename: false), | 346 namer.staticStateHolder, allowRename: false), |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 624 [classReference(cls), js.quoteName(method.aliasName), | 668 [classReference(cls), js.quoteName(method.aliasName), |
| 625 classReference(cls), js.quoteName(method.name)])); | 669 classReference(cls), js.quoteName(method.name)])); |
| 626 | 670 |
| 627 } | 671 } |
| 628 } | 672 } |
| 629 } | 673 } |
| 630 } | 674 } |
| 631 return new js.Block(assignments); | 675 return new js.Block(assignments); |
| 632 } | 676 } |
| 633 | 677 |
| 678 /// Encodes the optional default values so that the runtime Function.apply | |
| 679 /// can use them. | |
| 680 js.Expression _encodeOptionalParameterDefaultValues(DartMethod method) { | |
| 681 // TODO(herhut): Replace [js.LiteralNull] with [js.ArrayHole]. | |
| 682 if (method.optionalParameterDefaultValues is List) { | |
| 683 List<ConstantValue> defaultValues = method.optionalParameterDefaultValues; | |
| 684 Iterable<js.Expression> elements = | |
| 685 defaultValues.map(generateConstantReference); | |
| 686 return new js.ArrayInitializer(elements.toList()); | |
| 687 } else { | |
| 688 Map<String, ConstantValue> defaultValues = | |
| 689 method.optionalParameterDefaultValues; | |
| 690 List<js.Property> properties = <js.Property>[]; | |
| 691 defaultValues.forEach((String name, ConstantValue value) { | |
| 692 properties.add(new js.Property(js.string(name), | |
| 693 generateConstantReference(value))); | |
| 694 }); | |
| 695 return new js.ObjectInitializer(properties); | |
| 696 } | |
| 697 } | |
| 698 | |
| 699 /// Emits the statement that installs a tear off for a method. | |
| 700 /// | |
| 701 /// Tear-offs might be passed to `Function.apply` which means that all | |
| 702 /// calling-conventions (with or without optional positional/named arguments) | |
| 703 /// are possible. As such, the tear-off needs enough information to fill in | |
| 704 /// missing parameters. | |
| 705 js.Statement emitInstallTearOff(js.Expression container, DartMethod method) { | |
| 706 List<js.Name> callNames = <js.Name>[]; | |
| 707 List<js.Name> funNames = <js.Name>[]; | |
| 708 | |
| 709 callNames.add(method.callName); | |
| 710 funNames.add(method.name); | |
| 711 for (ParameterStubMethod stubMethod in method.parameterStubs) { | |
| 712 callNames.add(stubMethod.callName); | |
| 713 funNames.add(stubMethod.name); | |
| 714 } | |
| 715 | |
| 716 js.ArrayInitializer callNameArray = | |
| 717 new js.ArrayInitializer(callNames.map(js.quoteName).toList()); | |
| 718 js.ArrayInitializer funNameArray = | |
| 719 new js.ArrayInitializer(funNames.map(js.quoteName).toList()); | |
| 720 | |
| 721 bool isIntercepted = false; | |
| 722 if (method is InstanceMethod) { | |
| 723 isIntercepted = backend.isInterceptedMethod(method.element); | |
| 724 } | |
| 725 int requiredParameterCount = 0; | |
| 726 js.Expression optionalParameterDefaultValues = new js.LiteralNull(); | |
| 727 if (method.canBeApplied) { | |
| 728 requiredParameterCount = method.requiredParameterCount; | |
| 729 optionalParameterDefaultValues = | |
| 730 _encodeOptionalParameterDefaultValues(method); | |
| 731 } | |
| 732 | |
| 733 // TODO(floitsch): this can be more efficient. | |
|
Siggi Cherem (dart-lang)
2015/07/22 20:51:28
what are you referring to by `this`?
floitsch
2015/07/29 17:27:15
removed.
The tear-off function is redirecting to a
| |
| 734 return js.js.statement(''' | |
| 735 installTearOff(#container, #getterName, #isStatic, #isIntercepted, | |
| 736 #requiredParameterCount, #optionalParameterDefaultValues, | |
| 737 #callNames, #funNames, #funType)''', | |
| 738 { | |
| 739 "container": container, | |
| 740 "getterName": js.quoteName(method.tearOffName), | |
| 741 "isStatic": new js.LiteralBool(method.isStatic), | |
| 742 "isIntercepted": new js.LiteralBool(isIntercepted), | |
| 743 "requiredParameterCount": js.number(requiredParameterCount), | |
| 744 "optionalParameterDefaultValues": optionalParameterDefaultValues, | |
| 745 "callNames": callNameArray, | |
| 746 "funNames": funNameArray, | |
| 747 "funType": method.functionType, | |
| 748 }); | |
| 749 } | |
| 750 | |
| 634 /// Emits the section that installs tear-off getters. | 751 /// Emits the section that installs tear-off getters. |
| 635 js.Statement emitInstallTearOffs(fragment) { | 752 js.Statement emitInstallTearOffs(Fragment fragment) { |
| 636 throw new UnimplementedError('emitInstallTearOffs'); | 753 List<js.Statement> inits = <js.Statement>[]; |
| 754 | |
| 755 for (Library library in fragment.libraries) { | |
| 756 for (StaticMethod method in library.statics) { | |
| 757 // TODO(floitsch): can there be anything else than a StaticDartMethod? | |
| 758 if (method is StaticDartMethod) { | |
| 759 if (method.needsTearOff) { | |
| 760 Holder holder = method.holder; | |
| 761 inits.add( | |
| 762 emitInstallTearOff(new js.VariableUse(holder.name), method)); | |
| 763 } | |
| 764 } | |
| 765 } | |
| 766 for (Class cls in library.classes) { | |
| 767 for (InstanceMethod method in cls.methods) { | |
| 768 if (method.needsTearOff) { | |
| 769 js.Expression container = js.js("#.prototype", classReference(cls)); | |
| 770 inits.add(emitInstallTearOff(container, method)); | |
| 771 } | |
| 772 } | |
| 773 } | |
| 774 } | |
| 775 return new js.Block(inits); | |
| 637 } | 776 } |
| 638 | 777 |
| 639 /// Emits the constants section. | 778 /// Emits the constants section. |
| 640 js.Statement emitConstants(Fragment fragment) { | 779 js.Statement emitConstants(Fragment fragment) { |
| 641 List<js.Statement> assignments = <js.Statement>[]; | 780 List<js.Statement> assignments = <js.Statement>[]; |
| 642 for (Constant constant in fragment.constants) { | 781 for (Constant constant in fragment.constants) { |
| 643 // TODO(floitsch): instead of just updating the constant holder, we should | 782 // TODO(floitsch): instead of just updating the constant holder, we should |
| 644 // find the constants that don't have any dependency on other constants | 783 // find the constants that don't have any dependency on other constants |
| 645 // and create an object-literal with them (and assign it to the | 784 // and create an object-literal with them (and assign it to the |
| 646 // constant-holder variable). | 785 // constant-holder variable). |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 688 } | 827 } |
| 689 | 828 |
| 690 emitEmbeddedGlobals(program) { | 829 emitEmbeddedGlobals(program) { |
| 691 throw new UnimplementedError('emitEmbeddedGlobals'); | 830 throw new UnimplementedError('emitEmbeddedGlobals'); |
| 692 } | 831 } |
| 693 | 832 |
| 694 emitNativeSupport(fragment) { | 833 emitNativeSupport(fragment) { |
| 695 throw new UnimplementedError('emitNativeSupport'); | 834 throw new UnimplementedError('emitNativeSupport'); |
| 696 } | 835 } |
| 697 } | 836 } |
| OLD | NEW |