Skip to content

Commit 995ab17

Browse files
authored
Merge branch 'dev' into dev-inspector
2 parents bbc04a7 + fa44007 commit 995ab17

38 files changed

+1353
-525
lines changed

NativeScript/NativeScript.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ - (instancetype)initWithConfig:(Config*)config {
3737
RuntimeConfig.LogToSystemConsole = [config LogToSystemConsole];
3838

3939
Runtime::Initialize();
40+
runtime_ = nullptr;
4041
runtime_ = std::make_unique<Runtime>();
4142

4243
std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
4344
Isolate* isolate = runtime_->CreateIsolate();
45+
v8::Locker l(isolate);
4446
runtime_->Init(isolate);
4547
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
4648
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();

NativeScript/runtime/ArgConverter.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "Common.h"
77
#include "Caches.h"
88
#include "DataWrapper.h"
9+
#include "IsolateWrapper.h"
910

1011
namespace tns {
1112

@@ -14,13 +15,13 @@ class ArgConverter;
1415
struct MethodCallbackWrapper {
1516
public:
1617
MethodCallbackWrapper(v8::Isolate* isolate, std::shared_ptr<v8::Persistent<v8::Value>> callback, const uint8_t initialParamIndex, const uint8_t paramsCount, const TypeEncoding* typeEncoding)
17-
: isolate_(isolate),
18+
: isolateWrapper_(isolate),
1819
callback_(callback),
1920
initialParamIndex_(initialParamIndex),
2021
paramsCount_(paramsCount),
2122
typeEncoding_(typeEncoding) {
2223
}
23-
v8::Isolate* isolate_;
24+
IsolateWrapper isolateWrapper_;
2425
std::shared_ptr<v8::Persistent<v8::Value>> callback_;
2526
const uint8_t initialParamIndex_;
2627
const uint8_t paramsCount_;

NativeScript/runtime/ArgConverter.mm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@
9191
void ArgConverter::MethodCallback(ffi_cif* cif, void* retValue, void** argValues, void* userData) {
9292
MethodCallbackWrapper* data = static_cast<MethodCallbackWrapper*>(userData);
9393

94-
Isolate* isolate = data->isolate_;
94+
Isolate* isolate = data->isolateWrapper_.Isolate();
9595

96-
if (!Runtime::IsAlive(isolate)) {
96+
if (!Runtime::IsAlive(isolate) || !data->isolateWrapper_.IsValid()) {
9797
memset(retValue, 0, cif->rtype->size);
9898
return;
9999
}
@@ -138,10 +138,11 @@
138138
id self_ = *static_cast<const id*>(argValues[0]);
139139
auto it = cache->Instances.find(self_);
140140
if (it != cache->Instances.end()) {
141-
thiz = it->second->Get(data->isolate_).As<Object>();
141+
thiz = it->second->Get(data->isolateWrapper_.Isolate()).As<Object>();
142142
} else {
143143
ObjCDataWrapper* wrapper = new ObjCDataWrapper(self_);
144144
thiz = ArgConverter::CreateJsWrapper(context, wrapper, Local<Object>(), true).As<Object>();
145+
tns::DeleteWrapperIfUnused(isolate, thiz, wrapper);
145146
}
146147
}
147148

@@ -249,7 +250,11 @@
249250
if (type == BinaryTypeEncodingType::IdEncoding ||
250251
type == BinaryTypeEncodingType::InterfaceDeclarationReference) {
251252
id data = tns::ToNSString(isolate, value);
252-
*(CFTypeRef*)retValue = CFBridgingRetain(data);
253+
// this feels wrong but follows the other CFBridgingRetain calls
254+
// and also solves a leak
255+
auto ref = CFBridgingRetain(data);
256+
*(CFTypeRef*)retValue = ref;
257+
CFRelease(ref);
253258
return;
254259
}
255260
} else if (value->IsObject()) {
@@ -863,7 +868,9 @@
863868
}
864869

865870
Local<Context> context = isolate->GetCurrentContext();
866-
Local<Value> result = ArgConverter::ConvertArgument(context, new ObjCDataWrapper(obj));
871+
auto newWrapper = new ObjCDataWrapper(obj);
872+
Local<Value> result = ArgConverter::ConvertArgument(context, wrapper);
873+
tns::DeleteWrapperIfUnused(isolate, result, newWrapper);
867874
args.GetReturnValue().Set(result);
868875
}
869876

NativeScript/runtime/Caches.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
#include "Caches.h"
2+
#include "Constants.h"
23

34
using namespace v8;
45

56
namespace tns {
67

7-
Caches::Caches(Isolate* isolate)
8-
: isolate_(isolate) {
8+
Caches::Caches(Isolate* isolate, const int& isolateId)
9+
: isolate_(isolate), isolateId_(isolateId) {
910
}
1011

1112
Caches::~Caches() {
@@ -21,11 +22,12 @@ Caches::~Caches() {
2122
this->Instances.clear();
2223
this->StructInstances.clear();
2324
this->PointerInstances.clear();
25+
this->cacheBoundObjects_.clear();
2426
}
2527

2628
void Caches::Remove(v8::Isolate* isolate) {
27-
auto cache = isolate->GetData(0);
28-
isolate->SetData(0, nullptr);
29+
auto cache = isolate->GetData(Constants::CACHES_ISOLATE_SLOT);
30+
isolate->SetData(Constants::CACHES_ISOLATE_SLOT, nullptr);
2931
if (cache != nullptr) {
3032
delete reinterpret_cast<std::shared_ptr<Caches>*>(cache);
3133
}

NativeScript/runtime/Caches.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class Caches {
2424
class WorkerState {
2525
public:
2626
WorkerState(v8::Isolate* isolate, std::shared_ptr<v8::Persistent<v8::Value>> poWorker, void* userData)
27-
: isolate_(isolate),
28-
poWorker_(poWorker),
29-
userData_(userData) {
27+
: isolate_(isolate),
28+
poWorker_(poWorker),
29+
userData_(userData) {
3030
}
3131

3232
v8::Isolate* GetIsolate() {
@@ -46,14 +46,14 @@ class Caches {
4646
void* userData_;
4747
};
4848

49-
Caches(v8::Isolate* isolate);
49+
Caches(v8::Isolate* isolate, const int& isolateId_ = -1);
5050
~Caches();
5151

5252
static std::shared_ptr<ConcurrentMap<std::string, const Meta*>> Metadata;
5353
static std::shared_ptr<ConcurrentMap<int, std::shared_ptr<Caches::WorkerState>>> Workers;
5454

55-
inline static std::shared_ptr<Caches> Init(v8::Isolate* isolate) {
56-
auto cache = std::make_shared<Caches>(isolate);
55+
inline static std::shared_ptr<Caches> Init(v8::Isolate* isolate, const int& isolateId) {
56+
auto cache = std::make_shared<Caches>(isolate, isolateId);
5757
// create a new shared_ptr that will live until Remove is called
5858
isolate->SetData(0, static_cast<void*>(new std::shared_ptr<Caches>(cache)));
5959
return cache;
@@ -68,6 +68,10 @@ class Caches {
6868
return std::make_shared<Caches>(isolate);
6969
}
7070
static void Remove(v8::Isolate* isolate);
71+
72+
inline int getIsolateId() {
73+
return isolateId_;
74+
}
7175

7276
void SetContext(v8::Local<v8::Context> context);
7377
v8::Local<v8::Context> GetContext();
@@ -101,9 +105,26 @@ class Caches {
101105
std::unique_ptr<v8::Persistent<v8::Function>> PointerCtorFunc = std::unique_ptr<v8::Persistent<v8::Function>>(nullptr);
102106
std::unique_ptr<v8::Persistent<v8::Function>> FunctionReferenceCtorFunc = std::unique_ptr<v8::Persistent<v8::Function>>(nullptr);
103107
std::unique_ptr<v8::Persistent<v8::Function>> UnmanagedTypeCtorFunc = std::unique_ptr<v8::Persistent<v8::Function>>(nullptr);
108+
109+
110+
using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;
111+
template<typename T>
112+
auto unique_void(T * ptr) -> unique_void_ptr
113+
{
114+
return unique_void_ptr(ptr, [](void const * data) {
115+
T const * p = static_cast<T const*>(data);
116+
delete p;
117+
});
118+
}
119+
std::vector<unique_void_ptr> cacheBoundObjects_;
120+
template<typename T>
121+
void registerCacheBoundObject(T *ptr) {
122+
this->cacheBoundObjects_.push_back(unique_void(ptr));
123+
}
104124
private:
105125
v8::Isolate* isolate_;
106126
std::shared_ptr<v8::Persistent<v8::Context>> context_;
127+
int isolateId_;
107128
};
108129

109130
}

NativeScript/runtime/ClassBuilder.mm

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
Local<FunctionTemplate> ClassBuilder::GetExtendFunction(Isolate* isolate, const InterfaceMeta* interfaceMeta) {
2020
CacheItem* item = new CacheItem(interfaceMeta, nullptr);
21+
Caches::Get(isolate)->registerCacheBoundObject(item);
2122
Local<External> ext = External::New(isolate, item);
2223
return FunctionTemplate::New(isolate, ClassBuilder::ExtendCallback, ext);
2324
}
@@ -68,6 +69,7 @@
6869
Local<v8::Function> baseCtorFunc = cache->CtorFuncs.find(item->meta_->name())->second->Get(isolate);
6970

7071
CacheItem* cacheItem = new CacheItem(nullptr, extendedClass);
72+
Caches::Get(isolate)->registerCacheBoundObject(cacheItem);
7173
Local<External> ext = External::New(isolate, cacheItem);
7274
Local<FunctionTemplate> extendedClassCtorFuncTemplate = FunctionTemplate::New(isolate, ExtendedClassConstructorCallback, ext);
7375
extendedClassCtorFuncTemplate->InstanceTemplate()->SetInternalFieldCount(1);
@@ -105,7 +107,9 @@
105107
ObjCClassWrapper* wrapper = new ObjCClassWrapper(extendedClass, true);
106108
tns::SetValue(isolate, extendClassCtorFunc, wrapper);
107109

108-
cache->CtorFuncs.emplace(extendedClassName, std::make_unique<Persistent<v8::Function>>(isolate, extendClassCtorFunc));
110+
auto extendedPersistent = std::make_unique<Persistent<v8::Function>>(isolate, extendClassCtorFunc);
111+
extendedPersistent->SetWrapperClassId(Constants::ClassTypes::DataWrapper);
112+
cache->CtorFuncs.emplace(extendedClassName, std::move(extendedPersistent));
109113
cache->ClassPrototypes.emplace(extendedClassName, std::make_unique<Persistent<Object>>(isolate, extendFuncPrototype));
110114

111115
info.GetReturnValue().Set(extendClassCtorFunc);
@@ -164,6 +168,7 @@
164168

165169
Local<v8::Function> extendsFunc = v8::Function::New(context, [](const FunctionCallbackInfo<Value>& info) {
166170
Isolate* isolate = info.GetIsolate();
171+
IsolateWrapper isolateWrapper(isolate);
167172
tns::Assert(info.Length() == 2, isolate);
168173
Local<Context> context = isolate->GetCurrentContext();
169174

@@ -217,6 +222,7 @@
217222
cache->ClassPrototypes.emplace(extendedClassName, std::make_unique<Persistent<Object>>(isolate, extendedClassCtorFuncPrototype));
218223

219224
Persistent<v8::Function>* poExtendedClassCtorFunc = new Persistent<v8::Function>(isolate, extendedClassCtorFunc);
225+
poExtendedClassCtorFunc->SetWrapperClassId(Constants::ClassTypes::DataWrapper);
220226

221227
cache->CtorFuncs.emplace(extendedClassName, poExtendedClassCtorFunc);
222228

@@ -276,7 +282,7 @@
276282

277283
void (*release)(id, SEL) = (void (*)(id, SEL))FindNotOverridenMethod(extendedClass, @selector(release));
278284
IMP newRelease = imp_implementationWithBlock(^(id self) {
279-
if (!Runtime::IsAlive(isolate)) {
285+
if (!Runtime::IsAlive(isolate) || isolateWrapper.IsValid()) {
280286
return;
281287
}
282288

@@ -547,6 +553,9 @@
547553
std::string methodNameStr = tns::ToString(isolate, methodName);
548554
SEL selector = sel_registerName(methodNameStr.c_str());
549555

556+
// TODO: Investigate and maybe find a way to free this
557+
// Currently this is added to the meta cache by the Interop::CreateMethod
558+
// but when the isolate dies we might need to free it? Or maybe this is cached throughout all isolates
550559
TypeEncoding* typeEncoding = reinterpret_cast<TypeEncoding*>(calloc((argsCount + 1), sizeof(TypeEncoding)));
551560
typeEncoding->type = returnType;
552561

NativeScript/runtime/ConcurrentMap.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ class ConcurrentMap {
4040
this->container_.erase(key);
4141
}
4242

43+
inline void ForEach(const std::function<bool(TKey&, TValue&)>& func) {
44+
std::lock_guard<std::mutex> writerLock(this->containerMutex_);
45+
for(auto i : this->container_) {
46+
if(func(i.first, i.second)) {
47+
break;
48+
}
49+
}
50+
}
51+
4352
ConcurrentMap() = default;
4453
ConcurrentMap(const ConcurrentMap&) = delete;
4554
ConcurrentMap& operator=(const ConcurrentMap&) = delete;

NativeScript/runtime/ConcurrentQueue.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
namespace tns {
55

66
void ConcurrentQueue::Initialize(CFRunLoopRef runLoop, void (*performWork)(void*), void* info) {
7+
std::unique_lock<std::mutex> lock(initializationMutex_);
8+
if (terminated) {
9+
return;
10+
}
711
this->runLoop_ = runLoop;
812
CFRunLoopSourceContext sourceContext = { 0, info, 0, 0, 0, 0, 0, 0, 0, performWork };
913
this->runLoopTasksSource_ = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sourceContext);
@@ -48,13 +52,16 @@ void ConcurrentQueue::SignalAndWakeUp() {
4852
}
4953

5054
void ConcurrentQueue::Terminate() {
55+
std::unique_lock<std::mutex> lock(initializationMutex_);
56+
terminated = true;
5157
if (this->runLoop_) {
5258
CFRunLoopStop(this->runLoop_);
5359
}
5460

5561
if (this->runLoopTasksSource_) {
5662
CFRunLoopRemoveSource(this->runLoop_, this->runLoopTasksSource_, kCFRunLoopCommonModes);
5763
CFRunLoopSourceInvalidate(this->runLoopTasksSource_);
64+
CFRelease(this->runLoopTasksSource_);
5865
}
5966
}
6067

NativeScript/runtime/ConcurrentQueue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ struct ConcurrentQueue {
1919
std::queue<std::string> messagesQueue_;
2020
CFRunLoopSourceRef runLoopTasksSource_ = nullptr;
2121
CFRunLoopRef runLoop_ = nullptr;
22+
bool terminated = false;
2223
std::mutex mutex_;
24+
std::mutex initializationMutex_;
2325
void SignalAndWakeUp();
2426
};
2527

NativeScript/runtime/Constants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ namespace tns {
88
class Constants {
99
public:
1010
static const std::string SwizzledPrefix;
11+
static const int CACHES_ISOLATE_SLOT = 0;
12+
static const int RUNTIME_SLOT = 1;
13+
14+
enum ClassTypes{ DataWrapper = 100, ObjectManagedValue };
1115
};
1216

1317
}

0 commit comments

Comments
 (0)