From 0b7e94db904d536aad4f50dd338ad3cfc67b89e6 Mon Sep 17 00:00:00 2001 From: Douglas Machado Date: Wed, 2 Feb 2022 16:57:29 -0300 Subject: [PATCH 1/2] Improvements for crash report --- NativeScript/runtime/Helpers.h | 3 ++ NativeScript/runtime/Helpers.mm | 10 ++++ NativeScript/runtime/Interop.h | 1 + NativeScript/runtime/Interop.mm | 66 ++++++++++++++++++++++++- NativeScript/runtime/Metadata.h | 25 ++++++++++ NativeScript/runtime/MetadataBuilder.mm | 8 +++ 6 files changed, 112 insertions(+), 1 deletion(-) diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index e840943a..d9fb3ffa 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -67,6 +67,9 @@ bool LiveSync(v8::Isolate* isolate); void Assert(bool condition, v8::Isolate* isolate = nullptr); +void LogDebugMessage(std::string message); +void StopExecutionAndLogStackTraceIfInDebug(v8::Isolate* isolate); + } #endif /* Helpers_h */ diff --git a/NativeScript/runtime/Helpers.mm b/NativeScript/runtime/Helpers.mm index 578ded00..ea234f89 100644 --- a/NativeScript/runtime/Helpers.mm +++ b/NativeScript/runtime/Helpers.mm @@ -691,3 +691,13 @@ Log(@"%s", stack.c_str()); assert(false); } + +void tns::StopExecutionAndLogStackTraceIfInDebug(v8::Isolate* isolate) { + Assert(false, isolate); +} + +void tns::LogDebugMessage(std::string message) { + if (RuntimeConfig.IsDebug) { + Log(@"%s", message.c_str()); + } +} diff --git a/NativeScript/runtime/Interop.h b/NativeScript/runtime/Interop.h index b5057163..9601a097 100644 --- a/NativeScript/runtime/Interop.h +++ b/NativeScript/runtime/Interop.h @@ -126,6 +126,7 @@ class Interop { static id ToObject(v8::Local context, v8::Local arg); static v8::Local GetPrimitiveReturnType(v8::Local context, BinaryTypeEncodingType type, BaseCall* call); private: + static void ExecuteWriteValueDebugValidationsIfInDebug(v8::Local context, const TypeEncoding* typeEncoding, void* dest, v8::Local arg); static std::pair CreateMethodInternal(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData); template diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index de86059c..fc94e80e 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -15,6 +15,7 @@ #include "Reference.h" #include "Pointer.h" #include "ExtVector.h" +#include "RuntimeConfig.h" #include "SymbolIterator.h" #include "UnmanagedType.h" #include "OneByteStringResource.h" @@ -143,7 +144,7 @@ void Interop::WriteValue(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { Isolate* isolate = context->GetIsolate(); - + ExecuteWriteValueDebugValidationsIfInDebug(context, typeEncoding, dest, arg); if (arg.IsEmpty() || arg->IsNullOrUndefined()) { ffi_type* ffiType = FFICall::GetArgumentType(typeEncoding, true); size_t size = ffiType->size; @@ -1464,4 +1465,67 @@ return result; } +// MARK: - Debug Messages for the runtime + +void ExecuteWriteValueValidationsAndStopExecutionAndLogStackTraceIfInDebug(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { + Isolate* isolate = context->GetIsolate(); + + std::string destName = typeEncoding->details.interfaceDeclarationReference.name.valuePtr(); + Local originArg = arg; + if (typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference) { + if (originArg->IsObject()) { + Local originObj = originArg.As(); + if ((originObj->IsArrayBuffer() || originObj->IsArrayBufferView()) && + destName != "NSArray") { + tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + } + } + if (destName == "NSString" && tns::IsNumber(originArg)) { + tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + } + if (destName == "NSString" && tns::IsBool(originArg)) { + tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + } + if (destName == "NSString" && tns::IsArrayOrArrayLike(isolate, originArg)) { + tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + } + } +} + +bool IsTypeEncondingHandldedByDebugMessages(const TypeEncoding* typeEncoding) { + if (typeEncoding->type != BinaryTypeEncodingType::InterfaceDeclarationReference && + typeEncoding->type != BinaryTypeEncodingType::StructDeclarationReference && + typeEncoding->type != BinaryTypeEncodingType::IdEncoding) { + return true; + } else { + return false; + } +} + +void LogWriteValueTraceMessage(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { + Isolate* isolate = context->GetIsolate(); + std::string destName = typeEncoding->details.interfaceDeclarationReference.name.valuePtr(); + std::string originName = tns::ToString(isolate, arg); + if (originName == "") { + // empty string + originName = "\"\""; + } + NSString* message = [NSString stringWithFormat:@"Interop::WriteValue: from {%s} to {%s}", originName.c_str(), destName.c_str()]; + tns::LogDebugMessage(message.UTF8String); +} + +void Interop::ExecuteWriteValueDebugValidationsIfInDebug(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { + if (!RuntimeConfig.IsDebug) { + return; + } + if (arg.IsEmpty() || arg->IsNullOrUndefined()) { + return; + } + if (IsTypeEncondingHandldedByDebugMessages(typeEncoding)) { + return; + } + LogWriteValueTraceMessage(context, typeEncoding, dest, arg); + ExecuteWriteValueValidationsAndStopExecutionAndLogStackTraceIfInDebug(context, typeEncoding, dest, arg); +} + } diff --git a/NativeScript/runtime/Metadata.h b/NativeScript/runtime/Metadata.h index 7f532552..6b32c015 100644 --- a/NativeScript/runtime/Metadata.h +++ b/NativeScript/runtime/Metadata.h @@ -563,6 +563,31 @@ struct Meta { return (MetaType)(this->_flags & MetaTypeMask); } + const char* typeName() const { + switch (type()) { + case Undefined: + return "Undefined"; + case Struct: + return "Struct"; + case Union: + return "Union"; + case Function: + return "Function"; + case JsCode: + return "JsCode"; + case Var: + return "Var"; + case Interface: + return "Interface"; + case ProtocolType: + return "ProtocolType"; + case Vector: + return "Vector"; + default: + return "Unknwon"; + } + } + const ModuleMeta* topLevelModule() const { return this->_topLevelModule.valuePtr(); } diff --git a/NativeScript/runtime/MetadataBuilder.mm b/NativeScript/runtime/MetadataBuilder.mm index e619eb54..e2f8a473 100644 --- a/NativeScript/runtime/MetadataBuilder.mm +++ b/NativeScript/runtime/MetadataBuilder.mm @@ -810,6 +810,14 @@ Class klass = objc_getClass(containingClass.c_str()); // TODO: Find out if the isMethodCallback property can be determined based on a UITableViewController.prototype.viewDidLoad.call(this) or super.viewDidLoad() call + NSString* message = [NSString stringWithFormat:@"MetadataBuilder::InvokeMethod class {%s}, selector {%s}, isInitializer {%s}, type {%s}, lib {%s}", + containingClass.c_str(), + meta->selectorAsString(), + meta->isInitializer() ? "true":"false", + meta->typeName(), + meta->topLevelModule()->getName()]; + tns::LogDebugMessage(message.UTF8String); + try { return ArgConverter::Invoke(context, klass, receiver, args, meta, isMethodCallback); } catch (NativeScriptException& ex) { From 82f0599c0eca7031bb48811ca15c565e25b3294f Mon Sep 17 00:00:00 2001 From: Douglas Machado Date: Thu, 3 Feb 2022 17:54:10 -0300 Subject: [PATCH 2/2] Code review feedback --- NativeScript/runtime/Helpers.h | 3 +-- NativeScript/runtime/Helpers.mm | 8 +------- NativeScript/runtime/Interop.mm | 21 +++++++++++++-------- NativeScript/runtime/MetadataBuilder.mm | 19 +++++++++++-------- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/NativeScript/runtime/Helpers.h b/NativeScript/runtime/Helpers.h index d9fb3ffa..5c15d459 100644 --- a/NativeScript/runtime/Helpers.h +++ b/NativeScript/runtime/Helpers.h @@ -67,8 +67,7 @@ bool LiveSync(v8::Isolate* isolate); void Assert(bool condition, v8::Isolate* isolate = nullptr); -void LogDebugMessage(std::string message); -void StopExecutionAndLogStackTraceIfInDebug(v8::Isolate* isolate); +void StopExecutionAndLogStackTrace(v8::Isolate* isolate); } diff --git a/NativeScript/runtime/Helpers.mm b/NativeScript/runtime/Helpers.mm index ea234f89..d759c1c9 100644 --- a/NativeScript/runtime/Helpers.mm +++ b/NativeScript/runtime/Helpers.mm @@ -692,12 +692,6 @@ assert(false); } -void tns::StopExecutionAndLogStackTraceIfInDebug(v8::Isolate* isolate) { +void tns::StopExecutionAndLogStackTrace(v8::Isolate* isolate) { Assert(false, isolate); } - -void tns::LogDebugMessage(std::string message) { - if (RuntimeConfig.IsDebug) { - Log(@"%s", message.c_str()); - } -} diff --git a/NativeScript/runtime/Interop.mm b/NativeScript/runtime/Interop.mm index fc94e80e..052113ac 100644 --- a/NativeScript/runtime/Interop.mm +++ b/NativeScript/runtime/Interop.mm @@ -1467,9 +1467,11 @@ // MARK: - Debug Messages for the runtime -void ExecuteWriteValueValidationsAndStopExecutionAndLogStackTraceIfInDebug(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { +void ExecuteWriteValueValidationsAndStopExecutionAndLogStackTrace(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { + if (!RuntimeConfig.IsDebug) { + return; + } Isolate* isolate = context->GetIsolate(); - std::string destName = typeEncoding->details.interfaceDeclarationReference.name.valuePtr(); Local originArg = arg; if (typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference) { @@ -1477,17 +1479,17 @@ void ExecuteWriteValueValidationsAndStopExecutionAndLogStackTraceIfInDebug(Local Local originObj = originArg.As(); if ((originObj->IsArrayBuffer() || originObj->IsArrayBufferView()) && destName != "NSArray") { - tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + tns::StopExecutionAndLogStackTrace(isolate); } } if (destName == "NSString" && tns::IsNumber(originArg)) { - tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + tns::StopExecutionAndLogStackTrace(isolate); } if (destName == "NSString" && tns::IsBool(originArg)) { - tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + tns::StopExecutionAndLogStackTrace(isolate); } if (destName == "NSString" && tns::IsArrayOrArrayLike(isolate, originArg)) { - tns::StopExecutionAndLogStackTraceIfInDebug(isolate); + tns::StopExecutionAndLogStackTrace(isolate); } } } @@ -1503,6 +1505,9 @@ bool IsTypeEncondingHandldedByDebugMessages(const TypeEncoding* typeEncoding) { } void LogWriteValueTraceMessage(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { + if (!RuntimeConfig.IsDebug) { + return; + } Isolate* isolate = context->GetIsolate(); std::string destName = typeEncoding->details.interfaceDeclarationReference.name.valuePtr(); std::string originName = tns::ToString(isolate, arg); @@ -1511,7 +1516,7 @@ void LogWriteValueTraceMessage(Local context, const TypeEncoding* typeE originName = "\"\""; } NSString* message = [NSString stringWithFormat:@"Interop::WriteValue: from {%s} to {%s}", originName.c_str(), destName.c_str()]; - tns::LogDebugMessage(message.UTF8String); + Log(@"%@", message); } void Interop::ExecuteWriteValueDebugValidationsIfInDebug(Local context, const TypeEncoding* typeEncoding, void* dest, Local arg) { @@ -1525,7 +1530,7 @@ void LogWriteValueTraceMessage(Local context, const TypeEncoding* typeE return; } LogWriteValueTraceMessage(context, typeEncoding, dest, arg); - ExecuteWriteValueValidationsAndStopExecutionAndLogStackTraceIfInDebug(context, typeEncoding, dest, arg); + ExecuteWriteValueValidationsAndStopExecutionAndLogStackTrace(context, typeEncoding, dest, arg); } } diff --git a/NativeScript/runtime/MetadataBuilder.mm b/NativeScript/runtime/MetadataBuilder.mm index e2f8a473..2237abae 100644 --- a/NativeScript/runtime/MetadataBuilder.mm +++ b/NativeScript/runtime/MetadataBuilder.mm @@ -11,6 +11,7 @@ #include "Worker.h" #include "Caches.h" #include "Tasks.h" +#include "RuntimeConfig.h" using namespace v8; @@ -810,14 +811,16 @@ Class klass = objc_getClass(containingClass.c_str()); // TODO: Find out if the isMethodCallback property can be determined based on a UITableViewController.prototype.viewDidLoad.call(this) or super.viewDidLoad() call - NSString* message = [NSString stringWithFormat:@"MetadataBuilder::InvokeMethod class {%s}, selector {%s}, isInitializer {%s}, type {%s}, lib {%s}", - containingClass.c_str(), - meta->selectorAsString(), - meta->isInitializer() ? "true":"false", - meta->typeName(), - meta->topLevelModule()->getName()]; - tns::LogDebugMessage(message.UTF8String); - + if (RuntimeConfig.IsDebug) { + NSString* message = [NSString stringWithFormat:@"MetadataBuilder::InvokeMethod class {%s}, selector {%s}, isInitializer {%s}, type {%s}, lib {%s}", + containingClass.c_str(), + meta->selectorAsString(), + meta->isInitializer() ? "true":"false", + meta->typeName(), + meta->topLevelModule()->getName()]; + Log(@"%@", message); + } + try { return ArgConverter::Invoke(context, klass, receiver, args, meta, isMethodCallback); } catch (NativeScriptException& ex) {