Skip to content

Commit 70b1802

Browse files
authored
fix: bridge release adapters (#224)
* fix: bridge release adapters * fix: adapter cleanup and thread safety * fix: safeguards on dictionary adapter dealloc
1 parent a6d7332 commit 70b1802

File tree

11 files changed

+213
-130
lines changed

11 files changed

+213
-130
lines changed

NativeScript/runtime/ArgConverter.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393

9494
Isolate* isolate = data->isolateWrapper_.Isolate();
9595

96-
if (!Runtime::IsAlive(isolate) || !data->isolateWrapper_.IsValid()) {
96+
if (!data->isolateWrapper_.IsValid()) {
9797
memset(retValue, 0, cif->rtype->size);
9898
return;
9999
}

NativeScript/runtime/ArrayAdapter.mm

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,71 @@
22
#include "DataWrapper.h"
33
#include "Helpers.h"
44
#include "Interop.h"
5-
#include "Caches.h"
5+
#include "IsolateWrapper.h"
66

77
using namespace tns;
88
using namespace v8;
99

1010
@implementation ArrayAdapter {
11-
Isolate* isolate_;
11+
IsolateWrapper* wrapper_;
1212
std::shared_ptr<Persistent<Value>> object_;
13-
std::shared_ptr<Caches> cache_;
13+
// we're responsible for this wrapper
14+
ObjCDataWrapper* dataWrapper_;
1415
}
1516

1617
- (instancetype)initWithJSObject:(Local<Object>)jsObject isolate:(Isolate*)isolate {
1718
if (self) {
18-
self->isolate_ = isolate;
19-
self->cache_ = Caches::Get(isolate);
19+
self->wrapper_ = new IsolateWrapper(isolate);
2020
self->object_ = std::make_shared<Persistent<Value>>(isolate, jsObject);
21-
self->cache_->Instances.emplace(self, self->object_);
22-
tns::SetValue(isolate, jsObject, new ObjCDataWrapper(self));
21+
self->wrapper_->GetCache()->Instances.emplace(self, self->object_);
22+
tns::SetValue(isolate, jsObject, (self->dataWrapper_ = new ObjCDataWrapper(self)));
2323
}
24-
24+
2525
return self;
2626
}
2727

2828
- (NSUInteger)count {
29-
v8::Locker locker(self->isolate_);
30-
Isolate::Scope isolate_scope(self->isolate_);
31-
HandleScope handle_scope(self->isolate_);
32-
33-
Local<Object> object = self->object_->Get(self->isolate_).As<Object>();
29+
auto isolate = wrapper_->Isolate();
30+
if(!wrapper_->IsValid()) {
31+
return 0;
32+
}
33+
v8::Locker locker(isolate);
34+
Isolate::Scope isolate_scope(isolate);
35+
HandleScope handle_scope(isolate);
36+
37+
Local<Object> object = self->object_->Get(isolate).As<Object>();
3438
if (object->IsArray()) {
3539
uint32_t length = object.As<v8::Array>()->Length();
3640
return length;
3741
}
38-
39-
Local<Context> context = self->cache_->GetContext();
42+
43+
Local<Context> context = wrapper_->GetCache()->GetContext();
4044
Local<v8::Array> propertyNames;
4145
bool success = object->GetPropertyNames(context).ToLocal(&propertyNames);
42-
tns::Assert(success, self->isolate_);
46+
tns::Assert(success, isolate);
4347
uint32_t length = propertyNames->Length();
4448
return length;
4549
}
4650

4751
- (id)objectAtIndex:(NSUInteger)index {
48-
v8::Locker locker(self->isolate_);
49-
Isolate::Scope isolate_scope(self->isolate_);
50-
HandleScope handle_scope(self->isolate_);
51-
52+
auto isolate = wrapper_->Isolate();
53+
if (!wrapper_->IsValid()) {
54+
return nil;
55+
}
56+
v8::Locker locker(isolate);
57+
Isolate::Scope isolate_scope(isolate);
58+
HandleScope handle_scope(isolate);
59+
5260
if (!(index < [self count])) {
53-
tns::Assert(false, self->isolate_);
61+
tns::Assert(false, isolate);
5462
}
55-
56-
Local<Object> object = self->object_->Get(self->isolate_).As<Object>();
57-
Local<Context> context = self->cache_->GetContext();
63+
64+
Local<Object> object = self->object_->Get(isolate).As<Object>();
65+
Local<Context> context = wrapper_->GetCache()->GetContext();
5866
Local<Value> item;
5967
bool success = object->Get(context, (uint)index).ToLocal(&item);
60-
tns::Assert(success, self->isolate_);
61-
68+
tns::Assert(success, isolate);
69+
6270
if (item->IsNullOrUndefined()) {
6371
return nil;
6472
}
@@ -68,16 +76,29 @@ - (id)objectAtIndex:(NSUInteger)index {
6876
}
6977

7078
- (void)dealloc {
71-
self->cache_->Instances.erase(self);
72-
Local<Value> value = self->object_->Get(self->isolate_);
73-
BaseDataWrapper* wrapper = tns::GetValue(self->isolate_, value);
74-
if (wrapper != nullptr) {
75-
tns::DeleteValue(self->isolate_, value);
76-
delete wrapper;
79+
if (wrapper_->IsValid()) {
80+
auto isolate = wrapper_->Isolate();
81+
v8::Locker locker(isolate);
82+
Isolate::Scope isolate_scope(isolate);
83+
HandleScope handle_scope(isolate);
84+
wrapper_->GetCache()->Instances.erase(self);
85+
Local<Value> value = self->object_->Get(isolate);
86+
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
87+
if (wrapper != nullptr) {
88+
tns::DeleteValue(isolate, value);
89+
// ensure we don't delete the same wrapper twice
90+
// this is just needed as a failsafe in case some other wrapper is assigned to this object
91+
if (wrapper == dataWrapper_) {
92+
dataWrapper_ = nullptr;
93+
}
94+
delete wrapper;
95+
}
96+
self->object_->Reset();
97+
}
98+
delete wrapper_;
99+
if (dataWrapper_ != nullptr) {
100+
delete dataWrapper_;
77101
}
78-
self->object_->Reset();
79-
self->isolate_ = nullptr;
80-
self->cache_ = nullptr;
81102
self->object_ = nullptr;
82103
[super dealloc];
83104
}

NativeScript/runtime/ClassBuilder.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@
227227
cache->CtorFuncs.emplace(extendedClassName, poExtendedClassCtorFunc);
228228

229229
IMP newInitialize = imp_implementationWithBlock(^(id self) {
230-
if (!Runtime::IsAlive(isolate) || !isolateWrapper.IsValid()) {
230+
if (!isolateWrapper.IsValid()) {
231231
return;
232232
}
233233
v8::Locker locker(isolate);
@@ -264,7 +264,7 @@
264264
/// in order to make both of them destroyable/GC-able. When the JavaScript object is GC-ed we release the native counterpart as well.
265265
void (*retain)(id, SEL) = (void (*)(id, SEL))FindNotOverridenMethod(extendedClass, @selector(retain));
266266
IMP newRetain = imp_implementationWithBlock(^(id self) {
267-
if (!Runtime::IsAlive(isolate) || !isolateWrapper.IsValid()) {
267+
if (!isolateWrapper.IsValid()) {
268268
return retain(self, @selector(retain));
269269
}
270270
if ([self retainCount] == 1) {
@@ -289,7 +289,7 @@
289289

290290
void (*release)(id, SEL) = (void (*)(id, SEL))FindNotOverridenMethod(extendedClass, @selector(release));
291291
IMP newRelease = imp_implementationWithBlock(^(id self) {
292-
if (!Runtime::IsAlive(isolate) || !isolateWrapper.IsValid()) {
292+
if (!isolateWrapper.IsValid()) {
293293
release(self, @selector(release));
294294
return;
295295
}

0 commit comments

Comments
 (0)