Skip to content

Commit 55ffdef

Browse files
authored
feat: web-compliant error handling (unhandled rejections, error events, interop.escapeException) (#409)
1 parent 164e752 commit 55ffdef

35 files changed

Lines changed: 5164 additions & 1958 deletions

‎NativeScript/runtime/ArgConverter.h‎

Lines changed: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,61 +2,128 @@
22
#define ArgConverter_h
33

44
#include <vector>
5-
#include "libffi.h"
6-
#include "Common.h"
5+
76
#include "Caches.h"
7+
#include "Common.h"
88
#include "DataWrapper.h"
99
#include "IsolateWrapper.h"
10+
#include "libffi.h"
1011

1112
namespace tns {
1213

1314
class ArgConverter;
1415

1516
struct MethodCallbackWrapper {
16-
public:
17-
MethodCallbackWrapper(v8::Isolate* isolate, std::shared_ptr<v8::Persistent<v8::Value>> callback, const uint8_t initialParamIndex, const uint8_t paramsCount, const TypeEncoding* typeEncoding)
18-
: isolateWrapper_(isolate),
19-
callback_(callback),
20-
initialParamIndex_(initialParamIndex),
21-
paramsCount_(paramsCount),
22-
typeEncoding_(typeEncoding) {
23-
}
24-
IsolateWrapper isolateWrapper_;
25-
std::shared_ptr<v8::Persistent<v8::Value>> callback_;
26-
const uint8_t initialParamIndex_;
27-
const uint8_t paramsCount_;
28-
const TypeEncoding* typeEncoding_;
17+
public:
18+
MethodCallbackWrapper(v8::Isolate* isolate,
19+
std::shared_ptr<v8::Persistent<v8::Value>> callback,
20+
const uint8_t initialParamIndex,
21+
const uint8_t paramsCount,
22+
const TypeEncoding* typeEncoding)
23+
: isolateWrapper_(isolate),
24+
callback_(callback),
25+
initialParamIndex_(initialParamIndex),
26+
paramsCount_(paramsCount),
27+
typeEncoding_(typeEncoding) {}
28+
IsolateWrapper isolateWrapper_;
29+
std::shared_ptr<v8::Persistent<v8::Value>> callback_;
30+
const uint8_t initialParamIndex_;
31+
const uint8_t paramsCount_;
32+
const TypeEncoding* typeEncoding_;
2933
};
3034

3135
class ArgConverter {
32-
public:
33-
static void Init(v8::Local<v8::Context> context, v8::GenericNamedPropertyGetterCallback structPropertyGetter, v8::GenericNamedPropertySetterCallback structPropertySetter);
34-
static v8::Local<v8::Value> Invoke(v8::Local<v8::Context> context, Class klass, v8::Local<v8::Object> receiver, V8Args& args, const MethodMeta* meta, bool isMethodCallback);
35-
static v8::Local<v8::Value> ConvertArgument(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, bool skipGCRegistration = false, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
36-
static v8::Local<v8::Value> CreateJsWrapper(v8::Local<v8::Context> context, BaseDataWrapper* wrapper, v8::Local<v8::Object> receiver, bool skipGCRegistration = false, const std::vector<std::string>& additionalProtocols = std::vector<std::string>());
37-
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyObject(v8::Local<v8::Context> context, bool skipGCRegistration = false);
38-
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyStruct(v8::Local<v8::Context> context);
39-
static const Meta* FindMeta(Class klass, const TypeEncoding* typeEncoding = nullptr);
40-
static const Meta* GetMeta(std::string name);
41-
static const ProtocolMeta* FindProtocolMeta(Protocol* protocol);
42-
static void MethodCallback(ffi_cif* cif, void* retValue, void** argValues, void* userData);
43-
static void SetValue(v8::Local<v8::Context> context, void* retValue, v8::Local<v8::Value> value, const TypeEncoding* typeEncoding);
44-
static void ConstructObject(v8::Local<v8::Context> context, const v8::FunctionCallbackInfo<v8::Value>& info, Class klass, const InterfaceMeta* interfaceMeta = nullptr);
45-
private:
46-
static v8::Local<v8::Function> CreateEmptyInstanceFunction(v8::Local<v8::Context> context, v8::GenericNamedPropertyGetterCallback propertyGetter = nullptr, v8::GenericNamedPropertySetterCallback propertySetter = nullptr);
47-
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyInstance(v8::Local<v8::Context> context, v8::Persistent<v8::Function>* ctorFunc, bool skipGCRegistration = false);
48-
static void FindMethodOverloads(Class klass, std::string methodName, MemberType type, std::vector<const MethodMeta*>& overloads);
49-
static const MethodMeta* FindInitializer(v8::Local<v8::Context> context, Class klass, const InterfaceMeta* interfaceMeta, const v8::FunctionCallbackInfo<v8::Value>& info, std::vector<v8::Local<v8::Value>>& args);
50-
static bool CanInvoke(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, v8::Local<v8::Value> arg);
51-
static bool CanInvoke(v8::Local<v8::Context> context, const MethodMeta* candidate, const v8::FunctionCallbackInfo<v8::Value>& info);
52-
static std::vector<v8::Local<v8::Value>> GetInitializerArgs(v8::Local<v8::Object> obj, std::string& constructorTokens);
53-
static void IndexedPropertyGetterCallback(uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& args);
54-
static void IndexedPropertySetterCallback(uint32_t index, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& args);
55-
static bool IsErrorOutParameter(const TypeEncoding* typeEncoding);
56-
static std::vector<const MethodMeta*> GetInitializers(Caches* cache, Class klass, const InterfaceMeta* interfaceMeta);
57-
static void MethodCallbackInternal(ffi_cif* cif, void* retValue, void** argValues, void* userData);
36+
public:
37+
static void Init(v8::Local<v8::Context> context,
38+
v8::GenericNamedPropertyGetterCallback structPropertyGetter,
39+
v8::GenericNamedPropertySetterCallback structPropertySetter);
40+
static v8::Local<v8::Value> Invoke(v8::Local<v8::Context> context,
41+
Class klass,
42+
v8::Local<v8::Object> receiver,
43+
V8Args& args, const MethodMeta* meta,
44+
bool isMethodCallback);
45+
static v8::Local<v8::Value> ConvertArgument(
46+
v8::Local<v8::Context> context, BaseDataWrapper* wrapper,
47+
bool skipGCRegistration = false,
48+
const std::vector<std::string>& additionalProtocols =
49+
std::vector<std::string>());
50+
static v8::Local<v8::Value> CreateJsWrapper(
51+
v8::Local<v8::Context> context, BaseDataWrapper* wrapper,
52+
v8::Local<v8::Object> receiver, bool skipGCRegistration = false,
53+
const std::vector<std::string>& additionalProtocols =
54+
std::vector<std::string>());
55+
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyObject(
56+
v8::Local<v8::Context> context, bool skipGCRegistration = false);
57+
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyStruct(
58+
v8::Local<v8::Context> context);
59+
static const Meta* FindMeta(Class klass,
60+
const TypeEncoding* typeEncoding = nullptr);
61+
static const Meta* GetMeta(std::string name);
62+
static const ProtocolMeta* FindProtocolMeta(Protocol* protocol);
63+
static void MethodCallback(ffi_cif* cif, void* retValue, void** argValues,
64+
void* userData);
65+
static void SetValue(v8::Local<v8::Context> context, void* retValue,
66+
v8::Local<v8::Value> value,
67+
const TypeEncoding* typeEncoding);
68+
// Returns (lazily creating) the per-isolate interop.escapeException brand
69+
// private stored in Caches. Empty handle if the isolate cache is invalid.
70+
static v8::Local<v8::Private> GetEscapeExceptionBrand(v8::Isolate* isolate);
71+
// If `value` carries the escapeException brand, returns the NSException to
72+
// throw (typed `id` so this header is usable from the pure-C++ TUs that
73+
// include it) — the original wrapped NSException when present, otherwise one
74+
// synthesized from the branded name/message/stack payload. Returns nil when
75+
// `value` is not branded. Never reports; the caller decides what to do.
76+
static id ExtractEscapedException(v8::Local<v8::Context> context,
77+
v8::Local<v8::Value> value);
78+
// Shared JS<->native boundary helper. Reads tc.Exception(): if it carries
79+
// the escapeException brand, returns the NSException (as `id`) the caller
80+
// must @throw AFTER closing every live V8 scope (Locker/HandleScope/
81+
// Context::Scope). Otherwise reports the exception exactly once through the
82+
// uncaught path (error-event dispatch + shims + log) and returns nil, so the
83+
// caller returns its defined default. Resets `tc` in both cases.
84+
static id HandleBoundaryException(v8::Local<v8::Context> context,
85+
v8::TryCatch& tc);
86+
static void ConstructObject(v8::Local<v8::Context> context,
87+
const v8::FunctionCallbackInfo<v8::Value>& info,
88+
Class klass,
89+
const InterfaceMeta* interfaceMeta = nullptr);
90+
91+
private:
92+
static v8::Local<v8::Function> CreateEmptyInstanceFunction(
93+
v8::Local<v8::Context> context,
94+
v8::GenericNamedPropertyGetterCallback propertyGetter = nullptr,
95+
v8::GenericNamedPropertySetterCallback propertySetter = nullptr);
96+
static std::shared_ptr<v8::Persistent<v8::Value>> CreateEmptyInstance(
97+
v8::Local<v8::Context> context, v8::Persistent<v8::Function>* ctorFunc,
98+
bool skipGCRegistration = false);
99+
static void FindMethodOverloads(Class klass, std::string methodName,
100+
MemberType type,
101+
std::vector<const MethodMeta*>& overloads);
102+
static const MethodMeta* FindInitializer(
103+
v8::Local<v8::Context> context, Class klass,
104+
const InterfaceMeta* interfaceMeta,
105+
const v8::FunctionCallbackInfo<v8::Value>& info,
106+
std::vector<v8::Local<v8::Value>>& args);
107+
static bool CanInvoke(v8::Local<v8::Context> context,
108+
const TypeEncoding* typeEncoding,
109+
v8::Local<v8::Value> arg);
110+
static bool CanInvoke(v8::Local<v8::Context> context,
111+
const MethodMeta* candidate,
112+
const v8::FunctionCallbackInfo<v8::Value>& info);
113+
static std::vector<v8::Local<v8::Value>> GetInitializerArgs(
114+
v8::Local<v8::Object> obj, std::string& constructorTokens);
115+
static void IndexedPropertyGetterCallback(
116+
uint32_t index, const v8::PropertyCallbackInfo<v8::Value>& args);
117+
static void IndexedPropertySetterCallback(
118+
uint32_t index, v8::Local<v8::Value> value,
119+
const v8::PropertyCallbackInfo<v8::Value>& args);
120+
static bool IsErrorOutParameter(const TypeEncoding* typeEncoding);
121+
static std::vector<const MethodMeta*> GetInitializers(
122+
Caches* cache, Class klass, const InterfaceMeta* interfaceMeta);
123+
static void MethodCallbackInternal(ffi_cif* cif, void* retValue,
124+
void** argValues, void* userData);
58125
};
59126

60-
}
127+
} // namespace tns
61128

62129
#endif /* ArgConverter_h */

0 commit comments

Comments
 (0)