Skip to content
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ FetchContent_Declare(llhttp
URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v8.1.0.tar.gz")
FetchContent_Declare(UrlLib
GIT_REPOSITORY https://github.com/BabylonJS/UrlLib.git
GIT_TAG 59917f32f6ddfa26af07dd981842c51ce02dafcd)
GIT_TAG c7c162be129e170a12bb8766c727b59c42853826)
# --------------------------------------------------

FetchContent_MakeAvailable(CMakeExtensions)
Expand Down
5 changes: 5 additions & 0 deletions Core/AppRuntime/Include/Babylon/AppRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <Babylon/JsRuntime.h>

#include <napi/utilities.h>

#include <memory>
#include <functional>
#include <exception>
Expand All @@ -21,6 +23,9 @@ namespace Babylon
// Optional handler for unhandled exceptions.
std::function<void(const Napi::Error&)> UnhandledExceptionHandler{DefaultUnhandledExceptionHandler};

// Defines whether to enable the debugger. Only implemented for V8 and Chakra.
bool EnableDebugger{false};

// Waits for the debugger to be attached before the execution of any script. Only implemented for V8.
bool WaitForDebugger{false};
};
Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_Android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Babylon
{
void AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
__android_log_print(ANDROID_LOG_ERROR, "BabylonNative", "[Uncaught Error] %s", error.Get("stack").As<Napi::String>().Utf8Value().data());
__android_log_print(ANDROID_LOG_ERROR, "BabylonNative", "[Uncaught Error] %s", Napi::GetErrorString(error).data());
}

void AppRuntime::RunPlatformTier()
Expand Down
30 changes: 16 additions & 14 deletions Core/AppRuntime/Source/AppRuntime_Chakra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <gsl/gsl>
#include <cassert>
#include <sstream>

namespace Babylon
{
Expand All @@ -15,7 +16,9 @@ namespace Babylon
{
if (errorCode != JsErrorCode::JsNoError)
{
throw std::exception();
std::ostringstream ss;
ss << "Chakra function failed with error code (" << static_cast<int>(errorCode) << ")";
throw std::runtime_error{ss.str()};
}
}
}
Expand All @@ -35,29 +38,28 @@ namespace Babylon
JsContextRef context;
ThrowIfFailed(JsCreateContext(jsRuntime, &context));
ThrowIfFailed(JsSetCurrentContext(context));
ThrowIfFailed(JsSetPromiseContinuationCallback([](JsValueRef task, void* callbackState) {
ThrowIfFailed(JsAddRef(task, nullptr));
auto* dispatch = reinterpret_cast<DispatchFunction*>(callbackState);
dispatch->operator()([task]() {
JsValueRef undefined;
ThrowIfFailed(JsGetUndefinedValue(&undefined));
ThrowIfFailed(JsCallFunction(task, &undefined, 1, nullptr));
ThrowIfFailed(JsRelease(task, nullptr));
});
},
ThrowIfFailed(JsSetPromiseContinuationCallback(
[](JsValueRef task, void* callbackState) {
ThrowIfFailed(JsAddRef(task, nullptr));
auto* dispatch = reinterpret_cast<DispatchFunction*>(callbackState);
dispatch->operator()([task]() {
JsValueRef undefined;
ThrowIfFailed(JsGetUndefinedValue(&undefined));
ThrowIfFailed(JsCallFunction(task, &undefined, 1, nullptr));
ThrowIfFailed(JsRelease(task, nullptr));
});
},
&dispatchFunction));
ThrowIfFailed(JsProjectWinRTNamespace(L"Windows"));

#if defined(_DEBUG)
// Put Chakra in debug mode.
if (m_options.EnableDebugger)
{
auto result = JsStartDebugging();
if (result != JsErrorCode::JsNoError)
{
OutputDebugStringW(L"Failed to initialize JavaScript debugging support.\n");
}
}
#endif

Napi::Env env = Napi::Attach();

Expand Down
4 changes: 4 additions & 0 deletions Core/AppRuntime/Source/AppRuntime_JavaScriptCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ namespace Babylon
void AppRuntime::RunEnvironmentTier(const char*)
{
auto globalContext = JSGlobalContextCreateInGroup(nullptr, nullptr);

// REVIEW: Ideally, we should call this, but it's not always available in all situations.
//JSGlobalContextSetInspectable(globalContext, m_options.EnableDebugger);

Napi::Env env = Napi::Attach(globalContext);

Run(env);
Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_UWP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Babylon
void BABYLON_API AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
std::ostringstream ss{};
ss << "[Uncaught Error] " << error.Get("stack").As<Napi::String>().Utf8Value() << std::endl;
ss << "[Uncaught Error] " << Napi::GetErrorString(error) << std::endl;
OutputDebugStringA(ss.str().data());
}

Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_Unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Babylon
{
void AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
std::cerr << "[Uncaught Error] " << error.Get("stack").As<Napi::String>().Utf8Value().data() << std::endl;
std::cerr << "[Uncaught Error] " << Napi::GetErrorString(error) << std::endl;
}

void AppRuntime::RunPlatformTier()
Expand Down
31 changes: 15 additions & 16 deletions Core/AppRuntime/Source/AppRuntime_V8.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
#include "AppRuntime.h"
#include <napi/env.h>

#if defined(_MSC_VER)
#pragma warning(disable : 4100 4267 4127)
#endif
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <v8.h>
#include <libplatform/libplatform.h>

#ifdef ENABLE_V8_INSPECTOR
#include <V8InspectorAgent.h>
#endif

#include <optional>

namespace Babylon
{
namespace
Expand Down Expand Up @@ -90,19 +82,26 @@ namespace Babylon
Napi::Env env = Napi::Attach(context);

#ifdef ENABLE_V8_INSPECTOR
V8InspectorAgent agent{Module::Instance().Platform(), isolate, context, "JsRuntimeHost"};
agent.Start(5643, "JsRuntimeHost");

if (m_options.WaitForDebugger)
std::optional<V8InspectorAgent> agent;
if (m_options.EnableDebugger)
{
agent.WaitForDebugger();
agent.emplace(Module::Instance().Platform(), isolate, context, "JsRuntimeHost");
agent->Start(5643, "JsRuntimeHost");

if (m_options.WaitForDebugger)
{
agent->WaitForDebugger();
}
}
#endif

Run(env);

#ifdef ENABLE_V8_INSPECTOR
agent.Stop();
if (agent.has_value())
{
agent->Stop();
}
#endif

Napi::Detach(env);
Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Babylon
void BABYLON_API AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
std::ostringstream ss{};
ss << "[Uncaught Error] " << error.Get("stack").As<Napi::String>().Utf8Value() << std::endl;
ss << "[Uncaught Error] " << Napi::GetErrorString(error) << std::endl;
OutputDebugStringA(ss.str().data());
}

Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_iOS.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
void AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
NSLog(@"[Uncaught Error] %s", error.Get("stack").As<Napi::String>().Utf8Value().data());
NSLog(@"[Uncaught Error] %s", Napi::GetErrorString(error).data());
}

void AppRuntime::RunPlatformTier()
Expand Down
2 changes: 1 addition & 1 deletion Core/AppRuntime/Source/AppRuntime_macOS.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
void AppRuntime::DefaultUnhandledExceptionHandler(const Napi::Error& error)
{
NSLog(@"[Uncaught Error] %s", error.Get("stack").As<Napi::String>().Utf8Value().data());
NSLog(@"[Uncaught Error] %s", Napi::GetErrorString(error).data());
}

void AppRuntime::RunPlatformTier()
Expand Down
13 changes: 13 additions & 0 deletions Core/AppRuntime/V8Inspector/Include/V8Inc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
#pragma once

// Enable V8 Pointer Compression
// https://v8.dev/blog/pointer-compression
// https://stackoverflow.com/q/62921373
#ifndef V8_COMPRESS_POINTERS
#define V8_COMPRESS_POINTERS 1
#endif

// Enable V8 Sandbox
// https://v8.dev/blog/sandbox
#ifndef V8_ENABLE_SANDBOX
#define V8_ENABLE_SANDBOX 1
#endif

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4100 4267 4127)
Expand Down
3 changes: 3 additions & 0 deletions Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ else()
add_subdirectory(Node-API)
endif()

add_subdirectory(Node-API-Extensions)

add_subdirectory(Foundation)

add_subdirectory(JsRuntime)

if(JSRUNTIMEHOST_CORE_APPRUNTIME)
Expand Down
1 change: 1 addition & 0 deletions Core/JsRuntime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target_include_directories(JsRuntime PUBLIC "Include")
target_link_libraries(JsRuntime
PUBLIC Foundation
PUBLIC napi
PUBLIC napi-extensions
PRIVATE arcana)

set_property(TARGET JsRuntime PROPERTY FOLDER Core)
Expand Down
2 changes: 2 additions & 0 deletions Core/Node-API-Extensions/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_library(napi-extensions INTERFACE)
target_include_directories(napi-extensions INTERFACE "include")
87 changes: 87 additions & 0 deletions Core/Node-API-Extensions/include/napi/pointer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#pragma once

#include <napi/napi.h>

#include <array>
#include <type_traits>

namespace Napi
{
template<typename PointerT>
struct PointerTraits
{
using RepresentationT = uint32_t;
static_assert(sizeof(PointerT) % sizeof(RepresentationT) == 0);
static inline constexpr size_t ByteSize{sizeof(PointerT)};
static inline constexpr size_t ArraySize{sizeof(PointerT) / sizeof(RepresentationT)};
};

template<typename PointerT>
auto NapiPointerDeleter(PointerT pointer)
{
return [pointer]()
{
delete pointer;
};
}

class FunctionPointer
{
public:
template<typename ClassT, typename ReturnT, typename... ArgsT>
static Napi::Value Create(Napi::Env env, ReturnT (ClassT::*functionPtr)(ArgsT...))
{
using PointerT = decltype(functionPtr);
auto arrayBuffer = Napi::ArrayBuffer::New(env, PointerTraits<PointerT>::ByteSize);
std::memcpy(arrayBuffer.Data(), &functionPtr, sizeof(PointerT));
return Napi::Uint32Array::New(env, PointerTraits<PointerT>::ArraySize, arrayBuffer, 0).template As<Napi::Value>();
}
};

template<typename T>
class Pointer
{
public:
static Napi::Value Create(Napi::Env env, const T* pointer)
{
using PointerT = T*;
auto arrayBuffer = Napi::ArrayBuffer::New(env, PointerTraits<PointerT>::ByteSize);
std::memcpy(arrayBuffer.Data(), &pointer, sizeof(PointerT));
return Napi::Uint32Array::New(env, PointerTraits<PointerT>::ArraySize, arrayBuffer, 0);
}

template<typename CallableT>
static Napi::Value Create(Napi::Env env, const T* pointer, CallableT&& finalizationCallback)
{
using PointerT = T*;
using DataT = std::array<uint32_t, PointerTraits<PointerT>::ArraySize>;
auto finalizer = [callback = std::forward<CallableT>(finalizationCallback)](Napi::Env, void* ptr)
{
callback();
delete reinterpret_cast<DataT*>(ptr);
};
auto arrayBuffer = Napi::ArrayBuffer::New(env, new DataT, PointerTraits<PointerT>::ByteSize, std::move(finalizer));
std::memcpy(arrayBuffer.Data(), &pointer, sizeof(PointerT));
return Napi::Uint32Array::New(env, PointerTraits<PointerT>::ArraySize, arrayBuffer, 0);
}

template<typename EnvT, typename ValueT>
Pointer(EnvT&& env, ValueT&& value)
: m_pointer{*reinterpret_cast<T**>(Napi::Value(std::forward<EnvT>(env), std::forward<ValueT>(value)).As<Uint32Array>().Data())}
{
}

T* Get() const
{
return m_pointer;
}

T& operator*() const
{
return *m_pointer;
}

private:
T* m_pointer;
};
}
20 changes: 20 additions & 0 deletions Core/Node-API-Extensions/include/napi/utilities.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include <napi/napi.h>
#include <string>

namespace Napi
{
// Gets the `stack` or `message` property from the error object.
// The `message` property will be returned if the `stack` property is not defined.
static inline std::string GetErrorString(const Napi::Error& error)
{
Napi::Value value = error.Get("stack");
if (value.IsUndefined())
{
value = error.Get("message");
}

return value.ToString().Utf8Value();
}
}
2 changes: 2 additions & 0 deletions Core/Node-API-JSI/Include/napi/napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,8 @@ inline Error Error::New(napi_env env, const std::exception& exception) {
inline Error Error::New(napi_env env, const std::exception_ptr& exception_ptr) {
try {
std::rethrow_exception(exception_ptr);
} catch (const Napi::Error& error) {
return error;
} catch (const std::exception& exception) {
return Error::New(env, exception);
}
Expand Down
Loading