Skip to content

Commit 2ba7f87

Browse files
authored
Merge branch 'main' into feat/visionos-unit-tests
2 parents accd6aa + b73693a commit 2ba7f87

File tree

12 files changed

+1058
-837
lines changed

12 files changed

+1058
-837
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
## [8.8.3-alpha.0](https://github.com/NativeScript/ios/compare/v8.8.2...v8.8.3-alpha.0) (2024-12-05)
2+
3+
4+
### Bug Fixes
5+
6+
* handle gc protection in runtime run loop ([78b5e37](https://github.com/NativeScript/ios/commit/78b5e3799f1305b3eafe7d3deb60a7e56b86b230))
7+
* possible race condition extending native class ([8b932a3](https://github.com/NativeScript/ios/commit/8b932a31fe735c69b9d72b76eb106037653764ce))
8+
9+
10+
11+
## [8.8.2](https://github.com/NativeScript/ios/compare/v8.8.1...v8.8.2) (2024-09-06)
12+
13+
14+
### Bug Fixes
15+
16+
* ensure same mtime for js and code cache to prevent loading old code caches ([#261](https://github.com/NativeScript/ios/issues/261)) ([055b042](https://github.com/NativeScript/ios/commit/055b0427cf49e7c4cb37991c9419b899868b6bbd))
17+
* revert visionOS changes to iOS project template ([55c5c51](https://github.com/NativeScript/ios/commit/55c5c5198f04ff2b5cbe1be6f5add92acb3ed23f))
18+
19+
20+
121
## [8.8.1](https://github.com/NativeScript/ios/compare/v8.8.0...v8.8.1) (2024-07-10)
222

323

NativeScript/runtime/ClassBuilder.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,34 @@
22

33
namespace tns {
44

5-
// Moved this method in a separate .cpp file because ARC destroys the class created with objc_allocateClassPair
6-
// when the control leaves this method scope
5+
// Moved this method in a separate .cpp file because ARC destroys the class
6+
// created with objc_allocateClassPair when the control leaves this method scope
77

8-
Class ClassBuilder::GetExtendedClass(std::string baseClassName, std::string staticClassName) {
9-
Class baseClass = objc_getClass(baseClassName.c_str());
10-
std::string name = !staticClassName.empty() ? staticClassName : baseClassName + "_" + std::to_string(++ClassBuilder::classNameCounter_);
11-
Class clazz = objc_getClass(name.c_str());
8+
Class ClassBuilder::GetExtendedClass(std::string baseClassName,
9+
std::string staticClassName) {
10+
Class baseClass = objc_getClass(baseClassName.c_str());
11+
std::string name =
12+
!staticClassName.empty()
13+
? staticClassName
14+
: baseClassName + "_" +
15+
std::to_string(++ClassBuilder::classNameCounter_);
16+
// here we could either call objc_getClass with the name to see if the class
17+
// already exists or we can just try allocating it, which will return nil if
18+
// the class already exists so we try allocating it every time to avoid race
19+
// conditions in case this method is being executed by multiple threads
20+
Class clazz = objc_allocateClassPair(baseClass, name.c_str(), 0);
1221

13-
if (clazz != nil) {
14-
int i = 1;
15-
std::string initialName = name;
16-
while (clazz != nil) {
17-
name = initialName + std::to_string(i++);
18-
clazz = objc_getClass(name.c_str());
19-
}
22+
if (clazz == nil) {
23+
int i = 1;
24+
std::string initialName = name;
25+
while (clazz == nil) {
26+
name = initialName + std::to_string(i++);
27+
clazz = objc_allocateClassPair(baseClass, name.c_str(), 0);
2028
}
29+
}
2130

22-
clazz = objc_allocateClassPair(baseClass, name.c_str(), 0);
23-
24-
objc_registerClassPair(clazz);
25-
return clazz;
31+
objc_registerClassPair(clazz);
32+
return clazz;
2633
}
2734

28-
}
35+
} // namespace tns

NativeScript/runtime/ClassBuilder.mm

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -268,19 +268,30 @@
268268
return retain(self, @selector(retain));
269269
}
270270
if ([self retainCount] == 1) {
271-
auto innerCache = isolateWrapper.GetCache();
272-
auto it = innerCache->Instances.find(self);
273-
if (it != innerCache->Instances.end()) {
274-
v8::Locker locker(isolate);
275-
Isolate::Scope isolate_scope(isolate);
276-
HandleScope handle_scope(isolate);
277-
Local<Value> value = it->second->Get(isolate);
278-
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
279-
if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) {
280-
ObjCDataWrapper* objcWrapper = static_cast<ObjCDataWrapper*>(wrapper);
281-
objcWrapper->GcProtect();
271+
auto runtime = Runtime::GetRuntime(isolate);
272+
auto runtimeLoop = runtime->RuntimeLoop();
273+
void* weakSelf = (__bridge void*) self;
274+
auto gcProtect = ^() {
275+
auto innerCache = isolateWrapper.GetCache();
276+
auto it = innerCache->Instances.find((id)weakSelf);
277+
if (it != innerCache->Instances.end()) {
278+
v8::Locker locker(isolate);
279+
Isolate::Scope isolate_scope(isolate);
280+
HandleScope handle_scope(isolate);
281+
Local<Value> value = it->second->Get(isolate);
282+
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
283+
if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) {
284+
ObjCDataWrapper* objcWrapper = static_cast<ObjCDataWrapper*>(wrapper);
285+
objcWrapper->GcProtect();
286+
}
282287
}
288+
};
289+
if(CFRunLoopGetCurrent() != runtimeLoop) {
290+
tns::ExecuteOnRunLoop(runtimeLoop, gcProtect);
291+
} else {
292+
gcProtect();
283293
}
294+
284295
}
285296

286297
return retain(self, @selector(retain));
@@ -295,18 +306,44 @@
295306
}
296307

297308
if ([self retainCount] == 2) {
298-
auto innerCache = isolateWrapper.GetCache();
299-
auto it = innerCache->Instances.find(self);
300-
if (it != innerCache->Instances.end()) {
301-
v8::Locker locker(isolate);
302-
Isolate::Scope isolate_scope(isolate);
303-
HandleScope handle_scope(isolate);
304-
if (it->second != nullptr) {
305-
Local<Value> value = it->second->Get(isolate);
306-
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
307-
if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) {
308-
ObjCDataWrapper* objcWrapper = static_cast<ObjCDataWrapper*>(wrapper);
309-
objcWrapper->GcUnprotect();
309+
void* weakSelf = (__bridge void*) self;
310+
auto gcUnprotect = ^() {
311+
312+
313+
auto innerCache = isolateWrapper.GetCache();
314+
auto it = innerCache->Instances.find((id)weakSelf);
315+
if (it != innerCache->Instances.end()) {
316+
v8::Locker locker(isolate);
317+
Isolate::Scope isolate_scope(isolate);
318+
HandleScope handle_scope(isolate);
319+
if (it->second != nullptr) {
320+
Local<Value> value = it->second->Get(isolate);
321+
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
322+
if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) {
323+
ObjCDataWrapper* objcWrapper = static_cast<ObjCDataWrapper*>(wrapper);
324+
objcWrapper->GcUnprotect();
325+
}
326+
}
327+
}
328+
};
329+
auto runtime = Runtime::GetRuntime(isolate);
330+
auto runtimeLoop = runtime->RuntimeLoop();
331+
if(CFRunLoopGetCurrent() != runtimeLoop) {
332+
tns::ExecuteOnRunLoop(runtimeLoop, gcUnprotect);
333+
} else {
334+
auto innerCache = isolateWrapper.GetCache();
335+
auto it = innerCache->Instances.find(self);
336+
if (it != innerCache->Instances.end()) {
337+
v8::Locker locker(isolate);
338+
Isolate::Scope isolate_scope(isolate);
339+
HandleScope handle_scope(isolate);
340+
if (it->second != nullptr) {
341+
Local<Value> value = it->second->Get(isolate);
342+
BaseDataWrapper* wrapper = tns::GetValue(isolate, value);
343+
if (wrapper != nullptr && wrapper->Type() == WrapperType::ObjCObject) {
344+
ObjCDataWrapper* objcWrapper = static_cast<ObjCDataWrapper*>(wrapper);
345+
objcWrapper->GcUnprotect();
346+
}
310347
}
311348
}
312349
}

NativeScript/runtime/ModuleInternal.h

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,75 @@
77
namespace tns {
88

99
class ModuleInternal {
10-
public:
11-
ModuleInternal(v8::Local<v8::Context> context);
12-
bool RunModule(v8::Isolate* isolate, std::string path);
13-
void RunScript(v8::Isolate* isolate, std::string script);
14-
15-
private:
16-
static void RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
17-
v8::Local<v8::Function> GetRequireFunction(v8::Isolate* isolate, const std::string& dirName);
18-
v8::Local<v8::Object> LoadImpl(v8::Isolate* isolate, const std::string& moduleName, const std::string& baseDir, bool& isData);
19-
v8::Local<v8::Script> LoadScript(v8::Isolate* isolate, const std::string& path);
20-
v8::Local<v8::String> WrapModuleContent(v8::Isolate* isolate, const std::string& path);
21-
v8::Local<v8::Object> LoadModule(v8::Isolate* isolate, const std::string& modulePath, const std::string& cacheKey);
22-
v8::Local<v8::Object> LoadData(v8::Isolate* isolate, const std::string& modulePath);
23-
std::string ResolvePath(v8::Isolate* isolate, const std::string& baseDir, const std::string& moduleName);
24-
std::string ResolvePathFromPackageJson(const std::string& packageJson, bool& error);
25-
v8::ScriptCompiler::CachedData* LoadScriptCache(const std::string& path);
26-
void SaveScriptCache(const v8::Local<v8::Script> script, const std::string& path);
27-
std::string GetCacheFileName(const std::string& path);
28-
v8::MaybeLocal<v8::Value> RunScriptString(v8::Isolate* isolate, v8::Local<v8::Context> context, const std::string script);
29-
30-
31-
std::unique_ptr<v8::Persistent<v8::Function>> requireFunction_;
32-
std::unique_ptr<v8::Persistent<v8::Function>> requireFactoryFunction_;
33-
robin_hood::unordered_map<std::string, std::shared_ptr<v8::Persistent<v8::Object>>> loadedModules_;
34-
35-
struct TempModule {
36-
public:
37-
TempModule(ModuleInternal* module, std::string modulePath, std::string cacheKey, std::shared_ptr<v8::Persistent<v8::Object>> poModuleObj)
38-
: module_(module), dispose_(true), modulePath_(modulePath), cacheKey_(cacheKey) {
39-
module->loadedModules_.emplace(modulePath, poModuleObj);
40-
module->loadedModules_.emplace(cacheKey, poModuleObj);
41-
}
42-
43-
~TempModule() {
44-
if (this->dispose_) {
45-
this->module_->loadedModules_.erase(modulePath_);
46-
this->module_->loadedModules_.erase(cacheKey_);
47-
}
48-
}
49-
50-
void SaveToCache() {
51-
this->dispose_ = false;
52-
}
53-
private:
54-
ModuleInternal* module_;
55-
bool dispose_;
56-
std::string modulePath_;
57-
std::string cacheKey_;
58-
};
10+
public:
11+
ModuleInternal(v8::Local<v8::Context> context);
12+
bool RunModule(v8::Isolate* isolate, std::string path);
13+
void RunScript(v8::Isolate* isolate, std::string script);
14+
15+
private:
16+
static void RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
17+
v8::Local<v8::Function> GetRequireFunction(v8::Isolate* isolate,
18+
const std::string& dirName);
19+
v8::Local<v8::Object> LoadImpl(v8::Isolate* isolate,
20+
const std::string& moduleName,
21+
const std::string& baseDir, bool& isData);
22+
v8::Local<v8::Script> LoadScript(v8::Isolate* isolate,
23+
const std::string& path);
24+
v8::Local<v8::String> WrapModuleContent(v8::Isolate* isolate,
25+
const std::string& path);
26+
v8::Local<v8::Object> LoadModule(v8::Isolate* isolate,
27+
const std::string& modulePath,
28+
const std::string& cacheKey);
29+
v8::Local<v8::Object> LoadData(v8::Isolate* isolate,
30+
const std::string& modulePath);
31+
std::string ResolvePath(v8::Isolate* isolate, const std::string& baseDir,
32+
const std::string& moduleName);
33+
std::string ResolvePathFromPackageJson(const std::string& packageJson,
34+
bool& error);
35+
v8::ScriptCompiler::CachedData* LoadScriptCache(const std::string& path);
36+
void SaveScriptCache(const v8::Local<v8::Script> script,
37+
const std::string& path);
38+
std::string GetCacheFileName(const std::string& path);
39+
v8::MaybeLocal<v8::Value> RunScriptString(v8::Isolate* isolate,
40+
v8::Local<v8::Context> context,
41+
const std::string script);
42+
43+
std::unique_ptr<v8::Persistent<v8::Function>> requireFunction_;
44+
std::unique_ptr<v8::Persistent<v8::Function>> requireFactoryFunction_;
45+
robin_hood::unordered_map<std::string,
46+
std::shared_ptr<v8::Persistent<v8::Object>>>
47+
loadedModules_;
48+
49+
struct TempModule {
50+
public:
51+
TempModule(ModuleInternal* module, std::string modulePath,
52+
std::string cacheKey,
53+
std::shared_ptr<v8::Persistent<v8::Object>> poModuleObj)
54+
: module_(module),
55+
dispose_(true),
56+
modulePath_(modulePath),
57+
cacheKey_(cacheKey) {
58+
module->loadedModules_.emplace(modulePath, poModuleObj);
59+
module->loadedModules_.emplace(cacheKey, poModuleObj);
60+
}
61+
62+
~TempModule() {
63+
if (this->dispose_) {
64+
this->module_->loadedModules_.erase(modulePath_);
65+
this->module_->loadedModules_.erase(cacheKey_);
66+
}
67+
}
68+
69+
void SaveToCache() { this->dispose_ = false; }
70+
71+
private:
72+
ModuleInternal* module_;
73+
bool dispose_;
74+
std::string modulePath_;
75+
std::string cacheKey_;
76+
};
5977
};
6078

61-
}
79+
} // namespace tns
6280

6381
#endif /* ModuleInternal_h */

0 commit comments

Comments
 (0)