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 |