@@ -171,32 +171,86 @@ static EncodedJSValue JSC_HOST_CALL getIterator(ExecState* execState) {
171
171
Base::getOwnPropertyNames (object, execState, propertyNames, enumerationMode);
172
172
}
173
173
174
+ void ObjCPrototype::defineNativeProperty (VM& vm, GlobalObject* globalObject, const PropertyMeta* propertyMeta) {
175
+ SymbolLoader::instance ().ensureModule (propertyMeta->topLevelModule ());
176
+
177
+ const MethodMeta* getter = (propertyMeta->hasGetter () && propertyMeta->getter ()->isAvailable ()) ? propertyMeta->getter () : nullptr ;
178
+ const MethodMeta* setter = (propertyMeta->hasSetter () && propertyMeta->setter ()->isAvailable ()) ? propertyMeta->setter () : nullptr ;
179
+
180
+ PropertyDescriptor descriptor;
181
+ descriptor.setConfigurable (true );
182
+ Strong<ObjCMethodWrapper> strongGetter;
183
+ Strong<ObjCMethodWrapper> strongSetter;
184
+ if (getter) {
185
+ MembersCollection getters = { getter };
186
+ strongGetter = ObjCMethodWrapper::create (vm, globalObject, globalObject->objCMethodWrapperStructure (), getters);
187
+ descriptor.setGetter (strongGetter.get ());
188
+ }
189
+
190
+ if (setter) {
191
+ MembersCollection setters = { setter };
192
+ strongSetter = ObjCMethodWrapper::create (vm, globalObject, globalObject->objCMethodWrapperStructure (), setters);
193
+ descriptor.setSetter (strongSetter.get ());
194
+ }
195
+
196
+ Base::defineOwnProperty (this , globalObject->globalExec (), Identifier::fromString (globalObject->globalExec (), propertyMeta->jsName ()), descriptor, false );
197
+ }
198
+
174
199
void ObjCPrototype::materializeProperties (VM& vm, GlobalObject* globalObject) {
175
- std::vector<const PropertyMeta*> properties = this ->_metadata ->instancePropertiesWithProtocols (this ->klass ());
176
-
177
- for (const PropertyMeta* propertyMeta : properties) {
178
- SymbolLoader::instance ().ensureModule (propertyMeta->topLevelModule ());
179
-
180
- const MethodMeta* getter = (propertyMeta->getter () != nullptr && propertyMeta->getter ()->isAvailable ()) ? propertyMeta->getter () : nullptr ;
181
- const MethodMeta* setter = (propertyMeta->setter () != nullptr && propertyMeta->setter ()->isAvailable ()) ? propertyMeta->setter () : nullptr ;
182
-
183
- PropertyDescriptor descriptor;
184
- descriptor.setConfigurable (true );
185
- Strong<ObjCMethodWrapper> strongGetter;
186
- Strong<ObjCMethodWrapper> strongSetter;
187
- if (getter) {
188
- MembersCollection getters = { getter };
189
- strongGetter = ObjCMethodWrapper::create (vm, globalObject, globalObject->objCMethodWrapperStructure (), getters);
190
- descriptor.setGetter (strongGetter.get ());
191
- }
200
+ // The cycle here works around an issue with incorrect public headers of some iOS system frameworks.
201
+ // In particular:
202
+ // * UIBarItem doesn't define 6 of its declared properties (enabled, image, imageInsets,
203
+ // landscapeImagePhone, landscapeImagePhoneInsets and title) but its inheritors UIBarButtonItem and
204
+ // UITabBarItem do
205
+ // * MTLRenderPassAttachmentDescriptor doesn't define 11 of its properties but it's inheritors
206
+ // MTLRenderPassDepthAttachmentDescriptor, MTLRenderPassColorAttachmentDescriptor and
207
+ // MTLRenderPassStencilAttachmentDescriptor do.
208
+ // As a result we were not providing their implementation in JS before we started looking for missing
209
+ // properties in the base class. This additional overhead increased the time spent in materializeProperties
210
+ // from ~5.3 sec to ~7.5 sec (~40%) when running TestRunner with ApiIterator test enabled in RelWithDebInfo configuration
211
+ // on an iPhone 6s device and from 3.0-3.2 to 4.4 sec (~40%) on an iPhone X
212
+
213
+ // std::chrono::time_point<std::chrono::system_clock> startTime = std::chrono::system_clock::now();
214
+ // int addedProps = 0;
215
+
216
+ const BaseClassMeta* meta = this ->metadata ();
217
+ Class klass = this ->klass ();
218
+ while (meta) {
219
+ std::vector<const PropertyMeta*> properties = meta->instancePropertiesWithProtocols (nullptr );
220
+
221
+ for (const PropertyMeta* propertyMeta : properties) {
222
+ bool shouldDefine = false ;
223
+
224
+ if (klass == this ->klass ()) {
225
+ // Property is coming from this class, define it if available
226
+ shouldDefine = propertyMeta->isAvailableInClass (klass, false );
227
+ } else {
228
+ // Property is coming from a base class, define it as our property if isn't available there, but we've got it
229
+ shouldDefine = !propertyMeta->isAvailableInClass (klass, false ) && propertyMeta->isAvailableInClass (this ->klass (), false );
230
+ // addedProps += shouldDefine ? 1 : 0;
231
+ }
192
232
193
- if (setter) {
194
- MembersCollection setters = { setter };
195
- strongSetter = ObjCMethodWrapper::create (vm, globalObject, globalObject->objCMethodWrapperStructure (), setters);
196
- descriptor.setSetter (strongSetter.get ());
233
+ if (shouldDefine) {
234
+ this ->defineNativeProperty (vm, globalObject, propertyMeta);
235
+ }
197
236
}
198
237
199
- Base::defineOwnProperty (this , globalObject->globalExec (), Identifier::fromString (globalObject->globalExec (), propertyMeta->jsName ()), descriptor, false );
238
+ if (klass == this ->klass () && meta->type () == Interface) {
239
+ meta = static_cast <const InterfaceMeta*>(meta)->baseMeta ();
240
+ klass = meta ? objc_getClass (meta->name ()) : nullptr ;
241
+ } else {
242
+ // Check only properties from the direct base class and then stop.
243
+ // All the cases that we need to fix are like that so we don't have
244
+ // to pay the additional overhead of looking intothe whole inheritance chain.
245
+ meta = nullptr ;
246
+ }
200
247
}
248
+ // std::chrono::time_point<std::chrono::system_clock> endTime = std::chrono::system_clock::now();
249
+ // double duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count() / 1000.;
250
+ // static double totalDuration = 0;
251
+ // totalDuration += duration;
252
+ //
253
+ // std::cout << "**** materializeProperties " << this->metadata()->jsName() << ": " << duration << "(Total: " << totalDuration << ") added " << addedProps << std::endl;
201
254
}
255
+
202
256
}
0 commit comments