diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0a5aa548..f63ea5f14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,9 @@ jobs: - name: Check FFI backend boundaries run: npm run check:ffi-boundaries + - name: Test React Native package + run: npm run test:react-native + - name: Download V8 run: ./scripts/download_v8.sh diff --git a/NativeScript/CMakeLists.txt b/NativeScript/CMakeLists.txt index 518bf735a..b8748ce41 100644 --- a/NativeScript/CMakeLists.txt +++ b/NativeScript/CMakeLists.txt @@ -309,7 +309,6 @@ if(ENABLE_JS_RUNTIME) runtime/apple/modules/worker/MessageV8.cpp runtime/apple/modules/worker/ConcurrentQueue.cpp runtime/apple/modules/worker/WorkerImpl.mm - runtime/apple/modules/worker/WorkerImpl.mm runtime/apple/modules/module/ModuleInternal.cpp runtime/apple/modules/node/Node.cpp runtime/apple/modules/node/FS.cpp diff --git a/NativeScript/ffi/jni/napi/callbackhandlers/CallbackHandlers.cpp b/NativeScript/ffi/jni/napi/callbackhandlers/CallbackHandlers.cpp index ac74a4916..8d1ed0bbc 100644 --- a/NativeScript/ffi/jni/napi/callbackhandlers/CallbackHandlers.cpp +++ b/NativeScript/ffi/jni/napi/callbackhandlers/CallbackHandlers.cpp @@ -461,7 +461,7 @@ bool CallbackHandlers::RegisterInstance(napi_env env, napi_value jsObject, int javaObjectID = objectManager->GenerateNewObjectID(); - objectManager->Link(jsObject, javaObjectID, nullptr); + objectManager->Link(jsObject, javaObjectID); // resolve constructor auto mi = MethodCache::ResolveConstructorSignature(env, argWrapper, fullClassName, @@ -514,8 +514,6 @@ bool CallbackHandlers::RegisterInstance(napi_env env, napi_value jsObject, success = !localInstance.IsNull(); if (success) { - jclass instanceClass = jEnv.FindClass(fullClassName); - objectManager->SetJavaClass(jsObject, instanceClass); *jsThisProxy = objectManager->GetOrCreateProxy(javaObjectID, jsObject); } else { DEBUG_WRITE_FORCE("RegisterInstance failed with null new instance class: %s", @@ -1245,18 +1243,21 @@ void CallbackHandlers::InitChoreographer() { } void CallbackHandlers::RemoveEnvEntries(napi_env env) { - for (auto &item: cache_) { - if (item.second.env_ == env) { - cache_.erase(item.first); + for (auto it = cache_.begin(); it != cache_.end();) { + if (it->second.env_ == env) { + it = cache_.erase(it); + } else { + ++it; } } - for (auto &item: frameCallbackCache_) { - if (item.second.env == env) { - frameCallbackCache_.erase(item.first); + for (auto it = frameCallbackCache_.begin(); it != frameCallbackCache_.end();) { + if (it->second.env == env) { + it = frameCallbackCache_.erase(it); + } else { + ++it; } } - } // Worker @@ -1922,4 +1923,4 @@ jmethodID CallbackHandlers::WORKER_SCOPE_CLOSE_METHOD_ID = nullptr; NumericCasts CallbackHandlers::castFunctions; ArrayElementAccessor CallbackHandlers::arrayElementAccessor; -FieldAccessor CallbackHandlers::fieldAccessor; \ No newline at end of file +FieldAccessor CallbackHandlers::fieldAccessor; diff --git a/NativeScript/ffi/jni/napi/conversion/JsArgConverter.cpp b/NativeScript/ffi/jni/napi/conversion/JsArgConverter.cpp index ec025b17f..bc078c47f 100644 --- a/NativeScript/ffi/jni/napi/conversion/JsArgConverter.cpp +++ b/NativeScript/ffi/jni/napi/conversion/JsArgConverter.cpp @@ -279,7 +279,7 @@ bool JsArgConverter::ConvertArg(napi_env env, napi_value arg, int index) { success = !obj.IsNull(); if (success) { - SetConvertedObject(index, obj.Move(), obj.IsGlobal()); + SetConvertedObject(index, obj.Move(), false); } else { if (napi_util::is_number_object(env, arg)) { success = ConvertJavaScriptNumber(env, arg, index, true); @@ -717,16 +717,9 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool &offset); } - jobject directBuffer; - - if (isDataView || isTypedArray) { - directBuffer =jEnv.NewDirectByteBuffer(static_cast(data) + offset, length); - } else { - directBuffer = jEnv.NewDirectByteBuffer(static_cast(data), length); - } - - - auto directBufferClazz = jEnv.GetObjectClass(directBuffer); + JniLocalRef directBuffer(jEnv.NewDirectByteBuffer( + static_cast(data) + (isDataView || isTypedArray ? offset : 0), length)); + JniLocalRef directBufferClazz(jEnv.GetObjectClass(directBuffer)); auto byteOrderId = BYTE_ORDER_METHOD_ID; @@ -736,7 +729,7 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool BYTE_ORDER_METHOD_ID = byteOrderId; } - auto byteOrderClazz = jEnv.FindClass("java/nio/ByteOrder"); + JniLocalRef byteOrderClazz(jEnv.FindClass("java/nio/ByteOrder")); auto byteOrderEnumId = BYTE_ORDER_ENUM_ID; @@ -747,14 +740,13 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool BYTE_ORDER_ENUM_ID = byteOrderEnumId; } - auto nativeByteOrder = jEnv.CallStaticObjectMethodA(byteOrderClazz, - byteOrderEnumId, - nullptr); - - directBuffer = jEnv.CallObjectMethod(directBuffer, byteOrderId, - nativeByteOrder); + JniLocalRef nativeByteOrder(jEnv.CallStaticObjectMethodA(byteOrderClazz, + byteOrderEnumId, + nullptr)); + directBuffer = JniLocalRef(jEnv.CallObjectMethod(directBuffer, byteOrderId, + static_cast(nativeByteOrder))); - jobject buffer; + JniLocalRef buffer; if (bufferCastType == BufferCastType::Short) { auto id = AS_SHORT_BUFFER; @@ -764,7 +756,7 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool AS_SHORT_BUFFER = id; } - buffer = jEnv.CallObjectMethodA(directBuffer, id, nullptr); + buffer = JniLocalRef(jEnv.CallObjectMethodA(directBuffer, id, nullptr)); } else if (bufferCastType == BufferCastType::Int) { auto id = AS_INT_BUFFER; @@ -773,7 +765,7 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool "()Ljava/nio/IntBuffer;"); AS_INT_BUFFER = id; } - buffer = jEnv.CallObjectMethodA(directBuffer, id, nullptr); + buffer = JniLocalRef(jEnv.CallObjectMethodA(directBuffer, id, nullptr)); } else if (bufferCastType == BufferCastType::Long) { auto id = AS_LONG_BUFFER; @@ -783,7 +775,7 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool AS_LONG_BUFFER = id; } - buffer = jEnv.CallObjectMethodA(directBuffer, id, nullptr); + buffer = JniLocalRef(jEnv.CallObjectMethodA(directBuffer, id, nullptr)); } else if (bufferCastType == BufferCastType::Float) { auto id = AS_FLOAT_BUFFER; @@ -793,7 +785,7 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool AS_FLOAT_BUFFER = id; } - buffer = jEnv.CallObjectMethodA(directBuffer, id, nullptr); + buffer = JniLocalRef(jEnv.CallObjectMethodA(directBuffer, id, nullptr)); } else if (bufferCastType == BufferCastType::Double) { auto id = AS_DOUBLE_BUFFER; @@ -802,21 +794,17 @@ JniLocalRef JsArgConverter::GetByteBuffer(napi_env env, napi_value object, bool "()Ljava/nio/DoubleBuffer;"); AS_DOUBLE_BUFFER = id; } - buffer = jEnv.CallObjectMethodA(directBuffer, id, nullptr); + buffer = JniLocalRef(jEnv.CallObjectMethodA(directBuffer, id, nullptr)); } else { - buffer = directBuffer; + buffer = std::move(directBuffer); } - buffer = jEnv.NewGlobalRef(buffer); - ObjectManager *objectManager = Runtime::GetRuntime(env)->GetObjectManager(); int id = objectManager->GetOrCreateObjectId(buffer); - auto clazz = jEnv.GetObjectClass(buffer); - ObjectManager::MarkObject(env, object); - objectManager->Link(object, id, clazz); + objectManager->Link(object, id); return objectManager->GetJavaObjectByJsObject(object); } @@ -827,4 +815,4 @@ jmethodID JsArgConverter::AS_SHORT_BUFFER = nullptr; jmethodID JsArgConverter::AS_LONG_BUFFER = nullptr; jmethodID JsArgConverter::AS_FLOAT_BUFFER = nullptr; jmethodID JsArgConverter::AS_INT_BUFFER = nullptr; -jmethodID JsArgConverter::AS_DOUBLE_BUFFER = nullptr; \ No newline at end of file +jmethodID JsArgConverter::AS_DOUBLE_BUFFER = nullptr; diff --git a/NativeScript/ffi/jni/napi/conversion/JsArgToArrayConverter.cpp b/NativeScript/ffi/jni/napi/conversion/JsArgToArrayConverter.cpp index f71940a2b..2548c1339 100644 --- a/NativeScript/ffi/jni/napi/conversion/JsArgToArrayConverter.cpp +++ b/NativeScript/ffi/jni/napi/conversion/JsArgToArrayConverter.cpp @@ -296,7 +296,7 @@ bool JsArgToArrayConverter::ConvertArg(napi_env env, napi_value arg, int index) success = !obj.IsNull(); if (success) { - SetConvertedObject(jEnv, index, obj.Move(), obj.IsGlobal()); + SetConvertedObject(jEnv, index, obj.Move(), false); } else { if (napi_util::is_number_object(env, arg)) { napi_value numValue = napi_util::valueOf(env, arg); @@ -426,4 +426,4 @@ JsArgToArrayConverter::~JsArgToArrayConverter() { } } -jclass JsArgToArrayConverter::JAVA_LANG_OBJECT_CLASS = nullptr; \ No newline at end of file +jclass JsArgToArrayConverter::JAVA_LANG_OBJECT_CLASS = nullptr; diff --git a/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.cpp b/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.cpp index df11c4901..966164c4c 100644 --- a/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.cpp +++ b/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.cpp @@ -9,7 +9,7 @@ using namespace std; using namespace tns; NativeScriptException::NativeScriptException(JEnv& env) - : m_javascriptException(nullptr) { + : m_javascriptException(nullptr), m_napiEnv(nullptr) { jthrowable thrw = env.ExceptionOccurred(); m_javaException = JniLocalRef(thrw); env.ExceptionClear(); @@ -17,26 +17,42 @@ NativeScriptException::NativeScriptException(JEnv& env) } NativeScriptException::NativeScriptException(const string& message) - : m_javascriptException(nullptr), m_javaException(JniLocalRef()), m_message(message) { + : m_javascriptException(nullptr), m_napiEnv(nullptr), m_javaException(JniLocalRef()), m_message(message) { DEBUG_WRITE("%s", m_message.c_str()); } NativeScriptException::NativeScriptException(const string& message, const string& stackTrace) - : m_javascriptException(nullptr), m_javaException(JniLocalRef()), m_message(message), m_stackTrace(stackTrace) { + : m_javascriptException(nullptr), m_napiEnv(nullptr), m_javaException(JniLocalRef()), m_message(message), m_stackTrace(stackTrace) { DEBUG_WRITE("%s, %s ", m_message.c_str(), m_stackTrace.c_str()); } NativeScriptException::NativeScriptException(napi_env env, napi_value error, const string& message) - : m_javaException(JniLocalRef()) { - m_javascriptException = nullptr; + : m_javascriptException(nullptr), m_napiEnv(env), m_javaException(JniLocalRef()) { napi_create_reference(env, error, 1, &m_javascriptException); m_message = GetErrorMessage(env, error, message); m_stackTrace = GetErrorStackTrace(env, error); m_fullMessage = GetFullMessage(env, error, m_message); } +NativeScriptException::NativeScriptException(NativeScriptException&& other) noexcept + : m_javascriptException(other.m_javascriptException), + m_napiEnv(other.m_napiEnv), + m_javaException(std::move(other.m_javaException)), + m_message(std::move(other.m_message)), + m_stackTrace(std::move(other.m_stackTrace)), + m_fullMessage(std::move(other.m_fullMessage)) { + other.m_javascriptException = nullptr; + other.m_napiEnv = nullptr; +} + +NativeScriptException::~NativeScriptException() { + if (m_javascriptException != nullptr && m_napiEnv != nullptr) { + napi_delete_reference(m_napiEnv, m_javascriptException); + } +} + void NativeScriptException::ReThrowToNapi(napi_env env) { napi_value errObj; @@ -61,6 +77,12 @@ void NativeScriptException::ReThrowToNapi(napi_env env) { napi_throw(env, errObj); + if (m_javascriptException != nullptr) { + napi_delete_reference(env, m_javascriptException); + m_javascriptException = nullptr; + m_napiEnv = nullptr; + } + // JSLeave } @@ -69,6 +91,7 @@ void NativeScriptException::ReThrowToJava(napi_env env) { NapiScope scope(env); } jthrowable ex = nullptr; + bool transferredJavascriptException = false; JEnv jEnv; if (!m_javaException.IsNull()) { @@ -98,6 +121,7 @@ void NativeScriptException::ReThrowToJava(napi_env env) { if (ex == nullptr) { ex = static_cast(jEnv.NewObject(NATIVESCRIPTEXCEPTION_CLASS, NATIVESCRIPTEXCEPTION_JSVALUE_CTOR_ID, (jstring)msg, (jstring)stackTrace, reinterpret_cast(m_javascriptException))); + transferredJavascriptException = true; } else { auto objectManager = Runtime::GetRuntime(env)->GetObjectManager(); auto excClassName = objectManager->GetClassName(ex); @@ -114,6 +138,14 @@ void NativeScriptException::ReThrowToJava(napi_env env) { ex = static_cast(jEnv.NewObject(NATIVESCRIPTEXCEPTION_CLASS, NATIVESCRIPTEXCEPTION_JSVALUE_CTOR_ID, (jstring)msg, (jstring)nullptr, (jlong)0)); } jEnv.Throw(ex); + + if (m_javascriptException != nullptr) { + if (!transferredJavascriptException && m_napiEnv != nullptr) { + napi_delete_reference(m_napiEnv, m_javascriptException); + } + m_javascriptException = nullptr; + m_napiEnv = nullptr; + } } void NativeScriptException::Init() { @@ -183,6 +215,7 @@ napi_value NativeScriptException::WrapJavaToJsException(napi_env env) { auto pv = reinterpret_cast(addr); napi_get_reference_value(env, pv, &errObj); napi_delete_reference(env, pv); + jenv.SetLongField(m_javaException, fieldID, 0); } else { errObj = GetJavaExceptionFromEnv(env, m_javaException, jenv); } @@ -369,4 +402,4 @@ jclass NativeScriptException::NATIVESCRIPTEXCEPTION_CLASS = nullptr; jmethodID NativeScriptException::NATIVESCRIPTEXCEPTION_JSVALUE_CTOR_ID = nullptr; jmethodID NativeScriptException::NATIVESCRIPTEXCEPTION_THROWABLE_CTOR_ID = nullptr; jmethodID NativeScriptException::NATIVESCRIPTEXCEPTION_GET_MESSAGE_METHOD_ID = nullptr; -jmethodID NativeScriptException::NATIVESCRIPTEXCEPTION_GET_STACK_TRACE_AS_STRING_METHOD_ID = nullptr; \ No newline at end of file +jmethodID NativeScriptException::NATIVESCRIPTEXCEPTION_GET_STACK_TRACE_AS_STRING_METHOD_ID = nullptr; diff --git a/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.h b/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.h index e7f82e22e..3a93db615 100644 --- a/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.h +++ b/NativeScript/ffi/jni/napi/exceptions/NativeScriptException.h @@ -29,6 +29,11 @@ class NativeScriptException { */ NativeScriptException(napi_env env, napi_value error, const std::string& message = ""); + NativeScriptException(const NativeScriptException&) = delete; + NativeScriptException& operator=(const NativeScriptException&) = delete; + NativeScriptException(NativeScriptException&& other) noexcept; + ~NativeScriptException(); + void ReThrowToNapi(napi_env env); void ReThrowToJava(napi_env env); @@ -86,6 +91,7 @@ class NativeScriptException { std::string GetFullMessage(napi_env env, napi_value error, const std::string& jsExceptionMessage); napi_ref m_javascriptException; + napi_env m_napiEnv; JniLocalRef m_javaException; std::string m_message; std::string m_stackTrace; @@ -103,4 +109,4 @@ class NativeScriptException { }; } -#endif /* NATIVESCRIPTEXCEPTION_H_ */ \ No newline at end of file +#endif /* NATIVESCRIPTEXCEPTION_H_ */ diff --git a/NativeScript/ffi/jni/napi/jni/JniLocalRef.h b/NativeScript/ffi/jni/napi/jni/JniLocalRef.h index f950740cf..069864339 100644 --- a/NativeScript/ffi/jni/napi/jni/JniLocalRef.h +++ b/NativeScript/ffi/jni/napi/jni/JniLocalRef.h @@ -8,19 +8,19 @@ namespace tns { class JniLocalRef { public: JniLocalRef() - : m_obj(nullptr), m_isGlobal(false) { + : m_obj(nullptr) { } - JniLocalRef(jobject obj, bool isGlobal = false) - : m_obj(obj), m_isGlobal(isGlobal) { + JniLocalRef(jobject obj) + : m_obj(obj) { } JniLocalRef(jclass obj) - : m_obj(obj), m_isGlobal(false) { + : m_obj(obj) { } JniLocalRef(JniLocalRef&& rhs) - : m_obj(rhs.m_obj), m_isGlobal(rhs.m_isGlobal) { + : m_obj(rhs.m_obj) { rhs.m_obj = nullptr; } @@ -28,10 +28,6 @@ class JniLocalRef { return m_obj == nullptr; } - bool IsGlobal() const { - return m_isGlobal; - } - jobject Move() { auto value = m_obj; m_obj = nullptr; @@ -39,8 +35,14 @@ class JniLocalRef { } JniLocalRef& operator=(JniLocalRef&& rhs) { + if (this == &rhs) { + return *this; + } + if (m_obj != nullptr) { + JEnv env; + env.DeleteLocalRef(m_obj); + } m_obj = rhs.m_obj; - m_isGlobal = rhs.m_isGlobal; rhs.m_obj = nullptr; return *this; } @@ -107,7 +109,7 @@ class JniLocalRef { } ~JniLocalRef() { - if ((m_obj != nullptr) && !m_isGlobal) { + if (m_obj != nullptr) { JEnv env; env.DeleteLocalRef(m_obj); } @@ -115,7 +117,6 @@ class JniLocalRef { private: jobject m_obj; - bool m_isGlobal; }; } diff --git a/NativeScript/ffi/jni/napi/metadata/MetadataNode.cpp b/NativeScript/ffi/jni/napi/metadata/MetadataNode.cpp index 8dacf23ab..bfe667475 100644 --- a/NativeScript/ffi/jni/napi/metadata/MetadataNode.cpp +++ b/NativeScript/ffi/jni/napi/metadata/MetadataNode.cpp @@ -1122,6 +1122,7 @@ std::vector MetadataNode::SetClassMembersFro if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); + MetadataNode::GetMetadataNodeCache(env)->methodCallbackData.push_back(callbackData); napi_value method; napi_create_function(env, methodName.c_str(), methodName.size(), MethodCallback, @@ -1151,6 +1152,7 @@ std::vector MetadataNode::SetClassMembersFro if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); + MetadataNode::GetMetadataNodeCache(env)->methodCallbackData.push_back(callbackData); napi_value method; napi_create_function(env, methodName.c_str(), methodName.size(), MethodCallback, callbackData, &method); @@ -1218,6 +1220,7 @@ std::vector MetadataNode::SetClassMembersFro auto propertyInfo = new PropertyCallbackData(propertyName, getterMethodName, setterMethodName); + MetadataNode::GetMetadataNodeCache(env)->propertyCallbackData.push_back(propertyInfo); napi_util::define_property(env, prototype, propertyName.c_str(), nullptr, PropertyAccessorGetterCallback, PropertyAccessorSetterCallback, propertyInfo); @@ -1238,6 +1241,7 @@ std::vector MetadataNode::SetClassMembersFro auto &methodName = entry.getName(); if (methodName != lastMethodName) { callbackData = new MethodCallbackData(this); + MetadataNode::GetMetadataNodeCache(env)->methodCallbackData.push_back(callbackData); napi_value method; napi_create_function(env, methodName.c_str(), methodName.size(), MethodCallback, callbackData, &method); @@ -1345,6 +1349,7 @@ std::vector MetadataNode::SetInstanceMembers if (entry.name != lastMethodName) { entry.type = NodeType::Method; callbackData = new MethodCallbackData(this); + MetadataNode::GetMetadataNodeCache(env)->methodCallbackData.push_back(callbackData); instanceMethodData.push_back(callbackData); instanceMethodsCallbackData.push_back(callbackData); @@ -1427,11 +1432,6 @@ napi_value MetadataNode::GetConstructorFunctionInternal(napi_env env, MetadataTr } if (itFound != cache->CtorFuncCache.end()) { -#ifndef __JSC__ - for (auto data: itFound->second.instanceMethodCallbacks) { - delete data; - } -#endif itFound->second.instanceMethodCallbacks.clear(); if (itFound->second.constructorFunction != nullptr) { napi_delete_reference(env, itFound->second.constructorFunction); @@ -1888,13 +1888,15 @@ napi_value MetadataNode::ExtendMethodCallback(napi_env env, napi_callback_info i auto baseClassCtorFunction = node->GetConstructorFunction(env); + auto extendedClassCallbackData = new ExtendedClassCallbackData( + node, extendNameAndLocation, napi_util::make_ref(env, implementationObject), + fullClassName); + GetMetadataNodeCache(env)->extendedClassCallbackData.push_back(extendedClassCallbackData); + napi_value extendFuncCtor; napi_define_class(env, fullExtendedName.c_str(), NAPI_AUTO_LENGTH, MetadataNode::ExtendedClassConstructorCallback, - new ExtendedClassCallbackData(node, extendNameAndLocation, - napi_util::make_ref(env, - implementationObject), - fullClassName), 0, nullptr, + extendedClassCallbackData, 0, nullptr, &extendFuncCtor); napi_value extendFuncPrototype = napi_util::get_prototype(env, extendFuncCtor); ObjectManager::MarkObject(env, extendFuncPrototype); @@ -2119,6 +2121,7 @@ void MetadataNode::SetMissingBaseMethods( continue; } + callbackData = nullptr; for (auto data: instanceMethodData) { if (data->candidates.front().name == methodName) { callbackData = data; @@ -2128,6 +2131,7 @@ void MetadataNode::SetMissingBaseMethods( if (callbackData == nullptr) { callbackData = new MethodCallbackData(this); + MetadataNode::GetMetadataNodeCache(env)->methodCallbackData.push_back(callbackData); napi_value proto = napi_util::get_prototype(env, constructor); napi_value method; napi_create_function(env, methodName.c_str(), NAPI_AUTO_LENGTH, MethodCallback, @@ -2159,25 +2163,41 @@ void MetadataNode::onDisposeEnv(napi_env env) { auto it = s_metadata_node_cache.Get(env); if (it != nullptr) { for (const auto &entry: it->CtorFuncCache) { - if (entry.second.constructorFunction == nullptr) { + if (entry.second.constructorFunction != nullptr) { napi_delete_reference(env, entry.second.constructorFunction); } - for (const auto data: entry.second.instanceMethodCallbacks) { - delete data; - } } it->CtorFuncCache.clear(); for (const auto &entry: it->ExtendedCtorFuncCache) { - if (entry.second.extendedCtorFunction == nullptr) { + if (entry.second.extendedCtorFunction != nullptr) { napi_delete_reference(env, entry.second.extendedCtorFunction); } } it->ExtendedCtorFuncCache.clear(); + for (const auto data: it->methodCallbackData) { + delete data; + } + it->methodCallbackData.clear(); + for (const auto &entry: it->fieldCallbackData) { delete entry; } + it->fieldCallbackData.clear(); + + for (const auto data: it->propertyCallbackData) { + delete data; + } + it->propertyCallbackData.clear(); + + for (const auto data: it->extendedClassCallbackData) { + if (data->implementationObject != nullptr) { + napi_delete_reference(env, data->implementationObject); + } + delete data; + } + it->extendedClassCallbackData.clear(); } s_metadata_node_cache.Remove(env); delete it; diff --git a/NativeScript/ffi/jni/napi/metadata/MetadataNode.h b/NativeScript/ffi/jni/napi/metadata/MetadataNode.h index bdb6537c7..2813c2ee1 100644 --- a/NativeScript/ffi/jni/napi/metadata/MetadataNode.h +++ b/NativeScript/ffi/jni/napi/metadata/MetadataNode.h @@ -294,11 +294,14 @@ class MetadataNode { struct MetadataNodeCache { robin_hood::unordered_map CtorFuncCache; robin_hood::unordered_map ExtendedCtorFuncCache; + std::vector methodCallbackData; std::vector fieldCallbackData; + std::vector propertyCallbackData; + std::vector extendedClassCallbackData; }; static bool s_profilerEnabled; }; -#endif //METADATA_NODE_H \ No newline at end of file +#endif //METADATA_NODE_H diff --git a/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.cpp b/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.cpp index d60735381..7917bfd9d 100644 --- a/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.cpp +++ b/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.cpp @@ -144,7 +144,7 @@ napi_value ObjectManager::GetOrCreateProxy(jint javaObjectID, napi_value instanc napi_has_named_property(m_env, instance, "__is__javaArray", &is_array); - auto data = new JSInstanceInfo(javaObjectID, nullptr); + auto data = new JSInstanceInfo(javaObjectID); if (is_array) { napi_value global; @@ -177,7 +177,7 @@ napi_value ObjectManager::GetOrCreateProxy(jint javaObjectID, napi_value instanc } - auto data = new JSInstanceInfo(javaObjectID, nullptr); + auto data = new JSInstanceInfo(javaObjectID); napi_value external; napi_create_external(m_env, data, JSObjectProxyFinalizerCallback, data, &external); @@ -228,7 +228,7 @@ JniLocalRef ObjectManager::GetJavaObjectByJsObject(napi_value object, int *objec *objectId = javaObjectId; } - if (javaObjectId != -1) return {GetJavaObjectByID(javaObjectId), true}; + if (javaObjectId != -1) return GetJavaObjectByID(javaObjectId); return {}; } @@ -244,7 +244,7 @@ JniLocalRef ObjectManager::GetJavaObjectByJsObjectFast(napi_value object) { if (data) { auto info = reinterpret_cast(data); - return {GetJavaObjectByID(info->JavaObjectID), true}; + return GetJavaObjectByID(info->JavaObjectID); } return GetJavaObjectByJsObject(object); @@ -299,8 +299,9 @@ bool ObjectManager::IsRuntimeJsObject(napi_value object) { return result; } -jweak ObjectManager::GetJavaObjectByID(uint32_t javaObjectID) { - return m_cache(javaObjectID); +JniLocalRef ObjectManager::GetJavaObjectByID(uint32_t javaObjectID) { + JEnv env; + return JniLocalRef(env.NewLocalRef(m_cache(javaObjectID))); } jobject ObjectManager::GetJavaObjectByIDImpl(uint32_t javaObjectID) { @@ -314,18 +315,6 @@ void ObjectManager::UpdateCache(int objectID, jobject obj) { m_cache.update(objectID, obj); } -jclass ObjectManager::GetJavaClass(napi_value value) { - JSInstanceInfo *jsInfo = GetJSInstanceInfo(value); - jclass clazz = jsInfo->ObjectClazz; - - return clazz; -} - -void ObjectManager::SetJavaClass(napi_value value, jclass clazz) { - JSInstanceInfo *jsInfo = GetJSInstanceInfo(value); - jsInfo->ObjectClazz = clazz; -} - int ObjectManager::GetOrCreateObjectId(jobject object) { JEnv env; jint javaObjectID = env.CallIntMethod(m_javaRuntimeObject, @@ -366,9 +355,7 @@ ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const std::string &typeN napi_value proxy = nullptr; napi_value jsWrapper = node->CreateJSWrapper(m_env, this); if (jsWrapper != nullptr) { - JEnv jenv; - auto claz = jenv.FindClass(className); - Link(jsWrapper, javaObjectID, claz); + Link(jsWrapper, javaObjectID); if (node->isArray()) { napi_set_named_property(m_env, jsWrapper, "__is__javaArray", napi_util::get_true(m_env)); @@ -379,7 +366,7 @@ ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const std::string &typeN return proxy; } -void ObjectManager::Link(napi_value object, uint32_t javaObjectID, jclass clazz) { +void ObjectManager::Link(napi_value object, uint32_t javaObjectID) { if (!IsRuntimeJsObject(object)) { std::string errMsg("Trying to link invalid 'this' to a Java object"); throw NativeScriptException(errMsg); @@ -387,7 +374,7 @@ void ObjectManager::Link(napi_value object, uint32_t javaObjectID, jclass clazz) DEBUG_WRITE("Linking js object and java instance id: %d", javaObjectID); - auto jsInstanceInfo = new JSInstanceInfo(javaObjectID, clazz); + auto jsInstanceInfo = new JSInstanceInfo(javaObjectID); napi_ref objectHandle = napi_util::make_ref(m_env, object, 1); @@ -603,11 +590,14 @@ void ObjectManager::ReleaseNativeObject(napi_env env, napi_value object) { void ObjectManager::OnGarbageCollected(JNIEnv *jEnv, jintArray object_ids) { JEnv jenv(jEnv); + auto rt = Runtime::GetRuntimeUnchecked(m_env); + if (!rt || rt->is_destroying) return; + jsize length = jenv.GetArrayLength(object_ids); - int *cppArray = jenv.GetIntArrayElements(object_ids, nullptr); + jint *cppArray = jenv.GetIntArrayElements(object_ids, nullptr); + if (cppArray == nullptr) return; for (jsize i = 0; i < length; i++) { - auto rt = Runtime::GetRuntimeUnchecked(m_env); - if (rt && rt->is_destroying) return; + if (rt->is_destroying) break; int javaObjectId = cppArray[i]; auto itFound = this->m_idToObject.find(javaObjectId); if (itFound != this->m_idToObject.end()) { @@ -627,4 +617,5 @@ void ObjectManager::OnGarbageCollected(JNIEnv *jEnv, jintArray object_ids) { } } + jEnv->ReleaseIntArrayElements(object_ids, cppArray, JNI_ABORT); } diff --git a/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.h b/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.h index 4c5244918..52ca46a94 100644 --- a/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.h +++ b/NativeScript/ffi/jni/napi/objectmanager/ObjectManager.h @@ -4,7 +4,6 @@ #include "js_native_api.h" #include "JEnv.h" #include "JniLocalRef.h" -#include "JniLocalRef.h" #include "DirectBuffer.h" #include "LRUCache.h" #include @@ -31,10 +30,6 @@ namespace tns { void UpdateCache(int objectID, jobject obj); - jclass GetJavaClass(napi_value value); - - void SetJavaClass(napi_value instance, jclass clazz); - int GetOrCreateObjectId(jobject object); napi_value GetJsObjectByJavaObject(int javaObjectID); @@ -49,7 +44,7 @@ namespace tns { napi_value GetOrCreateProxyWeak(jint javaObjectID, napi_value instance); - void Link(napi_value object, uint32_t javaObjectID, jclass clazz); + void Link(napi_value object, uint32_t javaObjectID); bool CloneLink(napi_value src, napi_value dest); @@ -90,12 +85,11 @@ namespace tns { struct JSInstanceInfo { public: - JSInstanceInfo(uint32_t javaObjectID, jclass claz) - : JavaObjectID(javaObjectID), ObjectClazz(claz) { + explicit JSInstanceInfo(uint32_t javaObjectID) + : JavaObjectID(javaObjectID) { } uint32_t JavaObjectID; - jclass ObjectClazz; }; @@ -111,7 +105,7 @@ namespace tns { static void JSObjectProxyFinalizerCallback(napi_env env, void *finalizeData, void *finalizeHint); - jweak GetJavaObjectByID(uint32_t javaObjectID); + JniLocalRef GetJavaObjectByID(uint32_t javaObjectID); jobject GetJavaObjectByIDImpl(uint32_t javaObjectID); @@ -154,9 +148,7 @@ namespace tns { napi_ref m_jsObjectCtor; napi_ref m_jsObjectProxyCreator; - - napi_ref jid; }; } -#endif /* OBJECTMANAGER_H_ */ \ No newline at end of file +#endif /* OBJECTMANAGER_H_ */ diff --git a/NativeScript/ffi/objc/hermes/NativeApiJsi.mm b/NativeScript/ffi/objc/hermes/NativeApiJsi.mm index 6039fb8a4..091988a88 100644 --- a/NativeScript/ffi/objc/hermes/NativeApiJsi.mm +++ b/NativeScript/ffi/objc/hermes/NativeApiJsi.mm @@ -50,6 +50,7 @@ @protocol NativeApiClassBuilderProtocol using facebook::jsi::Function; using facebook::jsi::HostObject; using facebook::jsi::MutableBuffer; +using NativeApiNativeState = facebook::jsi::NativeState; using facebook::jsi::Object; using facebook::jsi::PropNameID; using facebook::jsi::Runtime; diff --git a/NativeScript/ffi/objc/hermes/NativeApiJsiGsd.mm b/NativeScript/ffi/objc/hermes/NativeApiJsiGsd.mm index 43ba137f9..2b2c5d53a 100644 --- a/NativeScript/ffi/objc/hermes/NativeApiJsiGsd.mm +++ b/NativeScript/ffi/objc/hermes/NativeApiJsiGsd.mm @@ -142,8 +142,8 @@ void setObject(id obj) { } // namespace (temporary close for GSD .inc) #if defined(__has_include) -#if __has_include("GeneratedGsdSignatureDispatch.inc") -#include "GeneratedGsdSignatureDispatch.inc" +#if __has_include("../shared/GeneratedGsdSignatureDispatch.inc") +#include "../shared/GeneratedGsdSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/hermes/NativeApiJsiReactNative.h b/NativeScript/ffi/objc/hermes/NativeApiJsiReactNative.h index e7619bb0a..fe315d609 100644 --- a/NativeScript/ffi/objc/hermes/NativeApiJsiReactNative.h +++ b/NativeScript/ffi/objc/hermes/NativeApiJsiReactNative.h @@ -63,7 +63,6 @@ inline NativeApiJsiConfig MakeReactNativeNativeApiJsiConfig( config.metadataPtr = metadataPtr; config.globalName = globalName; config.installGlobalSymbols = true; - config.invokeCallbacksOnNativeCallerThread = true; config.scheduler = std::make_shared( std::move(jsInvoker), std::move(uiInvoker)); return config; diff --git a/NativeScript/ffi/objc/hermes/NativeApiJsiSignatureDispatch.h b/NativeScript/ffi/objc/hermes/NativeApiJsiSignatureDispatch.h index 997e99ece..dc3a95969 100644 --- a/NativeScript/ffi/objc/hermes/NativeApiJsiSignatureDispatch.h +++ b/NativeScript/ffi/objc/hermes/NativeApiJsiSignatureDispatch.h @@ -4,8 +4,8 @@ #include "ffi/objc/shared/SignatureDispatchCore.h" #if defined(__has_include) -#if __has_include("GeneratedSignatureDispatch.inc") -#include "GeneratedSignatureDispatch.inc" +#if __has_include("../shared/GeneratedSignatureDispatch.inc") +#include "../shared/GeneratedSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSC.h b/NativeScript/ffi/objc/jsc/NativeApiJSC.h index cd03fd630..2199dd502 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSC.h +++ b/NativeScript/ffi/objc/jsc/NativeApiJSC.h @@ -11,6 +11,7 @@ using NativeApiConfig = NativeApiBackendConfig; void InstallNativeApi(JSGlobalContextRef context, const NativeApiConfig& config = NativeApiConfig{}); +void CleanupNativeApi(JSGlobalContextRef context); } // namespace nativescript diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSC.mm b/NativeScript/ffi/objc/jsc/NativeApiJSC.mm index 227af4c60..bd20cd8c6 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSC.mm +++ b/NativeScript/ffi/objc/jsc/NativeApiJSC.mm @@ -59,6 +59,12 @@ void InstallNativeApi(JSGlobalContextRef context, const NativeApiConfig& config) InstallNativeApi(runtime, config); } +void CleanupNativeApi(JSGlobalContextRef context) { + if (context != nullptr) { + engine::jscengine::releaseStateForContext(context); + } +} + } // namespace nativescript extern "C" void NativeScriptInstallNativeApi(JSGlobalContextRef context, diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSCGsd.mm b/NativeScript/ffi/objc/jsc/NativeApiJSCGsd.mm index 78c91cab2..13ee42c38 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSCGsd.mm +++ b/NativeScript/ffi/objc/jsc/NativeApiJSCGsd.mm @@ -282,8 +282,8 @@ void setObject(id obj) { } // namespace (temporary close for GSD .inc) #if defined(__has_include) -#if __has_include("GeneratedGsdSignatureDispatch.inc") -#include "GeneratedGsdSignatureDispatch.inc" +#if __has_include("../shared/GeneratedGsdSignatureDispatch.inc") +#include "../shared/GeneratedGsdSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSCHostObjects.mm b/NativeScript/ffi/objc/jsc/NativeApiJSCHostObjects.mm index 8c9f03a7a..d839e855c 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSCHostObjects.mm +++ b/NativeScript/ffi/objc/jsc/NativeApiJSCHostObjects.mm @@ -12,6 +12,47 @@ namespace jscengine { +namespace { +std::mutex& runtimeStatesMutex() { + static auto* mutex = new std::mutex(); + return *mutex; +} + +std::unordered_map>& +runtimeStates() { + static auto* states = + new std::unordered_map>(); + return *states; +} +} // namespace + +std::shared_ptr stateForContext(JSGlobalContextRef context) { + std::lock_guard lock(runtimeStatesMutex()); + auto& states = runtimeStates(); + auto it = states.find(context); + if (it != states.end()) { + return it->second; + } + auto state = std::make_shared(context); + states[context] = state; + return state; +} + +void releaseStateForContext(JSGlobalContextRef context) { + std::shared_ptr state; + { + std::lock_guard lock(runtimeStatesMutex()); + auto& states = runtimeStates(); + auto it = states.find(context); + if (it == states.end()) { + return; + } + state = std::move(it->second); + states.erase(it); + } + state->cleanup(); +} + JSClassRef hostClass(Runtime& runtime); JSClassRef functionClass(Runtime& runtime); void setFunctionPrototype(JSGlobalContextRef context, JSObjectRef function); @@ -112,7 +153,11 @@ void hostGetPropertyNames(JSContextRef, JSObjectRef object, } void hostFinalize(JSObjectRef object) { - delete static_cast(JSObjectGetPrivate(object)); + auto* holder = static_cast(JSObjectGetPrivate(object)); + if (holder != nullptr && holder->state != nullptr) { + holder->state->untrack(holder); + } + delete holder; } JSValueRef functionCall(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, @@ -139,7 +184,11 @@ JSValueRef functionCall(JSContextRef context, JSObjectRef function, JSObjectRef } void functionFinalize(JSObjectRef object) { - delete static_cast(JSObjectGetPrivate(object)); + auto* holder = static_cast(JSObjectGetPrivate(object)); + if (holder != nullptr && holder->state != nullptr) { + holder->state->untrack(holder); + } + delete holder; } JSClassRef hostClass(Runtime& runtime) { @@ -206,6 +255,11 @@ void setFunctionPrototype(JSGlobalContextRef context, JSObjectRef function) { Object Object::createFromHostObjectWithToken(Runtime& runtime, std::shared_ptr host, const void* typeToken) { auto* holder = new jscengine::HostObjectHolder(runtime.state(), std::move(host), typeToken); + runtime.state()->track(holder, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->hostObject.reset(); + tracked->state.reset(); + }); JSObjectRef object = JSObjectMake(runtime.context(), jscengine::hostClass(runtime), holder); return Object::fromValueStorage(Value(runtime, object).storage_); } @@ -213,6 +267,11 @@ void setFunctionPrototype(JSGlobalContextRef context, JSObjectRef function) { Function Function::createFromHostFunction(Runtime& runtime, const PropNameID& name, unsigned int, HostFunctionType callback) { auto* holder = new jscengine::FunctionHolder(runtime.state(), std::move(callback)); + runtime.state()->track(holder, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->callback = {}; + tracked->state.reset(); + }); JSObjectRef function = JSObjectMake(runtime.context(), jscengine::functionClass(runtime), holder); jscengine::setFunctionPrototype(runtime.context(), function); std::string functionName = name.utf8(runtime); diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSCRuntime.h b/NativeScript/ffi/objc/jsc/NativeApiJSCRuntime.h index bada6420b..817daed17 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSCRuntime.h +++ b/NativeScript/ffi/objc/jsc/NativeApiJSCRuntime.h @@ -33,6 +33,8 @@ #include #include +#include "../shared/RuntimeCleanupRegistry.h" + #include "Metadata.h" #include "MetadataReader.h" #include "ffi.h" @@ -178,7 +180,7 @@ inline void setException(JSContextRef context, JSValueRef* exception, const std: } } -struct RuntimeState { +struct RuntimeState : RuntimeCleanupRegistry { explicit RuntimeState(JSGlobalContextRef context) : context(context) {} ~RuntimeState() { @@ -199,6 +201,9 @@ struct RuntimeState { JSClassRef selectorGroupFunctionClass = nullptr; }; +std::shared_ptr stateForContext(JSGlobalContextRef context); +void releaseStateForContext(JSGlobalContextRef context); + struct ValueStorage { enum class Kind { Undefined, @@ -261,12 +266,13 @@ void setFunctionPrototype(JSGlobalContextRef context, JSObjectRef function); class Runtime { public: explicit Runtime(JSGlobalContextRef context) - : state_(std::make_shared(context)) {} + : state_(jscengine::stateForContext(context)) {} explicit Runtime(std::shared_ptr state) : state_(std::move(state)) {} JSGlobalContextRef context() const { return state_->context; } std::shared_ptr state() const { return state_; } + void detachState() { state_.reset(); } Object global(); Value evaluateJavaScript(std::shared_ptr buffer, const std::string& sourceURL); diff --git a/NativeScript/ffi/objc/jsc/NativeApiJSCSelectorGroups.mm b/NativeScript/ffi/objc/jsc/NativeApiJSCSelectorGroups.mm index 1020e8cf2..fde28cf11 100644 --- a/NativeScript/ffi/objc/jsc/NativeApiJSCSelectorGroups.mm +++ b/NativeScript/ffi/objc/jsc/NativeApiJSCSelectorGroups.mm @@ -238,8 +238,12 @@ JSValueRef NativeApiSelectorGroupCall( } void NativeApiSelectorGroupFinalize(JSObjectRef function) { - delete static_cast( + auto* data = static_cast( JSObjectGetPrivate(function)); + if (data != nullptr && data->runtime.state() != nullptr) { + data->runtime.state()->untrack(data); + } + delete data; } JSClassRef NativeApiSelectorGroupFunctionClass(Runtime& runtime) { @@ -267,6 +271,15 @@ Function CreateNativeApiSelectorGroupFunctionImpl( runtime.state(), std::move(bridge), lookupClass, receiverIsClass, std::move(selectors), std::move(preparedInvocations), std::move(boundReceiver), std::move(boundReceiverState)); + runtime.state()->track(data, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->runtime.detachState(); + tracked->bridge.reset(); + tracked->selectors.reset(); + tracked->preparedInvocations.reset(); + tracked->boundReceiver.reset(); + tracked->boundReceiverState.reset(); + }); JSObjectRef function = JSObjectMake(runtime.context(), NativeApiSelectorGroupFunctionClass(runtime), data); diff --git a/NativeScript/ffi/objc/jsc/SignatureDispatch.h b/NativeScript/ffi/objc/jsc/SignatureDispatch.h index 02ac6e805..1204cd120 100644 --- a/NativeScript/ffi/objc/jsc/SignatureDispatch.h +++ b/NativeScript/ffi/objc/jsc/SignatureDispatch.h @@ -4,8 +4,8 @@ #include "ffi/objc/shared/SignatureDispatchCore.h" #if defined(__has_include) -#if __has_include("GeneratedSignatureDispatch.inc") -#include "GeneratedSignatureDispatch.inc" +#if __has_include("../shared/GeneratedSignatureDispatch.inc") +#include "../shared/GeneratedSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/napi/Block.mm b/NativeScript/ffi/objc/napi/Block.mm index a99189a6a..2cc3887d2 100644 --- a/NativeScript/ffi/objc/napi/Block.mm +++ b/NativeScript/ffi/objc/napi/Block.mm @@ -174,6 +174,14 @@ napi_value callFunctionPointerAsCFunctionDirect(napi_env env, nativescript::Func cif->argTypes[i]->toNative(env, invocationArgs[i], avalues[i], &shouldFreeArg, &shouldFreeAny); shouldFree[i] = shouldFreeArg ? 1 : 0; + if (nativescript::ConsumeNapiArgumentConversionFailure(env)) { + for (unsigned int converted = 0; converted <= i; converted++) { + if (shouldFree[converted]) { + cif->argTypes[converted]->free(env, *((void**)avalues[converted])); + } + } + return nullptr; + } } void* rvalue = cif->rvalue; @@ -248,6 +256,14 @@ napi_value callFunctionPointerAsBlockDirect(napi_env env, nativescript::Function cif->argTypes[i]->toNative(env, invocationArgs[i], avalues[i + 1], &shouldFreeArg, &shouldFreeAny); shouldFree[i] = shouldFreeArg ? 1 : 0; + if (nativescript::ConsumeNapiArgumentConversionFailure(env)) { + for (unsigned int converted = 0; converted <= i; converted++) { + if (shouldFree[converted]) { + cif->argTypes[converted]->free(env, *((void**)avalues[converted + 1])); + } + } + return nullptr; + } } void* rvalue = cif->rvalue; diff --git a/NativeScript/ffi/objc/napi/CFunction.mm b/NativeScript/ffi/objc/napi/CFunction.mm index e23a2b673..44d934e91 100644 --- a/NativeScript/ffi/objc/napi/CFunction.mm +++ b/NativeScript/ffi/objc/napi/CFunction.mm @@ -124,56 +124,7 @@ explicit CFunctionInvocationFrame(Cif* cif) }; inline bool unwrapCompatNativeHandleForCFunction(napi_env env, napi_value value, void** out) { - if (value == nullptr || out == nullptr) { - return false; - } - - if (Pointer::isInstance(env, value)) { - Pointer* ptr = Pointer::unwrap(env, value); - *out = ptr != nullptr ? ptr->data : nullptr; - return ptr != nullptr; - } - - if (Reference::isInstance(env, value)) { - Reference* ref = Reference::unwrap(env, value); - *out = ref != nullptr ? ref->data : nullptr; - return ref != nullptr; - } - - napi_valuetype valueType = napi_undefined; - if (napi_typeof(env, value, &valueType) != napi_ok) { - return false; - } - - if (valueType == napi_bigint) { - uint64_t raw = 0; - bool lossless = false; - if (napi_get_value_bigint_uint64(env, value, &raw, &lossless) != napi_ok) { - return false; - } - *out = reinterpret_cast(static_cast(raw)); - return true; - } - - if (valueType == napi_external) { - return napi_get_value_external(env, value, out) == napi_ok; - } - - if (valueType != napi_object && valueType != napi_function) { - return false; - } - - bool hasNativePointer = false; - if (napi_has_named_property(env, value, "__ns_native_ptr", &hasNativePointer) == napi_ok && - hasNativePointer) { - napi_value nativePointerValue = nullptr; - if (napi_get_named_property(env, value, "__ns_native_ptr", &nativePointerValue) == napi_ok && - napi_get_value_external(env, nativePointerValue, out) == napi_ok && *out != nullptr) { - return true; - } - } - - return napi_unwrap(env, value, out) == napi_ok && *out != nullptr; + return unwrapKnownNativeHandle(env, value, out); } inline napi_value createCompatDispatchQueueWrapperForCFunction(napi_env env, @@ -463,6 +414,14 @@ inline void ensureCFunctionDispatchLookup(CFunction* function, Cif* cif) { cif->argTypes[i]->toNative(env, invocationArgs[i], avalues[i], &argShouldFree, &shouldFreeAny); shouldFree[i] = argShouldFree ? 1 : 0; + if (ConsumeNapiArgumentConversionFailure(env)) { + for (unsigned int converted = 0; converted <= i; converted++) { + if (shouldFree[converted]) { + cif->argTypes[converted]->free(env, *((void**)avalues[converted])); + } + } + return nullptr; + } } } diff --git a/NativeScript/ffi/objc/napi/CallbackThreading.h b/NativeScript/ffi/objc/napi/CallbackThreading.h index 08ffcea22..d4f15a94a 100644 --- a/NativeScript/ffi/objc/napi/CallbackThreading.h +++ b/NativeScript/ffi/objc/napi/CallbackThreading.h @@ -3,7 +3,6 @@ #include "js_native_api.h" -#include #include #include @@ -16,21 +15,11 @@ namespace nativescript { namespace detail { #if defined(ENABLE_JS_RUNTIME) && defined(TARGET_ENGINE_HERMES) -inline std::atomic native_call_unlocked_runtime_count{0}; inline thread_local int native_caller_thread_callback_depth = 0; #endif } // namespace detail -inline bool isNativeCallRuntimeUnlockedForCallbacks() { -#if defined(ENABLE_JS_RUNTIME) && defined(TARGET_ENGINE_HERMES) - return detail::native_call_unlocked_runtime_count.load( - std::memory_order_acquire) > 0; -#else - return false; -#endif -} - inline bool isNativeCallerThreadCallbackActive() { #if defined(ENABLE_JS_RUNTIME) && defined(TARGET_ENGINE_HERMES) return detail::native_caller_thread_callback_depth > 0; @@ -41,8 +30,7 @@ inline bool isNativeCallerThreadCallbackActive() { inline bool shouldInvokeCallbackOnNativeCallerThread() { #if defined(ENABLE_JS_RUNTIME) && defined(TARGET_ENGINE_HERMES) - return isNativeCallRuntimeUnlockedForCallbacks() || - isNativeCallerThreadCallbackActive(); + return isNativeCallerThreadCallbackActive(); #else return false; #endif @@ -56,12 +44,12 @@ class NativeCallRuntimeUnlockScope final { return; } - auto it = JSR::env_to_jsr_cache.find(env); - if (it == JSR::env_to_jsr_cache.end() || it->second == nullptr) { + JSR* runtime = JSR::ForEnv(env); + if (runtime == nullptr) { return; } - jsr_ = it->second; + jsr_ = runtime; unlockedDepth_ = js_current_env_lock_depth(env); for (int i = 0; i < unlockedDepth_; i++) { jsr_->unlock(); @@ -72,11 +60,6 @@ class NativeCallRuntimeUnlockScope final { relockRuntime_ = [runtime]() { runtime->lock(); }; unlockedRuntime_ = true; } - if (unlockedDepth_ > 0 || unlockedRuntime_) { - didUnlock_ = true; - detail::native_call_unlocked_runtime_count.fetch_add( - 1, std::memory_order_release); - } #else (void)env; #endif @@ -84,10 +67,6 @@ class NativeCallRuntimeUnlockScope final { ~NativeCallRuntimeUnlockScope() { #if defined(ENABLE_JS_RUNTIME) && defined(TARGET_ENGINE_HERMES) - if (didUnlock_) { - detail::native_call_unlocked_runtime_count.fetch_sub( - 1, std::memory_order_release); - } if (jsr_ != nullptr) { for (int i = 0; i < unlockedDepth_; i++) { jsr_->lock(); @@ -110,7 +89,6 @@ class NativeCallRuntimeUnlockScope final { #endif int unlockedDepth_ = 0; bool unlockedRuntime_ = false; - bool didUnlock_ = false; }; class NativeCallbackScope final { @@ -123,9 +101,9 @@ class NativeCallbackScope final { return; } - auto it = JSR::env_to_jsr_cache.find(env_); - if (it != JSR::env_to_jsr_cache.end() && it->second != nullptr) { - jsr_ = it->second; + JSR* runtime = JSR::ForEnv(env_); + if (runtime != nullptr) { + jsr_ = runtime; jsr_->lock(); detail::native_caller_thread_callback_depth += 1; napi_open_handle_scope(env_, &napiHandleScope_); diff --git a/NativeScript/ffi/objc/napi/Class.mm b/NativeScript/ffi/objc/napi/Class.mm index 12aea8230..d8b1021a6 100644 --- a/NativeScript/ffi/objc/napi/Class.mm +++ b/NativeScript/ffi/objc/napi/Class.mm @@ -690,7 +690,7 @@ void defineProtocolMembers(napi_env env, ObjCClassMemberMap& members, napi_value } ObjCClass::ObjCClass(napi_env env, MDSectionOffset offset) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE this->env = env; diff --git a/NativeScript/ffi/objc/napi/ClassBuilder.mm b/NativeScript/ffi/objc/napi/ClassBuilder.mm index aed65fdfb..bf6ed1745 100644 --- a/NativeScript/ffi/objc/napi/ClassBuilder.mm +++ b/NativeScript/ffi/objc/napi/ClassBuilder.mm @@ -7,6 +7,7 @@ #include "Metadata.h" #include "ObjCBridge.h" #include "Protocol.h" +#include "TypeConv.h" #include "Util.h" #include "js_native_api.h" #include "node_api_util.h" @@ -427,6 +428,9 @@ NSUInteger JS_SymbolIteratorCountByEnumerating(id self, SEL _cmd, NSFastEnumerat bool shouldFree = false; bool shouldFreeAny = false; objectConverter->toNative(env, value, &nativeValue, &shouldFree, &shouldFreeAny); + if (ConsumeNapiArgumentConversionFailure(env)) { + break; + } stackbuf[count++] = nativeValue; } diff --git a/NativeScript/ffi/objc/napi/ClassMember.mm b/NativeScript/ffi/objc/napi/ClassMember.mm index c2b8a9633..e7c102bcb 100644 --- a/NativeScript/ffi/objc/napi/ClassMember.mm +++ b/NativeScript/ffi/objc/napi/ClassMember.mm @@ -1404,6 +1404,17 @@ explicit CifReturnStorage(Cif* cif) { shouldFree[i] = false; avalues[i + 2] = argStorage.at(i); cif->argTypes[i]->toNative(env, cif->argv[i], avalues[i + 2], &shouldFree[i], &shouldFreeAny); + if (ConsumeNapiArgumentConversionFailure(env)) { + for (unsigned int converted = 0; converted <= i; converted++) { + if (shouldFree[converted]) { + cif->argTypes[converted]->free(env, *((void**)avalues[converted + 2])); + } + } + if (retainedReceiver) { + [self release]; + } + return nullptr; + } } } @@ -1752,12 +1763,28 @@ explicit CifReturnStorage(Cif* cif) { bool shouldFreeAny = false; bool shouldFree[cif->argc]; + memset(shouldFree, 0, sizeof(shouldFree)); std::vector fallbackBlocksToRelease; NSError* implicitNSError = nil; + auto cleanupArguments = [&]() { + for (id block : fallbackBlocksToRelease) { + [block release]; + } + fallbackBlocksToRelease.clear(); + + if (!shouldFreeAny) { + return; + } + for (unsigned int i = 0; i < cif->argc; i++) { + if (shouldFree[i]) { + cif->argTypes[i]->free(env, *reinterpret_cast(avalues[i + 2])); + } + } + }; + if (cif->argc > 0) { for (unsigned int i = 0; i < cif->argc; i++) { - shouldFree[i] = false; avalues[i + 2] = argStorage.at(i); const char* blockEncoding = blockEncodingForSelector(selectedSelectorName, i); @@ -1783,6 +1810,12 @@ explicit CifReturnStorage(Cif* cif) { if (!convertedViaBlockFallback) { cif->argTypes[i]->toNative(env, invocationArgs[i], avalues[i + 2], &shouldFree[i], &shouldFreeAny); + bool conversionFailed = false; + if (ConsumeNapiArgumentConversionFailure(env) || + napi_is_exception_pending(env, &conversionFailed) != napi_ok || conversionFailed) { + cleanupArguments(); + return nullptr; + } } } } @@ -1791,23 +1824,11 @@ explicit CifReturnStorage(Cif* cif) { if (!objcNativeCall(env, cif, self, receiverIsClass, selectedMethod, selectedMethod->dispatchFlags, avalues, rvalue)) { - for (id block : fallbackBlocksToRelease) { - [block release]; - } + cleanupArguments(); return nullptr; } - for (id block : fallbackBlocksToRelease) { - [block release]; - } - - if (shouldFreeAny) { - for (unsigned int i = 0; i < cif->argc; i++) { - if (shouldFree[i]) { - cif->argTypes[i]->free(env, *((void**)avalues[i + 2])); - } - } - } + cleanupArguments(); if (hasImplicitNSErrorOutArg && implicitNSError != nil) { const char* errorMessage = [[implicitNSError description] UTF8String]; @@ -1976,6 +1997,12 @@ NativeScriptException nativeScriptException(errorMessage != nullptr ? errorMessa bool shouldFree = false; cif->argTypes[0]->toNative(env, value, avalues[2], &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + if (shouldFree) { + cif->argTypes[0]->free(env, *((void**)avalues[2])); + } + return nullptr; + } if (!objcNativeCall(env, cif, self, receiverIsClass, &method->setter, method->setter.dispatchFlags, avalues, rvalue)) { diff --git a/NativeScript/ffi/objc/napi/Closure.mm b/NativeScript/ffi/objc/napi/Closure.mm index 1e5be935b..a04380486 100644 --- a/NativeScript/ffi/objc/napi/Closure.mm +++ b/NativeScript/ffi/objc/napi/Closure.mm @@ -216,6 +216,7 @@ inline void JSCallbackInner(Closure* closure, napi_value func, napi_value thisAr // fill the return value memory with something so that it doesn't crash. bool shouldFree; closure->returnType->toNative(env, result, ret, &shouldFree, &shouldFree); + ConsumeNapiArgumentConversionFailure(env); } // Bridge calls from Objective-C to JavaScript. @@ -334,6 +335,7 @@ void JSMethodCallback(ffi_cif* cif, void* ret, void* args[], void* data) { bool shouldFree; closure->returnType->toNative(env, result, ret, &shouldFree, &shouldFree); + ConsumeNapiArgumentConversionFailure(env); } void JSFunctionCallback(ffi_cif* cif, void* ret, void* args[], void* data) { @@ -557,7 +559,9 @@ void JSBlockCallback(ffi_cif* cif, void* ret, void* args[], void* data) { } ffi_status status = - ffi_prep_cif(&cif, FFI_DEFAULT_ABI, argTypes.size() + skipArgs, rtype, this->atypes); + ffi_prep_cif(&cif, FFI_DEFAULT_ABI, + static_cast(argTypes.size() + skipArgs), rtype, + this->atypes); if (status != FFI_OK) { std::cout << "Failed to prepare CIF, libffi returned error:" << status << std::endl; diff --git a/NativeScript/ffi/objc/napi/Interop.h b/NativeScript/ffi/objc/napi/Interop.h index e2c095296..bff58896f 100644 --- a/NativeScript/ffi/objc/napi/Interop.h +++ b/NativeScript/ffi/objc/napi/Interop.h @@ -10,6 +10,7 @@ namespace nativescript { class ObjCBridgeState; void registerInterop(napi_env env, napi_value global); +bool unwrapKnownNativeHandle(napi_env env, napi_value value, void** out); napi_value interop_addMethod(napi_env env, napi_callback_info info); napi_value interop_addProtocol(napi_env env, napi_callback_info info); @@ -46,6 +47,7 @@ class Pointer { void* data; bool adopted = false; + bool cached = false; }; class Reference { diff --git a/NativeScript/ffi/objc/napi/Interop.mm b/NativeScript/ffi/objc/napi/Interop.mm index ba9d7a8c9..012ebe624 100644 --- a/NativeScript/ffi/objc/napi/Interop.mm +++ b/NativeScript/ffi/objc/napi/Interop.mm @@ -21,7 +21,6 @@ namespace nativescript { namespace { -std::unordered_map g_pointerCache; constexpr const char* kPointerMarker = "__ns_pointer"; constexpr const char* kNativePointerProperty = "__ns_native_ptr"; constexpr const char* kReferenceMarker = "__ns_reference"; @@ -179,6 +178,9 @@ inline bool referenceSetValueAtIndex(napi_env env, Reference* ref, uint32_t inde bool shouldFree = false; ref->type->toNative(env, value, slot, &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + return false; + } bool hasPendingException = false; napi_is_exception_pending(env, &hasPendingException); return !hasPendingException; @@ -305,38 +307,50 @@ void finalizePointerNow(napi_env env, void* data, void* hint) { if (ptr == nullptr) { return; } - auto it = g_pointerCache.find(pointerKey(ptr->data)); - if (it != g_pointerCache.end()) { - g_pointerCache.erase(it); + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState != nullptr && ptr->cached) { + auto& cache = bridgeState->pointerCache; + auto it = cache.find(pointerKey(ptr->data)); + if (it != cache.end() && it->second.owner == ptr) { + napi_ref ref = it->second.ref; + cache.erase(it); + napi_delete_reference(env, ref); + } } delete ptr; } inline bool getCachedPointer(napi_env env, void* data, napi_value* value) { - auto it = g_pointerCache.find(pointerKey(data)); - if (it == g_pointerCache.end()) { + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState == nullptr) { return false; } - *value = get_ref_value(env, it->second); + auto& cache = bridgeState->pointerCache; + auto it = cache.find(pointerKey(data)); + if (it == cache.end()) { + return false; + } + + *value = get_ref_value(env, it->second.ref); if (*value == nullptr) { - napi_delete_reference(env, it->second); - g_pointerCache.erase(it); + napi_delete_reference(env, it->second.ref); + cache.erase(it); return false; } napi_valuetype valueType = napi_undefined; if (napi_typeof(env, *value, &valueType) != napi_ok || valueType != napi_object) { - napi_delete_reference(env, it->second); - g_pointerCache.erase(it); + napi_delete_reference(env, it->second.ref); + cache.erase(it); *value = nullptr; return false; } Pointer* ptr = Pointer::unwrap(env, *value); if (ptr == nullptr || ptr->data != data) { - napi_delete_reference(env, it->second); - g_pointerCache.erase(it); + napi_delete_reference(env, it->second.ref); + cache.erase(it); *value = nullptr; return false; } @@ -344,14 +358,23 @@ inline bool getCachedPointer(napi_env env, void* data, napi_value* value) { return true; } -inline void cachePointer(napi_env env, void* data, napi_value value) { - const uintptr_t key = pointerKey(data); - if (g_pointerCache.find(key) != g_pointerCache.end()) { - return; +inline bool cachePointer(napi_env env, Pointer* owner, napi_value value) { + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState == nullptr) { + return false; + } + + auto& cache = bridgeState->pointerCache; + const uintptr_t key = pointerKey(owner->data); + if (cache.find(key) != cache.end()) { + return false; } napi_ref ref = nullptr; - napi_create_reference(env, value, 0, &ref); - g_pointerCache[key] = ref; + if (napi_create_reference(env, value, 0, &ref) != napi_ok) { + return false; + } + cache[key] = {owner, ref}; + return true; } inline std::string pointerHexString(void* data) { @@ -385,8 +408,37 @@ inline void cachePointer(napi_env env, void* data, napi_value value) { return fn; } -inline bool unwrapKnownNativeHandle(napi_env env, napi_value value, void** out) { - if (value == nullptr) { +inline bool unwrapKnownNativeHandleImpl(napi_env env, napi_value value, void** out) { + if (env == nullptr || value == nullptr || out == nullptr) { + return false; + } + *out = nullptr; + + napi_valuetype valueType = napi_undefined; + if (napi_typeof(env, value, &valueType) != napi_ok) { + return false; + } + + if (valueType == napi_bigint) { + uint64_t raw = 0; + bool lossless = false; + if (napi_get_value_bigint_uint64(env, value, &raw, &lossless) != napi_ok) { + return false; + } + *out = reinterpret_cast(static_cast(raw)); + return true; + } + + if (valueType == napi_external) { + return napi_get_value_external(env, value, out) == napi_ok; + } + + if (valueType != napi_object && valueType != napi_function) { + return false; + } + + bool isArray = false; + if (valueType == napi_object && napi_is_array(env, value, &isArray) == napi_ok && isArray) { return false; } @@ -412,63 +464,69 @@ inline bool unwrapKnownNativeHandle(napi_env env, napi_value value, void** out) return true; } - if (StructObject* structObject = StructObject::unwrap(env, value)) { - *out = structObject->data; - return structObject->data != nullptr; + if (valueType == napi_object && StructObject::isInstance(env, value)) { + StructObject* object = StructObject::unwrap(env, value); + *out = object != nullptr ? object->data : nullptr; + return object != nullptr; } - void* wrapped = nullptr; - if (napi_unwrap(env, value, &wrapped) != napi_ok || wrapped == nullptr) { - bool hasNativePointer = false; - napi_has_named_property(env, value, kNativePointerProperty, &hasNativePointer); - if (hasNativePointer) { - napi_value nativePointerValue; - if (napi_get_named_property(env, value, kNativePointerProperty, &nativePointerValue) == - napi_ok) { - if (Pointer::isInstance(env, nativePointerValue)) { - Pointer* pointer = Pointer::unwrap(env, nativePointerValue); - if (pointer != nullptr && pointer->data != nullptr) { - *out = pointer->data; - return true; - } - } else { - void* nativePointer = nullptr; - if (napi_get_value_external(env, nativePointerValue, &nativePointer) == napi_ok && - nativePointer != nullptr) { - *out = nativePointer; - return true; - } + bool hasNativePointer = false; + napi_has_named_property(env, value, kNativePointerProperty, &hasNativePointer); + if (hasNativePointer) { + napi_value nativePointerValue = nullptr; + if (napi_get_named_property(env, value, kNativePointerProperty, &nativePointerValue) == + napi_ok) { + if (Pointer::isInstance(env, nativePointerValue)) { + Pointer* pointer = Pointer::unwrap(env, nativePointerValue); + if (pointer != nullptr && pointer->data != nullptr) { + *out = pointer->data; + return true; + } + } else { + void* nativePointer = nullptr; + if (napi_get_value_external(env, nativePointerValue, &nativePointer) == napi_ok && + nativePointer != nullptr) { + *out = nativePointer; + return true; } } } + } + + if (valueType != napi_function) { + return false; + } + void* wrapped = nullptr; + if (napi_unwrap(env, value, &wrapped) != napi_ok || wrapped == nullptr) { return false; } bridgeState = ObjCBridgeState::InstanceData(env); - for (const auto& entry : bridgeState->classes) { - if (entry.second == wrapped) { - *out = (void*)entry.second->nativeClass; - return true; + if (bridgeState != nullptr) { + for (const auto& entry : bridgeState->classes) { + if (entry.second == wrapped) { + *out = (void*)entry.second->nativeClass; + return true; + } } - } - for (const auto& entry : bridgeState->protocols) { - if (entry.second == wrapped) { - *out = (void*)objc_getProtocol(entry.second->name.c_str()); - return true; + for (const auto& entry : bridgeState->protocols) { + if (entry.second == wrapped) { + *out = (void*)objc_getProtocol(entry.second->name.c_str()); + return true; + } } - } - for (const auto& entry : bridgeState->cFunctionCache) { - if (entry.second == wrapped) { - *out = entry.second->fnptr; - return true; + for (const auto& entry : bridgeState->cFunctionCache) { + if (entry.second == wrapped) { + *out = entry.second->fnptr; + return true; + } } } - *out = wrapped; - return true; + return false; } inline bool resolveNativePointerFromRegisteredFunction(napi_env env, napi_value value, void** out) { @@ -570,6 +628,10 @@ inline void setObjectPrototype(napi_env env, napi_value object, napi_value proto } } // namespace +bool unwrapKnownNativeHandle(napi_env env, napi_value value, void** out) { + return unwrapKnownNativeHandleImpl(env, value, out); +} + inline napi_value createJSNumber(napi_env env, int32_t ival) { napi_value value; napi_create_int32(env, ival, &value); @@ -909,11 +971,16 @@ napi_value interop_free(napi_env env, napi_callback_info info) { napi_unwrap(env, arg, (void**)&ptr); if (ptr != nullptr && ptr->data != nullptr) { - auto it = g_pointerCache.find(pointerKey(ptr->data)); - if (it != g_pointerCache.end()) { - napi_delete_reference(env, it->second); - g_pointerCache.erase(it); + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState != nullptr) { + auto& cache = bridgeState->pointerCache; + auto it = cache.find(pointerKey(ptr->data)); + if (it != cache.end() && it->second.owner == ptr) { + napi_delete_reference(env, it->second.ref); + cache.erase(it); + } } + ptr->cached = false; free(ptr->data); ptr->data = nullptr; } @@ -1307,21 +1374,18 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { return false; } - bool hasMarker = false; - napi_has_named_property(env, value, kPointerMarker, &hasMarker); - if (!hasMarker) { + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState == nullptr || bridgeState->pointerClass == nullptr) { return false; } - napi_value marker = nullptr; - if (napi_get_named_property(env, value, kPointerMarker, &marker) != napi_ok || - marker == nullptr) { + napi_value constructor = get_ref_value(env, bridgeState->pointerClass); + bool result = false; + if (constructor == nullptr || + napi_instanceof(env, value, constructor, &result) != napi_ok) { return false; } - - bool markerValue = false; - napi_get_value_bool(env, marker, &markerValue); - return markerValue; + return result; } napi_value Pointer::create(napi_env env, void* data) { @@ -1416,10 +1480,10 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { } case napi_bigint: { - int64_t value = 0; + uint64_t value = 0; bool lossless = false; - napi_get_value_bigint_int64(env, arg, &value, &lossless); - data = (void*)((intptr_t)value); + napi_get_value_bigint_uint64(env, arg, &value, &lossless); + data = reinterpret_cast(static_cast(value)); break; } @@ -1465,7 +1529,7 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { Pointer* ptr = new Pointer(data); napi_wrap(env, jsThis, ptr, Pointer::finalize, nullptr, nullptr); - cachePointer(env, data, jsThis); + ptr->cached = cachePointer(env, ptr, jsThis); return jsThis; } @@ -1652,21 +1716,18 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { return false; } - bool hasMarker = false; - napi_has_named_property(env, value, kReferenceMarker, &hasMarker); - if (!hasMarker) { + ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); + if (bridgeState == nullptr || bridgeState->referenceClass == nullptr) { return false; } - napi_value marker = nullptr; - if (napi_get_named_property(env, value, kReferenceMarker, &marker) != napi_ok || - marker == nullptr) { + napi_value constructor = get_ref_value(env, bridgeState->referenceClass); + bool result = false; + if (constructor == nullptr || + napi_instanceof(env, value, constructor, &result) != napi_ok) { return false; } - - bool markerValue = false; - napi_get_value_bool(env, marker, &markerValue); - return markerValue; + return result; } napi_value Reference::create(napi_env env, std::shared_ptr type, void* data, @@ -1850,6 +1911,10 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { napi_value initValue = Reference::getInitValue(env, argv[1], other); if (initValue != nullptr) { reference->type->toNative(env, initValue, reference->data, &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + delete reference; + return nullptr; + } } } } else { @@ -1861,6 +1926,10 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { reference->ownsData = true; bool shouldFree; reference->type->toNative(env, argv[1], reference->data, &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + delete reference; + return nullptr; + } } } else { napi_throw_error(env, nullptr, "Invalid number of arguments"); @@ -1924,6 +1993,9 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { bool shouldFree = false; ref->type->toNative(env, arg, ref->data, &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + return nullptr; + } Reference::clearInitValue(env, jsThis, ref); return nullptr; @@ -1993,16 +2065,26 @@ napi_value interop_bufferFromData(napi_env env, napi_callback_info info) { } bool hasMarker = false; - napi_has_named_property(env, value, kFunctionReferenceMarker, &hasMarker); - if (!hasMarker) { + bool hasNativeRef = false; + if (napi_has_named_property(env, value, kFunctionReferenceMarker, &hasMarker) != napi_ok || + !hasMarker || + napi_has_named_property(env, value, kFunctionReferenceDataProperty, &hasNativeRef) != + napi_ok || + !hasNativeRef) { return false; } - napi_value marker; - napi_get_named_property(env, value, kFunctionReferenceMarker, &marker); + napi_value marker = nullptr; + napi_value nativeRef = nullptr; bool markerValue = false; - napi_get_value_bool(env, marker, &markerValue); - return markerValue; + void* nativeData = nullptr; + if (napi_get_named_property(env, value, kFunctionReferenceMarker, &marker) != napi_ok || + napi_get_value_bool(env, marker, &markerValue) != napi_ok || !markerValue || + napi_get_named_property(env, value, kFunctionReferenceDataProperty, &nativeRef) != napi_ok || + napi_get_value_external(env, nativeRef, &nativeData) != napi_ok) { + return false; + } + return nativeData != nullptr; } FunctionReference* FunctionReference::unwrap(napi_env env, napi_value value) { diff --git a/NativeScript/ffi/objc/napi/ObjCBridge.h b/NativeScript/ffi/objc/napi/ObjCBridge.h index 7b6228334..96a55ecf9 100644 --- a/NativeScript/ffi/objc/napi/ObjCBridge.h +++ b/NativeScript/ffi/objc/napi/ObjCBridge.h @@ -90,6 +90,9 @@ class ObjCBridgeState { ~ObjCBridgeState(); static inline ObjCBridgeState* InstanceData(napi_env env) { + if (env == nullptr) { + return nullptr; + } ObjCBridgeState* bridgeState; napi_status status = napi_get_instance_data(env, (void**)&bridgeState); if (status != napi_ok) { @@ -98,6 +101,9 @@ class ObjCBridgeState { return bridgeState; } + bool enqueueFinalizer(napi_finalize callback, void* data, void* hint); + void drainFinalizers(bool stop = false); + static inline uintptr_t NormalizeHandleKey(void* handle) { if (handle == nullptr) { return 0; @@ -170,6 +176,11 @@ class ObjCBridgeState { napi_value proxyNativeObject(napi_env env, napi_value object, id nativeObject); +#if defined(TARGET_ENGINE_HERMES) + bool registerObjectFinalizer(napi_env env, napi_value object, + JSObjectFinalizerContext* context); + bool takeObjectFinalizer(JSObjectFinalizerContext* context); +#endif napi_value getObject(napi_env env, id object, napi_value constructor, ObjectOwnership ownership = kUnownedObject); @@ -927,7 +938,21 @@ class ObjCBridgeState { uint64_t lifetimeToken = 0; std::thread::id jsThreadId = std::this_thread::get_id(); CFRunLoopRef jsRunLoop = CFRunLoopGetCurrent(); + struct PendingFinalizer { + napi_finalize callback; + void* data; + void* hint; + }; + std::mutex pendingFinalizersMutex; + std::vector pendingFinalizers; + bool finalizerDrainScheduled = false; + bool acceptingFinalizers = true; std::unordered_map objectRefs; + struct PointerCacheEntry { + void* owner = nullptr; + napi_ref ref = nullptr; + }; + std::unordered_map pointerCache; std::unordered_map handleObjectRefs; std::vector recentObjectWrappers; size_t nextRecentObjectWrapperSlot = 0; @@ -938,6 +963,10 @@ class ObjCBridgeState { napi_ref createNativeProxy = nullptr; napi_ref createFastEnumeratorIterator = nullptr; napi_ref transferOwnershipToNative = nullptr; +#if defined(TARGET_ENGINE_HERMES) + napi_ref objectFinalizationRegistry = nullptr; + std::unordered_set objectFinalizers; +#endif std::unordered_map classes; std::unordered_map protocols; @@ -946,6 +975,7 @@ class ObjCBridgeState { std::unordered_map mdProtocolsByPointer; std::unordered_map nativeObjectsByBridgeWrapper; std::unordered_map constructorsByPointer; + StructInfo* syntheticCGPointInfo = nullptr; std::unordered_map cifs; std::unordered_map mdValueCache; diff --git a/NativeScript/ffi/objc/napi/ObjCBridge.mm b/NativeScript/ffi/objc/napi/ObjCBridge.mm index 9dd865fd2..fe330f374 100644 --- a/NativeScript/ffi/objc/napi/ObjCBridge.mm +++ b/NativeScript/ffi/objc/napi/ObjCBridge.mm @@ -20,6 +20,7 @@ #include "node_api_util.h" #import + #include #include #include @@ -166,19 +167,23 @@ bool PostFinalizer(napi_env env, napi_finalize finalize_cb, void* finalize_data, ObjCBridgeState* bridgeState = ObjCBridgeState::InstanceData(env); if (bridgeState != nullptr && bridgeState->jsThreadId == std::this_thread::get_id()) { -#if !defined(TARGET_ENGINE_QUICKJS) +#if !defined(TARGET_ENGINE_QUICKJS) && !defined(TARGET_ENGINE_V8) finalize_cb(env, finalize_data, finalize_hint); return true; #endif } - CFRunLoopRef runLoop = bridgeState != nullptr ? bridgeState->jsRunLoop : CFRunLoopGetMain(); + if (bridgeState != nullptr) { + return bridgeState->enqueueFinalizer(finalize_cb, finalize_data, finalize_hint); + } + + CFRunLoopRef runLoop = CFRunLoopGetMain(); if (runLoop == nullptr) { return false; } if (bridgeState == nullptr && [NSThread isMainThread]) { -#if !defined(TARGET_ENGINE_QUICKJS) +#if !defined(TARGET_ENGINE_QUICKJS) && !defined(TARGET_ENGINE_V8) finalize_cb(env, finalize_data, finalize_hint); return true; #endif @@ -193,28 +198,118 @@ bool PostFinalizer(napi_env env, napi_finalize finalize_cb, void* finalize_data, return true; } +bool ObjCBridgeState::enqueueFinalizer(napi_finalize callback, void* data, void* hint) { + if (callback == nullptr || jsRunLoop == nullptr) { + return false; + } + + bool scheduleDrain = false; + { + std::lock_guard lock(pendingFinalizersMutex); + if (!acceptingFinalizers) { + return false; + } + pendingFinalizers.push_back({callback, data, hint}); + if (!finalizerDrainScheduled) { + finalizerDrainScheduled = true; + scheduleDrain = true; + } + } + + if (!scheduleDrain) { + return true; + } + + CFRunLoopRef runLoop = jsRunLoop; + const uint64_t token = lifetimeToken; + CFRunLoopPerformBlock(runLoop, kCFRunLoopCommonModes, ^{ + if (IsBridgeStateLive(this, token)) { + drainFinalizers(); + } + }); + CFRunLoopWakeUp(runLoop); + return true; +} + +void ObjCBridgeState::drainFinalizers(bool stop) { + std::vector pending; + { + std::lock_guard lock(pendingFinalizersMutex); + if (stop) { + acceptingFinalizers = false; + } + pending.swap(pendingFinalizers); + finalizerDrainScheduled = false; + } + + for (const auto& finalizer : pending) { + finalizer.callback(env, finalizer.data, finalizer.hint); + } +} + void finalize_bridge_data(napi_env env, void* data, void* hint) { auto bridgeState = (ObjCBridgeState*)data; delete bridgeState; } -MDMetadataReader* loadMetadataFromFile(const char* metadata_path) { - if (metadata_path == nullptr) { - metadata_path = "metadata.nsmd"; +#if defined(TARGET_ENGINE_HERMES) +napi_value runObjectFinalizer(napi_env env, napi_callback_info info) { + napi_value token = nullptr; + size_t argc = 1; + void* data = nullptr; + napi_get_cb_info(env, info, &argc, &token, nullptr, &data); + + uint64_t rawContext = 0; + bool lossless = false; + if (argc == 1 && napi_get_value_bigint_uint64(env, token, &rawContext, &lossless) == napi_ok && + lossless) { + auto* bridgeState = static_cast(data); + auto* context = reinterpret_cast( + static_cast(rawContext)); + if (IsBridgeStateLive(bridgeState, bridgeState != nullptr ? bridgeState->lifetimeToken : 0) && + bridgeState->takeObjectFinalizer(context)) { + finalize_objc_object(env, context, nullptr); + } } - auto f = fopen(metadata_path == nullptr ? "metadata.nsmd" : metadata_path, "r"); + napi_value undefined = nullptr; + napi_get_undefined(env, &undefined); + return undefined; +} +#endif + +MDMetadataReader* loadMetadataFromFile(const char* metadata_path) { + const char* path = metadata_path != nullptr ? metadata_path : "metadata.nsmd"; + auto f = fopen(path, "rb"); if (f == nullptr) { - fprintf(stderr, "metadata.nsmd not found\n"); + fprintf(stderr, "metadata.nsmd not found: %s\n", path); exit(1); } fseek(f, 0, SEEK_END); - auto size = ftell(f); + const long size = ftell(f); fseek(f, 0, SEEK_SET); - auto buffer = (uint8_t*)malloc(size); - fread(buffer, 1, size, f); + if (size <= 0) { + fclose(f); + fprintf(stderr, "metadata.nsmd is empty: %s\n", path); + exit(1); + } + + auto buffer = static_cast(malloc(static_cast(size))); + if (buffer == nullptr) { + fclose(f); + fprintf(stderr, "failed to allocate metadata buffer: %s\n", path); + exit(1); + } + + const size_t bytesRead = fread(buffer, 1, static_cast(size), f); fclose(f); - return new MDMetadataReader(buffer); + if (bytesRead != static_cast(size)) { + free(buffer); + fprintf(stderr, "failed to read metadata: %s\n", path); + exit(1); + } + + return new MDMetadataReader(buffer, true); } inline bool hasNamedProperty(napi_env env, napi_value object, const char* name) { @@ -435,12 +530,13 @@ inline void registerStructAlias(napi_env env, napi_value global, ObjCBridgeState } } -inline void ensureSyntheticCGPoint(napi_env env, napi_value global) { +inline void ensureSyntheticCGPoint(napi_env env, napi_value global, + ObjCBridgeState* bridgeState) { if (hasConstructableNamedProperty(env, global, "CGPoint")) { return; } - static StructInfo* syntheticInfo = nullptr; + StructInfo*& syntheticInfo = bridgeState->syntheticCGPointInfo; if (syntheticInfo == nullptr) { syntheticInfo = new StructInfo(); syntheticInfo->name = strdup("CGPoint"); @@ -511,9 +607,21 @@ inline void ensureConstructableStructAlias(napi_env env, napi_value global, } } -inline void installMacUIColorCompatShim(napi_env env) { +inline void installMacCompatShim(napi_env env) { const char* script = R"( (function (globalObject) { + ["CGPoint", "CGSize", "CGRect"].forEach(function (name) { + const constructor = globalObject[name + "Struct"]; + if (typeof globalObject[name] !== "function" && + typeof constructor === "function") { + Object.defineProperty(globalObject, name, { + configurable: true, + enumerable: true, + value: constructor + }); + } + }); + if (typeof globalObject.UIColor === "undefined" && typeof globalObject.NSColor !== "undefined") { globalObject.UIColor = globalObject.NSColor; @@ -576,56 +684,7 @@ inline void installMacUIColorCompatShim(napi_env env) { } inline bool unwrapCompatNativeHandle(napi_env env, napi_value value, void** out) { - if (value == nullptr || out == nullptr) { - return false; - } - - if (Pointer::isInstance(env, value)) { - Pointer* ptr = Pointer::unwrap(env, value); - *out = ptr != nullptr ? ptr->data : nullptr; - return ptr != nullptr; - } - - if (Reference::isInstance(env, value)) { - Reference* ref = Reference::unwrap(env, value); - *out = ref != nullptr ? ref->data : nullptr; - return ref != nullptr; - } - - napi_valuetype valueType = napi_undefined; - if (napi_typeof(env, value, &valueType) != napi_ok) { - return false; - } - - if (valueType == napi_bigint) { - uint64_t raw = 0; - bool lossless = false; - if (napi_get_value_bigint_uint64(env, value, &raw, &lossless) != napi_ok) { - return false; - } - *out = reinterpret_cast(static_cast(raw)); - return true; - } - - if (valueType == napi_external) { - return napi_get_value_external(env, value, out) == napi_ok; - } - - if (valueType != napi_object && valueType != napi_function) { - return false; - } - - bool hasNativePointer = false; - if (napi_has_named_property(env, value, "__ns_native_ptr", &hasNativePointer) == napi_ok && - hasNativePointer) { - napi_value nativePointerValue = nullptr; - if (napi_get_named_property(env, value, "__ns_native_ptr", &nativePointerValue) == napi_ok && - napi_get_value_external(env, nativePointerValue, out) == napi_ok && *out != nullptr) { - return true; - } - } - - return napi_unwrap(env, value, out) == napi_ok && *out != nullptr; + return unwrapKnownNativeHandle(env, value, out); } inline napi_value createCompatDispatchQueueWrapper(napi_env env, dispatch_queue_t queue) { @@ -782,11 +841,11 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat {"CGSize", "_CGSize", "NSSize", "_NSSize"}); registerStructAlias(env, global, bridgeState, "CGRect", {"CGRect", "_CGRect", "NSRect", "_NSRect"}); - ensureSyntheticCGPoint(env, global); + ensureSyntheticCGPoint(env, global, bridgeState); ensureConstructableStructAlias( env, global, bridgeState, "CGPoint", {"CGPointStruct", "NSPoint", "NSPointStruct", "_CGPoint", "_NSPoint", "CGPoint"}); - installMacUIColorCompatShim(env); + installMacCompatShim(env); #endif // CommonCrypto compatibility used by historical runtime tests and apps. @@ -844,6 +903,25 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat } ObjCBridgeState::~ObjCBridgeState() { + drainFinalizers(true); +#if defined(TARGET_ENGINE_HERMES) + auto pendingObjectFinalizers = std::move(objectFinalizers); + objectFinalizers.clear(); + if (env != nullptr && objectFinalizationRegistry != nullptr) { + napi_delete_reference(env, objectFinalizationRegistry); + objectFinalizationRegistry = nullptr; + } + for (auto* context : pendingObjectFinalizers) { + if (context == nullptr) { + continue; + } + unregisterObjectIfRefMatches(context->object, context->ref); + if (env != nullptr && context->ref != nullptr) { + napi_delete_reference(env, context->ref); + } + delete context; + } +#endif UnregisterBridgeState(this); auto deleteRef = [&](napi_ref& ref) { @@ -858,6 +936,11 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat } constructorsByPointer.clear(); + for (auto& pair : pointerCache) { + deleteRef(pair.second.ref); + } + pointerCache.clear(); + for (auto& frame : roundTripCacheFrames) { for (auto& entry : frame) { ObjCBridgeState::releaseRoundTripEntry(env, entry.second); @@ -937,10 +1020,21 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat // Clean up StructInfo objects for (auto& pair : structInfoCache) { + deleteRef(pair.second->jsClass); delete pair.second; } structInfoCache.clear(); + if (syntheticCGPointInfo != nullptr) { + deleteRef(syntheticCGPointInfo->jsClass); + std::free(syntheticCGPointInfo->name); + for (auto& field : syntheticCGPointInfo->fields) { + std::free(field.name); + } + delete syntheticCGPointInfo; + syntheticCGPointInfo = nullptr; + } + // Clean up CFunction objects for (auto& pair : cFunctionCache) { delete pair.second; @@ -956,6 +1050,8 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat trackedObjectLiveness = nullptr; [trackedObjectTable release]; + clearStructTypeCaches(env); + // if (objc_autoreleasePool != nullptr) // objc_autoreleasePoolPop(objc_autoreleasePool); @@ -964,7 +1060,7 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat } napi_value ObjCBridgeState::proxyNativeObject(napi_env env, napi_value object, id nativeObject) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_value result = object; const bool nativeIsArray = [nativeObject isKindOfClass:NSArray.class]; @@ -983,15 +1079,28 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat if (nativePointer != nullptr) { napi_set_named_property(env, result, kNativePointerProperty, nativePointer); } + napi_ref ref = nullptr; napi_wrap(env, result, nativeObject, nullptr, nullptr, nullptr); - napi_ref ref = nullptr; auto* finalizerContext = new JSObjectFinalizerContext{ .bridgeState = this, .bridgeStateToken = lifetimeToken, .object = nativeObject, .ref = nullptr, }; +#if defined(TARGET_ENGINE_HERMES) + NAPI_GUARD(napi_create_reference(env, result, 0, &ref)) { + delete finalizerContext; + NAPI_THROW_LAST_ERROR + return nullptr; + } + finalizerContext->ref = ref; + if (!registerObjectFinalizer(env, result, finalizerContext)) { + napi_delete_reference(env, ref); + delete finalizerContext; + return nullptr; + } +#else NAPI_GUARD( napi_add_finalizer(env, result, finalizerContext, finalize_objc_object, nullptr, &ref)) { delete finalizerContext; @@ -999,6 +1108,7 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat return nullptr; } finalizerContext->ref = ref; +#endif storeObjectRef(nativeObject, ref); cacheHandleObjectRef(env, nativeObject, ref); @@ -1009,6 +1119,46 @@ void registerLegacyCompatGlobals(napi_env env, napi_value global, ObjCBridgeStat return result; } +#if defined(TARGET_ENGINE_HERMES) +bool ObjCBridgeState::registerObjectFinalizer(napi_env env, napi_value object, + JSObjectFinalizerContext* context) { + if (objectFinalizationRegistry == nullptr) { + napi_value global = nullptr; + napi_value constructor = nullptr; + napi_value callback = nullptr; + napi_value registry = nullptr; + if (napi_get_global(env, &global) != napi_ok || + napi_get_named_property(env, global, "FinalizationRegistry", &constructor) != napi_ok || + napi_create_function(env, "", 0, runObjectFinalizer, this, &callback) != napi_ok || + napi_new_instance(env, constructor, 1, &callback, ®istry) != napi_ok || + napi_create_reference(env, registry, 1, &objectFinalizationRegistry) != napi_ok) { + return false; + } + } + + napi_value registry = get_ref_value(env, objectFinalizationRegistry); + napi_value registerFunction = nullptr; + napi_value token = nullptr; + napi_value args[2] = {object, nullptr}; + if (registry == nullptr || + napi_get_named_property(env, registry, "register", ®isterFunction) != napi_ok || + napi_create_bigint_uint64(env, reinterpret_cast(context), &token) != napi_ok) { + return false; + } + args[1] = token; + if (napi_call_function(env, registry, registerFunction, 2, args, nullptr) != napi_ok) { + return false; + } + + objectFinalizers.insert(context); + return true; +} + +bool ObjCBridgeState::takeObjectFinalizer(JSObjectFinalizerContext* context) { + return context != nullptr && objectFinalizers.erase(context) != 0; +} +#endif + void ObjCBridgeState::trackObject(id object) noexcept { if (object == nil) { return; diff --git a/NativeScript/ffi/objc/napi/Object.mm b/NativeScript/ffi/objc/napi/Object.mm index 5283280ed..7058a4e78 100644 --- a/NativeScript/ffi/objc/napi/Object.mm +++ b/NativeScript/ffi/objc/napi/Object.mm @@ -426,7 +426,7 @@ void attachObjectLifecycleAssociation(napi_env env, id object) { } namespace { -void finalize_objc_object_now(napi_env /*env*/, void* data, void* hint) { +void finalize_objc_object_now(napi_env env, void* data, void* hint) { (void)hint; JSObjectFinalizerContext* context = static_cast(data); if (context == nullptr) { @@ -438,6 +438,13 @@ void finalize_objc_object_now(napi_env /*env*/, void* data, void* hint) { bridgeState->unregisterObjectIfRefMatches(context->object, context->ref); } +#if defined(TARGET_ENGINE_HERMES) + if (env != nullptr && context->ref != nullptr) { + napi_delete_reference(env, context->ref); + context->ref = nullptr; + } +#endif + delete context; } } // namespace @@ -456,7 +463,7 @@ void finalize_objc_object(napi_env env, void* data, void* hint) { return nullptr; } - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE Class cls = object_getClass(obj); @@ -596,7 +603,8 @@ void finalize_objc_object(napi_env env, void* data, void* hint) { } JSWrapperObjectAssociation* association = [JSWrapperObjectAssociation associationFor:obj]; - if (association != nil) { + if (association != nil && association.env == env && association.bridgeState == this && + IsBridgeStateLive(association.bridgeState, association.bridgeStateToken)) { napi_value jsObject = get_ref_value(env, association.ref); if (jsObject != nullptr) { bool isArrayBuffer = false; @@ -704,7 +712,7 @@ napi_value findConstructorForObject(napi_env env, ObjCBridgeState* bridgeState, napi_value ObjCBridgeState::getObject(napi_env env, id obj, ObjectOwnership ownership, MDSectionOffset classOffset, std::vector* protocolOffsets) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE if (obj == nullptr) { return nullptr; diff --git a/NativeScript/ffi/objc/napi/ObjectRef.mm b/NativeScript/ffi/objc/napi/ObjectRef.mm index ccd6cb4bf..160f97b1d 100644 --- a/NativeScript/ffi/objc/napi/ObjectRef.mm +++ b/NativeScript/ffi/objc/napi/ObjectRef.mm @@ -41,6 +41,9 @@ void ObjectRef_finalize(napi_env env, void* data, void* hint) { auto conv = TypeConv::Make(env, &argenc); bool shouldFree; conv->toNative(env, arg, data, &shouldFree, &shouldFree); + if (ConsumeNapiArgumentConversionFailure(env)) { + return nullptr; + } } else { *(id*)data = nil; } @@ -91,6 +94,7 @@ void ObjectRef_finalize(napi_env env, void* data, void* hint) { auto conv = TypeConv::Make(env, &argenc); bool shouldFree; conv->toNative(env, arg, data, &shouldFree, &shouldFree); + ConsumeNapiArgumentConversionFailure(env); return nullptr; } diff --git a/NativeScript/ffi/objc/napi/SignatureDispatch.h b/NativeScript/ffi/objc/napi/SignatureDispatch.h index 5d4df5093..66a393831 100644 --- a/NativeScript/ffi/objc/napi/SignatureDispatch.h +++ b/NativeScript/ffi/objc/napi/SignatureDispatch.h @@ -51,8 +51,8 @@ struct CFunctionNapiDispatchEntry { (NS_GSD_BACKEND_HERMES || NS_GSD_BACKEND_NAPI || NS_GSD_BACKEND_PREPARED) #if defined(__has_include) -#if __has_include("GeneratedSignatureDispatch.inc") -#include "GeneratedSignatureDispatch.inc" +#if __has_include("../shared/GeneratedSignatureDispatch.inc") +#include "../shared/GeneratedSignatureDispatch.inc" #elif NS_REQUIRES_GENERATED_SIGNATURE_DISPATCH #error GeneratedSignatureDispatch.inc is required when generated signature dispatch is enabled. #endif diff --git a/NativeScript/ffi/objc/napi/Struct.h b/NativeScript/ffi/objc/napi/Struct.h index edb89a3f0..21249d059 100644 --- a/NativeScript/ffi/objc/napi/Struct.h +++ b/NativeScript/ffi/objc/napi/Struct.h @@ -40,6 +40,9 @@ class StructObject { bool owned; napi_env env = nullptr; napi_ref backingRef = nullptr; +#if defined(TARGET_ENGINE_HERMES) + napi_ref wrapperRef = nullptr; +#endif ObjCBridgeState* bridgeState = nullptr; uint64_t bridgeStateToken = 0; diff --git a/NativeScript/ffi/objc/napi/Struct.mm b/NativeScript/ffi/objc/napi/Struct.mm index 6d19ab857..ee798478b 100644 --- a/NativeScript/ffi/objc/napi/Struct.mm +++ b/NativeScript/ffi/objc/napi/Struct.mm @@ -153,7 +153,7 @@ } NAPI_FUNCTION(structGetter) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE void* data; napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, &data); @@ -165,7 +165,7 @@ } NAPI_FUNCTION(unionGetter) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE void* data; napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, &data); @@ -242,6 +242,11 @@ } namespace { +constexpr napi_type_tag kStructObjectTypeTag = { + 0x93d4bc8be2d74d2dULL, + 0xa3c150244f745f84ULL, +}; + void StructObject_finalize_now(napi_env env, void* data, void* hint) { auto structObject = (StructObject*)data; delete structObject; @@ -257,7 +262,7 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { } NAPI_FUNCTION(StructConstructor) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_value jsThis; napi_value argv[1]; @@ -323,14 +328,26 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { object = new StructObject(info); } - napi_ref ref; - napi_wrap(env, jsThis, object, StructObject_finalize, nullptr, &ref); + napi_ref* wrapperRef = nullptr; +#if defined(TARGET_ENGINE_HERMES) + wrapperRef = &object->wrapperRef; +#endif + if (napi_wrap(env, jsThis, object, StructObject_finalize, nullptr, wrapperRef) != napi_ok) { + delete object; + return nullptr; + } + if (napi_type_tag_object(env, jsThis, &kStructObjectTypeTag) != napi_ok) { + void* removed = nullptr; + napi_remove_wrap(env, jsThis, &removed); + delete static_cast(removed); + return nullptr; + } return jsThis; } NAPI_FUNCTION(StructPropertyGetter) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_value jsThis; StructFieldInfo* info; @@ -338,6 +355,10 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, (void**)&info); auto object = StructObject::unwrap(env, jsThis); + if (object == nullptr) { + napi_throw_type_error(env, nullptr, "Invalid struct receiver"); + return nullptr; + } auto value = object->get(env, info); if (StructObject::isInstance(env, value)) { @@ -353,7 +374,7 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { } NAPI_FUNCTION(StructPropertySetter) { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_value jsThis, arg; StructFieldInfo* info; @@ -362,6 +383,10 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { napi_get_cb_info(env, cbinfo, &argc, &arg, &jsThis, (void**)&info); auto object = StructObject::unwrap(env, jsThis); + if (object == nullptr) { + napi_throw_type_error(env, nullptr, "Invalid struct receiver"); + return nullptr; + } object->set(env, info, arg); return nullptr; @@ -372,6 +397,10 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { napi_get_cb_info(env, cbinfo, nullptr, nullptr, &jsThis, nullptr); auto object = StructObject::unwrap(env, jsThis); + if (object == nullptr) { + napi_throw_type_error(env, nullptr, "Invalid struct receiver"); + return nullptr; + } std::string str = "struct "; str += object->info->name; str += " {}"; @@ -476,6 +505,15 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { } StructObject::~StructObject() { +#if defined(TARGET_ENGINE_HERMES) + if (this->wrapperRef != nullptr && this->env != nullptr && + (this->bridgeState == nullptr || + IsBridgeStateLive(this->bridgeState, this->bridgeStateToken))) { + DeleteReferenceOnOwningThread(this->env, this->bridgeState, this->bridgeStateToken, + this->wrapperRef); + } + this->wrapperRef = nullptr; +#endif if (this->backingRef != nullptr && this->env != nullptr && (this->bridgeState == nullptr || IsBridgeStateLive(this->bridgeState, this->bridgeStateToken))) { @@ -497,12 +535,32 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { auto data = (char*)this->data + field->offset; bool shouldFree = false; field->type->toNative(env, value, data, &shouldFree, &shouldFree); + ConsumeNapiArgumentConversionFailure(env); } StructObject* StructObject::unwrap(napi_env env, napi_value object) { - StructObject* result; + bool matches = false; + if (napi_check_object_type_tag(env, object, &kStructObjectTypeTag, &matches) != napi_ok || + !matches) { + return nullptr; + } + + StructObject* result = nullptr; auto status = napi_unwrap(env, object, (void**)&result); if (status != napi_ok) return nullptr; +#if defined(TARGET_ENGINE_HERMES) + if (result == nullptr || result->wrapperRef == nullptr) { + return nullptr; + } + + napi_value wrapper = nullptr; + bool same = false; + if (napi_get_reference_value(env, result->wrapperRef, &wrapper) != napi_ok || + wrapper == nullptr || napi_strict_equals(env, object, wrapper, &same) != napi_ok || + !same) { + return nullptr; + } +#endif return result; } @@ -593,18 +651,11 @@ void StructObject_finalize(napi_env env, void* data, void* hint) { } bool StructObject::isInstance(napi_env env, napi_value object) { - napi_valuetype valueType = napi_undefined; - napi_typeof(env, object, &valueType); - if (valueType != napi_object && valueType != napi_function) { - return false; - } - - napi_value sizeofSymbol = jsSymbolFor(env, "sizeof"); - bool hasProp = false; - if (napi_has_property(env, object, sizeofSymbol, &hasProp) != napi_ok) { - return false; - } - return hasProp; + bool matches = false; + return object != nullptr && + napi_check_object_type_tag(env, object, &kStructObjectTypeTag, + &matches) == napi_ok && + matches && StructObject::unwrap(env, object) != nullptr; } napi_value StructObject::getJSClass(napi_env env, StructInfo* info) { diff --git a/NativeScript/ffi/objc/napi/TypeConv.h b/NativeScript/ffi/objc/napi/TypeConv.h index e3d024f27..a6133621b 100644 --- a/NativeScript/ffi/objc/napi/TypeConv.h +++ b/NativeScript/ffi/objc/napi/TypeConv.h @@ -29,9 +29,11 @@ class TypeConv { MDSectionOffset* offset, uint8_t opaquePointers = 0); - ffi_type* type; + ffi_type* type = nullptr; MDTypeKind kind = mdTypeChar; + virtual ~TypeConv() = default; + virtual napi_value toJS(napi_env env, void* value, uint32_t flags = 0) { return nullptr; } @@ -52,6 +54,10 @@ class TypeConv { bool TryFastConvertNapiArgument(napi_env env, MDTypeKind kind, napi_value value, void* result); +// Returns and clears conversion failures that cannot be observed through +// napi_is_exception_pending on every backend. +bool ConsumeNapiArgumentConversionFailure(napi_env env); + // Fast direct conversion for uint16_t / unichar arguments used by generated // dispatch wrappers. Supports both numeric values and single-character JS // strings. @@ -59,7 +65,7 @@ bool TryFastConvertNapiUInt16Argument(napi_env env, napi_value value, uint16_t* result); // Cleanup function to clear thread-local struct type caches -void clearStructTypeCaches(); +void clearStructTypeCaches(napi_env env); } // namespace nativescript diff --git a/NativeScript/ffi/objc/napi/TypeConv.mm b/NativeScript/ffi/objc/napi/TypeConv.mm index 7ac512969..eff1aaf49 100644 --- a/NativeScript/ffi/objc/napi/TypeConv.mm +++ b/NativeScript/ffi/objc/napi/TypeConv.mm @@ -137,6 +137,7 @@ static bool getJSBufferData(napi_env env, napi_value value, void** data, size_t* }; thread_local std::vector activeObjectConversions; +thread_local napi_env failedObjectConversionEnv = nullptr; class ScopedObjectConversion { public: @@ -153,6 +154,7 @@ static bool getJSBufferData(napi_env env, napi_value value, void** data, size_t* } if (isSameObject) { + failedObjectConversionEnv = env; napi_throw_error( env, nullptr, "Circular JavaScript object graphs cannot be converted to Objective-C collections."); @@ -179,6 +181,9 @@ static bool getJSBufferData(napi_env env, napi_value value, void** data, size_t* }; static bool hasPendingException(napi_env env) { + if (failedObjectConversionEnv == env) { + return true; + } bool pending = false; return napi_is_exception_pending(env, &pending) == napi_ok && pending; } @@ -467,21 +472,27 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha // Forward declaration class StructTypeConv; -// Thread-local storage for tracking structs currently being processed to detect cycles -thread_local std::unordered_set processingStructs; -thread_local std::unordered_set processingEncodingStructs; - -// Cache for forward-declared struct types that need deferred resolution -thread_local std::unordered_map forwardDeclaredStructs; -thread_local std::unordered_map forwardDeclaredEncodingStructs; +struct StructTypeCaches { + std::unordered_set processingStructs; + std::unordered_set processingEncodingStructs; + std::unordered_map forwardDeclaredStructs; + std::unordered_map forwardDeclaredEncodingStructs; + std::unordered_map> structTypes; + std::unordered_map> encodingStructTypes; +}; -// Cache for StructTypeConv instances to avoid recreating them and handle recursion -thread_local std::unordered_map> structTypeCache; +thread_local std::unordered_map structTypeCachesByEnv; -// Cache for encoding-based structs to handle recursion -thread_local std::unordered_map> encodingStructCache; +inline StructTypeCaches& structTypeCaches(napi_env env) { + return structTypeCachesByEnv[env]; +} -ffi_type* typeFromStruct(napi_env env, const char** encoding) { +ffi_type* typeFromStruct(napi_env env, const char** encoding, bool* ownsType, + std::vector>* retainedElementTypes) { + auto& caches = structTypeCaches(env); + auto& processingEncodingStructs = caches.processingEncodingStructs; + auto& forwardDeclaredEncodingStructs = caches.forwardDeclaredEncodingStructs; + *ownsType = false; // Extract struct name for cycle detection std::string structname; const char* nameStart = *encoding + 1; // skip '{' @@ -502,6 +513,20 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha return &ffi_type_pointer; } + // Reuse a single placeholder when a recursive layout references the same + // struct more than once. + auto existingForwardIt = forwardDeclaredEncodingStructs.find(structname); + if (existingForwardIt != forwardDeclaredEncodingStructs.end()) { + (*encoding)++; // skip '{' + while (**encoding != '\0' && **encoding != '}') { + (*encoding)++; + } + if (**encoding == '}') { + (*encoding)++; + } + return existingForwardIt->second; + } + // Check if we're already processing this struct (cycle detection) if (processingEncodingStructs.find(structname) != processingEncodingStructs.end()) { // Create a forward declaration placeholder @@ -514,19 +539,6 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha // Cache this forward declaration for later resolution forwardDeclaredEncodingStructs[structname] = forwardType; - // Skip the struct encoding - (*encoding)++; // skip '{' - while (**encoding != '}') { - (*encoding)++; - } - (*encoding)++; // skip '}' - - return forwardType; - } - - // Check if we already have a forward declaration for this struct - auto existingForwardIt = forwardDeclaredEncodingStructs.find(structname); - if (existingForwardIt != forwardDeclaredEncodingStructs.end()) { // Skip the struct encoding (*encoding)++; // skip '{' while (**encoding != '\0' && **encoding != '}') { @@ -536,7 +548,7 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha (*encoding)++; // skip '}' } - return existingForwardIt->second; + return forwardType; } // Mark this struct as being processed @@ -564,8 +576,9 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha (*encoding)++; // skip '=' while (**encoding != '\0' && **encoding != '}') { - ffi_type* elementType = TypeConv::Make(env, encoding)->type; - elements.push_back(elementType); + auto elementType = TypeConv::Make(env, encoding); + elements.push_back(elementType->type); + retainedElementTypes->push_back(std::move(elementType)); } if (**encoding == '}') { @@ -596,12 +609,23 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha // Remove from processing set processingEncodingStructs.erase(structname); + *ownsType = true; return type; } ffi_type* typeFromStruct(napi_env env, MDMetadataReader* reader, MDSectionOffset structOffset, - bool isUnion) { + bool isUnion, bool* ownsType, + std::vector>* retainedElementTypes) { + auto& caches = structTypeCaches(env); + auto& processingStructs = caches.processingStructs; + auto& forwardDeclaredStructs = caches.forwardDeclaredStructs; + *ownsType = false; + auto existingForwardIt = forwardDeclaredStructs.find(structOffset); + if (existingForwardIt != forwardDeclaredStructs.end()) { + return existingForwardIt->second; + } + // Check if we're already processing this struct (cycle detection) if (processingStructs.find(structOffset) != processingStructs.end()) { // Create a forward declaration placeholder @@ -616,12 +640,6 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha return forwardType; } - // Check if we already have a forward declaration for this struct - auto existingForwardIt = forwardDeclaredStructs.find(structOffset); - if (existingForwardIt != forwardDeclaredStructs.end()) { - return existingForwardIt->second; - } - // Mark this struct as being processed processingStructs.insert(structOffset); @@ -648,8 +666,9 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha } currentOffset += sizeof(MDSectionOffset); // skip name if (!isUnion) currentOffset += sizeof(uint16_t); // skip offset - ffi_type* elementType = TypeConv::Make(env, reader, ¤tOffset, 1)->type; - elements.push_back(elementType); + auto elementType = TypeConv::Make(env, reader, ¤tOffset, 1); + elements.push_back(elementType->type); + retainedElementTypes->push_back(std::move(elementType)); } type->elements = (ffi_type**)malloc(sizeof(ffi_type*) * (elements.size() + 1)); @@ -676,6 +695,7 @@ MDSectionOffset findProtocolMetadataOffset(MDMetadataReader* metadata, const cha // Remove from processing set processingStructs.erase(structOffset); + *ownsType = true; return type; } @@ -1355,68 +1375,10 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE void** res = (void**)result; - auto unwrapKnownNativeHandle = [&](napi_value input, void** out) -> bool { - auto bridgeState = ObjCBridgeState::InstanceData(env); - if (bridgeState != nullptr) { - napi_valuetype inputType = napi_undefined; - if (napi_typeof(env, input, &inputType) == napi_ok && - (inputType == napi_function || inputType == napi_object)) { - id bridgedType = nil; - if (bridgeState->tryResolveBridgedTypeConstructor(env, input, &bridgedType) && - bridgedType != nil) { - *out = (void*)bridgedType; - return true; - } - } - } - - void* wrapped = nullptr; - napi_status unwrapStatus = napi_unwrap(env, input, &wrapped); - if (unwrapStatus != napi_ok) { - bool hasNativePointer = false; - if (napi_has_named_property(env, input, "__ns_native_ptr", &hasNativePointer) == - napi_ok && - hasNativePointer) { - napi_value nativePointerValue = nullptr; - if (napi_get_named_property(env, input, "__ns_native_ptr", &nativePointerValue) == - napi_ok && - Pointer::isInstance(env, nativePointerValue)) { - Pointer* pointer = Pointer::unwrap(env, nativePointerValue); - if (pointer != nullptr && pointer->data != nullptr) { - *out = pointer->data; - return true; - } - } - } - return false; - } - - if (bridgeState != nullptr) { - for (const auto& entry : bridgeState->classes) { - auto bridgedClass = entry.second; - if (bridgedClass == wrapped) { - *out = (void*)bridgedClass->nativeClass; - return true; - } - } - - for (const auto& entry : bridgeState->protocols) { - auto bridgedProtocol = entry.second; - if (bridgedProtocol == wrapped) { - *out = (void*)objc_getProtocol(bridgedProtocol->name.c_str()); - return true; - } - } - } - - *out = wrapped; - return true; - }; - napi_valuetype type; napi_typeof(env, value, &type); @@ -1789,11 +1751,14 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, *res = data; return; } + if (unwrapKnownNativeHandle(env, value, res)) { + return; + } break; } case napi_function: { - if (unwrapKnownNativeHandle(value, res)) { + if (unwrapKnownNativeHandle(env, value, res)) { return; } break; @@ -1850,7 +1815,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE void** res = (void**)result; @@ -1975,7 +1940,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE void** res = (void**)result; @@ -2096,7 +2061,7 @@ napi_value toJS(napi_env env, void* cont, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_valuetype valuetype; napi_typeof(env, value, &valuetype); @@ -2347,7 +2312,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE id* res = (id*)result; @@ -2466,9 +2431,8 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, } void* wrapped = nullptr; - status = napi_unwrap(env, value, &wrapped); - - if (status != napi_ok) { + bool knownNativeHandle = unwrapKnownNativeHandle(env, value, &wrapped); + if (!knownNativeHandle) { bool isArrayBuffer = false; napi_is_arraybuffer(env, value, &isArrayBuffer); if (isArrayBuffer) { @@ -2874,7 +2838,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE napi_valuetype type; napi_typeof(env, value, &type); @@ -2915,24 +2879,25 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, kind = mdTypeClass; } - napi_value toJS(napi_env env, void* value, uint32_t flags) override { - Class cls = *((Class*)value); + napi_value toJS(napi_env env, void* value, uint32_t flags) override { + Class cls = *((Class*)value); - if (cls == nullptr) { - napi_value null; - napi_get_null(env, &null); - return null; - } + if (cls == nullptr) { + napi_value null; + napi_get_null(env, &null); + return null; + } - if (napi_value constructor = findRegisteredClassConstructor(env, cls); - constructor != nullptr) { - return constructor; - } + if (napi_value constructor = findRegisteredClassConstructor(env, cls); + constructor != nullptr) { + return constructor; + } - auto bridgeState = ObjCBridgeState::InstanceData(env); - return bridgeState != nullptr ? bridgeState->getObject(env, (id)cls, kUnownedObject, 0, nullptr) - : nullptr; - } + auto bridgeState = ObjCBridgeState::InstanceData(env); + return bridgeState != nullptr + ? bridgeState->getObject(env, (id)cls, kUnownedObject, 0, nullptr) + : nullptr; + } void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { @@ -2946,8 +2911,6 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, static const std::shared_ptr objcClassTypeConv = std::make_shared(); -char selector_name_buf[256]; - class SelectorTypeConv : public TypeConv { public: SelectorTypeConv() { @@ -2964,7 +2927,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE SEL* res = (SEL*)result; @@ -2972,14 +2935,24 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, napi_typeof(env, value, &type); switch (type) { - case napi_string: - NAPI_GUARD(napi_get_value_string_utf8(env, value, selector_name_buf, 256, NULL)) { + case napi_string: { + size_t length = 0; + NAPI_GUARD(napi_get_value_string_utf8(env, value, nullptr, 0, &length)) { + NAPI_THROW_LAST_ERROR + *res = NULL; + return; + } + + std::vector selectorName(length + 1, '\0'); + NAPI_GUARD(napi_get_value_string_utf8(env, value, selectorName.data(), + selectorName.size(), &length)) { NAPI_THROW_LAST_ERROR *res = NULL; return; } - *res = sel_registerName(selector_name_buf); + *res = sel_registerName(selectorName.data()); break; + } case napi_undefined: case napi_null: @@ -3005,12 +2978,22 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, StructInfo* info = nullptr; bool structInfoSearched = false; - StructTypeConv(MDSectionOffset structOffset, ffi_type* type) : structOffset(structOffset) { + StructTypeConv(MDSectionOffset structOffset, ffi_type* type, bool ownsType, + std::vector> retainedElementTypes) + : structOffset(structOffset), + ownsType(ownsType), + retainedElementTypes(std::move(retainedElementTypes)) { this->type = type; kind = mdTypeStruct; } - // ~StructTypeConv() { delete type; } + ~StructTypeConv() override { + if (ownsType && type != nullptr) { + std::free(type->elements); + delete type; + type = nullptr; + } + } inline StructInfo* getInfo(napi_env env) { if (!structInfoSearched) { @@ -3047,7 +3030,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE const size_t structSize = getStructSize(env); if (structSize == 0) { @@ -3096,7 +3079,9 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, return; } - auto structObject = StructObject::unwrap(env, value); + auto structObject = StructObject::isInstance(env, value) + ? StructObject::unwrap(env, value) + : nullptr; if (structObject != nullptr) { const size_t copySize = std::min(static_cast(structObject->info->size), structSize); memset(result, 0, structSize); @@ -3122,6 +3107,10 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, // Serialize directly to previously allocated memory. StructObject(env, info, value, result); } + + private: + bool ownsType; + std::vector> retainedElementTypes; }; class ArrayTypeConv : public TypeConv { @@ -3145,6 +3134,14 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, kind = mdTypeArray; } + ~ArrayTypeConv() override { + if (type != nullptr) { + std::free(type->elements); + delete type; + type = nullptr; + } + } + ffi_type* ffiTypeForArgument() override { decayToPointerForArguments = true; return &ffi_type_pointer; @@ -3187,7 +3184,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE if (decayToPointerForArguments) { void** pointerResult = static_cast(result); @@ -3386,6 +3383,14 @@ void copyToInlineArrayStorage(napi_env env, napi_value value, void* result, bool kind = vectorKind; } + ~VectorTypeConv() override { + if (type != nullptr) { + std::free(type->elements); + delete type; + type = nullptr; + } + } + napi_value toJS(napi_env env, void* value, uint32_t flags) override { napi_value result; napi_create_array_with_length(env, vectorSize, &result); @@ -3409,7 +3414,7 @@ napi_value toJS(napi_env env, void* value, uint32_t flags) override { void toNative(napi_env env, napi_value value, void* result, bool* shouldFree, bool* shouldFreeAny) override { - NAPI_PREAMBLE + NS_OBJC_NAPI_PREAMBLE memset(result, 0, getVectorByteSize()); @@ -3598,9 +3603,10 @@ void writeFromArrayElements(napi_env env, napi_value value, void* result, bool* (*encoding)++; } // skip array type (*encoding)++; // skip ']' - return std::make_shared(ArrayTypeConv(arraySize, elementType)); + return std::make_shared(arraySize, elementType); } case '{': { + auto& encodingStructCache = structTypeCaches(env).encodingStructTypes; std::string structname; const char* c = *encoding + 1; while (*c != '\0' && *c != '=') { @@ -3631,8 +3637,11 @@ void writeFromArrayElements(napi_env env, napi_value value, void* result, bool* structOffset = structOffsetIt->second; } } - auto type = typeFromStruct(env, encoding); - auto structTypeConv = std::make_shared(StructTypeConv(structOffset, type)); + bool ownsType = false; + std::vector> retainedElementTypes; + auto type = typeFromStruct(env, encoding, &ownsType, &retainedElementTypes); + auto structTypeConv = std::make_shared( + structOffset, type, ownsType, std::move(retainedElementTypes)); // Cache the StructTypeConv encodingStructCache[structname] = structTypeConv; @@ -3806,10 +3815,13 @@ void writeFromArrayElements(napi_env env, napi_value value, void* result, bool* auto arraySize = reader->getArraySize(*offset); *offset += sizeof(uint16_t); auto elementType = TypeConv::Make(env, reader, offset); - return std::make_shared(ArrayTypeConv(arraySize, elementType)); + return std::make_shared(arraySize, elementType); } case mdTypeStruct: { + auto& caches = structTypeCaches(env); + auto& processingStructs = caches.processingStructs; + auto& structTypeCache = caches.structTypes; auto structOffset = reader->getOffset(*offset); *offset += sizeof(MDSectionOffset); auto isUnion = (structOffset & mdSectionOffsetNext) != 0; @@ -3830,11 +3842,15 @@ void writeFromArrayElements(napi_env env, napi_value value, void* result, bool* bool isRecursive = processingStructs.find(structOffset) != processingStructs.end(); ffi_type* type = nullptr; + bool ownsType = false; + std::vector> retainedElementTypes; if (opaquePointers != 2 && !isRecursive) { - type = typeFromStruct(env, reader, structOffset, isUnion); + type = typeFromStruct(env, reader, structOffset, isUnion, &ownsType, + &retainedElementTypes); } - auto structTypeConv = std::make_shared(structOffset, type); + auto structTypeConv = std::make_shared( + structOffset, type, ownsType, std::move(retainedElementTypes)); // Cache the StructTypeConv to handle recursion and avoid duplicates structTypeCache[structOffset] = structTypeConv; @@ -4023,6 +4039,11 @@ bool tryFastConvertObjCObjectValue(napi_env env, napi_value value, napi_valuetyp }; if (valueType == napi_object) { + bool isArray = false; + if (napi_is_array(env, value, &isArray) == napi_ok && isArray) { + return false; + } + if (Pointer::isInstance(env, value)) { Pointer* ptr = Pointer::unwrap(env, value); void* pointerData = ptr != nullptr ? ptr->data : nullptr; @@ -4046,48 +4067,9 @@ bool tryFastConvertObjCObjectValue(napi_env env, napi_value value, napi_valuetyp } } - if (bridgeState != nullptr) { - id bridgedType = nil; - if (bridgeState->tryResolveBridgedTypeConstructor(env, value, &bridgedType) && - bridgedType != nil) { - *out = bridgedType; - return true; - } - } - - void* wrapped = nullptr; - if (napi_unwrap(env, value, &wrapped) == napi_ok) { - if (valueType == napi_function || valueType == napi_object) { - auto bridgeState = ObjCBridgeState::InstanceData(env); - if (bridgeState != nullptr && wrapped != nullptr) { - for (const auto& entry : bridgeState->classes) { - auto bridgedClass = entry.second; - if (bridgedClass == wrapped) { - *out = (id)bridgedClass->nativeClass; - return true; - } - } - - for (const auto& entry : bridgeState->protocols) { - auto bridgedProtocol = entry.second; - if (bridgedProtocol == wrapped) { - Protocol* runtimeProtocol = objc_getProtocol(bridgedProtocol->name.c_str()); - if (runtimeProtocol == nil) { - std::string baseName; - if (stripProtocolSuffix(bridgedProtocol->name.c_str(), &baseName)) { - runtimeProtocol = objc_getProtocol(baseName.c_str()); - } - } - if (runtimeProtocol != nil) { - *out = (id)runtimeProtocol; - return true; - } - } - } - } - } - - *out = (id)wrapped; + void* nativeHandle = nullptr; + if (unwrapKnownNativeHandle(env, value, &nativeHandle)) { + *out = (id)nativeHandle; cacheRoundTrip(*out); return true; } @@ -4195,6 +4177,14 @@ bool TryFastConvertNapiArgument(napi_env env, MDTypeKind kind, napi_value value, } } +bool ConsumeNapiArgumentConversionFailure(napi_env env) { + if (failedObjectConversionEnv != env) { + return false; + } + failedObjectConversionEnv = nullptr; + return true; +} + bool TryFastConvertNapiUInt16Argument(napi_env env, napi_value value, uint16_t* result) { if (result == nullptr || value == nullptr) { return false; @@ -4240,13 +4230,26 @@ bool TryFastConvertNapiUInt16Argument(napi_env env, napi_value value, uint16_t* } // Cleanup function to clear thread-local caches -void clearStructTypeCaches() { - processingStructs.clear(); - processingEncodingStructs.clear(); - forwardDeclaredStructs.clear(); - forwardDeclaredEncodingStructs.clear(); - structTypeCache.clear(); - encodingStructCache.clear(); +void clearStructTypeCaches(napi_env env) { + auto cacheIt = structTypeCachesByEnv.find(env); + if (cacheIt == structTypeCachesByEnv.end()) { + return; + } + + auto& caches = cacheIt->second; + caches.structTypes.clear(); + caches.encodingStructTypes.clear(); + + for (const auto& entry : caches.forwardDeclaredStructs) { + std::free(entry.second->elements); + delete entry.second; + } + for (const auto& entry : caches.forwardDeclaredEncodingStructs) { + std::free(entry.second->elements); + delete entry.second; + } + + structTypeCachesByEnv.erase(cacheIt); } } // namespace nativescript diff --git a/NativeScript/ffi/objc/napi/Util.mm b/NativeScript/ffi/objc/napi/Util.mm index f5816ed14..5b4ba0e1f 100644 --- a/NativeScript/ffi/objc/napi/Util.mm +++ b/NativeScript/ffi/objc/napi/Util.mm @@ -116,8 +116,6 @@ napi_value jsSymbolFor(napi_env env, const char* string) { return symbol; } -char name_buf[512]; - std::string getEncodedType(napi_env env, napi_value value) { napi_valuetype type; napi_typeof(env, value, &type); diff --git a/NativeScript/ffi/objc/napi/node_api_util.h b/NativeScript/ffi/objc/napi/node_api_util.h index 8a1a0dc00..9ffb7cb17 100644 --- a/NativeScript/ffi/objc/napi/node_api_util.h +++ b/NativeScript/ffi/objc/napi/node_api_util.h @@ -12,10 +12,10 @@ inline bool napiSupportsThreadsafeFunctions(void* dl) { #define NAPI_EXPORT __attribute__((visibility("default"))) -#define NAPI_PREAMBLE napi_status status; +#define NS_OBJC_NAPI_PREAMBLE napi_status status; #define NAPI_CALLBACK_BEGIN(n_args) \ - NAPI_PREAMBLE \ + NS_OBJC_NAPI_PREAMBLE \ napi_value argv[n_args]; \ size_t argc = n_args; \ napi_value jsThis; \ diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.h b/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.h index c26fe8bfa..d37467617 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.h +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.h @@ -12,6 +12,7 @@ using NativeApiConfig = NativeApiBackendConfig; void InstallNativeApi(JSContext* context, const NativeApiConfig& config = NativeApiConfig{}); +void CleanupNativeApi(JSContext* context); } // namespace nativescript diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.mm b/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.mm index 8f234d1bd..60a9f2b05 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.mm +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJS.mm @@ -64,6 +64,12 @@ void InstallNativeApi(JSContext* context, const NativeApiConfig& config) { InstallNativeApi(runtime, config); } +void CleanupNativeApi(JSContext* context) { + if (context != nullptr) { + engine::quickjsengine::releaseStateForContext(context); + } +} + } // namespace nativescript extern "C" void NativeScriptInstallNativeApi(JSContext* context, const char* metadataPath) { diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSGsd.mm b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSGsd.mm index 998dcfef5..eed6e786e 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSGsd.mm +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSGsd.mm @@ -269,8 +269,8 @@ void setObject(id obj) { } // namespace (temporary close for GSD .inc) #if defined(__has_include) -#if __has_include("GeneratedGsdSignatureDispatch.inc") -#include "GeneratedGsdSignatureDispatch.inc" +#if __has_include("../shared/GeneratedGsdSignatureDispatch.inc") +#include "../shared/GeneratedGsdSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSHostObjects.mm b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSHostObjects.mm index 15532e17f..2f38e3ffb 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSHostObjects.mm +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSHostObjects.mm @@ -39,6 +39,21 @@ return state; } +void releaseStateForContext(JSContext* context) { + std::shared_ptr state; + { + std::lock_guard lock(runtimeStatesMutex()); + auto& states = runtimeStates(); + auto it = states.find(context); + if (it == states.end()) { + return; + } + state = std::move(it->second); + states.erase(it); + } + state->cleanup(); +} + static bool isNativeInstancePrototypeBypassExcluded(JSContext* ctx, JSAtom atom) { const char* name = JS_AtomToCString(ctx, atom); @@ -215,6 +230,9 @@ static int nativeHostOwnNames(JSContext* ctx, JSPropertyEnum** ptab, uint32_t* p static void nativeHostFinalize(JSRuntime*, JSValue value) { auto* holder = static_cast(JS_GetOpaque(value, gHostClassId)); + if (holder != nullptr && holder->state != nullptr) { + holder->state->untrack(holder); + } delete holder; } @@ -252,6 +270,9 @@ static JSValue nativeFunctionCallData(JSContext* ctx, JSValue thisValue, int arg static void nativeFunctionFinalize(JSRuntime*, JSValue value) { auto* holder = static_cast(JS_GetOpaque(value, gFunctionClassId)); + if (holder != nullptr && holder->state != nullptr) { + holder->state->untrack(holder); + } delete holder; } @@ -311,6 +332,11 @@ void ensureClasses(Runtime& runtime) { auto* holder = new quickjsengine::HostObjectHolder(runtime.state(), std::move(host), typeToken); JSValue object = JS_NewObjectClass(runtime.context(), quickjsengine::gHostClassId); JS_SetOpaque(object, holder); + runtime.state()->track(holder, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->state.reset(); + tracked->hostObject.reset(); + }); Object result = Object::fromValueStorage(Value(runtime, object).storage_); JS_FreeValue(runtime.context(), object); return result; @@ -326,6 +352,11 @@ void ensureClasses(Runtime& runtime) { throw JSError(runtime, "QuickJS host function data allocation failed."); } JS_SetOpaque(data, holder); + runtime.state()->track(holder, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->state.reset(); + tracked->callback = {}; + }); JSValue function = JS_NewCFunctionData(runtime.context(), quickjsengine::nativeFunctionCallData, static_cast(parameterCount), 0, 1, &data); diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSRuntime.h b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSRuntime.h index 8d1e0983d..04f9620d4 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSRuntime.h +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSRuntime.h @@ -31,6 +31,7 @@ #include #include +#include "../shared/RuntimeCleanupRegistry.h" #include "Metadata.h" #include "MetadataReader.h" #include "ffi.h" @@ -110,7 +111,7 @@ const void* hostObjectTypeToken() { return &token; } -struct RuntimeState { +struct RuntimeState : RuntimeCleanupRegistry { explicit RuntimeState(JSContext* context) : context(context) {} JSContext* context = nullptr; bool hostClassRegistered = false; @@ -122,6 +123,7 @@ extern JSClassID gHostClassId; extern JSClassID gFunctionClassId; std::shared_ptr stateForContext(JSContext* context); +void releaseStateForContext(JSContext* context); struct ValueStorage { enum class Kind { @@ -211,6 +213,7 @@ class Runtime { explicit Runtime(std::shared_ptr state) : state_(std::move(state)) {} JSContext* context() const { return state_->context; } std::shared_ptr state() const { return state_; } + void detachState() { state_.reset(); } Object global(); Value evaluateJavaScript(std::shared_ptr buffer, const std::string& sourceURL); void drainMicrotasks() { diff --git a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSSelectorGroups.mm b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSSelectorGroups.mm index bb9fe56c2..570e8ae0e 100644 --- a/NativeScript/ffi/objc/quickjs/NativeApiQuickJSSelectorGroups.mm +++ b/NativeScript/ffi/objc/quickjs/NativeApiQuickJSSelectorGroups.mm @@ -185,6 +185,9 @@ throw JSError( void NativeApiSelectorGroupFinalize(JSRuntime*, JSValue value) { auto* data = static_cast( JS_GetOpaque(value, gNativeApiSelectorGroupDataClassId)); + if (data != nullptr && data->runtime.state() != nullptr) { + data->runtime.state()->untrack(data); + } delete data; } @@ -268,6 +271,15 @@ Function CreateNativeApiSelectorGroupFunctionImpl( throw JSError(runtime, "QuickJS selector group allocation failed."); } JS_SetOpaque(dataObject, data); + runtime.state()->track(data, [](void* pointer) { + auto* tracked = static_cast(pointer); + tracked->runtime.detachState(); + tracked->bridge.reset(); + tracked->selectors.reset(); + tracked->preparedInvocations.reset(); + tracked->boundReceiver.reset(); + tracked->boundReceiverState.reset(); + }); JSValue function = JS_NewCFunctionData(runtime.context(), NativeApiSelectorGroupCall, diff --git a/NativeScript/ffi/objc/quickjs/SignatureDispatch.h b/NativeScript/ffi/objc/quickjs/SignatureDispatch.h index 2b9c0436b..7151eb22e 100644 --- a/NativeScript/ffi/objc/quickjs/SignatureDispatch.h +++ b/NativeScript/ffi/objc/quickjs/SignatureDispatch.h @@ -4,8 +4,8 @@ #include "ffi/objc/shared/SignatureDispatchCore.h" #if defined(__has_include) -#if __has_include("GeneratedSignatureDispatch.inc") -#include "GeneratedSignatureDispatch.inc" +#if __has_include("../shared/GeneratedSignatureDispatch.inc") +#include "../shared/GeneratedSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/shared/RuntimeCleanupRegistry.h b/NativeScript/ffi/objc/shared/RuntimeCleanupRegistry.h new file mode 100644 index 000000000..d30928173 --- /dev/null +++ b/NativeScript/ffi/objc/shared/RuntimeCleanupRegistry.h @@ -0,0 +1,39 @@ +#ifndef NATIVESCRIPT_FFI_OBJC_RUNTIME_CLEANUP_REGISTRY_H +#define NATIVESCRIPT_FFI_OBJC_RUNTIME_CLEANUP_REGISTRY_H + +#include +#include + +namespace nativescript::engine { + +class RuntimeCleanupRegistry { + public: + using Cleanup = void (*)(void*); + + void track(void* pointer, Cleanup cleanup) { actions_[pointer] = cleanup; } + + template + void track(T* pointer) { + track(pointer, [](void* value) { delete static_cast(value); }); + } + + void untrack(void* pointer) { actions_.erase(pointer); } + bool empty() const { return actions_.empty(); } + + void cleanup() { + while (!actions_.empty()) { + auto action = actions_.begin(); + void* pointer = action->first; + Cleanup cleanup = action->second; + actions_.erase(action); + cleanup(pointer); + } + } + + private: + std::unordered_map actions_; +}; + +} // namespace nativescript::engine + +#endif // NATIVESCRIPT_FFI_OBJC_RUNTIME_CLEANUP_REGISTRY_H diff --git a/NativeScript/ffi/objc/shared/bridge/Callbacks.mm b/NativeScript/ffi/objc/shared/bridge/Callbacks.mm index 0188e6e78..4e8fb6146 100644 --- a/NativeScript/ffi/objc/shared/bridge/Callbacks.mm +++ b/NativeScript/ffi/objc/shared/bridge/Callbacks.mm @@ -1714,7 +1714,20 @@ NativeApiType parseObjCEncodedAggregateEngineType( NSUInteger fieldSize = 0; NSUInteger fieldAlignment = 0; - NSGetSizeAndAlignment(fieldStart, &fieldSize, &fieldAlignment); + @try { + NSGetSizeAndAlignment(fieldStart, &fieldSize, &fieldAlignment); + } @catch (NSException*) { + // Some valid method encodings contain standalone bitfields, which + // Foundation refuses to size. Mark the runtime-derived aggregate as + // unsupported so metadata remains authoritative instead of leaking an + // Objective-C exception through the engine host-object boundary. + type.supported = false; + type.ffiType = nullptr; + if (endEncoding != nullptr) { + *endEncoding = fieldEnd; + } + return type; + } size_t nativeFieldSize = fieldSize > 0 ? static_cast(fieldSize) : nativeSizeForType(field.type); diff --git a/NativeScript/ffi/objc/shared/bridge/HostObject.mm b/NativeScript/ffi/objc/shared/bridge/HostObject.mm index d16a91f96..e9efdafd9 100644 --- a/NativeScript/ffi/objc/shared/bridge/HostObject.mm +++ b/NativeScript/ffi/objc/shared/bridge/HostObject.mm @@ -2,6 +2,20 @@ #error Engine backends must define NATIVESCRIPT_NATIVE_API_BACKEND_NAME. #endif +extern "C" { +void* objc_autoreleasePoolPush(void); +void objc_autoreleasePoolPop(void* pool); +} + +class NativeApiAutoreleasePool final { + public: + NativeApiAutoreleasePool() : pool_(objc_autoreleasePoolPush()) {} + ~NativeApiAutoreleasePool() { objc_autoreleasePoolPop(pool_); } + + private: + void* pool_; +}; + #ifndef NATIVESCRIPT_NATIVE_API_RUNTIME_NAME #define NATIVESCRIPT_NATIVE_API_RUNTIME_NAME NATIVESCRIPT_NATIVE_API_BACKEND_NAME #endif @@ -40,6 +54,20 @@ Value get(Runtime& runtime, const PropNameID& name) override { if (property == "interop") { return createInteropObject(runtime, bridge_); } + if (property == "autoreleasepool") { + return Function::createFromHostFunction( + runtime, PropNameID::forAscii(runtime, "autoreleasepool"), 1, + [](Runtime& runtime, const Value&, const Value* args, + size_t count) -> Value { + if (count < 1 || !args[0].isObject() || + !args[0].asObject(runtime).isFunction(runtime)) { + throw JSError(runtime, + "autoreleasepool expects a callback function."); + } + NativeApiAutoreleasePool pool; + return args[0].asObject(runtime).asFunction(runtime).call(runtime); + }); + } #ifdef NATIVESCRIPT_NATIVE_API_HAS_ENGINE_LAZY_GLOBALS if (property == "__defineLazyGlobal") { auto bridge = bridge_; @@ -514,6 +542,7 @@ throw JSError(runtime, addPropertyName(runtime, names, "metadata"); addPropertyName(runtime, names, "hasScheduler"); addPropertyName(runtime, names, "interop"); + addPropertyName(runtime, names, "autoreleasepool"); #ifdef NATIVESCRIPT_NATIVE_API_HAS_ENGINE_LAZY_GLOBALS addPropertyName(runtime, names, "__defineLazyGlobal"); #endif diff --git a/NativeScript/ffi/objc/shared/bridge/Install.mm b/NativeScript/ffi/objc/shared/bridge/Install.mm index 611747cf8..64cad6a7d 100644 --- a/NativeScript/ffi/objc/shared/bridge/Install.mm +++ b/NativeScript/ffi/objc/shared/bridge/Install.mm @@ -1642,6 +1642,22 @@ function installInteropConstructors() { } } + function installObjcHelpers() { + var objc = globalThis.objc; + if (!objc || (typeof objc !== 'object' && typeof objc !== 'function')) { + objc = {}; + Object.defineProperty(globalThis, 'objc', { + configurable: true, + enumerable: true, + writable: true, + value: objc + }); + } + if (typeof objc.autoreleasepool !== 'function') { + objc.autoreleasepool = api.autoreleasepool; + } + } + function defineInlineFunction(name, value) { if (Object.prototype.hasOwnProperty.call(globalThis, name)) { return; @@ -1811,6 +1827,7 @@ function resolveNativeApiEnum(enumName) { defineLazyGlobal('CC_SHA256', function() { return api.CC_SHA256; }); installInteropConstructors(); + installObjcHelpers(); installTypeScriptNativeHelpers(); installInlineFunctions(); diff --git a/NativeScript/ffi/objc/shared/bridge/TypeConv.mm b/NativeScript/ffi/objc/shared/bridge/TypeConv.mm index 908c144c6..98ecf6994 100644 --- a/NativeScript/ffi/objc/shared/bridge/TypeConv.mm +++ b/NativeScript/ffi/objc/shared/bridge/TypeConv.mm @@ -86,9 +86,8 @@ id objectFromEngineValueImpl( if (object.isHostObject(runtime)) { return static_cast(object.getHostObject(runtime)->data()); } - if (object.isHostObject(runtime)) { - return static_cast( - object.getHostObject(runtime)->data()); + if (auto structObject = getNativeStructHostObject(runtime, object)) { + return static_cast(structObject->data()); } Value getTimeValue = object.getProperty(runtime, "getTime"); @@ -412,8 +411,8 @@ throw JSError(runtime, std::string(constructorName) + } return reference->data(); } - if (object.isHostObject(runtime)) { - return object.getHostObject(runtime)->data(); + if (auto structObject = getNativeStructHostObject(runtime, object)) { + return structObject->data(); } void* nativePointer = nullptr; if (readNativePointerProperty(runtime, object, &nativePointer)) { @@ -453,8 +452,8 @@ bool readPointerLikeValue(Runtime& runtime, const Value& value, void** pointer) *pointer = object.getHostObject(runtime)->data(); return true; } - if (object.isHostObject(runtime)) { - *pointer = object.getHostObject(runtime)->data(); + if (auto structObject = getNativeStructHostObject(runtime, object)) { + *pointer = structObject->data(); return true; } if (object.isHostObject(runtime)) { @@ -580,8 +579,7 @@ void convertAggregateArgument(Runtime& runtime, const std::shared_ptr(runtime)) { - auto structObject = object.getHostObject(runtime); + if (auto structObject = getNativeStructHostObject(runtime, object)) { if (structObject->data() != nullptr) { std::memcpy(target, structObject->data(), std::min(size, static_cast(structObject->info()->size))); @@ -863,8 +861,8 @@ throw JSError(runtime, "This native signature is not supported by " *static_cast(target) = pointer; break; } - if (object.isHostObject(runtime)) { - void* pointer = object.getHostObject(runtime)->data(); + if (auto structObject = getNativeStructHostObject(runtime, object)) { + void* pointer = structObject->data(); frame.rememberRoundTripValue(bridge, runtime, pointer, value); *static_cast(target) = pointer; break; @@ -1158,7 +1156,7 @@ throw JSError(runtime, "This native return type is not supported by " return ArrayBuffer( runtime, std::make_shared(value, nativeSizeForType(type))); } - return Object::createFromHostObject( + return createNativeStructHostObject( runtime, std::make_shared(bridge, type.aggregateInfo, value, true)); case metagen::mdTypeArray: @@ -1314,7 +1312,7 @@ throw JSError(runtime, "This native return type is not supported by " } void* fieldData = static_cast(data_) + field.offset; if (field.type.kind == metagen::mdTypeStruct && field.type.aggregateInfo != nullptr) { - return Object::createFromHostObject( + return createNativeStructHostObject( runtime, std::make_shared( bridge_, field.type.aggregateInfo, fieldData, false, ownedData_, backingValue_)); @@ -1434,8 +1432,7 @@ NativeApiType primitiveInteropType(MDTypeKind kind) { return nativeObjectReturnTypeForClass(descriptorClass); } - if (object.isHostObject(runtime)) { - auto structObject = object.getHostObject(runtime); + if (auto structObject = getNativeStructHostObject(runtime, object)) { NativeApiType type; type.kind = metagen::mdTypeStruct; type.aggregateInfo = structObject->info(); @@ -1520,10 +1517,10 @@ Value makeAggregateConstructor(Runtime& runtime, const std::shared_ptr 0 && args[0].isObject()) { void* pointer = nullptr; if (readPointerLikeValue(runtime, args[0], &pointer) && pointer != nullptr) { - return Object::createFromHostObject(runtime, - std::make_shared( - bridge, info, pointer, false, nullptr, - std::make_shared(runtime, args[0]))); + return createNativeStructHostObject( + runtime, std::make_shared( + bridge, info, pointer, false, nullptr, + std::make_shared(runtime, args[0]))); } } @@ -1532,7 +1529,7 @@ Value makeAggregateConstructor(Runtime& runtime, const std::shared_ptr(bridge, info, storage.data(), true)); }); @@ -1931,6 +1928,9 @@ Object createInteropObject(Runtime& runtime, const std::shared_ptr(runtime)) { data = object.getHostObject(runtime)->pointer(); usesExternalStorage = true; @@ -1942,9 +1942,8 @@ Object createInteropObject(Runtime& runtime, const std::shared_ptr(runtime)) { - data = object.getHostObject(runtime)->data(); + } else if (structObject != nullptr) { + data = structObject->data(); usesExternalStorage = true; } else if (type.kind == metagen::mdTypePointer || type.kind == metagen::mdTypeOpaquePointer || @@ -2086,8 +2085,7 @@ Object createInteropObject(Runtime& runtime, const std::shared_ptr(runtime)) { - auto structObject = object.getHostObject(runtime); + if (auto structObject = getNativeStructHostObject(runtime, object)) { if (structObject->backingValue() != nullptr) { return Value(runtime, *structObject->backingValue()); } diff --git a/NativeScript/ffi/objc/shared/bridge/host_objects/Object.mm b/NativeScript/ffi/objc/shared/bridge/host_objects/Object.mm index 2fd5b80be..afe14d2c5 100644 --- a/NativeScript/ffi/objc/shared/bridge/host_objects/Object.mm +++ b/NativeScript/ffi/objc/shared/bridge/host_objects/Object.mm @@ -553,6 +553,50 @@ static Value descriptionString(Runtime& runtime, id object) { return makeString(runtime, text); } + void finishInitializer(Runtime& runtime, id receiver, Value& result, + const std::optional& classWrapper) { + id resultObject = nativeObjectFromValue(runtime, result); + std::shared_ptr resultHost; + if (result.isObject()) { + Object resultValue = result.asObject(runtime); + if (resultValue.isHostObject(runtime)) { + resultHost = resultValue.getHostObject(runtime); + } + } + + const bool returnedThisWrapper = resultHost.get() == this; + disownObject(receiver, resultObject == receiver); + if (resultObject == nil) { + return; + } + + if (returnedThisWrapper) { + // disownObject transfers the receiver's existing ownership. Restoring it + // here must not add another retain. + object_ = resultObject; + ownsObject_ = true; + wrapperRetainedObject_ = false; + if (bridge_ != nullptr) { + bridge_->retainObjectExpandoOwner(object_); + } + if (lifetimeState_ != nullptr) { + lifetimeState_->setObject(object_); + } + } + + if (classWrapper) { + bridge_->setObjectExpando(runtime, resultObject, + "__nativeApiClassWrapper", + Value(runtime, *classWrapper)); + Value prototypeValue = classWrapper->getProperty(runtime, "prototype"); + if (prototypeValue.isObject()) { + Object resultValue = result.asObject(runtime); + Object prototype = prototypeValue.asObject(runtime); + SetNativeApiObjectPrototype(runtime, resultValue, prototype); + } + } + } + Value callObjectSelector(Runtime& runtime, const std::string& selectorName, const NativeApiMember* member, const Value* args, size_t count, Class dispatchSuperClass = Nil) { @@ -577,35 +621,7 @@ throw JSError(runtime, callObjCSelector(runtime, bridge_, receiver, false, selectorName, member, args, count, dispatchSuperClass); if (initializer) { - id resultObject = nativeObjectFromValue(runtime, result); - disownObject(receiver, resultObject == receiver); - if (resultObject != nil) { - // Re-adopt the init result on this host object so that JS overrides - // returning `this` still have a valid native object. - object_ = resultObject; - ownsObject_ = true; - wrapperRetainedObject_ = true; - if (bridge_ != nullptr) { - bridge_->retainObjectExpandoOwner(object_); - } - if (lifetimeState_ != nullptr) { - lifetimeState_->setObject(object_); - } - [object_ retain]; - if (classWrapper) { - bridge_->setObjectExpando(runtime, resultObject, - "__nativeApiClassWrapper", - Value(runtime, *classWrapper)); - if (result.isObject()) { - Value prototypeValue = classWrapper->getProperty(runtime, "prototype"); - if (prototypeValue.isObject()) { - Object resultValue = result.asObject(runtime); - Object prototype = prototypeValue.asObject(runtime); - SetNativeApiObjectPrototype(runtime, resultValue, prototype); - } - } - } - } + finishInitializer(runtime, receiver, result, classWrapper); } return result; } @@ -634,35 +650,7 @@ throw JSError(runtime, runtime, bridge_, receiver, false, prepared, args, count, dispatchSuperClass); if (initializer) { - id resultObject = nativeObjectFromValue(runtime, result); - disownObject(receiver, resultObject == receiver); - if (resultObject != nil) { - // Re-adopt the init result on this host object so that JS overrides - // returning `this` still have a valid native object. - object_ = resultObject; - ownsObject_ = true; - wrapperRetainedObject_ = true; - if (bridge_ != nullptr) { - bridge_->retainObjectExpandoOwner(object_); - } - if (lifetimeState_ != nullptr) { - lifetimeState_->setObject(object_); - } - [object_ retain]; - if (classWrapper) { - bridge_->setObjectExpando(runtime, resultObject, - "__nativeApiClassWrapper", - Value(runtime, *classWrapper)); - if (result.isObject()) { - Value prototypeValue = classWrapper->getProperty(runtime, "prototype"); - if (prototypeValue.isObject()) { - Object resultValue = result.asObject(runtime); - Object prototype = prototypeValue.asObject(runtime); - SetNativeApiObjectPrototype(runtime, resultValue, prototype); - } - } - } - } + finishInitializer(runtime, receiver, result, classWrapper); } return result; } diff --git a/NativeScript/ffi/objc/shared/bridge/host_objects/Struct.mm b/NativeScript/ffi/objc/shared/bridge/host_objects/Struct.mm index a71cea169..3a4475369 100644 --- a/NativeScript/ffi/objc/shared/bridge/host_objects/Struct.mm +++ b/NativeScript/ffi/objc/shared/bridge/host_objects/Struct.mm @@ -45,3 +45,110 @@ void* data_ = nullptr; bool ownsData_ = true; }; + +#ifdef TARGET_ENGINE_HERMES +class NativeApiStructObjectState final : public NativeApiNativeState { + public: + explicit NativeApiStructObjectState( + std::shared_ptr host) + : host_(std::move(host)) {} + + std::shared_ptr host() const { + return host_; + } + + private: + std::shared_ptr host_; +}; +#endif + +std::shared_ptr getNativeStructHostObject( + Runtime& runtime, const Object& object) { + if (object.isHostObject(runtime)) { + return object.getHostObject(runtime); + } +#ifdef TARGET_ENGINE_HERMES + if (!object.hasNativeState(runtime)) { + return nullptr; + } + return object.getNativeState(runtime)->host(); +#else + return nullptr; +#endif +} + +Object createNativeStructHostObject( + Runtime& runtime, std::shared_ptr host) { +#ifdef TARGET_ENGINE_HERMES + Object objectConstructor = + runtime.global().getPropertyAsObject(runtime, "Object"); + Function defineProperty = + objectConstructor.getPropertyAsFunction(runtime, "defineProperty"); + Object object(runtime); + object.setNativeState(runtime, + std::make_shared(host)); + std::weak_ptr weakHost = host; + + for (const auto& propertyName : host->getPropertyNames(runtime)) { + std::string property = propertyName.utf8(runtime); + const auto info = host->info(); + const bool isField = info != nullptr && std::any_of( + info->fields.begin(), info->fields.end(), + [&](const NativeApiAggregateField& field) { + return field.name == property; + }); + if (!isField) { + object.setProperty(runtime, property.c_str(), + host->get(runtime, propertyName)); + continue; + } + + Object descriptor(runtime); + descriptor.setProperty(runtime, "configurable", false); + descriptor.setProperty(runtime, "enumerable", true); + descriptor.setProperty( + runtime, "get", + Function::createFromHostFunction( + runtime, PropNameID::forUtf8(runtime, property), 0, + [weakHost, property](Runtime& runtime, const Value& receiver, + const Value*, size_t) -> Value { + auto host = weakHost.lock(); + if (host == nullptr || !receiver.isObject()) { + throw JSError(runtime, "Invalid struct receiver"); + } + Object receiverObject = receiver.asObject(runtime); + if (getNativeStructHostObject(runtime, receiverObject).get() != + host.get()) { + throw JSError(runtime, "Invalid struct receiver"); + } + return host->get(runtime, + PropNameID::forUtf8(runtime, property)); + })); + + descriptor.setProperty( + runtime, "set", + Function::createFromHostFunction( + runtime, PropNameID::forUtf8(runtime, property), 1, + [weakHost, property](Runtime& runtime, const Value& receiver, + const Value* args, size_t count) -> Value { + auto host = weakHost.lock(); + if (host == nullptr || !receiver.isObject() || count < 1) { + throw JSError(runtime, "Invalid struct receiver"); + } + Object receiverObject = receiver.asObject(runtime); + if (getNativeStructHostObject(runtime, receiverObject).get() != + host.get()) { + throw JSError(runtime, "Invalid struct receiver"); + } + host->set(runtime, PropNameID::forUtf8(runtime, property), + args[0]); + return Value::undefined(); + })); + defineProperty.call(runtime, object, makeString(runtime, property), + descriptor); + } + return object; +#else + return Object::createFromHostObject(runtime, host); +#endif +} diff --git a/NativeScript/ffi/objc/v8/NativeApiV8.h b/NativeScript/ffi/objc/v8/NativeApiV8.h index c3d1761f6..e9ed9c63f 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8.h +++ b/NativeScript/ffi/objc/v8/NativeApiV8.h @@ -12,6 +12,7 @@ using NativeApiConfig = NativeApiBackendConfig; void InstallNativeApi(v8::Isolate* isolate, v8::Local context, const NativeApiConfig& config = NativeApiConfig{}); +void CleanupNativeApi(v8::Isolate* isolate); } // namespace nativescript diff --git a/NativeScript/ffi/objc/v8/NativeApiV8.mm b/NativeScript/ffi/objc/v8/NativeApiV8.mm index 1ed1c20e0..8b162b79e 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8.mm +++ b/NativeScript/ffi/objc/v8/NativeApiV8.mm @@ -68,6 +68,12 @@ void InstallNativeApi(v8::Isolate* isolate, v8::Local context, InstallNativeApi(runtime, config); } +void CleanupNativeApi(v8::Isolate* isolate) { + if (isolate != nullptr) { + engine::v8engine::cleanupRuntimeAllocations(isolate); + } +} + } // namespace nativescript extern "C" void NativeScriptInstallNativeApi(v8::Isolate* isolate, v8::Local context, diff --git a/NativeScript/ffi/objc/v8/NativeApiV8Gsd.mm b/NativeScript/ffi/objc/v8/NativeApiV8Gsd.mm index fb62ddb9d..65bc6e243 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8Gsd.mm +++ b/NativeScript/ffi/objc/v8/NativeApiV8Gsd.mm @@ -193,8 +193,8 @@ void setObject(id obj) { } // namespace (temporary close for GSD .inc) #if defined(__has_include) -#if __has_include("GeneratedGsdSignatureDispatch.inc") -#include "GeneratedGsdSignatureDispatch.inc" +#if __has_include("../shared/GeneratedGsdSignatureDispatch.inc") +#include "../shared/GeneratedGsdSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/ffi/objc/v8/NativeApiV8HostObjects.mm b/NativeScript/ffi/objc/v8/NativeApiV8HostObjects.mm index b71245931..e6ff8f37a 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8HostObjects.mm +++ b/NativeScript/ffi/objc/v8/NativeApiV8HostObjects.mm @@ -299,10 +299,12 @@ } void hostObjectWeakCallback(const v8::WeakCallbackInfo& info) { + untrackRuntimeAllocation(info.GetIsolate(), info.GetParameter()); delete info.GetParameter(); } void functionWeakCallback(const v8::WeakCallbackInfo& info) { + untrackRuntimeAllocation(info.GetIsolate(), info.GetParameter()); delete info.GetParameter(); } @@ -313,6 +315,7 @@ void functionWeakCallback(const v8::WeakCallbackInfo& info) { v8::Local object = v8engine::hostObjectTemplate(runtime)->NewInstance(runtime.context()).ToLocalChecked(); auto* holder = new v8engine::HostObjectHolder(runtime.state(), std::move(host), typeToken); + v8engine::trackRuntimeAllocation(runtime.isolate(), holder); object->SetAlignedPointerInInternalField(0, holder); holder->object.Reset(runtime.isolate(), object); holder->object.SetWeak(holder, v8engine::hostObjectWeakCallback, @@ -325,6 +328,7 @@ void functionWeakCallback(const v8::WeakCallbackInfo& info) { v8::Local object = v8engine::nativeObjectTemplate(runtime)->NewInstance(runtime.context()).ToLocalChecked(); auto* holder = new v8engine::HostObjectHolder(runtime.state(), std::move(host), typeToken); + v8engine::trackRuntimeAllocation(runtime.isolate(), holder); object->SetAlignedPointerInInternalField(0, holder); holder->object.Reset(runtime.isolate(), object); holder->object.SetWeak(holder, v8engine::hostObjectWeakCallback, @@ -335,6 +339,7 @@ void functionWeakCallback(const v8::WeakCallbackInfo& info) { Function Function::createFromHostFunction(Runtime& runtime, const PropNameID& name, unsigned int, HostFunctionType callback) { auto* holder = new v8engine::FunctionHolder(runtime.state(), std::move(callback)); + v8engine::trackRuntimeAllocation(runtime.isolate(), holder); v8::Local data = v8::External::New(runtime.isolate(), holder); v8::Local functionTemplate = v8::FunctionTemplate::New( runtime.isolate(), diff --git a/NativeScript/ffi/objc/v8/NativeApiV8Runtime.h b/NativeScript/ffi/objc/v8/NativeApiV8Runtime.h index 7800c230e..633ae6099 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8Runtime.h +++ b/NativeScript/ffi/objc/v8/NativeApiV8Runtime.h @@ -31,6 +31,7 @@ #include #include +#include "../shared/RuntimeCleanupRegistry.h" #include "Metadata.h" #include "MetadataReader.h" #include "ffi.h" @@ -108,9 +109,8 @@ using HostFunctionType = std::function context) : isolate(isolate) { - this->context.Reset(isolate, context); - } + RuntimeState(v8::Isolate* isolate, v8::Local context) + : isolate(isolate), context(isolate, context) {} ~RuntimeState() { nativeClassArgumentLast.value.Reset(); @@ -129,15 +129,13 @@ struct RuntimeState { } v8::Local localContext() const { - v8::Local ctx = context.Get(isolate); - return ctx.IsEmpty() ? isolate->GetCurrentContext() : ctx; + return context.Get(isolate); } v8::Isolate* isolate = nullptr; v8::Global context; v8::Global hostObjectTemplate; v8::Global nativeObjectTemplate; // kNonMasking for instances - std::vector> retainedNativeData; struct NativeClassArgumentCacheEntry { v8::Global value; Class nativeClass = Nil; @@ -205,6 +203,36 @@ struct FunctionHolder { v8::Global function; }; +inline thread_local std::unordered_map + runtimeAllocations; + +template +void trackRuntimeAllocation(v8::Isolate* isolate, T* allocation) { + runtimeAllocations[isolate].track(allocation); +} + +inline void untrackRuntimeAllocation(v8::Isolate* isolate, + void* allocation) { + auto runtime = runtimeAllocations.find(isolate); + if (runtime == runtimeAllocations.end()) { + return; + } + runtime->second.untrack(allocation); + if (runtime->second.empty()) { + runtimeAllocations.erase(runtime); + } +} + +inline void cleanupRuntimeAllocations(v8::Isolate* isolate) { + auto runtime = runtimeAllocations.find(isolate); + if (runtime == runtimeAllocations.end()) { + return; + } + + runtime->second.cleanup(); + runtimeAllocations.erase(runtime); +} + struct ArrayBufferHolder { explicit ArrayBufferHolder(std::shared_ptr buffer) : buffer(std::move(buffer)) {} diff --git a/NativeScript/ffi/objc/v8/NativeApiV8RuntimeSupport.mm b/NativeScript/ffi/objc/v8/NativeApiV8RuntimeSupport.mm index 558f6565d..b23a0e02e 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8RuntimeSupport.mm +++ b/NativeScript/ffi/objc/v8/NativeApiV8RuntimeSupport.mm @@ -8,14 +8,23 @@ } ~NativeApiLazyGlobalData() { + external.Reset(); nameValue.Reset(); kindValue.Reset(); } + v8::Global external; v8::Global nameValue; v8::Global kindValue; }; +void NativeApiLazyGlobalWeakCallback( + const v8::WeakCallbackInfo& info) { + engine::v8engine::untrackRuntimeAllocation(info.GetIsolate(), + info.GetParameter()); + delete info.GetParameter(); +} + std::shared_ptr retainNativeApiRuntime(Runtime& runtime) { return std::make_shared(runtime.state()); } @@ -94,15 +103,21 @@ bool InstallNativeApiLazyGlobal(Runtime& runtime, std::shared_ptr(isolate, name, kind); - v8::Local external = v8::External::New(isolate, data.get()); + auto* data = new NativeApiLazyGlobalData(isolate, name, kind); + engine::v8engine::trackRuntimeAllocation(isolate, data); + v8::Local external = v8::External::New(isolate, data); bool installed = global ->SetNativeDataProperty(context, property, NativeApiLazyGlobalGetter, nullptr, external, v8::DontEnum) .FromMaybe(false); if (installed) { - runtime.state()->retainedNativeData.push_back(std::move(data)); + data->external.Reset(isolate, external); + data->external.SetWeak(data, NativeApiLazyGlobalWeakCallback, + v8::WeakCallbackType::kParameter); + } else { + engine::v8engine::untrackRuntimeAllocation(isolate, data); + delete data; } return installed; } @@ -118,4 +133,3 @@ throw JSError(runtime, tryCatch)); } } - diff --git a/NativeScript/ffi/objc/v8/NativeApiV8SelectorGroups.mm b/NativeScript/ffi/objc/v8/NativeApiV8SelectorGroups.mm index 66e621304..d4928e766 100644 --- a/NativeScript/ffi/objc/v8/NativeApiV8SelectorGroups.mm +++ b/NativeScript/ffi/objc/v8/NativeApiV8SelectorGroups.mm @@ -171,10 +171,29 @@ throw JSError( prepared.selectorName, info); } +struct NativeApiSelectorGroupDataHolder { + explicit NativeApiSelectorGroupDataHolder( + std::shared_ptr data) + : data(std::move(data)) {} + + ~NativeApiSelectorGroupDataHolder() { function.Reset(); } + + std::shared_ptr data; + v8::Global function; +}; + +void NativeApiSelectorGroupWeakCallback( + const v8::WeakCallbackInfo& info) { + engine::v8engine::untrackRuntimeAllocation(info.GetIsolate(), + info.GetParameter()); + delete info.GetParameter(); +} + void NativeApiSelectorGroupCallback( const v8::FunctionCallbackInfo& info) { - auto* data = static_cast( + auto* holder = static_cast( info.Data().As()->Value()); + auto* data = holder != nullptr ? holder->data.get() : nullptr; if (data == nullptr || data->selectors == nullptr || data->preparedInvocations == nullptr) { return; @@ -243,11 +262,11 @@ Function CreateNativeApiSelectorGroupFunctionImpl( runtime.state(), std::move(bridge), lookupClass, receiverIsClass, std::move(selectors), std::move(preparedInvocations), std::move(boundReceiver), std::move(boundReceiverState)); - auto* rawData = data.get(); - runtime.state()->retainedNativeData.push_back(std::move(data)); + auto* holder = new NativeApiSelectorGroupDataHolder(std::move(data)); + engine::v8engine::trackRuntimeAllocation(runtime.isolate(), holder); v8::Local external = - v8::External::New(runtime.isolate(), rawData); + v8::External::New(runtime.isolate(), holder); v8::Local functionTemplate = v8::FunctionTemplate::New(runtime.isolate(), NativeApiSelectorGroupCallback, external); @@ -255,6 +274,9 @@ Function CreateNativeApiSelectorGroupFunctionImpl( functionTemplate->GetFunction(runtime.context()).ToLocalChecked(); function->SetName( engine::v8engine::makeV8String(runtime.isolate(), "__nativeSelectorGroup")); + holder->function.Reset(runtime.isolate(), function); + holder->function.SetWeak(holder, NativeApiSelectorGroupWeakCallback, + v8::WeakCallbackType::kParameter); Value functionValue(runtime, function); return functionValue.asObject(runtime).asFunction(runtime); } diff --git a/NativeScript/ffi/objc/v8/SignatureDispatch.h b/NativeScript/ffi/objc/v8/SignatureDispatch.h index 7fd3b8533..d92d60f8d 100644 --- a/NativeScript/ffi/objc/v8/SignatureDispatch.h +++ b/NativeScript/ffi/objc/v8/SignatureDispatch.h @@ -38,8 +38,8 @@ // The main .inc (prepared invokers + tables) is included here. #if defined(__has_include) -#if __has_include("GeneratedSignatureDispatch.inc") -#include "GeneratedSignatureDispatch.inc" +#if __has_include("../shared/GeneratedSignatureDispatch.inc") +#include "../shared/GeneratedSignatureDispatch.inc" #endif #endif diff --git a/NativeScript/napi/android/jsc/jsc-api.cpp b/NativeScript/napi/android/jsc/jsc-api.cpp index 0f2a615d1..bb79440f4 100644 --- a/NativeScript/napi/android/jsc/jsc-api.cpp +++ b/NativeScript/napi/android/jsc/jsc-api.cpp @@ -1,9 +1,9 @@ #include "jsc-api.h" +#include "../../common/jsc_type_tag.h" #include #include #include #include -#include #include #include #include @@ -457,9 +457,7 @@ class BaseInfoT : public NativeInfo { public: static const NativeType StaticType = TType; - ~BaseInfoT() { - JSClassRelease(_class); - } + ~BaseInfoT() = default; napi_env Env() const { return _env; @@ -481,11 +479,8 @@ class BaseInfoT : public NativeInfo { protected: BaseInfoT(napi_env env, const char* className) : NativeInfo{TType} - , _env{env} { - JSClassDefinition definition{kJSClassDefinitionEmpty}; - definition.className = className; - definition.finalize = Finalize; - _class = JSClassCreate(&definition); + , _env{env} + , _class{SharedClass(className)} { } // JSObjectFinalizeCallback @@ -498,6 +493,24 @@ class BaseInfoT : public NativeInfo { delete info; } + static JSClassRef SharedClass(const char* className) { + struct SharedClassHolder { + explicit SharedClassHolder(const char* name) { + JSClassDefinition definition{kJSClassDefinitionEmpty}; + definition.className = name; + definition.finalize = BaseInfoT::Finalize; + value = JSClassCreate(&definition); + } + ~SharedClassHolder() { + JSClassRelease(value); + } + + JSClassRef value = nullptr; + }; + static SharedClassHolder sharedClass(className); + return sharedClass.value; + } + napi_env _env; void* _data{}; std::vector _finalizers{}; @@ -1865,9 +1878,26 @@ napi_status napi_wrap(napi_env env, return napi_ok; } +napi_status napi_type_tag_object(napi_env env, napi_value object, + const napi_type_tag* type_tag) { + napi_status status = + nativescript::napi::jsc::TypeTagObject(env, object, type_tag); + return env == nullptr ? status : napi_set_last_error(env, status); +} + +napi_status napi_check_object_type_tag(napi_env env, napi_value object, + const napi_type_tag* type_tag, + bool* result) { + napi_status status = nativescript::napi::jsc::CheckObjectTypeTag( + env, object, type_tag, result); + return env == nullptr ? status : napi_set_last_error(env, status); +} + napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) { CHECK_ENV(env); CHECK_ARG(env, js_object); + CHECK_ARG(env, result); + *result = nullptr; WrapperInfo* info{}; CHECK_NAPI(WrapperInfo::Unwrap(env, js_object, &info)); @@ -2699,4 +2729,4 @@ napi_status napi_object_seal(napi_env env, CHECK_NAPI(napi_get_named_property(env, object_ctor, "seal", &seal)); CHECK_NAPI(napi_call_function(env, object_ctor, seal, 1, &object, nullptr)); return napi_ok; -} \ No newline at end of file +} diff --git a/NativeScript/napi/android/jsc/jsc-api.h b/NativeScript/napi/android/jsc/jsc-api.h index d22aa1534..803d67481 100644 --- a/NativeScript/napi/android/jsc/jsc-api.h +++ b/NativeScript/napi/android/jsc/jsc-api.h @@ -8,8 +8,10 @@ #include "js_native_api.h" #include "js_native_api_types.h" #include +#include #include #include +#include #include #include @@ -24,29 +26,39 @@ struct napi_env__ { JSValueRef function_info_symbol{}; JSValueRef reference_info_symbol{}; JSValueRef wrapper_info_symbol{}; + JSValueRef type_tag_symbol{}; const std::thread::id thread_id{std::this_thread::get_id()}; napi_env__(JSGlobalContextRef context) : context{context} { - napi_envs[context] = this; + { + std::lock_guard lock(napi_envs_mutex); + napi_envs[context] = this; + } JSGlobalContextRetain(context); init_symbol(constructor_info_symbol, "NS_ConstructorInfo"); init_symbol(function_info_symbol, "NS_FunctionInfo"); init_symbol(reference_info_symbol, "NS_ReferenceInfo"); init_symbol(wrapper_info_symbol, "NS_WrapperInfo"); + init_symbol(type_tag_symbol, "NS_TypeTag"); } ~napi_env__() { deinit_refs(); - JSGlobalContextRelease(context); + deinit_symbol(type_tag_symbol); deinit_symbol(wrapper_info_symbol); deinit_symbol(reference_info_symbol); deinit_symbol(function_info_symbol); deinit_symbol(constructor_info_symbol); - napi_envs.erase(context); + { + std::lock_guard lock(napi_envs_mutex); + napi_envs.erase(context); + } + JSGlobalContextRelease(context); } static napi_env get(JSGlobalContextRef context) { + std::lock_guard lock(napi_envs_mutex); auto it = napi_envs.find(context); if (it != napi_envs.end()) { return it->second; @@ -56,6 +68,7 @@ struct napi_env__ { } private: + static inline std::mutex napi_envs_mutex; static inline std::unordered_map napi_envs{}; void deinit_refs(); void init_symbol(JSValueRef& symbol, const char* description); diff --git a/NativeScript/napi/android/jsc/jsr.h b/NativeScript/napi/android/jsc/jsr.h deleted file mode 100644 index 3bbc53130..000000000 --- a/NativeScript/napi/android/jsc/jsr.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// Created by Ammar Ahmed on 01/12/2024. -// - -#ifndef TEST_APP_JSR_H -#define TEST_APP_JSR_H - -#include "jsr_common.h" -#include "jsc-api.h" - -typedef struct napi_runtime__ *napi_runtime; - -class NapiScope { -public: - explicit NapiScope(napi_env env, bool openHandle = true) - : env_(env) - { -// napi_open_handle_scope(env_, &napiHandleScope_); - } - - ~NapiScope() { -// napi_close_handle_scope(env_, napiHandleScope_); - } - -private: - napi_env env_; - napi_handle_scope napiHandleScope_; -}; - -#define JSEnterScope - -#endif //TEST_APP_JSR_H diff --git a/NativeScript/napi/android/primjs/jsr.cpp b/NativeScript/napi/android/primjs/jsr.cpp index 47a7cc104..a3e1921d6 100644 --- a/NativeScript/napi/android/primjs/jsr.cpp +++ b/NativeScript/napi/android/primjs/jsr.cpp @@ -2,7 +2,7 @@ #include "jsr.h" JSR::JSR() = default; -tns::SimpleMap JSR::env_to_jsr_cache; +tns::ConcurrentMap JSR::env_to_jsr_cache; struct napi_runtime__ { LEPUSRuntime* runtime; diff --git a/NativeScript/napi/android/primjs/jsr.h b/NativeScript/napi/android/primjs/jsr.h index 2850370db..5398201d3 100644 --- a/NativeScript/napi/android/primjs/jsr.h +++ b/NativeScript/napi/android/primjs/jsr.h @@ -21,7 +21,7 @@ class JSR { js_mutex.unlock(); } - static tns::SimpleMap env_to_jsr_cache; + static tns::ConcurrentMap env_to_jsr_cache; }; class NapiScope { diff --git a/NativeScript/napi/android/quickjs/jsr.cpp b/NativeScript/napi/android/quickjs/jsr.cpp index b9ec43e77..c05830713 100644 --- a/NativeScript/napi/android/quickjs/jsr.cpp +++ b/NativeScript/napi/android/quickjs/jsr.cpp @@ -2,7 +2,7 @@ #include "quicks-runtime.h" JSR::JSR() = default; -tns::SimpleMap JSR::env_to_jsr_cache; +tns::ConcurrentMap JSR::env_to_jsr_cache; napi_status js_create_runtime(napi_runtime *runtime) { return qjs_create_runtime(runtime); diff --git a/NativeScript/napi/android/quickjs/jsr.h b/NativeScript/napi/android/quickjs/jsr.h deleted file mode 100644 index e6d62c9f5..000000000 --- a/NativeScript/napi/android/quickjs/jsr.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// Created by Ammar Ahmed on 01/12/2024. -// - -#ifndef TEST_APP_JSR_H -#define TEST_APP_JSR_H -#include "js_native_api.h" -#include "jsr_common.h" -#include "quicks-runtime.h" -#include "mutex" -#include -#include "ConcurrentMap.h" - -class JSR { -public: - JSR(); - std::recursive_mutex js_mutex; - void lock() { - js_mutex.lock(); - } - void unlock() { - js_mutex.unlock(); - } - - static tns::SimpleMap env_to_jsr_cache; -}; - -class NapiScope { -public: - explicit NapiScope(napi_env env, bool open_handle = true) - : env_(env) - { - js_lock_env(env_); - qjs_update_stack_top(env); - if (open_handle) { - napi_open_handle_scope(env_, &napiHandleScope_); - } else { - napiHandleScope_ = nullptr; - } - } - - ~NapiScope() { - if (napiHandleScope_) { - napi_close_handle_scope(env_, napiHandleScope_); - } - js_unlock_env(env_); - } - -private: - napi_env env_; - napi_handle_scope napiHandleScope_; -}; - -#define JSEnterScope - -#endif //TEST_APP_JSR_H diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/.gitattributes b/NativeScript/napi/android/quickjs/mimalloc-dev/.gitattributes deleted file mode 100644 index 0332e0315..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/.gitattributes +++ /dev/null @@ -1,12 +0,0 @@ -# default behavior is to always use unix style line endings -* text eol=lf -*.png binary -*.pdn binary -*.jpg binary -*.sln binary -*.suo binary -*.vcproj binary -*.patch binary -*.dll binary -*.lib binary -*.exe binary diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/.gitignore b/NativeScript/napi/android/quickjs/mimalloc-dev/.gitignore deleted file mode 100644 index df1d58eb2..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -ide/vs20??/*.db -ide/vs20??/*.opendb -ide/vs20??/*.user -ide/vs20??/*.vcxproj.filters -ide/vs20??/.vs -ide/vs20??/VTune* -out/ -docs/ -*.zip -*.tar -*.gz diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/CMakeLists.txt b/NativeScript/napi/android/quickjs/mimalloc-dev/CMakeLists.txt deleted file mode 100644 index bcfe91d86..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/CMakeLists.txt +++ /dev/null @@ -1,596 +0,0 @@ -cmake_minimum_required(VERSION 3.18) -project(libmimalloc C CXX) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 17) - -option(MI_SECURE "Use full security mitigations (like guard pages, allocation randomization, double-free mitigation, and free-list corruption detection)" OFF) -option(MI_DEBUG_FULL "Use full internal heap invariant checking in DEBUG mode (expensive)" OFF) -option(MI_PADDING "Enable padding to detect heap block overflow (always on in DEBUG or SECURE mode, or with Valgrind/ASAN)" OFF) -option(MI_OVERRIDE "Override the standard malloc interface (e.g. define entry points for malloc() etc)" ON) -option(MI_XMALLOC "Enable abort() call on memory allocation failure by default" OFF) -option(MI_SHOW_ERRORS "Show error and warning messages by default (only enabled by default in DEBUG mode)" OFF) -option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhead)" OFF) -option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF) -option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF) -option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF) -option(MI_SEE_ASM "Generate assembly files" OFF) -option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON) -option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON) -option(MI_WIN_REDIRECT "Use redirection module ('mimalloc-redirect') on Windows if compiling mimalloc as a DLL" ON) -option(MI_LOCAL_DYNAMIC_TLS "Use slightly slower, dlopen-compatible TLS mechanism (Unix)" OFF) -option(MI_LIBC_MUSL "Set this when linking with musl libc" OFF) -option(MI_BUILD_SHARED "Build shared library" ON) -option(MI_BUILD_STATIC "Build static library" ON) -option(MI_BUILD_OBJECT "Build object library" ON) -option(MI_BUILD_TESTS "Build test executables" ON) -option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) -option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) -option(MI_SKIP_COLLECT_ON_EXIT "Skip collecting memory on program exit" OFF) -option(MI_NO_PADDING "Force no use of padding even in DEBUG mode etc." OFF) -option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) -option(MI_NO_THP "Disable transparent huge pages support on Linux/Android for the mimalloc process only" OFF) - -# deprecated options -option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) -option(MI_USE_LIBATOMIC "Explicitly link with -latomic (on older systems) (deprecated and detected automatically)" OFF) - -include(CheckLinkerFlag) # requires cmake 3.18 -include(CheckIncludeFiles) -include(GNUInstallDirs) -include("cmake/mimalloc-config-version.cmake") - -set(mi_sources - src/alloc.c - src/alloc-aligned.c - src/alloc-posix.c - src/arena.c - src/bitmap.c - src/heap.c - src/init.c - src/libc.c - src/options.c - src/os.c - src/page.c - src/random.c - src/segment.c - src/segment-map.c - src/stats.c - src/prim/prim.c) - -set(mi_cflags "") -set(mi_cflags_static "") # extra flags for a static library build -set(mi_cflags_dynamic "") # extra flags for a shared-object library build -set(mi_defines "") -set(mi_libraries "") - -# ----------------------------------------------------------------------------- -# Convenience: set default build type depending on the build directory -# ----------------------------------------------------------------------------- - -message(STATUS "") -if (NOT CMAKE_BUILD_TYPE) - if ("${CMAKE_BINARY_DIR}" MATCHES ".*(D|d)ebug$" OR MI_DEBUG_FULL) - message(STATUS "No build type selected, default to: Debug") - set(CMAKE_BUILD_TYPE "Debug") - else() - message(STATUS "No build type selected, default to: Release") - set(CMAKE_BUILD_TYPE "Release") - endif() -endif() - -if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$") - message(STATUS "Default to secure build") - set(MI_SECURE "ON") -endif() - - -# ----------------------------------------------------------------------------- -# Process options -# ----------------------------------------------------------------------------- - -# put -Wall early so other warnings can be disabled selectively -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") - list(APPEND mi_cflags -Wall -Wextra -Wpedantic) -endif() -if(CMAKE_C_COMPILER_ID MATCHES "GNU") - list(APPEND mi_cflags -Wall -Wextra) -endif() -if(CMAKE_C_COMPILER_ID MATCHES "Intel") - list(APPEND mi_cflags -Wall) -endif() - -if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel") - set(MI_USE_CXX "ON") -endif() - -if(MI_OVERRIDE) - message(STATUS "Override standard malloc (MI_OVERRIDE=ON)") - if(APPLE) - if(MI_OSX_ZONE) - # use zone's on macOS - message(STATUS " Use malloc zone to override malloc (MI_OSX_ZONE=ON)") - list(APPEND mi_sources src/prim/osx/alloc-override-zone.c) - list(APPEND mi_defines MI_OSX_ZONE=1) - if (NOT MI_OSX_INTERPOSE) - message(STATUS " WARNING: zone overriding usually also needs interpose (use -DMI_OSX_INTERPOSE=ON)") - endif() - endif() - if(MI_OSX_INTERPOSE) - # use interpose on macOS - message(STATUS " Use interpose to override malloc (MI_OSX_INTERPOSE=ON)") - list(APPEND mi_defines MI_OSX_INTERPOSE=1) - if (NOT MI_OSX_ZONE) - message(STATUS " WARNING: interpose usually also needs zone overriding (use -DMI_OSX_INTERPOSE=ON)") - endif() - endif() - if(MI_USE_CXX AND MI_OSX_INTERPOSE) - message(STATUS " WARNING: if dynamically overriding malloc/free, it is more reliable to build mimalloc as C code (use -DMI_USE_CXX=OFF)") - endif() - endif() -endif() - -if(WIN32) - if (MI_WIN_REDIRECT) - if (MSVC_C_ARCHITECTURE_ID MATCHES "ARM") - message(STATUS "Cannot use redirection on Windows ARM (MI_WIN_REDIRECT=OFF)") - set(MI_WIN_REDIRECT OFF) - endif() - endif() - if (NOT MI_WIN_REDIRECT) - # use a negative define for backward compatibility - list(APPEND mi_defines MI_WIN_NOREDIRECT=1) - endif() -endif() - -if(MI_SECURE) - message(STATUS "Set full secure build (MI_SECURE=ON)") - list(APPEND mi_defines MI_SECURE=4) -endif() - -if(MI_TRACK_VALGRIND) - CHECK_INCLUDE_FILES("valgrind/valgrind.h;valgrind/memcheck.h" MI_HAS_VALGRINDH) - if (NOT MI_HAS_VALGRINDH) - set(MI_TRACK_VALGRIND OFF) - message(WARNING "Cannot find the 'valgrind/valgrind.h' and 'valgrind/memcheck.h' -- install valgrind first") - message(STATUS "Compile **without** Valgrind support (MI_TRACK_VALGRIND=OFF)") - else() - message(STATUS "Compile with Valgrind support (MI_TRACK_VALGRIND=ON)") - list(APPEND mi_defines MI_TRACK_VALGRIND=1) - endif() -endif() - -if(MI_TRACK_ASAN) - if (APPLE AND MI_OVERRIDE) - set(MI_TRACK_ASAN OFF) - message(WARNING "Cannot enable address sanitizer support on macOS if MI_OVERRIDE is ON (MI_TRACK_ASAN=OFF)") - endif() - if (MI_TRACK_VALGRIND) - set(MI_TRACK_ASAN OFF) - message(WARNING "Cannot enable address sanitizer support with also Valgrind support enabled (MI_TRACK_ASAN=OFF)") - endif() - if(MI_TRACK_ASAN) - CHECK_INCLUDE_FILES("sanitizer/asan_interface.h" MI_HAS_ASANH) - if (NOT MI_HAS_ASANH) - set(MI_TRACK_ASAN OFF) - message(WARNING "Cannot find the 'sanitizer/asan_interface.h' -- install address sanitizer support first") - message(STATUS "Compile **without** address sanitizer support (MI_TRACK_ASAN=OFF)") - else() - message(STATUS "Compile with address sanitizer support (MI_TRACK_ASAN=ON)") - list(APPEND mi_defines MI_TRACK_ASAN=1) - list(APPEND mi_cflags -fsanitize=address) - list(APPEND mi_libraries -fsanitize=address) - endif() - endif() -endif() - -if(MI_TRACK_ETW) - if(NOT WIN32) - set(MI_TRACK_ETW OFF) - message(WARNING "Can only enable ETW support on Windows (MI_TRACK_ETW=OFF)") - endif() - if (MI_TRACK_VALGRIND OR MI_TRACK_ASAN) - set(MI_TRACK_ETW OFF) - message(WARNING "Cannot enable ETW support with also Valgrind or ASAN support enabled (MI_TRACK_ETW=OFF)") - endif() - if(MI_TRACK_ETW) - message(STATUS "Compile with Windows event tracing support (MI_TRACK_ETW=ON)") - list(APPEND mi_defines MI_TRACK_ETW=1) - endif() -endif() - -if(MI_SEE_ASM) - message(STATUS "Generate assembly listings (MI_SEE_ASM=ON)") - list(APPEND mi_cflags -save-temps) - if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") - message(STATUS "No GNU Line marker") - list(APPEND mi_cflags -Wno-gnu-line-marker) - endif() -endif() - -if(MI_CHECK_FULL) - message(STATUS "The MI_CHECK_FULL option is deprecated, use MI_DEBUG_FULL instead") - set(MI_DEBUG_FULL "ON") -endif() - -if (MI_SKIP_COLLECT_ON_EXIT) - message(STATUS "Skip collecting memory on program exit (MI_SKIP_COLLECT_ON_EXIT=ON)") - list(APPEND mi_defines MI_SKIP_COLLECT_ON_EXIT=1) -endif() - -if(MI_DEBUG_FULL) - message(STATUS "Set debug level to full internal invariant checking (MI_DEBUG_FULL=ON)") - list(APPEND mi_defines MI_DEBUG=3) # full invariant checking -endif() - -if(MI_NO_PADDING) - message(STATUS "Suppress any padding of heap blocks (MI_NO_PADDING=ON)") - list(APPEND mi_defines MI_PADDING=0) -else() - if(MI_PADDING) - message(STATUS "Enable explicit padding of heap blocks (MI_PADDING=ON)") - list(APPEND mi_defines MI_PADDING=1) - endif() -endif() - -if(MI_XMALLOC) - message(STATUS "Enable abort() calls on memory allocation failure (MI_XMALLOC=ON)") - list(APPEND mi_defines MI_XMALLOC=1) -endif() - -if(MI_SHOW_ERRORS) - message(STATUS "Enable printing of error and warning messages by default (MI_SHOW_ERRORS=ON)") - list(APPEND mi_defines MI_SHOW_ERRORS=1) -endif() - -if(MI_DEBUG_TSAN) - if(CMAKE_C_COMPILER_ID MATCHES "Clang") - message(STATUS "Build with thread sanitizer (MI_DEBUG_TSAN=ON)") - list(APPEND mi_defines MI_TSAN=1) - list(APPEND mi_cflags -fsanitize=thread -g -O1) - list(APPEND mi_libraries -fsanitize=thread) - else() - message(WARNING "Can only use thread sanitizer with clang (MI_DEBUG_TSAN=ON but ignored)") - endif() -endif() - -if(MI_DEBUG_UBSAN) - if(CMAKE_BUILD_TYPE MATCHES "Debug") - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - message(STATUS "Build with undefined-behavior sanitizer (MI_DEBUG_UBSAN=ON)") - list(APPEND mi_cflags -fsanitize=undefined -g -fno-sanitize-recover=undefined) - list(APPEND mi_libraries -fsanitize=undefined) - if (NOT MI_USE_CXX) - message(STATUS "(switch to use C++ due to MI_DEBUG_UBSAN)") - set(MI_USE_CXX "ON") - endif() - else() - message(WARNING "Can only use undefined-behavior sanitizer with clang++ (MI_DEBUG_UBSAN=ON but ignored)") - endif() - else() - message(WARNING "Can only use undefined-behavior sanitizer with a debug build (CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE})") - endif() -endif() - -if(MI_USE_CXX) - message(STATUS "Use the C++ compiler to compile (MI_USE_CXX=ON)") - set_source_files_properties(${mi_sources} PROPERTIES LANGUAGE CXX ) - set_source_files_properties(src/static.c test/test-api.c test/test-api-fill test/test-stress PROPERTIES LANGUAGE CXX ) - if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang|Clang") - list(APPEND mi_cflags -Wno-deprecated) - endif() - if(CMAKE_CXX_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_CXX_COMPILER_ID MATCHES "IntelLLVM") - list(APPEND mi_cflags -Kc++) - endif() -endif() - -if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android") - if(MI_NO_THP) - message(STATUS "Disable transparent huge pages support (MI_NO_THP=ON)") - list(APPEND mi_defines MI_NO_THP=1) - endif() -endif() - -if(MI_LIBC_MUSL) - message(STATUS "Assume using musl libc (MI_LIBC_MUSL=ON)") - list(APPEND mi_defines MI_LIBC_MUSL=1) -endif() - -# On Haiku use `-DCMAKE_INSTALL_PREFIX` instead, issue #788 -# if(CMAKE_SYSTEM_NAME MATCHES "Haiku") -# SET(CMAKE_INSTALL_LIBDIR ~/config/non-packaged/lib) -# SET(CMAKE_INSTALL_INCLUDEDIR ~/config/non-packaged/headers) -# endif() - -# Compiler flags -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU") - list(APPEND mi_cflags -Wno-unknown-pragmas -fvisibility=hidden) - if(NOT MI_USE_CXX) - list(APPEND mi_cflags -Wstrict-prototypes) - endif() - if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang") - list(APPEND mi_cflags -Wno-static-in-inline) - endif() -endif() - -if(CMAKE_C_COMPILER_ID MATCHES "Intel") - list(APPEND mi_cflags -fvisibility=hidden) -endif() - -if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku") - if(MI_LOCAL_DYNAMIC_TLS) - list(APPEND mi_cflags -ftls-model=local-dynamic) - else() - if(MI_LIBC_MUSL) - # with musl we use local-dynamic for the static build, see issue #644 - list(APPEND mi_cflags_static -ftls-model=local-dynamic) - list(APPEND mi_cflags_dynamic -ftls-model=initial-exec) - message(STATUS "Use local dynamic TLS for the static build (since MI_LIBC_MUSL=ON)") - else() - list(APPEND mi_cflags -ftls-model=initial-exec) - endif() - endif() - if(MI_OVERRIDE) - list(APPEND mi_cflags -fno-builtin-malloc) - endif() -endif() - -if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) - list(APPEND mi_cflags /Zc:__cplusplus) -endif() - -if(MINGW) - add_definitions(-D_WIN32_WINNT=0x600) -endif() - -# extra needed libraries - -# we prefer -l test over `find_library` as sometimes core libraries -# like `libatomic` are not on the system path (see issue #898) -function(find_link_library libname outlibname) - check_linker_flag(C "-l${libname}" mi_has_lib${libname}) - if (mi_has_lib${libname}) - message(VERBOSE "link library: -l${libname}") - set(${outlibname} ${libname} PARENT_SCOPE) - else() - find_library(MI_LIBPATH libname) - if (MI_LIBPATH) - message(VERBOSE "link library ${libname} at ${MI_LIBPATH}") - set(${outlibname} ${MI_LIBPATH} PARENT_SCOPE) - else() - message(VERBOSE "link library not found: ${libname}") - set(${outlibname} "" PARENT_SCOPE) - endif() - endif() -endfunction() - -if(WIN32) - list(APPEND mi_libraries psapi shell32 user32 advapi32 bcrypt) -else() - find_link_library("pthread" MI_LIB_PTHREAD) - if(MI_LIB_PTHREAD) - list(APPEND mi_libraries "${MI_LIB_PTHREAD}") - endif() - find_link_library("rt" MI_LIB_RT) - if(MI_LIB_RT) - list(APPEND mi_libraries "${MI_LIB_RT}") - endif() - find_link_library("atomic" MI_LIB_ATOMIC) - if(MI_LIB_ATOMIC) - list(APPEND mi_libraries "${MI_LIB_ATOMIC}") - endif() -endif() - -# ----------------------------------------------------------------------------- -# Install and output names -# ----------------------------------------------------------------------------- - -# dynamic/shared library and symlinks always go to /usr/local/lib equivalent -set(mi_install_libdir "${CMAKE_INSTALL_LIBDIR}") -set(mi_install_bindir "${CMAKE_INSTALL_BINDIR}") - -# static libraries and object files, includes, and cmake config files -# are either installed at top level, or use versioned directories for side-by-side installation (default) -if (MI_INSTALL_TOPLEVEL) - set(mi_install_objdir "${CMAKE_INSTALL_LIBDIR}") - set(mi_install_incdir "${CMAKE_INSTALL_INCLUDEDIR}") - set(mi_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/mimalloc") -else() - set(mi_install_objdir "${CMAKE_INSTALL_LIBDIR}/mimalloc-${mi_version}") # for static library and object files - set(mi_install_incdir "${CMAKE_INSTALL_INCLUDEDIR}/mimalloc-${mi_version}") # for includes - set(mi_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/mimalloc-${mi_version}") # for cmake package info -endif() - -set(mi_basename "mimalloc") -if(MI_SECURE) - set(mi_basename "${mi_basename}-secure") -endif() -if(MI_TRACK_VALGRIND) - set(mi_basename "${mi_basename}-valgrind") -endif() -if(MI_TRACK_ASAN) - set(mi_basename "${mi_basename}-asan") -endif() -string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC) -if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel|none)$")) - set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version -endif() - -if(MI_BUILD_SHARED) - list(APPEND mi_build_targets "shared") -endif() -if(MI_BUILD_STATIC) - list(APPEND mi_build_targets "static") -endif() -if(MI_BUILD_OBJECT) - list(APPEND mi_build_targets "object") -endif() -if(MI_BUILD_TESTS) - list(APPEND mi_build_targets "tests") -endif() - -message(STATUS "") -message(STATUS "Library base name: ${mi_basename}") -message(STATUS "Version : ${mi_version}") -message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}") -if(MI_USE_CXX) - message(STATUS "C++ Compiler : ${CMAKE_CXX_COMPILER}") -else() - message(STATUS "C Compiler : ${CMAKE_C_COMPILER}") -endif() -message(STATUS "Compiler flags : ${mi_cflags}") -message(STATUS "Compiler defines : ${mi_defines}") -message(STATUS "Link libraries : ${mi_libraries}") -message(STATUS "Build targets : ${mi_build_targets}") -message(STATUS "") - -# ----------------------------------------------------------------------------- -# Main targets -# ----------------------------------------------------------------------------- - -# shared library -if(MI_BUILD_SHARED) - add_library(mimalloc SHARED ${mi_sources}) - set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} SOVERSION ${mi_version_major} OUTPUT_NAME ${mi_basename} ) - target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT) - target_compile_options(mimalloc PRIVATE ${mi_cflags} ${mi_cflags_dynamic}) - target_link_libraries(mimalloc PRIVATE ${mi_libraries}) - target_include_directories(mimalloc PUBLIC - $ - $ - ) - if(WIN32 AND MI_WIN_REDIRECT) - # On windows, link and copy the mimalloc redirection dll too. - if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(MIMALLOC_REDIRECT_SUFFIX "32") - else() - set(MIMALLOC_REDIRECT_SUFFIX "") - endif() - - target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib) - add_custom_command(TARGET mimalloc POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" $ - COMMENT "Copy mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll to output directory") - install(FILES "$/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" DESTINATION ${mi_install_bindir}) - endif() - - install(TARGETS mimalloc EXPORT mimalloc ARCHIVE DESTINATION ${mi_install_libdir} RUNTIME DESTINATION ${mi_install_bindir} LIBRARY DESTINATION ${mi_install_libdir}) - install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir}) -endif() - -# static library -if (MI_BUILD_STATIC) - add_library(mimalloc-static STATIC ${mi_sources}) - set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON) - target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB) - target_compile_options(mimalloc-static PRIVATE ${mi_cflags} ${mi_cflags_static}) - target_link_libraries(mimalloc-static PRIVATE ${mi_libraries}) - target_include_directories(mimalloc-static PUBLIC - $ - $ - ) - if(WIN32) - # When building both static and shared libraries on Windows, a static library should use a - # different output name to avoid the conflict with the import library of a shared one. - string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename}) - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name}) - else() - set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename}) - endif() - - install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_objdir} LIBRARY) - install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir}) -endif() - -# install include files -install(FILES include/mimalloc.h DESTINATION ${mi_install_incdir}) -install(FILES include/mimalloc-override.h DESTINATION ${mi_install_incdir}) -install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_incdir}) -install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_cmakedir}) -install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_cmakedir}) - - -# single object file for more predictable static overriding -if (MI_BUILD_OBJECT) - add_library(mimalloc-obj OBJECT src/static.c) - set_property(TARGET mimalloc-obj PROPERTY POSITION_INDEPENDENT_CODE ON) - target_compile_definitions(mimalloc-obj PRIVATE ${mi_defines}) - target_compile_options(mimalloc-obj PRIVATE ${mi_cflags} ${mi_cflags_static}) - target_include_directories(mimalloc-obj PUBLIC - $ - $ - ) - - # Copy the generated object file (`static.o`) to the output directory (as `mimalloc.o`) - if(NOT WIN32) - set(mimalloc-obj-static "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION}") - set(mimalloc-obj-out "${CMAKE_CURRENT_BINARY_DIR}/${mi_basename}${CMAKE_C_OUTPUT_EXTENSION}") - add_custom_command(OUTPUT ${mimalloc-obj-out} DEPENDS mimalloc-obj COMMAND "${CMAKE_COMMAND}" -E copy "${mimalloc-obj-static}" "${mimalloc-obj-out}") - add_custom_target(mimalloc-obj-target ALL DEPENDS ${mimalloc-obj-out}) - endif() - - # the following seems to lead to cmake warnings/errors on some systems, disable for now :-( - # install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_objdir}) - - # the FILES expression can also be: $ - # but that fails cmake versions less than 3.10 so we leave it as is for now - install(FILES ${mimalloc-obj-static} - DESTINATION ${mi_install_objdir} - RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} ) -endif() - -# pkg-config file support -set(pc_libraries "") -foreach(item IN LISTS mi_libraries) - if(item MATCHES " *[-].*") - set(pc_libraries "${pc_libraries} ${item}") - else() - set(pc_libraries "${pc_libraries} -l${item}") - endif() -endforeach() - -include("cmake/JoinPaths.cmake") -join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}") -join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}") - -configure_file(mimalloc.pc.in mimalloc.pc @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mimalloc.pc" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") - - - -# ----------------------------------------------------------------------------- -# API surface testing -# ----------------------------------------------------------------------------- - -if (MI_BUILD_TESTS) - enable_testing() - - foreach(TEST_NAME api api-fill stress) - add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c) - target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines}) - target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags}) - target_include_directories(mimalloc-test-${TEST_NAME} PRIVATE include) - target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries}) - - add_test(NAME test-${TEST_NAME} COMMAND mimalloc-test-${TEST_NAME}) - endforeach() -endif() - -# ----------------------------------------------------------------------------- -# Set override properties -# ----------------------------------------------------------------------------- -if (MI_OVERRIDE) - if (MI_BUILD_SHARED) - target_compile_definitions(mimalloc PRIVATE MI_MALLOC_OVERRIDE) - endif() - if(NOT WIN32) - # It is only possible to override malloc on Windows when building as a DLL. - if (MI_BUILD_STATIC) - target_compile_definitions(mimalloc-static PRIVATE MI_MALLOC_OVERRIDE) - endif() - if (MI_BUILD_OBJECT) - target_compile_definitions(mimalloc-obj PRIVATE MI_MALLOC_OVERRIDE) - endif() - endif() -endif() diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/LICENSE b/NativeScript/napi/android/quickjs/mimalloc-dev/LICENSE deleted file mode 100644 index 670b668a0..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/SECURITY.md b/NativeScript/napi/android/quickjs/mimalloc-dev/SECURITY.md deleted file mode 100644 index b3c89efc8..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/SECURITY.md +++ /dev/null @@ -1,41 +0,0 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). - -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. - -## Reporting Security Issues - -**Please do not report security vulnerabilities through public GitHub issues.** - -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). - -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). - -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). - -Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: - - * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs. - -## Preferred Languages - -We prefer all communications to be in English. - -## Policy - -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). - - diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/azure-pipelines.yml b/NativeScript/napi/android/quickjs/mimalloc-dev/azure-pipelines.yml deleted file mode 100644 index 0247c76fd..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/azure-pipelines.yml +++ /dev/null @@ -1,197 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - -trigger: - branches: - include: - - master - - dev - - dev-slice - tags: - include: - - v* - -jobs: -- job: - displayName: Windows - pool: - vmImage: - windows-2022 - strategy: - matrix: - Debug: - BuildType: debug - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - MSBuildConfiguration: Debug - Release: - BuildType: release - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release - MSBuildConfiguration: Release - Secure: - BuildType: secure - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON - MSBuildConfiguration: Release - steps: - - task: CMake@1 - inputs: - workingDirectory: $(BuildType) - cmakeArgs: .. $(cmakeExtraArgs) - - task: MSBuild@1 - inputs: - solution: $(BuildType)/libmimalloc.sln - configuration: '$(MSBuildConfiguration)' - msbuildArguments: -m - - script: ctest --verbose --timeout 120 -C $(MSBuildConfiguration) - workingDirectory: $(BuildType) - displayName: CTest - #- script: $(BuildType)\$(BuildType)\mimalloc-test-stress - # displayName: TestStress - #- upload: $(Build.SourcesDirectory)/$(BuildType) - # artifact: mimalloc-windows-$(BuildType) - -- job: - displayName: Linux - pool: - vmImage: - ubuntu-22.04 - strategy: - matrix: - Debug: - CC: gcc - CXX: g++ - BuildType: debug - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - Release: - CC: gcc - CXX: g++ - BuildType: release - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release - Secure: - CC: gcc - CXX: g++ - BuildType: secure - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON - Debug++: - CC: gcc - CXX: g++ - BuildType: debug-cxx - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON - Debug Clang: - CC: clang - CXX: clang++ - BuildType: debug-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - Release Clang: - CC: clang - CXX: clang++ - BuildType: release-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release - Secure Clang: - CC: clang - CXX: clang++ - BuildType: secure-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON - Debug++ Clang: - CC: clang - CXX: clang++ - BuildType: debug-clang-cxx - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON - Debug ASAN Clang: - CC: clang - CXX: clang++ - BuildType: debug-asan-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_TRACK_ASAN=ON - Debug UBSAN Clang: - CC: clang - CXX: clang++ - BuildType: debug-ubsan-clang - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_DEBUG_UBSAN=ON - Debug TSAN Clang++: - CC: clang - CXX: clang++ - BuildType: debug-tsan-clang-cxx - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_USE_CXX=ON -DMI_DEBUG_TSAN=ON - - steps: - - task: CMake@1 - inputs: - workingDirectory: $(BuildType) - cmakeArgs: .. $(cmakeExtraArgs) - - script: make -j$(nproc) -C $(BuildType) - displayName: Make - - script: ctest --verbose --timeout 180 - workingDirectory: $(BuildType) - displayName: CTest -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-ubuntu-$(BuildType) - -- job: - displayName: macOS - pool: - vmImage: - macOS-latest - strategy: - matrix: - Debug: - BuildType: debug - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON - Release: - BuildType: release - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release - Secure: - BuildType: secure - cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON - steps: - - task: CMake@1 - inputs: - workingDirectory: $(BuildType) - cmakeArgs: .. $(cmakeExtraArgs) - - script: make -j$(sysctl -n hw.ncpu) -C $(BuildType) - displayName: Make - # - script: MIMALLOC_VERBOSE=1 ./mimalloc-test-api - # workingDirectory: $(BuildType) - # displayName: TestAPI - # - script: MIMALLOC_VERBOSE=1 ./mimalloc-test-stress - # workingDirectory: $(BuildType) - # displayName: TestStress - - script: ctest --verbose --timeout 120 - workingDirectory: $(BuildType) - displayName: CTest - -# - upload: $(Build.SourcesDirectory)/$(BuildType) -# artifact: mimalloc-macos-$(BuildType) - -# - job: -# displayName: Windows-2017 -# pool: -# vmImage: -# vs2017-win2016 -# strategy: -# matrix: -# Debug: -# BuildType: debug -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -# MSBuildConfiguration: Debug -# Release: -# BuildType: release -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -# MSBuildConfiguration: Release -# Secure: -# BuildType: secure -# cmakeExtraArgs: -A x64 -DCMAKE_BUILD_TYPE=Release -DMI_SECURE=ON -# MSBuildConfiguration: Release -# steps: -# - task: CMake@1 -# inputs: -# workingDirectory: $(BuildType) -# cmakeArgs: .. $(cmakeExtraArgs) -# - task: MSBuild@1 -# inputs: -# solution: $(BuildType)/libmimalloc.sln -# configuration: '$(MSBuildConfiguration)' -# - script: | -# cd $(BuildType) -# ctest --verbose --timeout 120 -# displayName: CTest diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.dll b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.dll deleted file mode 100644 index a3a3591ff..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.dll and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.lib b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.lib deleted file mode 100644 index de128bb94..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect.lib and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.dll b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.dll deleted file mode 100644 index 522723e50..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.dll and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.lib b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.lib deleted file mode 100644 index 87f19b8ec..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/mimalloc-redirect32.lib and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject.exe b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject.exe deleted file mode 100644 index dba8f80fd..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject.exe and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject32.exe b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject32.exe deleted file mode 100644 index f837383b9..000000000 Binary files a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/minject32.exe and /dev/null differ diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/readme.md b/NativeScript/napi/android/quickjs/mimalloc-dev/bin/readme.md deleted file mode 100644 index 9b121bda5..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/bin/readme.md +++ /dev/null @@ -1,71 +0,0 @@ -# Windows Override - -Dynamically overriding on mimalloc on Windows -is robust and has the particular advantage to be able to redirect all malloc/free calls that go through -the (dynamic) C runtime allocator, including those from other DLL's or libraries. -As it intercepts all allocation calls on a low level, it can be used reliably -on large programs that include other 3rd party components. -There are four requirements to make the overriding work robustly: - -1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch). - -2. Link your program explicitly with `mimalloc-override.dll` library. - To ensure the `mimalloc-override.dll` is loaded at run-time it is easiest to insert some - call to the mimalloc API in the `main` function, like `mi_version()` - (or use the `/INCLUDE:mi_version` switch on the linker). See the `mimalloc-override-test` project - for an example on how to use this. - -3. The `mimalloc-redirect.dll` (or `mimalloc-redirect32.dll`) must be put - in the same folder as the main `mimalloc-override.dll` at runtime (as it is a dependency of that DLL). - The redirection DLL ensures that all calls to the C runtime malloc API get redirected to - mimalloc functions (which reside in `mimalloc-override.dll`). - -4. Ensure the `mimalloc-override.dll` comes as early as possible in the import - list of the final executable (so it can intercept all potential allocations). - -For best performance on Windows with C++, it -is also recommended to also override the `new`/`delete` operations (by including -[`mimalloc-new-delete.h`](../include/mimalloc-new-delete.h) -a single(!) source file in your project). - -The environment variable `MIMALLOC_DISABLE_REDIRECT=1` can be used to disable dynamic -overriding at run-time. Use `MIMALLOC_VERBOSE=1` to check if mimalloc was successfully redirected. - -## Minject - -We cannot always re-link an executable with `mimalloc-override.dll`, and similarly, we cannot always -ensure the the DLL comes first in the import table of the final executable. -In many cases though we can patch existing executables without any recompilation -if they are linked with the dynamic C runtime (`ucrtbase.dll`) -- just put the `mimalloc-override.dll` -into the import table (and put `mimalloc-redirect.dll` in the same folder) -Such patching can be done for example with [CFF Explorer](https://ntcore.com/?page_id=388). - -The `minject` program can also do this from the command line, use `minject --help` for options: - -``` -> minject --help - -minject: - Injects the mimalloc dll into the import table of a 64-bit executable, - and/or ensures that it comes first in het import table. - -usage: - > minject [options] - -options: - -h --help show this help - -v --verbose be verbose - -l --list only list imported modules - -i --inplace update the exe in-place (make sure there is a backup!) - -f --force always overwrite without prompting - --postfix=

use

as a postfix to the mimalloc dll (default is 'override') - e.g. use --postfix=override-debug to link with mimalloc-override-debug.dll - -notes: - Without '--inplace' an injected is generated with the same name ending in '-mi'. - Ensure 'mimalloc-redirect.dll' is in the same folder as the mimalloc dll. - -examples: - > minject --list myprogram.exe - > minject --force --inplace myprogram.exe -``` diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/JoinPaths.cmake b/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/JoinPaths.cmake deleted file mode 100644 index c68d91b84..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/JoinPaths.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# This module provides function for joining paths -# known from most languages -# -# SPDX-License-Identifier: (MIT OR CC0-1.0) -# Copyright 2020 Jan Tojnar -# https://github.com/jtojnar/cmake-snips -# -# Modelled after Python’s os.path.join -# https://docs.python.org/3.7/library/os.path.html#os.path.join -# Windows not supported -function(join_paths joined_path first_path_segment) - set(temp_path "${first_path_segment}") - foreach(current_segment IN LISTS ARGN) - if(NOT ("${current_segment}" STREQUAL "")) - if(IS_ABSOLUTE "${current_segment}") - set(temp_path "${current_segment}") - else() - set(temp_path "${temp_path}/${current_segment}") - endif() - endif() - endforeach() - set(${joined_path} "${temp_path}" PARENT_SCOPE) -endfunction() diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config-version.cmake b/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config-version.cmake deleted file mode 100644 index 81fd3c9da..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config-version.cmake +++ /dev/null @@ -1,19 +0,0 @@ -set(mi_version_major 2) -set(mi_version_minor 1) -set(mi_version_patch 7) -set(mi_version ${mi_version_major}.${mi_version_minor}) - -set(PACKAGE_VERSION ${mi_version}) -if(PACKAGE_FIND_VERSION_MAJOR) - if("${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "${mi_version_major}") - if ("${PACKAGE_FIND_VERSION_MINOR}" EQUAL "${mi_version_minor}") - set(PACKAGE_VERSION_EXACT TRUE) - elseif("${PACKAGE_FIND_VERSION_MINOR}" LESS "${mi_version_minor}") - set(PACKAGE_VERSION_COMPATIBLE TRUE) - else() - set(PACKAGE_VERSION_UNSUITABLE TRUE) - endif() - else() - set(PACKAGE_VERSION_UNSUITABLE TRUE) - endif() -endif() diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config.cmake b/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config.cmake deleted file mode 100644 index a49b02a25..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/cmake/mimalloc-config.cmake +++ /dev/null @@ -1,14 +0,0 @@ -include(${CMAKE_CURRENT_LIST_DIR}/mimalloc.cmake) -get_filename_component(MIMALLOC_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}" PATH) # one up from the cmake dir, e.g. /usr/local/lib/cmake/mimalloc-2.0 -get_filename_component(MIMALLOC_VERSION_DIR "${CMAKE_CURRENT_LIST_DIR}" NAME) -string(REPLACE "/lib/cmake" "/lib" MIMALLOC_LIBRARY_DIR "${MIMALLOC_CMAKE_DIR}") -if("${MIMALLOC_VERSION_DIR}" EQUAL "mimalloc") - # top level install - string(REPLACE "/lib/cmake" "/include" MIMALLOC_INCLUDE_DIR "${MIMALLOC_CMAKE_DIR}") - set(MIMALLOC_OBJECT_DIR "${MIMALLOC_LIBRARY_DIR}") -else() - # versioned - string(REPLACE "/lib/cmake/" "/include/" MIMALLOC_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}") - string(REPLACE "/lib/cmake/" "/lib/" MIMALLOC_OBJECT_DIR "${CMAKE_CURRENT_LIST_DIR}") -endif() -set(MIMALLOC_TARGET_DIR "${MIMALLOC_LIBRARY_DIR}") # legacy diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg deleted file mode 100644 index 900509742..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg +++ /dev/null @@ -1,887 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg deleted file mode 100644 index 2d853edcb..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg +++ /dev/null @@ -1,1185 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg deleted file mode 100644 index 393bfad97..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg +++ /dev/null @@ -1,757 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg deleted file mode 100644 index 419dc250f..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg +++ /dev/null @@ -1,1028 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-1.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-1.svg deleted file mode 100644 index c296a0489..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-1.svg +++ /dev/null @@ -1,769 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg deleted file mode 100644 index b8a2f20e5..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg +++ /dev/null @@ -1,868 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg deleted file mode 100644 index 4a7e21e71..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg +++ /dev/null @@ -1,1157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-2.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-2.svg deleted file mode 100644 index 917ea5730..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-2.svg +++ /dev/null @@ -1,983 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-1.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-1.svg deleted file mode 100644 index 375ebd204..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-1.svg +++ /dev/null @@ -1,683 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-2.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-2.svg deleted file mode 100644 index cb2bbc89e..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-r5a-rss-2.svg +++ /dev/null @@ -1,854 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec-rss.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec-rss.svg deleted file mode 100644 index 2c936166c..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec-rss.svg +++ /dev/null @@ -1,713 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec.svg deleted file mode 100644 index af2b41ba9..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-spec.svg +++ /dev/null @@ -1,713 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-1.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-1.svg deleted file mode 100644 index dacd8ab94..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-1.svg +++ /dev/null @@ -1,890 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-2.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-2.svg deleted file mode 100644 index 9990cdcc3..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-2.svg +++ /dev/null @@ -1,1146 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-1.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-1.svg deleted file mode 100644 index 891f7d68f..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-1.svg +++ /dev/null @@ -1,796 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-2.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-2.svg deleted file mode 100644 index f4265378a..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2020/bench-z4-rss-2.svg +++ /dev/null @@ -1,974 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg deleted file mode 100644 index 86a97bfd2..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg +++ /dev/null @@ -1,952 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg deleted file mode 100644 index c74887702..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg +++ /dev/null @@ -1,1255 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg deleted file mode 100644 index bc91c218c..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg deleted file mode 100644 index e8b04a0d9..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg +++ /dev/null @@ -1,1269 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg deleted file mode 100644 index 6cd36aaab..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg +++ /dev/null @@ -1,836 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg deleted file mode 100644 index c81072e9b..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg +++ /dev/null @@ -1,1131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-macmini-2021-01-30.svg b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-macmini-2021-01-30.svg deleted file mode 100644 index ece64185f..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/bench-2021/bench-macmini-2021-01-30.svg +++ /dev/null @@ -1,766 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/doxyfile b/NativeScript/napi/android/quickjs/mimalloc-dev/doc/doxyfile deleted file mode 100644 index d03a70f57..000000000 --- a/NativeScript/napi/android/quickjs/mimalloc-dev/doc/doxyfile +++ /dev/null @@ -1,2659 +0,0 @@ -# Doxyfile 1.9.1 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the configuration -# file that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# https://www.gnu.org/software/libiconv/ for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = mi-malloc - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = 1.8/2.1 - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify a logo or an icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy -# the logo to the output directory. - -PROJECT_LOGO = mimalloc-logo.svg - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = .. - -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII -# characters to appear in the names of generated files. If set to NO, non-ASCII -# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode -# U+3044. -# The default value is: NO. - -ALLOW_UNICODE_NAMES = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - -# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = YES - -# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line -# such as -# /*************** -# as being the beginning of a Javadoc-style comment "banner". If set to NO, the -# Javadoc-style will behave just like regular comments and it will not be -# interpreted by doxygen. -# The default value is: NO. - -JAVADOC_BANNER = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# By default Python docstrings are displayed as preformatted text and doxygen's -# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the -# doxygen's special commands can be used and the contents of the docstring -# documentation blocks is shown as doxygen documentation. -# The default value is: YES. - -PYTHON_DOCSTRING = YES - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new -# page for each member. If set to NO, the documentation of a member will be part -# of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 2 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice -# sources only. Doxygen will then generate output that is more tailored for that -# language. For instance, namespaces will be presented as modules, types will be -# separated into more groups, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_SLICE = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: -# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser -# tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files). For instance to make doxygen treat .inc files -# as Fortran files (default is PHP), and .f files as C (default is Fortran), -# use: inc=Fortran f=C. -# -# Note: For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. When specifying no_extension you should add -# * to the FILE_PATTERNS. -# -# Note see also the list of default file extension mappings. - -EXTENSION_MAPPING = - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See https://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up -# to that level are automatically included in the table of contents, even if -# they do not have an id attribute. -# Note: This feature currently applies only to Markdown headings. -# Minimum value: 0, maximum value: 99, default value: 5. -# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. - -TOC_INCLUDE_HEADINGS = 0 - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# If one adds a struct or class to a group and this option is enabled, then also -# any nested class or struct is added to the same group. By default this option -# is disabled and one has to add nested compounds explicitly via \ingroup. -# The default value is: NO. - -GROUP_NESTED_COMPOUNDS = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = YES - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = YES - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use -# during processing. When set to 0 doxygen will based this on the number of -# cores available in the system. You can set it explicitly to a value larger -# than 0 to get more control over the balance between CPU load and processing -# speed. At this moment only the input processing can be done using multiple -# threads. Since this is still an experimental feature the default is set to 1, -# which effectively disables parallel processing. Please report any issues you -# encounter. Generating dot graphs in parallel is controlled by the -# DOT_NUM_THREADS setting. -# Minimum value: 0, maximum value: 32, default value: 1. - -NUM_PROC_THREADS = 1 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual -# methods of a class will be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIV_VIRTUAL = NO - -# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO, -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. If set to YES, local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO, only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If this flag is set to YES, the name of an unnamed parameter in a declaration -# will be determined by the corresponding definition. By default unnamed -# parameters remain unnamed in the output. -# The default value is: YES. - -RESOLVE_UNNAMED_PARAMS = YES - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# declarations. If set to NO, these declarations will be included in the -# documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO, these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# With the correct setting of option CASE_SENSE_NAMES doxygen will better be -# able to match the capabilities of the underlying filesystem. In case the -# filesystem is case sensitive (i.e. it supports files in the same directory -# whose names only differ in casing), the option must be set to YES to properly -# deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with -# output files written for symbols that only differ in casing, such as for two -# classes, one named CLASS and the other named Class, and to also support -# references to files without having to specify the exact matching casing. On -# Windows (including Cygwin) and MacOS, users should typically set this option -# to NO, whereas on Linux or other Unix flavors it should typically be set to -# YES. -# The default value is: system dependent. - -CASE_SENSE_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES, the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will -# append additional text to a page's title, such as Class Reference. If set to -# YES the compound reference will be hidden. -# The default value is: NO. - -HIDE_COMPOUND_REFERENCE= NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - -# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each -# grouped member an include statement to the documentation, telling the reader -# which file to include in order to use the member. -# The default value is: NO. - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO, the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo -# list. This list is created by putting \todo commands in the documentation. -# The default value is: YES. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test -# list. This list is created by putting \test commands in the documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 0 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES, the -# list will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = NO - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. See also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS -# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but -# at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. -# The default value is: NO. - -WARN_AS_ERROR = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING -# Note: If this tag is empty the current directory is searched. - -INPUT = mimalloc-doc.h - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: -# https://www.gnu.org/software/libiconv/) for the list of possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# read by doxygen. -# -# Note the list of default checked file patterns might differ from the list of -# default file extension mappings. -# -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl, -# *.ucf, *.qsf and *.ice. - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.idl \ - *.ddl \ - *.odl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.pyw \ - *.f90 \ - *.f95 \ - *.f03 \ - *.f08 \ - *.f \ - *.for \ - *.tcl \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = * - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. -# -# Note that for custom extensions or not directly supported extensions you also -# need to set EXTENSION_MAPPING for the extension otherwise the files are not -# properly processed by doxygen. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# entity all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see https://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: -# http://clang.llvm.org/) for more accurate parsing at the cost of reduced -# performance. This can be particularly helpful with template rich C++ code for -# which doxygen's built-in parser lacks the necessary type information. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse_libclang=ON option for CMake. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to -# YES then doxygen will add the directory of each input to the include path. -# The default value is: YES. - -CLANG_ADD_INC_PATHS = YES - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - -# If clang assisted parsing is enabled you can provide the clang parser with the -# path to the directory containing a file called compile_commands.json. This -# file is the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the -# options used when the source files were built. This is equivalent to -# specifying the -p option to a clang tool, such as clang-check. These options -# will then be passed to the parser. Any options specified with CLANG_OPTIONS -# will be added as well. -# Note: The availability of this option depends on whether or not doxygen was -# generated with the -Duse_libclang=ON option for CMake. - -CLANG_DATABASE_PATH = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = docs - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined -# cascading style sheets that are included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefore more robust against future updates. -# Doxygen will copy the style sheet files to the output directory. -# Note: The order of the extra style sheet files is of importance (e.g. the last -# style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = mimalloc-doxygen.css - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# https://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 189 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 12 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 240 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML -# documentation will contain a main index with vertical navigation menus that -# are dynamically created via JavaScript. If disabled, the navigation index will -# consists of multiple levels of tabs that are statically embedded in every HTML -# page. Disable this option to support browsers that do not have JavaScript, -# like the Qt help browser. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_MENUS = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: -# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To -# create a documentation set, doxygen will generate a Makefile in the HTML -# output directory. Running make will produce the docset in that directory and -# running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy -# genXcode/_index.html for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: -# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler (hhc.exe). If non-empty, -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the main .chm file (NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated -# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it -# enables the Previous and Next buttons. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location (absolute path -# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to -# run qhelpgenerator on the generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = YES - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 180 - -# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg -# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see -# https://inkscape.org) to generate formulas as SVG images instead of PNGs for -# the HTML output. These images will generally look nicer at scaled resolutions. -# Possible values are: png (the default) and svg (looks nicer but requires the -# pdf2svg or inkscape tool). -# The default value is: png. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FORMULA_FORMAT = png - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands -# to create new LaTeX commands to be used in formulas as building blocks. See -# the section "Including formulas" for details. - -FORMULA_MACROFILE = - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# https://www.mathjax.org) which uses client side JavaScript for the rendering -# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: -# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /