|
1 | 1 | #include <Foundation/Foundation.h> |
2 | 2 | #include <sstream> |
3 | | -#include <unordered_set> |
4 | 3 | #include "ArgConverter.h" |
5 | 4 | #include "NativeScriptException.h" |
6 | 5 | #include "DictionaryAdapter.h" |
|
32 | 31 |
|
33 | 32 | if (wrapper == nullptr) { |
34 | 33 | // During fast view churn like HMR in development, JS objects can outlive their |
35 | | - // native wrappers briefly. In Debug, avoid a crash and just skip the native call. |
| 34 | + // native wrappers briefly. In Debug, throw a catchable JS error instead of crashing. |
36 | 35 | // In Release, assert so crash reporting can capture unexpected cases. |
37 | 36 | if (RuntimeConfig.IsDebug) { |
38 | 37 | const char* selectorStr = meta ? meta->selectorAsString() : "<unknown>"; |
39 | 38 | const char* jsNameStr = meta ? meta->jsName() : "<unknown>"; |
40 | 39 | const char* classNameStr = klass ? class_getName(klass) : "<unknown>"; |
41 | | - // Suppress duplicate logs: only log once per class+selector for this process. |
42 | | - static std::unordered_set<std::string> s_logged; |
43 | | - std::string key = std::string(classNameStr) + ":" + selectorStr; |
44 | | - if (s_logged.insert(key).second) { |
45 | | - Log(@"Note: ignore method on non-native receiver (class: %s, selector: %s, jsName: %s, args: %d). Common during HMR.", |
46 | | - classNameStr, selectorStr, jsNameStr, (int)args.Length()); |
47 | | - } |
| 40 | + std::string errMsg = std::string("Cannot call method '") + jsNameStr + |
| 41 | + "' on a disposed native object (class: " + classNameStr + |
| 42 | + ", selector: " + selectorStr + "). This can happen during HMR or fast view churn."; |
| 43 | + isolate->ThrowException(Exception::Error(tns::ToV8String(isolate, errMsg))); |
48 | 44 | return v8::Undefined(isolate); |
49 | 45 | } else { |
50 | 46 | tns::Assert(false, isolate); |
|
69 | 65 | const char* selectorStr = meta ? meta->selectorAsString() : "<unknown>"; |
70 | 66 | const char* jsNameStr = meta ? meta->jsName() : "<unknown>"; |
71 | 67 | const char* classNameStr = klass ? class_getName(klass) : "<unknown>"; |
72 | | - // Suppress duplicate logs: only log once per class+selector for this process. |
73 | | - static std::unordered_set<std::string> s_logged; |
74 | | - std::string key = std::string(classNameStr) + ":" + selectorStr; |
75 | | - if (s_logged.insert(key).second) { |
76 | | - Log(@"Note: ignore receiver wrapper type %d (class: %s, selector: %s, jsName: %s). Common during HMR.", |
77 | | - (int)wrapper->Type(), classNameStr, selectorStr, jsNameStr); |
78 | | - } |
| 68 | + std::string errMsg = std::string("Unexpected receiver wrapper type ") + |
| 69 | + std::to_string((int)wrapper->Type()) + " for method '" + jsNameStr + |
| 70 | + "' (class: " + classNameStr + ", selector: " + selectorStr + |
| 71 | + "). This can happen during HMR or fast view churn."; |
| 72 | + isolate->ThrowException(Exception::Error(tns::ToV8String(isolate, errMsg))); |
79 | 73 | return v8::Undefined(isolate); |
80 | 74 | } else { |
81 | 75 | tns::Assert(false, isolate); |
|
0 commit comments