From 3843218d57aa9d4b50e8389a048b2bebca2133bc Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 30 Jun 2022 23:31:47 +0200 Subject: [PATCH 1/7] perf: cache swizzled selector construction --- .gitignore | 5 +++ NativeScript/runtime/Interop.h | 2 ++ NativeScript/runtime/Interop.mm | 61 +++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index aa6017ed..8e3a4c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,8 @@ v8 .npmrc llvm/ + +# v8 build files... +.gclient_entries +.gclient +.cipd/ diff --git a/NativeScript/runtime/Interop.h b/NativeScript/runtime/Interop.h index b5057163..78bc31c1 100644 --- a/NativeScript/runtime/Interop.h +++ b/NativeScript/runtime/Interop.h @@ -148,6 +148,7 @@ class Interop { static bool IsNumbericType(BinaryTypeEncodingType type); static v8::Local GetInteropType(v8::Local context, BinaryTypeEncodingType type); static std::vector GetAdditionalProtocols(const TypeEncoding* typeEncoding); + static SEL GetSwizzledMethodSelector(SEL selector); template static inline void SetValue(void* dest, T value) { @@ -192,6 +193,7 @@ class Interop { static JSBlockDescriptor kJSBlockDescriptor; } JSBlock; + }; } diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index de86059c..3444bd67 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -1366,6 +1366,63 @@ return result.As(); } +SEL Interop::GetSwizzledMethodSelector(SEL selector) { + if(/* DISABLES CODE */ (false)) { + // old impl + NSString* selectorStr = NSStringFromSelector(selector); + NSString* swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; + SEL swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); + + return swizzledMethodSelector; + } + + static std::map *swizzledMethodSelectorCache = new std::map(); + +// static NSMutableDictionary *swizzledMethodSelectorCache = [[NSMutableDictionary alloc] init]; + +// auto key = [NSValue valueWithPointer:selector]; + SEL swizzledMethodSelector = NULL; + + try { + swizzledMethodSelector = swizzledMethodSelectorCache->at(selector); + } catch(const std::out_of_range&) { + // ignore... + } +// swizzledMethodSelector = static_cast([[swizzledMethodSelectorCache objectForKey:key] pointerValue]); + + if(!swizzledMethodSelector) { + NSString* selectorStr = NSStringFromSelector(selector); + NSString* swizzledMethodSelectorStr; + // todo: replace with faster string concat if that makes an impact... + swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; + + swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); + + // save to cache + swizzledMethodSelectorCache->emplace(selector, swizzledMethodSelector); +// swizzledMethodSelectorCacheAmazeballs->insert(selector, swizzledMethodSelector); +// [swizzledMethodSelectorCache setObject: [NSValue valueWithPointer:swizzledMethodSelector] forKey:key]; + } + + return swizzledMethodSelector; + +// CACHE based on strings... +// static NSMutableDictionary *cache = [[NSMutableDictionary alloc] init]; +// NSString* selectorStr = NSStringFromSelector(selector); +// NSString* swizzledMethodSelectorStr; +// +// swizzledMethodSelectorStr = [cache valueForKey:selectorStr]; +// +// if(!swizzledMethodSelectorStr) { +// swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; +// +// // save it to the cache... +// [cache setObject:swizzledMethodSelectorStr forKey:selectorStr]; +// } +// +// return NSSelectorFromString(swizzledMethodSelectorStr); +} + Local Interop::CallFunctionInternal(MethodCall& methodCall) { int initialParameterIndex = methodCall.isPrimitiveFunction_ ? 0 : 2; @@ -1401,9 +1458,7 @@ SEL selector = methodCall.selector_; if (isInstanceMethod) { - NSString* selectorStr = NSStringFromSelector(selector); - NSString* swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; - SEL swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); + SEL swizzledMethodSelector = Interop::GetSwizzledMethodSelector(selector); if ([methodCall.target_ respondsToSelector:swizzledMethodSelector]) { selector = swizzledMethodSelector; } From a0cb9ca56dd02de52ce194da45805161e06a68bd Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 30 Jun 2022 23:32:27 +0200 Subject: [PATCH 2/7] perf: inline simple helpers and pass const references --- NativeScript/runtime/Helpers.h | 24 +++++++++++++++++++----- NativeScript/runtime/Helpers.mm | 30 +++++++++++++++--------------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index e840943a..4cdab8f4 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -37,11 +37,25 @@ BaseDataWrapper* GetValue(v8::Isolate* isolate, const v8::Local& val) void DeleteValue(v8::Isolate* isolate, const v8::Local& val); std::vector> ArgsToVector(const v8::FunctionCallbackInfo& info); -bool IsString(v8::Local value); -bool IsNumber(v8::Local value); -bool IsBool(v8::Local value); -bool IsArrayOrArrayLike(v8::Isolate* isolate, v8::Local value); -void* TryGetBufferFromArrayBuffer(v8::Local value, bool& isArrayBuffer); +//bool IsString(const v8::Local& value); +//bool IsNumber(const v8::Local& value); +//bool IsBool(const v8::Local& value); + +inline bool IsString(const v8::Local& value) { + return !value.IsEmpty() && (value->IsString() || value->IsStringObject()); +} + +inline bool IsNumber(const v8::Local& value) { + return !value.IsEmpty() && (value->IsNumber() || value->IsNumberObject()); +} + +inline bool IsBool(const v8::Local& value) { + return !value.IsEmpty() && (value->IsBoolean() || value->IsBooleanObject()); +} + + +bool IsArrayOrArrayLike(v8::Isolate* isolate, const v8::Local& value); +void* TryGetBufferFromArrayBuffer(const v8::Local& value, bool& isArrayBuffer); void ExecuteOnMainThread(std::function func, bool async = true); diff --git a/NativeScript/runtime/Helpers.mm b/NativeScript/runtime/Helpers.mm index 578ded00..8aae29f8 100644 --- a/NativeScript/runtime/Helpers.mm +++ b/NativeScript/runtime/Helpers.mm @@ -336,20 +336,20 @@ } return args; } - -bool tns::IsString(Local value) { - return !value.IsEmpty() && (value->IsString() || value->IsStringObject()); -} - -bool tns::IsNumber(Local value) { - return !value.IsEmpty() && (value->IsNumber() || value->IsNumberObject()); -} - -bool tns::IsBool(Local value) { - return !value.IsEmpty() && (value->IsBoolean() || value->IsBooleanObject()); -} - -bool tns::IsArrayOrArrayLike(Isolate* isolate, Local value) { +// +//bool tns::IsString(const Local& value) { +// return !value.IsEmpty() && (value->IsString() || value->IsStringObject()); +//} +// +//bool tns::IsNumber(const Local& value) { +// return !value.IsEmpty() && (value->IsNumber() || value->IsNumberObject()); +//} +// +//bool tns::IsBool(const Local& value) { +// return !value.IsEmpty() && (value->IsBoolean() || value->IsBooleanObject()); +//} +// +bool tns::IsArrayOrArrayLike(Isolate* isolate, const Local& value) { if (value->IsArray()) { return true; } @@ -365,7 +365,7 @@ return obj->Has(context, ToV8String(isolate, "length")).FromMaybe(false); } -void* tns::TryGetBufferFromArrayBuffer(v8::Local value, bool& isArrayBuffer) { +void* tns::TryGetBufferFromArrayBuffer(const v8::Local& value, bool& isArrayBuffer) { isArrayBuffer = false; if (value.IsEmpty() || (!value->IsArrayBuffer() && !value->IsArrayBufferView())) { From 54a2400be568909e916d8c264cc57d7825d85cc3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 1 Jul 2022 00:00:26 +0200 Subject: [PATCH 3/7] perf: use robin_hood map for swizzled selector cache --- NativeScript/runtime/Interop.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index 3444bd67..46b53cb8 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -18,6 +18,7 @@ #include "SymbolIterator.h" #include "UnmanagedType.h" #include "OneByteStringResource.h" +#include "robin_hood.h" using namespace v8; @@ -1376,7 +1377,9 @@ return swizzledMethodSelector; } - static std::map *swizzledMethodSelectorCache = new std::map(); + static robin_hood::unordered_map *swizzledMethodSelectorCache = new robin_hood::unordered_map(); + +// static std::map *swizzledMethodSelectorCache = new std::map(); // static NSMutableDictionary *swizzledMethodSelectorCache = [[NSMutableDictionary alloc] init]; From ed069cebbbb2bd13d7cb0de8a764d3568ca6689e Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 1 Jul 2022 00:01:05 +0200 Subject: [PATCH 4/7] perf: faster swizzled method selector lookup Co-Authored-By: Eduardo Speroni --- NativeScript/runtime/Interop.mm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index 46b53cb8..5ea49056 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -1394,12 +1394,14 @@ // swizzledMethodSelector = static_cast([[swizzledMethodSelectorCache objectForKey:key] pointerValue]); if(!swizzledMethodSelector) { - NSString* selectorStr = NSStringFromSelector(selector); - NSString* swizzledMethodSelectorStr; + swizzledMethodSelector = sel_registerName((Constants::SwizzledPrefix + std::string(sel_getName(selector))).c_str()); + +// NSString* selectorStr = NSStringFromSelector(selector); +// NSString* swizzledMethodSelectorStr; // todo: replace with faster string concat if that makes an impact... - swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; +// swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; - swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); +// swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); // save to cache swizzledMethodSelectorCache->emplace(selector, swizzledMethodSelector); From 707faf2dd8194f12068e1580eccf8530db88ae0b Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 1 Jul 2022 00:09:02 +0200 Subject: [PATCH 5/7] chore(release): 8.3.1-alpha.1 --- NativeScript/NativeScript-Prefix.pch | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NativeScript/NativeScript-Prefix.pch b/NativeScript/NativeScript-Prefix.pch index 2d5e9175..a7fc6edd 100644 --- a/NativeScript/NativeScript-Prefix.pch +++ b/NativeScript/NativeScript-Prefix.pch @@ -1,7 +1,7 @@ #ifndef NativeScript_Prefix_pch #define NativeScript_Prefix_pch -#define NATIVESCRIPT_VERSION "8.3.1-alpha.0" +#define NATIVESCRIPT_VERSION "8.3.1-alpha.1" #ifdef DEBUG #define SIZEOF_OFF_T 8 diff --git a/package.json b/package.json index 80e7586d..f64a5e7c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@nativescript/ios", "description": "NativeScript Runtime for iOS", - "version": "8.3.1-alpha.0", + "version": "8.3.1-alpha.1", "keywords": [ "NativeScript", "iOS", From 73bbf61f2bfb10410bc1524e9fefccdb9d2b8abe Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 1 Jul 2022 23:46:39 +0200 Subject: [PATCH 6/7] chore: remove commented out code --- NativeScript/runtime/Interop.mm | 45 ++------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index 5ea49056..53bb1adc 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -1368,22 +1368,8 @@ } SEL Interop::GetSwizzledMethodSelector(SEL selector) { - if(/* DISABLES CODE */ (false)) { - // old impl - NSString* selectorStr = NSStringFromSelector(selector); - NSString* swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; - SEL swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); - - return swizzledMethodSelector; - } - static robin_hood::unordered_map *swizzledMethodSelectorCache = new robin_hood::unordered_map(); - -// static std::map *swizzledMethodSelectorCache = new std::map(); - -// static NSMutableDictionary *swizzledMethodSelectorCache = [[NSMutableDictionary alloc] init]; - -// auto key = [NSValue valueWithPointer:selector]; + SEL swizzledMethodSelector = NULL; try { @@ -1391,41 +1377,14 @@ } catch(const std::out_of_range&) { // ignore... } -// swizzledMethodSelector = static_cast([[swizzledMethodSelectorCache objectForKey:key] pointerValue]); - + if(!swizzledMethodSelector) { swizzledMethodSelector = sel_registerName((Constants::SwizzledPrefix + std::string(sel_getName(selector))).c_str()); - -// NSString* selectorStr = NSStringFromSelector(selector); -// NSString* swizzledMethodSelectorStr; - // todo: replace with faster string concat if that makes an impact... -// swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; - -// swizzledMethodSelector = NSSelectorFromString(swizzledMethodSelectorStr); - // save to cache swizzledMethodSelectorCache->emplace(selector, swizzledMethodSelector); -// swizzledMethodSelectorCacheAmazeballs->insert(selector, swizzledMethodSelector); -// [swizzledMethodSelectorCache setObject: [NSValue valueWithPointer:swizzledMethodSelector] forKey:key]; } return swizzledMethodSelector; - -// CACHE based on strings... -// static NSMutableDictionary *cache = [[NSMutableDictionary alloc] init]; -// NSString* selectorStr = NSStringFromSelector(selector); -// NSString* swizzledMethodSelectorStr; -// -// swizzledMethodSelectorStr = [cache valueForKey:selectorStr]; -// -// if(!swizzledMethodSelectorStr) { -// swizzledMethodSelectorStr = [NSString stringWithFormat:@"%s%@", Constants::SwizzledPrefix.c_str(), selectorStr]; -// -// // save it to the cache... -// [cache setObject:swizzledMethodSelectorStr forKey:selectorStr]; -// } -// -// return NSSelectorFromString(swizzledMethodSelectorStr); } Local Interop::CallFunctionInternal(MethodCall& methodCall) { From 3dff59ace35e5d059e77c862d59fa6106c7d6ab9 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 1 Jul 2022 23:47:24 +0200 Subject: [PATCH 7/7] chore: remove commented out code --- NativeScript/runtime/Helpers.h | 4 ---- NativeScript/runtime/Helpers.mm | 14 +------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index 4cdab8f4..f614bd9d 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -37,10 +37,6 @@ BaseDataWrapper* GetValue(v8::Isolate* isolate, const v8::Local& val) void DeleteValue(v8::Isolate* isolate, const v8::Local& val); std::vector> ArgsToVector(const v8::FunctionCallbackInfo& info); -//bool IsString(const v8::Local& value); -//bool IsNumber(const v8::Local& value); -//bool IsBool(const v8::Local& value); - inline bool IsString(const v8::Local& value) { return !value.IsEmpty() && (value->IsString() || value->IsStringObject()); } diff --git a/NativeScript/runtime/Helpers.mm b/NativeScript/runtime/Helpers.mm index 8aae29f8..0dd1d59f 100644 --- a/NativeScript/runtime/Helpers.mm +++ b/NativeScript/runtime/Helpers.mm @@ -336,19 +336,7 @@ } return args; } -// -//bool tns::IsString(const Local& value) { -// return !value.IsEmpty() && (value->IsString() || value->IsStringObject()); -//} -// -//bool tns::IsNumber(const Local& value) { -// return !value.IsEmpty() && (value->IsNumber() || value->IsNumberObject()); -//} -// -//bool tns::IsBool(const Local& value) { -// return !value.IsEmpty() && (value->IsBoolean() || value->IsBooleanObject()); -//} -// + bool tns::IsArrayOrArrayLike(Isolate* isolate, const Local& value) { if (value->IsArray()) { return true;