Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use node module bindings like the iOS runtime #1795

Merged
merged 1 commit into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test-app/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ add_library(
src/main/cpp/MetadataReader.cpp
src/main/cpp/MetadataTreeNode.cpp
src/main/cpp/MethodCache.cpp
src/main/cpp/ModuleBinding.cpp
src/main/cpp/ModuleInternal.cpp
src/main/cpp/NativeScriptException.cpp
src/main/cpp/NumericCasts.cpp
Expand Down
8 changes: 8 additions & 0 deletions test-app/runtime/src/main/cpp/IsolateDisposer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@
#include <console/Console.h>



namespace tns {
void disposeIsolate(v8::Isolate *isolate) {
tns::ArgConverter::onDisposeIsolate(isolate);
tns::MetadataNode::onDisposeIsolate(isolate);
tns::V8GlobalHelpers::onDisposeIsolate(isolate);
tns::Console::onDisposeIsolate(isolate);
// clear all isolate bound objects
std::lock_guard<std::mutex> lock(isolateBoundObjectsMutex_);
auto it = isolateBoundObjects_.find(isolate);
if (it != isolateBoundObjects_.end()) {
it->second->clear();
isolateBoundObjects_.erase(it);
}
}
}
27 changes: 27 additions & 0 deletions test-app/runtime/src/main/cpp/IsolateDisposer.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,36 @@
#ifndef TEST_APP_ISOLATEDISPOSER_H
#define TEST_APP_ISOLATEDISPOSER_H
#include "v8.h"
#include "robin_hood.h"
#include <vector>
#include <mutex>
#include <memory>

namespace tns {
void disposeIsolate(v8::Isolate* isolate);
using unique_void_ptr = std::unique_ptr<void, void(*)(void const*)>;
template<typename T>
auto unique_void(T * ptr) -> unique_void_ptr
{
return unique_void_ptr(ptr, [](void const * data) {
T const * p = static_cast<T const*>(data);
delete p;
});
}
robin_hood::unordered_map<v8::Isolate*, std::shared_ptr<std::vector<unique_void_ptr>>> isolateBoundObjects_;
std::mutex isolateBoundObjectsMutex_;
template<typename T>
void registerIsolateBoundObject(v8::Isolate* isolate, T *ptr) {
std::lock_guard<std::mutex> lock(isolateBoundObjectsMutex_);
auto it = isolateBoundObjects_.find(isolate);
if (it == isolateBoundObjects_.end()) {
auto vec = std::make_shared<std::vector<unique_void_ptr>>();
vec->push_back(unique_void(ptr));
isolateBoundObjects_.emplace(isolate, vec);
} else {
it->second->push_back(unique_void(ptr));
}
}
}

#endif //TEST_APP_ISOLATEDISPOSER_H
101 changes: 101 additions & 0 deletions test-app/runtime/src/main/cpp/ModuleBinding.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//
// ModuleBinding.cpp
// NativeScript
//
// Created by Eduardo Speroni on 5/11/23.
// Copyright © 2023 Progress. All rights reserved.
//

#include "ModuleBinding.h"

// TODO: add here
//#define NSC_BUILTIN_STANDARD_BINDINGS(V) \
//V(fs)

#define NSC_BUILTIN_STANDARD_BINDINGS(V)


#define NSC_BUILTIN_BINDINGS(V) \
NSC_BUILTIN_STANDARD_BINDINGS(V)

// This is used to load built-in bindings. Instead of using
// __attribute__((constructor)), we call the _register_<modname>
// function for each built-in bindings explicitly in
// binding::RegisterBuiltinBindings(). This is only forward declaration.
// The definitions are in each binding's implementation when calling
// the NODE_BINDING_CONTEXT_AWARE_INTERNAL.
#define V(modname) void _register_##modname();
NSC_BUILTIN_BINDINGS(V)
#undef V




#define V(modname) \
void _register_isolate_##modname(v8::Isolate* isolate, \
v8::Local<v8::FunctionTemplate> target);
NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V)
#undef V



using v8::Context;
using v8::EscapableHandleScope;
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;

namespace tns {
// Globals per process
static ns_module* modlist_internal;
static ns_module* modlist_linked;
static thread_local ns_module* thread_local_modpending;
bool node_is_initialized = false;

extern "C" void nativescript_module_register(void* m) {
struct ns_module* mp = reinterpret_cast<struct ns_module*>(m);

if (mp->nm_flags & NM_F_INTERNAL) {
mp->nm_link = modlist_internal;
modlist_internal = mp;
} else if (!node_is_initialized) {
// "Linked" modules are included as part of the node project.
// Like builtins they are registered *before* node::Init runs.
mp->nm_flags = NM_F_LINKED;
mp->nm_link = modlist_linked;
modlist_linked = mp;
} else {
thread_local_modpending = mp;
}
}

namespace binding {

void RegisterBuiltinBindings() {
#define V(modname) _register_##modname();
NSC_BUILTIN_BINDINGS(V)
#undef V
}

void CreateInternalBindingTemplates(v8::Isolate* isolate, Local<FunctionTemplate> templ) {
#define V(modname) \
do { \
/*templ->InstanceTemplate()->SetInternalFieldCount( \
BaseObject::kInternalFieldCount);*/ \
_register_isolate_##modname(isolate, templ); \
/*isolate_data->set_##modname##_binding(templ);*/ \
} while (0);
NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V)
#undef V
}

};

};

98 changes: 98 additions & 0 deletions test-app/runtime/src/main/cpp/ModuleBinding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// ModuleBinding.hpp
// NativeScript
//
// Created by Eduardo Speroni on 5/11/23.
// Copyright © 2023 Progress. All rights reserved.
//

#ifndef ModuleBinding_hpp
#define ModuleBinding_hpp

#include "v8.h"


namespace tns {

#define NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
static tns::ns_module _module = { \
NODE_MODULE_VERSION, \
flags, \
nullptr, \
__FILE__, \
nullptr, \
(tns::addon_context_register_func)(regfunc), \
NODE_STRINGIFY(modname), \
priv, \
nullptr}; \
void _register_##modname() { node_module_register(&_module); }

#define NODE_BINDING_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL)








#define NODE_BINDING_PER_ISOLATE_INIT(modname, per_isolate_func) \
void _register_isolate_##modname(v8::Isolate* isolate, \
v8::Local<v8::FunctionTemplate> target) { \
per_isolate_func(isolate, target); \
}


// This is a helepr that gives the target as an ObjectTemplate (using target.PrototypeTemplate())

#define NODE_BINDING_PER_ISOLATE_INIT_OBJ(modname, per_isolate_func) \
void _register_isolate_##modname(v8::Isolate* isolate, \
v8::Local<v8::FunctionTemplate> target) { \
per_isolate_func(isolate, target->PrototypeTemplate()); \
}


#define NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) \
V(timers)

enum {
NM_F_BUILTIN = 1 << 0, // Unused.
NM_F_LINKED = 1 << 1,
NM_F_INTERNAL = 1 << 2,
NM_F_DELETEME = 1 << 3,
};

typedef void (*addon_register_func)(
v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
void* priv);

typedef void (*addon_context_register_func)(
v8::Local<v8::Object> exports,
v8::Local<v8::Value> module,
v8::Local<v8::Context> context,
void* priv);

struct ns_module {
int nm_version;
unsigned int nm_flags;
void* nm_dso_handle;
const char* nm_filename;
tns::addon_register_func nm_register_func;
tns::addon_context_register_func nm_context_register_func;
const char* nm_modname;
void* nm_priv;
struct ns_module* nm_link;
};

namespace binding {
void RegisterBuiltinBindings();
void CreateInternalBindingTemplates(v8::Isolate* isolate, v8::Local<v8::FunctionTemplate> templ);
};


};


#endif /* ModuleBinding_hpp */
4 changes: 2 additions & 2 deletions test-app/runtime/src/main/cpp/Runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <unistd.h>
#include <thread>
#include "File.h"
#include "ModuleBinding.h"

#ifdef APPLICATION_IN_DEBUG
// #include "NetworkDomainCallbackHandlers.h"
Expand Down Expand Up @@ -500,6 +501,7 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native

auto globalFunctionTemplate = FunctionTemplate::New(isolate);
globalFunctionTemplate->SetClassName(ArgConverter::ConvertToV8String(isolate, "NativeScriptGlobalObject"));
tns::binding::CreateInternalBindingTemplates(isolate, globalFunctionTemplate);
auto globalTemplate = ObjectTemplate::New(isolate, globalFunctionTemplate);

const auto readOnlyFlags = static_cast<PropertyAttribute>(PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
Expand Down Expand Up @@ -582,8 +584,6 @@ Isolate* Runtime::PrepareV8Runtime(const string& filesPath, const string& native

CallbackHandlers::CreateGlobalCastFunctions(isolate, globalTemplate);

m_timers.Init(isolate, globalTemplate);

Local<Context> context = Context::New(isolate, nullptr, globalTemplate);

auto global = context->Global();
Expand Down
2 changes: 0 additions & 2 deletions test-app/runtime/src/main/cpp/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ class Runtime {

WeakRef m_weakRef;

Timers m_timers;

Profiler m_profiler;

MessageLoopTimer* m_loopTimer;
Expand Down
36 changes: 22 additions & 14 deletions test-app/runtime/src/main/cpp/Timers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include <android/looper.h>
#include <unistd.h>
#include <thread>
#include "ModuleBinding.h"
#include "IsolateDisposer.h"
#include "Util.h"


/**
Expand All @@ -15,7 +18,6 @@
* ALL changes and scheduling of a TimerTask MUST be done when locked in an isolate to ensure consistency
*/

using namespace tns;
using namespace v8;

// Takes a value and transform into a positive number
Expand Down Expand Up @@ -43,22 +45,18 @@ static double now_ms() {
return 1000.0 * res.tv_sec + (double) res.tv_nsec / 1e6;
}

namespace tns {




void Timers::Init(v8::Isolate *isolate, v8::Local<v8::ObjectTemplate> &globalObjectTemplate) {
isolate_ = isolate;
// TODO: remove the __ns__ prefix once this is validated
globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__ns__setTimeout"),
FunctionTemplate::New(isolate, SetTimeoutCallback,
External::New(isolate, this)));
globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__ns__setInterval"),
FunctionTemplate::New(isolate, SetIntervalCallback,
External::New(isolate, this)));
globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__ns__clearTimeout"),
FunctionTemplate::New(isolate, ClearTimer,
External::New(isolate, this)));
globalObjectTemplate->Set(ArgConverter::ConvertToV8String(isolate, "__ns__clearInterval"),
FunctionTemplate::New(isolate, ClearTimer,
External::New(isolate, this)));
SetMethod(isolate, globalObjectTemplate, "__ns__setTimeout", SetTimeoutCallback, External::New(isolate, this));
SetMethod(isolate, globalObjectTemplate, "__ns__setInterval", SetIntervalCallback, External::New(isolate, this));
SetMethod(isolate, globalObjectTemplate, "__ns__clearTimeout", ClearTimer, External::New(isolate, this));
SetMethod(isolate, globalObjectTemplate, "__ns__clearInterval", ClearTimer, External::New(isolate, this));
auto res = pipe(fd_);
assert(res != -1);
res = fcntl(fd_[1], F_SETFL, O_NONBLOCK);
Expand Down Expand Up @@ -324,4 +322,14 @@ int Timers::PumpTimerLoopCallback(int fd, int events, void *data) {
}
thiz->bufferFull.notify_one();
return 1;
}
}

void Timers::InitStatic(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> globalObjectTemplate) {
auto timers = new Timers();
timers->Init(isolate, globalObjectTemplate);
registerIsolateBoundObject(isolate, timers);
}

};

NODE_BINDING_PER_ISOLATE_INIT_OBJ(timers, tns::Timers::InitStatic);
2 changes: 2 additions & 0 deletions test-app/runtime/src/main/cpp/Timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ namespace tns {
*/
void Init(v8::Isolate *isolate, v8::Local<v8::ObjectTemplate> &globalObjectTemplate);

static void InitStatic(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> globalObjectTemplate);

/**
* Disposes the timers. This will clear all references and stop all thread.
* MUST be called in the same thread Init was called
Expand Down
Loading