Skip to content

Commit 62dff97

Browse files
authored
chore: 8.1 memory leak fixes + readme improvements (#123)
1 parent 1f40861 commit 62dff97

26 files changed

+315
-223
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ Thumbs.db
4141
node_modules/
4242
package-lock.json
4343
*.pyc
44-
v8
44+
v8

NativeScript/NativeScript-Prefix.pch

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef NativeScript_Prefix_pch
22
#define NativeScript_Prefix_pch
33

4-
#define NATIVESCRIPT_VERSION "7.2.0"
4+
#define NATIVESCRIPT_VERSION "8.1.0-rc.1"
55

66
#ifdef DEBUG
77
#define SIZEOF_OFF_T 8

NativeScript/runtime/ArgConverter.mm

+1
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@
268268
id adapter = [[DictionaryAdapter alloc] initWithJSObject:value.As<Object>() isolate:isolate];
269269
memset(retValue, 0, sizeof(id));
270270
*static_cast<id __strong *>(retValue) = adapter;
271+
// CFAutorelease(adapter);
271272
return;
272273
}
273274
} else if (type == BinaryTypeEncodingType::StructDeclarationReference) {

NativeScript/runtime/ClassBuilder.mm

+2
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,8 @@
466466
return pdw->TypeEncoding()->type;
467467
} else if (wrapper->Type() == WrapperType::ObjCObject) {
468468
return BinaryTypeEncodingType::IdEncoding;
469+
} else if (wrapper->Type() == WrapperType::PointerType) {
470+
return BinaryTypeEncodingType::PointerEncoding;
469471
}
470472
}
471473

NativeScript/runtime/DataWrapper.h

+12-5
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,17 @@ class ReferenceWrapper: public BaseDataWrapper {
259259
disposeData_(false) {
260260
}
261261

262+
~ReferenceWrapper() {
263+
if(this->value_ != nullptr) {
264+
value_->Reset();
265+
delete value_;
266+
}
267+
268+
if (this->data_ != nullptr) {
269+
std::free(this->data_);
270+
}
271+
}
272+
262273
const WrapperType Type() {
263274
return WrapperType::Reference;
264275
}
@@ -291,16 +302,12 @@ class ReferenceWrapper: public BaseDataWrapper {
291302
}
292303

293304
void SetData(void* data, bool disposeData = false) {
294-
if (this->data_ != nullptr && data != nullptr && this->disposeData_) {
305+
if (this->data_ != nullptr && this->disposeData_) {
295306
std::free(this->data_);
296307
}
297308
this->data_ = data;
298309
this->disposeData_ = disposeData;
299310
}
300-
301-
bool ShouldDisposeData() {
302-
return this->disposeData_;
303-
}
304311
private:
305312
BaseDataWrapper* typeWrapper_;
306313
v8::Persistent<v8::Value>* value_;

NativeScript/runtime/DictionaryAdapter.mm

+24-2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ - (id)nextObject {
5555
}
5656

5757
- (void)dealloc {
58+
self->isolate_ = nullptr;
59+
self->map_ = nil;
60+
self->cache_ = nil;
61+
5862
[super dealloc];
5963
}
6064

@@ -138,6 +142,10 @@ - (NSArray*)allObjects {
138142
}
139143

140144
- (void)dealloc {
145+
self->isolate_ = nullptr;
146+
self->dictionary_ = nil;
147+
self->cache_ = nil;
148+
141149
[super dealloc];
142150
}
143151

@@ -147,6 +155,7 @@ @implementation DictionaryAdapter {
147155
Isolate* isolate_;
148156
std::shared_ptr<Persistent<Value>> object_;
149157
std::shared_ptr<Caches> cache_;
158+
NSEnumerator* enumerator_;
150159
}
151160

152161
- (instancetype)initWithJSObject:(Local<Object>)jsObject isolate:(Isolate*)isolate {
@@ -225,10 +234,14 @@ - (NSEnumerator*)keyEnumerator {
225234
Local<Value> obj = self->object_->Get(self->isolate_);
226235

227236
if (obj->IsMap()) {
228-
return [[DictionaryAdapterMapKeysEnumerator alloc] initWithMap:self->object_ isolate:self->isolate_ cache:self->cache_];
237+
self->enumerator_ = [[DictionaryAdapterMapKeysEnumerator alloc] initWithMap:self->object_ isolate:self->isolate_ cache:self->cache_];
238+
239+
return self->enumerator_;
229240
}
230241

231-
return [[DictionaryAdapterObjectKeysEnumerator alloc] initWithProperties:self->object_ isolate:self->isolate_ cache:self->cache_];
242+
self->enumerator_ = [[DictionaryAdapterObjectKeysEnumerator alloc] initWithProperties:self->object_ isolate:self->isolate_ cache:self->cache_];
243+
244+
return self->enumerator_;
232245
}
233246

234247
- (void)dealloc {
@@ -240,6 +253,15 @@ - (void)dealloc {
240253
delete wrapper;
241254
}
242255
self->object_->Reset();
256+
self->isolate_ = nullptr;
257+
self->cache_ = nil;
258+
self->object_ = nil;
259+
260+
if (self->enumerator_ != nullptr) {
261+
// CFAutorelease(self->enumerator_);
262+
self->enumerator_ = nullptr;
263+
}
264+
243265
[super dealloc];
244266
}
245267

NativeScript/runtime/Helpers.mm

+1
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
return Local<Value>();
257257
}
258258

259+
v8::Locker locker(isolate);
259260
Local<Value> result;
260261
if (!obj->GetPrivate(context, privateKey).ToLocal(&result)) {
261262
tns::Assert(false, isolate);

NativeScript/runtime/Interop.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class Interop {
126126
static id ToObject(v8::Local<v8::Context> context, v8::Local<v8::Value> arg);
127127
static v8::Local<v8::Value> GetPrimitiveReturnType(v8::Local<v8::Context> context, BinaryTypeEncodingType type, BaseCall* call);
128128
private:
129+
static std::pair<IMP, ffi_closure*> CreateMethodInternal(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData);
129130
static CFTypeRef CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData);
130131
template <typename T>
131132
static void SetStructValue(v8::Local<v8::Value> value, void* destBuffer, ptrdiff_t position);
@@ -138,6 +139,7 @@ class Interop {
138139
static void RegisterAdoptFunction(v8::Local<v8::Context> context, v8::Local<v8::Object> interop);
139140
static void RegisterSizeOfFunction(v8::Local<v8::Context> context, v8::Local<v8::Object> interop);
140141
static void SetFFIParams(v8::Local<v8::Context> context, const TypeEncoding* typeEncoding, FFICall* call, const int argsCount, const int initialParameterIndex, V8Args& args);
142+
static bool isRefTypeEqual(const TypeEncoding* typeEncoding,const char* clazz);
141143
static v8::Local<v8::Array> ToArray(v8::Local<v8::Object> object);
142144
static v8::Local<v8::Value> StructToValue(v8::Local<v8::Context> context, void* result, StructInfo structInfo, std::shared_ptr<v8::Persistent<v8::Value>> parentStruct);
143145
static const TypeEncoding* CreateEncoding(BinaryTypeEncodingType type);
@@ -186,7 +188,8 @@ class Interop {
186188
const void* invoke;
187189
JSBlockDescriptor* descriptor;
188190
void* userData;
189-
191+
ffi_closure* ffiClosure;
192+
190193
static JSBlockDescriptor kJSBlockDescriptor;
191194
} JSBlock;
192195
};

NativeScript/runtime/Interop.mm

+33-8
Original file line numberDiff line numberDiff line change
@@ -46,40 +46,50 @@
4646
v8::Locker locker(isolate);
4747
Isolate::Scope isolate_scope(isolate);
4848
HandleScope handle_scope(isolate);
49+
BlockWrapper* blockWrapper = static_cast<BlockWrapper*>(tns::GetValue(isolate, callback));
4950
tns::DeleteValue(isolate, callback);
5051
wrapper->callback_->Reset();
52+
delete blockWrapper;
5153
}
5254
}
5355
delete wrapper;
56+
ffi_closure_free(block->ffiClosure);
5457
block->~JSBlock();
5558
}
5659
}
5760
};
5861

59-
IMP Interop::CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) {
62+
std::pair<IMP, ffi_closure*> Interop::CreateMethodInternal(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) {
6063
void* functionPointer;
6164
ffi_closure* closure = static_cast<ffi_closure*>(ffi_closure_alloc(sizeof(ffi_closure), &functionPointer));
6265
ParametrizedCall* call = ParametrizedCall::Get(typeEncoding, initialParamIndex, initialParamIndex + argsCount);
6366
ffi_status status = ffi_prep_closure_loc(closure, call->Cif, callback, userData, functionPointer);
6467
tns::Assert(status == FFI_OK);
6568

66-
return (IMP)functionPointer;
69+
return std::make_pair((IMP)functionPointer, closure);
70+
71+
}
72+
73+
IMP Interop::CreateMethod(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) {
74+
std::pair<IMP, ffi_closure*> result = Interop::CreateMethodInternal(initialParamIndex, argsCount, typeEncoding, callback, userData);
75+
return result.first;
6776
}
6877

6978
CFTypeRef Interop::CreateBlock(const uint8_t initialParamIndex, const uint8_t argsCount, const TypeEncoding* typeEncoding, FFIMethodCallback callback, void* userData) {
7079
JSBlock* blockPointer = reinterpret_cast<JSBlock*>(malloc(sizeof(JSBlock)));
71-
void* functionPointer = (void*)CreateMethod(initialParamIndex, argsCount, typeEncoding, callback, userData);
80+
81+
std::pair<IMP, ffi_closure*> result = Interop::CreateMethodInternal(initialParamIndex, argsCount, typeEncoding, callback, userData);
7282

7383
*blockPointer = {
7484
.isa = nullptr,
7585
.flags = JSBlock::BLOCK_HAS_COPY_DISPOSE | JSBlock::BLOCK_NEEDS_FREE | (1 /* ref count */ << 1),
7686
.reserved = 0,
77-
.invoke = functionPointer,
87+
.invoke = (void*)result.first,
7888
.descriptor = &JSBlock::kJSBlockDescriptor,
89+
.userData = userData,
90+
.ffiClosure = result.second,
7991
};
8092

81-
blockPointer->userData = userData;
82-
8393
object_setClass((__bridge id)blockPointer, objc_getClass("__NSMallocBlock__"));
8494

8595
return blockPointer;
@@ -125,13 +135,22 @@
125135
}
126136
}
127137

138+
bool Interop::isRefTypeEqual(const TypeEncoding* typeEncoding, const char* clazz){
139+
std::string n(&typeEncoding->details.interfaceDeclarationReference.name.value());
140+
return n.compare(clazz) == 0;
141+
}
142+
128143
void Interop::WriteValue(Local<Context> context, const TypeEncoding* typeEncoding, void* dest, Local<Value> arg) {
129144
Isolate* isolate = context->GetIsolate();
130145

131146
if (arg.IsEmpty() || arg->IsNullOrUndefined()) {
132147
ffi_type* ffiType = FFICall::GetArgumentType(typeEncoding, true);
133148
size_t size = ffiType->size;
134149
memset(dest, 0, size);
150+
} else if (tns::IsBool(arg) && typeEncoding->type == BinaryTypeEncodingType::InterfaceDeclarationReference && isRefTypeEqual(typeEncoding, "NSNumber")) {
151+
bool value = tns::ToBool(arg);
152+
NSNumber *num = [NSNumber numberWithBool: value];
153+
Interop::SetValue(dest, num);
135154
} else if (tns::IsBool(arg) && typeEncoding->type == BinaryTypeEncodingType::IdEncoding) {
136155
bool value = tns::ToBool(arg);
137156
NSObject* o = @(value);
@@ -286,8 +305,10 @@
286305
Local<Value> value = referenceWrapper->Value() != nullptr ? referenceWrapper->Value()->Get(isolate) : Local<Value>();
287306
ffi_type* ffiType = FFICall::GetArgumentType(innerType);
288307
data = calloc(1, ffiType->size);
289-
referenceWrapper->SetData(data);
308+
309+
referenceWrapper->SetData(data, true);
290310
referenceWrapper->SetEncoding(innerType);
311+
291312
// Initialize the ref/out parameter value before passing it to the function call
292313
if (!value.IsEmpty()) {
293314
Interop::WriteValue(context, innerType, data, value);
@@ -341,7 +362,7 @@
341362
BaseDataWrapper* baseWrapper = tns::GetValue(isolate, arg);
342363
if (baseWrapper != nullptr && baseWrapper->Type() == WrapperType::Block) {
343364
BlockWrapper* wrapper = static_cast<BlockWrapper*>(baseWrapper);
344-
blockPtr = wrapper->Block();
365+
blockPtr = Block_copy(wrapper->Block());
345366
} else {
346367
std::shared_ptr<Persistent<Value>> poCallback = std::make_shared<Persistent<Value>>(isolate, arg);
347368
MethodCallbackWrapper* userData = new MethodCallbackWrapper(isolate, poCallback, 1, argsCount, blockTypeEncoding);
@@ -503,13 +524,16 @@
503524
Local<ArrayBuffer> buffer = arg.As<ArrayBuffer>();
504525
NSDataAdapter* adapter = [[NSDataAdapter alloc] initWithJSObject:buffer isolate:isolate];
505526
Interop::SetValue(dest, adapter);
527+
// CFAutorelease(adapter);
506528
} else if (tns::IsArrayOrArrayLike(isolate, obj)) {
507529
Local<v8::Array> array = Interop::ToArray(obj);
508530
ArrayAdapter* adapter = [[ArrayAdapter alloc] initWithJSObject:array isolate:isolate];
509531
Interop::SetValue(dest, adapter);
532+
// CFAutorelease(adapter);
510533
} else {
511534
DictionaryAdapter* adapter = [[DictionaryAdapter alloc] initWithJSObject:obj isolate:isolate];
512535
Interop::SetValue(dest, adapter);
536+
// CFAutorelease(adapter);
513537
}
514538
} else {
515539
tns::Assert(false, isolate);
@@ -565,6 +589,7 @@
565589
} else {
566590
Local<Object> obj = arg.As<Object>();
567591
DictionaryAdapter* adapter = [[DictionaryAdapter alloc] initWithJSObject:obj isolate:isolate];
592+
// CFAutorelease(adapter);
568593
return adapter;
569594
}
570595
}

NativeScript/runtime/MetadataBuilder.mm

+1
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@
532532
}
533533

534534
names.emplace(methodName, 0);
535+
535536
}
536537
}
537538
}

NativeScript/runtime/ObjectManager.mm

-3
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,6 @@
112112
case WrapperType::Reference: {
113113
ReferenceWrapper* referenceWrapper = static_cast<ReferenceWrapper*>(wrapper);
114114
if (referenceWrapper->Data() != nullptr) {
115-
if (referenceWrapper->ShouldDisposeData()) {
116-
std::free(referenceWrapper->Data());
117-
}
118115
referenceWrapper->SetData(nullptr);
119116
referenceWrapper->SetEncoding(nullptr);
120117
}

NativeScript/runtime/Reference.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ void Reference::ReferenceConstructorCallback(const FunctionCallbackInfo<Value>&
8080
val = new Persistent<Value>(isolate, info[1]);
8181
}
8282
}
83+
84+
if(val != nullptr) {
85+
val->SetWeak();
86+
}
8387

8488
ReferenceWrapper* wrapper = new ReferenceWrapper(typeWrapper, val);
8589
Local<Object> thiz = info.This();

0 commit comments

Comments
 (0)