diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6e8ba29 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/grexie/isolates + +go 1.17 + +require github.com/grexie/refutils v0.1.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..83b4973 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/grexie/refutils v0.1.1 h1:106Cml8XyqD9eiBNg9lNurvfe6IuvuydS1YJEc9cs4o= +github.com/grexie/refutils v0.1.1/go.mod h1:jnl4Ft2YXrxwMKPiBrHYwMO6tAEtFzn6M0oHBEgBWRA= diff --git a/install-v8.sh b/install-v8.sh index 46cdfe5..06205eb 100755 --- a/install-v8.sh +++ b/install-v8.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash -ex V8DIR="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)" @@ -15,7 +15,11 @@ go env >libv8.env rm libv8.env case $GOOS in - darwin) curl -sSL https://rubygems.org/downloads/libv8-6.3.292.48.1-universal-darwin-18.gem | tar -xf -;; + darwin) case $GOARCH in + arm64) curl -sSL https://rubygems.org/downloads/libv8-6.3.292.48.1-universal-darwin-18.gem | tar -xf -;; + amd64) curl -sSL https://rubygems.org/downloads/libv8-6.3.292.48.1-x86_64-darwin-18.gem | tar -xf -;; + *) curl -sSL https://rubygems.org/downloads/libv8-6.3.292.48.1-${GOARCH}-darwin-18.gem | tar -xf -;; + esac;; linux) case $GOARCH in arm) curl -sSL http://tim-behrsin-portfolio.s3.amazonaws.com/libv8-6.3.292.48.1-arm-linux.gem | tar -xf -;; amd64) curl -sSL https://rubygems.org/downloads/libv8-6.3.292.48.1-x86_64-linux.gem | tar -xf -;; diff --git a/v8.go b/v8.go index c5a438b..ffc5fde 100644 --- a/v8.go +++ b/v8.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 diff --git a/v8_arch_386.go b/v8_arch_386.go index 7ae91d3..511a894 100644 --- a/v8_arch_386.go +++ b/v8_arch_386.go @@ -1,3 +1,3 @@ -package v8 +package isolates const maxArraySize uint8 = 30 diff --git a/v8_arch_amd64.go b/v8_arch_amd64.go index dd2756c..7db7cb7 100644 --- a/v8_arch_amd64.go +++ b/v8_arch_amd64.go @@ -1,3 +1,3 @@ -package v8 +package isolates const maxArraySize uint8 = 62 diff --git a/v8_arch_arm.go b/v8_arch_arm.go index 7ae91d3..511a894 100644 --- a/v8_arch_arm.go +++ b/v8_arch_arm.go @@ -1,3 +1,3 @@ -package v8 +package isolates const maxArraySize uint8 = 30 diff --git a/v8_arch_arm64.go b/v8_arch_arm64.go new file mode 100644 index 0000000..7db7cb7 --- /dev/null +++ b/v8_arch_arm64.go @@ -0,0 +1,3 @@ +package isolates + +const maxArraySize uint8 = 62 diff --git a/v8_c_bridge.h b/v8_c_bridge.h index 1e6c1e5..5fb58cb 100644 --- a/v8_c_bridge.h +++ b/v8_c_bridge.h @@ -9,30 +9,33 @@ #define V8_C_BRIDGE_H #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -typedef void* IsolatePtr; -typedef void* ContextPtr; -typedef void* ValuePtr; -typedef void* PropertyDescriptorPtr; -typedef void* InspectorPtr; -typedef void* FunctionTemplatePtr; -typedef void* ObjectTemplatePtr; -typedef void* PrivatePtr; -typedef void* ExternalPtr; -typedef void* ResolverPtr; - -typedef struct { - const char* data; + typedef void *IsolatePtr; + typedef void *ContextPtr; + typedef void *ValuePtr; + typedef void *PropertyDescriptorPtr; + typedef void *InspectorPtr; + typedef void *FunctionTemplatePtr; + typedef void *ObjectTemplatePtr; + typedef void *PrivatePtr; + typedef void *ExternalPtr; + typedef void *ResolverPtr; + + typedef struct + { + const char *data; int length; -} String; + } String; -typedef String Error; -typedef String StartupData; -typedef String ByteArray; + typedef String Error; + typedef String StartupData; + typedef String ByteArray; -typedef struct { + typedef struct + { size_t totalHeapSize; size_t totalHeapSizeExecutable; size_t totalPhysicalSize; @@ -42,10 +45,10 @@ typedef struct { size_t mallocedMemory; size_t peakMallocedMemory; size_t doesZapGarbage; -} HeapStatistics; + } HeapStatistics; - -typedef enum { + typedef enum + { kUndefined = 0, kNull, kName, @@ -94,83 +97,95 @@ typedef enum { kProxy, kWebAssemblyCompiledModule, kNumKinds, -} Kind; + } Kind; -// Each kind can be represent using only single 64 bit bitmask since there -// are less than 64 kinds so far. If this grows beyond 64 kinds, we can switch -// to multiple bitmasks or a dynamically-allocated array. -typedef uint64_t Kinds; + // Each kind can be represent using only single 64 bit bitmask since there + // are less than 64 kinds so far. If this grows beyond 64 kinds, we can switch + // to multiple bitmasks or a dynamically-allocated array. + typedef uint64_t Kinds; -typedef struct { + typedef struct + { ValuePtr value; Kinds kinds; Error error; -} ValueTuple; + } ValueTuple; -typedef struct { + typedef struct + { String funcname; String filename; int line; int column; -} CallerInfo; - -typedef struct { int major, minor, build, patch; } Version; -extern Version version; - -typedef enum { - kFunctionCallback, - kGetterCallback, - kSetterCallback -} CallbackType; - -typedef struct { - CallbackType _type; - String id; - CallerInfo caller; - ValueTuple self; - ValueTuple holder; - - bool isConstructCall; - int argc; - ValueTuple* argv; - - String key; - ValueTuple value; -} CallbackInfo; - -// typedef unsigned int uint32_t; - -// v8_init must be called once before anything else. -extern void v8_Initialize(); - -extern StartupData v8_CreateSnapshotDataBlob(const char* js); - -extern IsolatePtr v8_Isolate_New(StartupData data); -extern void v8_Isolate_Terminate(IsolatePtr isolate); -extern void v8_Isolate_Release(IsolatePtr isolate); -extern void v8_Isolate_RequestGarbageCollectionForTesting(IsolatePtr pIsolate); -extern HeapStatistics v8_Isolate_GetHeapStatistics(IsolatePtr isolate); -extern void v8_Isolate_LowMemoryNotification(IsolatePtr isolate); - -extern ContextPtr v8_Context_New(IsolatePtr isolate); -extern ValueTuple v8_Context_Run(ContextPtr ctx, const char* code, const char* filename); - -extern FunctionTemplatePtr v8_FunctionTemplate_New(ContextPtr ctx, const char* id); -extern void v8_FunctionTemplate_Release(ContextPtr ctxptr, FunctionTemplatePtr fnptr); -extern void v8_FunctionTemplate_Inherit(ContextPtr ctxptr, FunctionTemplatePtr fnptr, FunctionTemplatePtr parentptr); -extern void v8_FunctionTemplate_SetName(ContextPtr pContext, FunctionTemplatePtr pFunction, const char* name); -extern void v8_FunctionTemplate_SetHiddenPrototype(ContextPtr ctxptr, FunctionTemplatePtr fnptr, bool value); -extern ValuePtr v8_FunctionTemplate_GetFunction(ContextPtr ctx, FunctionTemplatePtr fn); -extern ObjectTemplatePtr v8_FunctionTemplate_PrototypeTemplate(ContextPtr ctxptr, FunctionTemplatePtr function_ptr); -extern ObjectTemplatePtr v8_FunctionTemplate_InstanceTemplate(ContextPtr ctxptr, FunctionTemplatePtr function_ptr); -extern void v8_ObjectTemplate_SetAccessor(ContextPtr ctxptr, ObjectTemplatePtr object_ptr, const char* name, const char* id, bool setter); -extern void v8_ObjectTemplate_SetInternalFieldCount(ContextPtr ctxptr, ObjectTemplatePtr object_ptr, int count); -extern void v8_ObjectTemplate_Release(ContextPtr pContext, ObjectTemplatePtr pObjectTemplate); - -extern ValuePtr v8_Context_Global(ContextPtr ctx); -extern void v8_Context_Release(ContextPtr ctx); - -typedef enum { + } CallerInfo; + + typedef struct + { + int major, minor, build, patch; + } Version; + extern Version version; + + typedef enum + { + kFunctionCallback, + kGetterCallback, + kSetterCallback + } CallbackType; + + typedef struct + { + CallbackType _type; + String id; + CallerInfo caller; + ValueTuple self; + ValueTuple holder; + + bool isConstructCall; + int argc; + ValueTuple *argv; + + String key; + ValueTuple value; + } CallbackInfo; + + // typedef unsigned int uint32_t; + + // v8_init must be called once before anything else. + extern void v8_Initialize(); + + extern StartupData v8_CreateSnapshotDataBlob(const char *js); + + extern IsolatePtr v8_Isolate_New(StartupData data); + extern void v8_Isolate_Terminate(IsolatePtr isolate); + extern void v8_Isolate_Release(IsolatePtr isolate); + extern void v8_Isolate_RequestGarbageCollectionForTesting(IsolatePtr pIsolate); + extern HeapStatistics v8_Isolate_GetHeapStatistics(IsolatePtr isolate); + extern void v8_Isolate_LowMemoryNotification(IsolatePtr isolate); + extern void v8_Isolate_Enter(IsolatePtr pIsolate); + extern void v8_Isolate_Exit(IsolatePtr pIsolate); + extern Error v8_Isolate_EnqueueMicrotask(IsolatePtr pIsolate, ContextPtr pContext, ValuePtr pFunction); + extern void v8_Isolate_RunMicrotasks(IsolatePtr pIsolate); + + extern ContextPtr v8_Context_New(IsolatePtr isolate); + extern ValueTuple v8_Context_Run(ContextPtr ctx, const char *code, const char *filename); + + extern FunctionTemplatePtr v8_FunctionTemplate_New(ContextPtr ctx, const char *id); + extern void v8_FunctionTemplate_Release(ContextPtr ctxptr, FunctionTemplatePtr fnptr); + extern void v8_FunctionTemplate_Inherit(ContextPtr ctxptr, FunctionTemplatePtr fnptr, FunctionTemplatePtr parentptr); + extern void v8_FunctionTemplate_SetName(ContextPtr pContext, FunctionTemplatePtr pFunction, const char *name); + extern void v8_FunctionTemplate_SetHiddenPrototype(ContextPtr ctxptr, FunctionTemplatePtr fnptr, bool value); + extern ValuePtr v8_FunctionTemplate_GetFunction(ContextPtr ctx, FunctionTemplatePtr fn); + extern ObjectTemplatePtr v8_FunctionTemplate_PrototypeTemplate(ContextPtr ctxptr, FunctionTemplatePtr function_ptr); + extern ObjectTemplatePtr v8_FunctionTemplate_InstanceTemplate(ContextPtr ctxptr, FunctionTemplatePtr function_ptr); + extern void v8_ObjectTemplate_SetAccessor(ContextPtr ctxptr, ObjectTemplatePtr object_ptr, const char *name, const char *id, bool setter); + extern void v8_ObjectTemplate_SetInternalFieldCount(ContextPtr ctxptr, ObjectTemplatePtr object_ptr, int count); + extern void v8_ObjectTemplate_Release(ContextPtr pContext, ObjectTemplatePtr pObjectTemplate); + + extern ValuePtr v8_Context_Global(ContextPtr ctx); + extern void v8_Context_Release(ContextPtr ctx); + + typedef enum + { tSTRING, tBOOL, tFLOAT64, @@ -180,63 +195,65 @@ typedef enum { tARRAYBUFFER, tUNDEFINED, tDATE, // uses Float64 for msec since Unix epoch -} ImmediateValueType; + } ImmediateValueType; -typedef struct { + typedef struct + { ImmediateValueType _type; - ByteArray _data; - bool _bool; - double _float64; - int64_t _int64; -} ImmediateValue; - -extern ValuePtr v8_Context_Create(ContextPtr ctx, ImmediateValue val); - -extern void v8_Value_SetWeak(ContextPtr pContext, ValuePtr pValue, const char* id); -extern ValueTuple v8_Value_Get(ContextPtr ctx, ValuePtr value, const char* field); -extern Error v8_Value_Set(ContextPtr ctx, ValuePtr value, - const char* field, ValuePtr new_value); -extern Error v8_Value_DefineProperty(ContextPtr ctxptr, ValuePtr valueptr, const char* key, ValuePtr getptr, ValuePtr setptr, bool enumerable, bool configurable); -extern ValueTuple v8_Value_GetIndex(ContextPtr ctx, ValuePtr value, int idx); -extern int64_t v8_Object_GetInternalField(ContextPtr pContext, ValuePtr pValue, int field); -extern Error v8_Value_SetIndex(ContextPtr ctx, ValuePtr value, int idx, ValuePtr new_value); -extern void v8_Object_SetInternalField(ContextPtr ctxptr, ValuePtr value_ptr, int field, uint32_t newValue); -extern Error v8_Value_SetPrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr, ValuePtr new_valueptr); -extern ValueTuple v8_Value_GetPrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr); -extern Error v8_Value_DeletePrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr); -extern int v8_Object_GetInternalFieldCount(ContextPtr pContext, ValuePtr pValue); -extern ValueTuple v8_Value_Call(ContextPtr ctx, ValuePtr func, ValuePtr self, int argc, ValuePtr* argv); -extern ValueTuple v8_Value_New(ContextPtr ctx, - ValuePtr func, - int argc, ValuePtr* argv); -extern void v8_Value_Release(ContextPtr ctx, ValuePtr value); -extern String v8_Value_String(ContextPtr ctx, ValuePtr value); - -extern double v8_Value_Float64(ContextPtr ctx, ValuePtr value); -extern int64_t v8_Value_Int64(ContextPtr ctx, ValuePtr value); -extern int v8_Value_Bool(ContextPtr ctx, ValuePtr value); -extern ByteArray v8_Value_Bytes(ContextPtr ctx, ValuePtr value); - -extern ResolverPtr v8_Promise_NewResolver(ContextPtr pContext); -extern Error v8_Resolver_Resolve(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue); -extern Error v8_Resolver_Reject(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue); -extern ValuePtr v8_Resolver_GetPromise(ContextPtr pContext, ResolverPtr pResolver); -extern void v8_Resolver_Release(ContextPtr pContext, ResolverPtr pResolver); -extern ValueTuple v8_Value_PromiseInfo(ContextPtr ctx, ValuePtr value, int* promise_state); - -extern PrivatePtr v8_Private_New(IsolatePtr isoptr, const char *name); - -extern InspectorPtr v8_Inspector_New(IsolatePtr isolate_ptr, int id); -extern void v8_Inspector_AddContext(InspectorPtr inspector_ptr, ContextPtr ctxptr, const char* name); -extern void v8_Inspector_RemoveContext(InspectorPtr inspector_ptr, ContextPtr ctxptr); -extern void v8_Inspector_DispatchMessage(InspectorPtr inspector_ptr, const char* message); -extern void v8_Inspector_Release(InspectorPtr pInspector); - -extern ValueTuple v8_JSON_Parse(ContextPtr pContext, const char* data); -extern ValueTuple v8_JSON_Stringify(ContextPtr pContext, ValuePtr pValue); + ByteArray _data; + bool _bool; + double _float64; + int64_t _int64; + } ImmediateValue; + + extern ValuePtr v8_Context_Create(ContextPtr ctx, ImmediateValue val); + + extern void v8_Value_SetWeak(ContextPtr pContext, ValuePtr pValue, const char *id); + extern ValueTuple v8_Value_Get(ContextPtr ctx, ValuePtr value, const char *field); + extern Error v8_Value_Set(ContextPtr ctx, ValuePtr value, + const char *field, ValuePtr new_value); + extern Error v8_Value_DefineProperty(ContextPtr ctxptr, ValuePtr valueptr, const char *key, ValuePtr getptr, ValuePtr setptr, bool enumerable, bool configurable); + extern ValueTuple v8_Value_GetIndex(ContextPtr ctx, ValuePtr value, int idx); + extern int64_t v8_Object_GetInternalField(ContextPtr pContext, ValuePtr pValue, int field); + extern Error v8_Value_SetIndex(ContextPtr ctx, ValuePtr value, int idx, ValuePtr new_value); + extern void v8_Object_SetInternalField(ContextPtr ctxptr, ValuePtr value_ptr, int field, uint32_t newValue); + extern Error v8_Value_SetPrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr, ValuePtr new_valueptr); + extern ValueTuple v8_Value_GetPrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr); + extern Error v8_Value_DeletePrivate(ContextPtr ctxptr, ValuePtr valueptr, PrivatePtr privateptr); + extern int v8_Object_GetInternalFieldCount(ContextPtr pContext, ValuePtr pValue); + extern ValueTuple v8_Value_Call(ContextPtr ctx, ValuePtr func, ValuePtr self, int argc, ValuePtr *argv); + extern ValueTuple v8_Value_New(ContextPtr ctx, + ValuePtr func, + int argc, ValuePtr *argv); + extern void v8_Value_Release(ContextPtr ctx, ValuePtr value); + extern String v8_Value_String(ContextPtr ctx, ValuePtr value); + + extern double v8_Value_Float64(ContextPtr ctx, ValuePtr value); + extern int64_t v8_Value_Int64(ContextPtr ctx, ValuePtr value); + extern int v8_Value_Bool(ContextPtr ctx, ValuePtr value); + extern ByteArray v8_Value_Bytes(ContextPtr ctx, ValuePtr value); + extern int v8_Value_ByteLength(ContextPtr ctx, ValuePtr value); + + extern ResolverPtr v8_Promise_NewResolver(ContextPtr pContext); + extern Error v8_Resolver_Resolve(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue); + extern Error v8_Resolver_Reject(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue); + extern ValuePtr v8_Resolver_GetPromise(ContextPtr pContext, ResolverPtr pResolver); + extern void v8_Resolver_Release(ContextPtr pContext, ResolverPtr pResolver); + extern ValueTuple v8_Value_PromiseInfo(ContextPtr ctx, ValuePtr value, int *promise_state); + + extern PrivatePtr v8_Private_New(IsolatePtr isoptr, const char *name); + + extern InspectorPtr v8_Inspector_New(IsolatePtr isolate_ptr, int id); + extern void v8_Inspector_AddContext(InspectorPtr inspector_ptr, ContextPtr ctxptr, const char *name); + extern void v8_Inspector_RemoveContext(InspectorPtr inspector_ptr, ContextPtr ctxptr); + extern void v8_Inspector_DispatchMessage(InspectorPtr inspector_ptr, const char *message); + extern void v8_Inspector_Release(InspectorPtr pInspector); + + extern ValueTuple v8_JSON_Parse(ContextPtr pContext, const char *data); + extern ValueTuple v8_JSON_Stringify(ContextPtr pContext, ValuePtr pValue); #ifdef __cplusplus } #endif -#endif // !defined(V8_C_BRIDGE_H) +#endif // !defined(V8_C_BRIDGE_H) diff --git a/v8_c_isolate.cc b/v8_c_isolate.cc index 23dbe07..1669e73 100644 --- a/v8_c_isolate.cc +++ b/v8_c_isolate.cc @@ -3,19 +3,23 @@ auto allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); -extern "C" { - StartupData v8_CreateSnapshotDataBlob(const char* js) { +extern "C" +{ + StartupData v8_CreateSnapshotDataBlob(const char *js) + { v8::StartupData data = v8::V8::CreateSnapshotDataBlob(js); return StartupData{data.data, data.raw_size}; } - IsolatePtr v8_Isolate_New(StartupData startupData) { + IsolatePtr v8_Isolate_New(StartupData startupData) + { v8::Isolate::CreateParams createParams; createParams.array_buffer_allocator = allocator; - if (startupData.length > 0 && startupData.data != NULL) { - v8::StartupData* data = new v8::StartupData; + if (startupData.length > 0 && startupData.data != NULL) + { + v8::StartupData *data = new v8::StartupData; data->data = startupData.data; data->raw_size = startupData.length; createParams.snapshot_blob = data; @@ -24,53 +28,99 @@ extern "C" { return static_cast(v8::Isolate::New(createParams)); } - void v8_Isolate_Terminate(IsolatePtr isolate_ptr) { - v8::Isolate* isolate = static_cast(isolate_ptr); + void v8_Isolate_Enter(IsolatePtr pIsolate) + { + ISOLATE_SCOPE(static_cast(pIsolate)); + + isolate->Enter(); + } + + void v8_Isolate_Exit(IsolatePtr pIsolate) + { + ISOLATE_SCOPE(static_cast(pIsolate)); + + isolate->Exit(); + } + + Error v8_Isolate_EnqueueMicrotask(IsolatePtr pIsolate, ContextPtr pContext, ValuePtr pFunction) + { + VALUE_SCOPE(pContext); + v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kRunMicrotasks); + + v8::Local value = static_cast(pFunction)->Get(isolate); + if (!value->IsFunction()) + { + return v8_String_Create("Not a function"); + } + v8::Local function = v8::Local::Cast(value); + + isolate->EnqueueMicrotask(function); + + // return Error{NULL, 0}; + return Error{NULL, 0}; + } + + void v8_Isolate_RunMicrotasks(IsolatePtr pIsolate) + { + ISOLATE_SCOPE(static_cast(pIsolate)); + + isolate->RunMicrotasks(); + } + + void v8_Isolate_Terminate(IsolatePtr isolate_ptr) + { + v8::Isolate *isolate = static_cast(isolate_ptr); isolate->TerminateExecution(); } - void v8_Isolate_RequestGarbageCollectionForTesting(IsolatePtr pIsolate) { - ISOLATE_SCOPE(static_cast(pIsolate)); + void v8_Isolate_RequestGarbageCollectionForTesting(IsolatePtr pIsolate) + { + ISOLATE_SCOPE(static_cast(pIsolate)); - isolate->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection); - } + isolate->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection); + } - HeapStatistics v8_Isolate_GetHeapStatistics(IsolatePtr pIsolate) { - if (pIsolate == NULL) { + HeapStatistics v8_Isolate_GetHeapStatistics(IsolatePtr pIsolate) + { + if (pIsolate == NULL) + { return HeapStatistics{0}; } - ISOLATE_SCOPE(static_cast(pIsolate)); + ISOLATE_SCOPE(static_cast(pIsolate)); v8::HeapStatistics hs; isolate->GetHeapStatistics(&hs); return HeapStatistics{ - hs.total_heap_size(), - hs.total_heap_size_executable(), - hs.total_physical_size(), - hs.total_available_size(), - hs.used_heap_size(), - hs.heap_size_limit(), - hs.malloced_memory(), - hs.peak_malloced_memory(), - hs.does_zap_garbage() - }; + hs.total_heap_size(), + hs.total_heap_size_executable(), + hs.total_physical_size(), + hs.total_available_size(), + hs.used_heap_size(), + hs.heap_size_limit(), + hs.malloced_memory(), + hs.peak_malloced_memory(), + hs.does_zap_garbage()}; } - void v8_Isolate_LowMemoryNotification(IsolatePtr pIsolate) { - if (pIsolate == NULL) { + void v8_Isolate_LowMemoryNotification(IsolatePtr pIsolate) + { + if (pIsolate == NULL) + { return; } - ISOLATE_SCOPE(static_cast(pIsolate)); + ISOLATE_SCOPE(static_cast(pIsolate)); isolate->LowMemoryNotification(); } - void v8_Isolate_Release(IsolatePtr isolate_ptr) { - if (isolate_ptr == nullptr) { + void v8_Isolate_Release(IsolatePtr isolate_ptr) + { + if (isolate_ptr == nullptr) + { return; } - v8::Isolate* isolate = static_cast(isolate_ptr); + v8::Isolate *isolate = static_cast(isolate_ptr); isolate->Dispose(); } } diff --git a/v8_c_private.h b/v8_c_private.h index 67754bb..7526a9c 100644 --- a/v8_c_private.h +++ b/v8_c_private.h @@ -6,47 +6,52 @@ #include "libplatform/libplatform.h" #include "v8.h" -#define ISOLATE_SCOPE(iso) \ - v8::Isolate* isolate = iso; \ +#define ISOLATE_SCOPE(iso) \ + v8::Isolate *isolate = iso; \ v8::Locker __locker(isolate); \ v8::Isolate::Scope __isolateScope(isolate); -#define VALUE_SCOPE(pContext) \ - ISOLATE_SCOPE(static_cast(pContext)->isolate) \ - v8::HandleScope __handleScope(isolate); \ - v8::Local context(static_cast(pContext)->pointer.Get(isolate)); \ +#define VALUE_SCOPE(pContext) \ + ISOLATE_SCOPE(static_cast(pContext)->isolate) \ + v8::HandleScope __handleScope(isolate); \ + v8::Local context(static_cast(pContext)->pointer.Get(isolate)); \ v8::Context::Scope __contextScope(context); +#define MICROTASKS_SCOPE(isolate) \ + v8::MicrotasksScope __microtasksScope(isolate); + static v8::Platform *platform; -typedef struct { +typedef struct +{ v8::Persistent pointer; - v8::Isolate* isolate; + v8::Isolate *isolate; } Context; -inline String v8_String_Create(const v8::String::Utf8Value& src); -inline String v8_String_Create(const v8::Local& val); -inline String v8_String_Create(const char* msg); -inline String v8_String_Create(const std::string& src); +inline String v8_String_Create(const v8::String::Utf8Value &src); +inline String v8_String_Create(const v8::Local &val); +inline String v8_String_Create(const char *msg); +inline String v8_String_Create(const std::string &src); inline std::string v8_String_ToStdString(v8::Local value); -inline v8::Local v8_String_FromString(v8::Isolate* isolate, const String& string); +inline v8::Local v8_String_FromString(v8::Isolate *isolate, const String &string); typedef v8::Persistent FunctionTemplate; typedef v8::Persistent ObjectTemplate; typedef v8::Persistent Value; typedef v8::Persistent Private; -inline ValueTuple v8_Value_ValueTuple(v8::Isolate* isolate, v8::Local value); -inline ValueTuple v8_Value_ValueTuple_Error(const v8::Local& value); +inline ValueTuple v8_Value_ValueTuple(v8::Isolate *isolate, v8::Local value); +inline ValueTuple v8_Value_ValueTuple_Error(const v8::Local &value); -inline v8::Local v8_StackTrace_FormatException(v8::Isolate* isolate, v8::Local ctx, v8::TryCatch& try_catch); -inline CallerInfo v8_StackTrace_CallerInfo(v8::Isolate* isolate); +inline v8::Local v8_StackTrace_FormatException(v8::Isolate *isolate, v8::Local ctx, v8::TryCatch &try_catch); +inline CallerInfo v8_StackTrace_CallerInfo(v8::Isolate *isolate); -extern "C" { - ValueTuple callbackHandler(const CallbackInfo& info); - void GetterCallbackHandler(v8::Local property, const v8::PropertyCallbackInfo& info); - void SetterCallbackHandler(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& info); - void FunctionCallbackHandler(const v8::FunctionCallbackInfo& args); +extern "C" +{ + ValueTuple callbackHandler(const CallbackInfo &info); + void GetterCallbackHandler(v8::Local property, const v8::PropertyCallbackInfo &info); + void SetterCallbackHandler(v8::Local property, v8::Local value, const v8::PropertyCallbackInfo &info); + void FunctionCallbackHandler(const v8::FunctionCallbackInfo &args); void inspectorSendResponse(int inspectorId, int callId, String message); void inspectorSendNotification(int inspectorId, String message); @@ -57,5 +62,4 @@ extern "C" { #include "v8_c_value.h" #include "v8_c_stack_trace.h" - #endif diff --git a/v8_c_promise.cc b/v8_c_promise.cc index d261330..6ffe4a7 100644 --- a/v8_c_promise.cc +++ b/v8_c_promise.cc @@ -3,65 +3,78 @@ typedef v8::Persistent Resolver; -extern "C" { +extern "C" +{ - ResolverPtr v8_Promise_NewResolver(ContextPtr pContext) { - VALUE_SCOPE(pContext); + ResolverPtr v8_Promise_NewResolver(ContextPtr pContext) + { + VALUE_SCOPE(pContext); - v8::MaybeLocal resolver = v8::Promise::Resolver::New(context); - if (resolver.IsEmpty()) { - return NULL; - } - - return new Resolver(isolate, resolver.ToLocalChecked()); + v8::MaybeLocal resolver = v8::Promise::Resolver::New(context); + if (resolver.IsEmpty()) + { + return NULL; } - Error v8_Resolver_Resolve(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue) { - VALUE_SCOPE(pContext); + return new Resolver(isolate, resolver.ToLocalChecked()); + } - v8::Local value = static_cast(pValue)->Get(isolate); - v8::Local resolver = static_cast(pResolver)->Get(isolate); + Error v8_Resolver_Resolve(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue) + { + VALUE_SCOPE(pContext); - v8::Maybe result = resolver->Resolve(context, value); + v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local resolver = static_cast(pResolver)->Get(isolate); - if (result.IsNothing()) { - return v8_String_Create("Something went wrong: resolve returned nothing."); - } else if (!result.FromJust()) { - return v8_String_Create("Something went wrong: resolve failed."); - } + v8::Maybe result = resolver->Resolve(context, value); - return Error{ NULL, 0 }; + if (result.IsNothing()) + { + return v8_String_Create("Something went wrong: resolve returned nothing."); + } + else if (!result.FromJust()) + { + return v8_String_Create("Something went wrong: resolve failed."); } - Error v8_Resolver_Reject(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue) { - VALUE_SCOPE(pContext); + return Error{NULL, 0}; + } - v8::Local value = static_cast(pValue)->Get(isolate); - v8::Local resolver = static_cast(pResolver)->Get(isolate); + Error v8_Resolver_Reject(ContextPtr pContext, ResolverPtr pResolver, ValuePtr pValue) + { + VALUE_SCOPE(pContext); - v8::Maybe result = resolver->Reject(context, value); + v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local resolver = static_cast(pResolver)->Get(isolate); - if (result.IsNothing()) { - return v8_String_Create("Something went wrong: resolve returned nothing."); - } else if (!result.FromJust()) { - return v8_String_Create("Something went wrong: resolve failed."); - } + v8::Maybe result = resolver->Reject(context, value); - return Error{ NULL, 0 }; + if (result.IsNothing()) + { + return v8_String_Create("Something went wrong: resolve returned nothing."); + } + else if (!result.FromJust()) + { + return v8_String_Create("Something went wrong: resolve failed."); } - ValuePtr v8_Resolver_GetPromise(ContextPtr pContext, ResolverPtr pResolver) { - VALUE_SCOPE(pContext); + return Error{NULL, 0}; + } - v8::Local resolver = static_cast(pResolver)->Get(isolate); - return new Value(isolate, resolver->GetPromise()); - } + ValuePtr v8_Resolver_GetPromise(ContextPtr pContext, ResolverPtr pResolver) + { + VALUE_SCOPE(pContext); - void v8_Resolver_Release(ContextPtr pContext, ResolverPtr pResolver) { - VALUE_SCOPE(pContext); + v8::Local resolver = static_cast(pResolver)->Get(isolate); + return new Value(isolate, resolver->GetPromise()); + } - Resolver* resolver = static_cast(pResolver); - resolver->Reset(); - delete resolver; - } + void v8_Resolver_Release(ContextPtr pContext, ResolverPtr pResolver) + { + VALUE_SCOPE(pContext); + + Resolver *resolver = static_cast(pResolver); + resolver->Reset(); + delete resolver; + } } diff --git a/v8_c_value.cc b/v8_c_value.cc index a3cb5d1..bc5ebb1 100644 --- a/v8_c_value.cc +++ b/v8_c_value.cc @@ -3,12 +3,14 @@ extern "C" void valueWeakCallbackHandler(String id); -typedef struct { +typedef struct +{ String id; } WeakCallbackParameter; -void ValueWeakCallback(const v8::WeakCallbackInfo& data) { - WeakCallbackParameter* param = data.GetParameter(); +void ValueWeakCallback(const v8::WeakCallbackInfo &data) +{ + WeakCallbackParameter *param = data.GetParameter(); valueWeakCallbackHandler(param->id); @@ -16,22 +18,26 @@ void ValueWeakCallback(const v8::WeakCallbackInfo& data) delete param; } -extern "C" { +extern "C" +{ - void v8_Value_SetWeak(ContextPtr pContext, ValuePtr pValue, const char* id) { + void v8_Value_SetWeak(ContextPtr pContext, ValuePtr pValue, const char *id) + { VALUE_SCOPE(pContext); - WeakCallbackParameter* param = new WeakCallbackParameter{v8_String_Create(id)}; + WeakCallbackParameter *param = new WeakCallbackParameter{v8_String_Create(id)}; - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); value->SetWeak(param, ValueWeakCallback, v8::WeakCallbackType::kParameter); } - ValueTuple v8_Value_Get(ContextPtr pContext, ValuePtr pObject, const char* field) { + ValueTuple v8_Value_Get(ContextPtr pContext, ValuePtr pObject, const char *field) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pObject)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pObject)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not an object")); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); @@ -40,33 +46,43 @@ extern "C" { return v8_Value_ValueTuple(isolate, value); } - ValueTuple v8_Value_GetIndex(ContextPtr pContext, ValuePtr pObject, int index) { + ValueTuple v8_Value_GetIndex(ContextPtr pContext, ValuePtr pObject, int index) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pObject)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pObject)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not an object")); } - if (maybeObject->IsArrayBuffer()) { + if (maybeObject->IsArrayBuffer()) + { v8::Local arrayBuffer = v8::Local::Cast(maybeObject); - if (index < arrayBuffer->GetContents().ByteLength()) { - return v8_Value_ValueTuple(isolate, v8::Number::New(isolate, ((unsigned char*)arrayBuffer->GetContents().Data())[index])); - } else { + if (index < arrayBuffer->GetContents().ByteLength()) + { + return v8_Value_ValueTuple(isolate, v8::Number::New(isolate, ((unsigned char *)arrayBuffer->GetContents().Data())[index])); + } + else + { return v8_Value_ValueTuple(isolate, v8::Undefined(isolate)); } - } else { + } + else + { v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); return v8_Value_ValueTuple(isolate, object->Get(context, uint32_t(index)).ToLocalChecked()); } } - int64_t v8_Object_GetInternalField(ContextPtr pContext, ValuePtr pValue, int field) { + int64_t v8_Object_GetInternalField(ContextPtr pContext, ValuePtr pValue, int field) + { VALUE_SCOPE(pContext); - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); v8::Local maybeObject = value->Get(isolate); - if (!maybeObject->IsObject()) { + if (!maybeObject->IsObject()) + { return 0; } @@ -74,60 +90,79 @@ extern "C" { v8::Local result = object->GetInternalField(field); v8::Maybe maybe = result->IntegerValue(context); - if (maybe.IsNothing()) { + if (maybe.IsNothing()) + { return 0; } return maybe.ToChecked(); } - Error v8_Value_Set(ContextPtr pContext, ValuePtr pValue, const char* field, ValuePtr pNewValue) { + Error v8_Value_Set(ContextPtr pContext, ValuePtr pValue, const char *field, ValuePtr pNewValue) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pValue)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pValue)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_String_Create("Not an object"); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); - v8::Local newValue = static_cast(pNewValue)->Get(isolate); + v8::Local newValue = static_cast(pNewValue)->Get(isolate); v8::Maybe result = object->Set(context, v8::String::NewFromUtf8(isolate, field), newValue); - if (result.IsNothing()) { + if (result.IsNothing()) + { return v8_String_Create("Something went wrong: set returned nothing."); - } else if (!result.FromJust()) { + } + else if (!result.FromJust()) + { return v8_String_Create("Something went wrong: set failed."); } - return Error{ NULL, 0 }; + return Error{NULL, 0}; } - Error v8_Value_SetIndex(ContextPtr pContext, ValuePtr pValue, int index, ValuePtr pNewValue) { + Error v8_Value_SetIndex(ContextPtr pContext, ValuePtr pValue, int index, ValuePtr pNewValue) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pValue)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pValue)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_String_Create("Not an object"); } - v8::Local newValue = static_cast(pNewValue)->Get(isolate); - if (maybeObject->IsArrayBuffer()) { + v8::Local newValue = static_cast(pNewValue)->Get(isolate); + if (maybeObject->IsArrayBuffer()) + { v8::Local arrayBuffer = v8::Local::Cast(maybeObject); - if (!newValue->IsNumber()) { + if (!newValue->IsNumber()) + { return v8_String_Create("Cannot assign non-number into array buffer"); - } else if (index >= arrayBuffer->GetContents().ByteLength()) { + } + else if (index >= arrayBuffer->GetContents().ByteLength()) + { return v8_String_Create("Cannot assign to an index beyond the size of an array buffer"); - } else { - ((unsigned char*)arrayBuffer->GetContents().Data())[index] = newValue->ToNumber(context).ToLocalChecked()->Value(); } - } else { + else + { + ((unsigned char *)arrayBuffer->GetContents().Data())[index] = newValue->ToNumber(context).ToLocalChecked()->Value(); + } + } + else + { v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); v8::Maybe result = object->Set(context, uint32_t(index), newValue); - if (result.IsNothing()) { + if (result.IsNothing()) + { return v8_String_Create("Something went wrong: set returned nothing."); - } else if (!result.FromJust()) { + } + else if (!result.FromJust()) + { return v8_String_Create("Something went wrong: set failed."); } } @@ -135,12 +170,14 @@ extern "C" { return Error{NULL, 0}; } - void v8_Object_SetInternalField(ContextPtr pContext, ValuePtr pValue, int field, uint32_t newValue) { + void v8_Object_SetInternalField(ContextPtr pContext, ValuePtr pValue, int field, uint32_t newValue) + { VALUE_SCOPE(pContext); - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); v8::Local maybeObject = value->Get(isolate); - if (!maybeObject->IsObject()) { + if (!maybeObject->IsObject()) + { return; } @@ -148,12 +185,14 @@ extern "C" { object->SetInternalField(field, v8::Integer::New(isolate, newValue)); } - int v8_Object_GetInternalFieldCount(ContextPtr pContext, ValuePtr pValue) { + int v8_Object_GetInternalFieldCount(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); v8::Local maybeObject = value->Get(isolate); - if (!maybeObject->IsObject()) { + if (!maybeObject->IsObject()) + { return 0; } @@ -161,235 +200,301 @@ extern "C" { return object->InternalFieldCount(); } - Error v8_Value_DefineProperty(ContextPtr pContext, ValuePtr pValue, const char* key, ValuePtr pGetHandler, ValuePtr pSetHandler, bool enumerable, bool configurable) { + Error v8_Value_DefineProperty(ContextPtr pContext, ValuePtr pValue, const char *key, ValuePtr pGetHandler, ValuePtr pSetHandler, bool enumerable, bool configurable) + { VALUE_SCOPE(pContext); - v8::PropertyDescriptor propertyDescriptor(static_cast(pGetHandler)->Get(isolate), static_cast(pSetHandler)->Get(isolate)); + v8::PropertyDescriptor propertyDescriptor(static_cast(pGetHandler)->Get(isolate), static_cast(pSetHandler)->Get(isolate)); propertyDescriptor.set_enumerable(enumerable); propertyDescriptor.set_configurable(configurable); - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); v8::Local maybeObject = value->Get(isolate); - if (!maybeObject->IsObject()) { + if (!maybeObject->IsObject()) + { return v8_String_Create("Not an object"); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); v8::Maybe result = object->DefineProperty(context, v8::String::NewFromUtf8(isolate, key), propertyDescriptor); - if (result.IsNothing()) { + if (result.IsNothing()) + { return v8_String_Create("Something went wrong: define property returned nothing."); - } else if (!result.FromJust()) { + } + else if (!result.FromJust()) + { return v8_String_Create("Something went wrong: define property failed."); } return Error{NULL, 0}; } - ValueTuple v8_Value_GetPrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate) { + ValueTuple v8_Value_GetPrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pValue)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pValue)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not an object")); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); - v8::Local _private = static_cast(pPrivate)->Get(isolate); + v8::Local _private = static_cast(pPrivate)->Get(isolate); v8::Local result = object->GetPrivate(context, _private).ToLocalChecked(); return v8_Value_ValueTuple(isolate, result); } - - Error v8_Value_SetPrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate, ValuePtr pNewValue) { + Error v8_Value_SetPrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate, ValuePtr pNewValue) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pValue)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pValue)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_String_Create("Not an object"); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); - v8::Local _private = static_cast(pPrivate)->Get(isolate); - v8::Local newValue = static_cast(pNewValue)->Get(isolate); + v8::Local _private = static_cast(pPrivate)->Get(isolate); + v8::Local newValue = static_cast(pNewValue)->Get(isolate); object->SetPrivate(context, _private, newValue); return Error{NULL, 0}; } - - - Error v8_Value_DeletePrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate) { + Error v8_Value_DeletePrivate(ContextPtr pContext, ValuePtr pValue, PrivatePtr pPrivate) + { VALUE_SCOPE(pContext); - v8::Local maybeObject = static_cast(pValue)->Get(isolate); - if (!maybeObject->IsObject()) { + v8::Local maybeObject = static_cast(pValue)->Get(isolate); + if (!maybeObject->IsObject()) + { return v8_String_Create("Not an object"); } v8::Local object = maybeObject->ToObject(context).ToLocalChecked(); - v8::Local _private = static_cast(pPrivate)->Get(isolate); + v8::Local _private = static_cast(pPrivate)->Get(isolate); object->DeletePrivate(context, _private); return Error{NULL, 0}; } - ValueTuple v8_Value_Call(ContextPtr pContext, ValuePtr pFunction, ValuePtr pSelf, int argc, ValuePtr* pArgv) { + ValueTuple v8_Value_Call(ContextPtr pContext, ValuePtr pFunction, ValuePtr pSelf, int argc, ValuePtr *pArgv) + { VALUE_SCOPE(pContext); v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(false); - v8::Local value = static_cast(pFunction)->Get(isolate); - if (!value->IsFunction()) { + v8::Local value = static_cast(pFunction)->Get(isolate); + if (!value->IsFunction()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not a function")); } v8::Local function = v8::Local::Cast(value); v8::Local self; - if (pSelf == NULL) { + if (pSelf == NULL) + { self = context->Global(); - } else { - self = static_cast(pSelf)->Get(isolate); + } + else + { + self = static_cast(pSelf)->Get(isolate); } - v8::Local* argv = new v8::Local[argc]; - for (int i = 0; i < argc; i++) { - argv[i] = static_cast(pArgv[i])->Get(isolate); + v8::Local *argv = new v8::Local[argc]; + for (int i = 0; i < argc; i++) + { + argv[i] = static_cast(pArgv[i])->Get(isolate); } v8::MaybeLocal result = function->Call(context, self, argc, argv); delete[] argv; - if (result.IsEmpty()) { + if (result.IsEmpty()) + { return v8_Value_ValueTuple_Error(v8_StackTrace_FormatException(isolate, context, tryCatch)); } return v8_Value_ValueTuple(isolate, result.ToLocalChecked()); } - ValueTuple v8_Value_New(ContextPtr pContext, ValuePtr pFunction, int argc, ValuePtr* pArgv) { + ValueTuple v8_Value_New(ContextPtr pContext, ValuePtr pFunction, int argc, ValuePtr *pArgv) + { VALUE_SCOPE(pContext); v8::TryCatch tryCatch(isolate); tryCatch.SetVerbose(false); - v8::Local value = static_cast(pFunction)->Get(isolate); - if (!value->IsFunction()) { + v8::Local value = static_cast(pFunction)->Get(isolate); + if (!value->IsFunction()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not a function")); } v8::Local function = v8::Local::Cast(value); - v8::Local* argv = new v8::Local[argc]; - for (int i = 0; i < argc; i++) { - argv[i] = static_cast(pArgv[i])->Get(isolate); + v8::Local *argv = new v8::Local[argc]; + for (int i = 0; i < argc; i++) + { + argv[i] = static_cast(pArgv[i])->Get(isolate); } v8::MaybeLocal result = function->NewInstance(context, argc, argv); delete[] argv; - if (result.IsEmpty()) { + if (result.IsEmpty()) + { return v8_Value_ValueTuple_Error(v8_StackTrace_FormatException(isolate, context, tryCatch)); } return v8_Value_ValueTuple(isolate, result.ToLocalChecked()); } - void v8_Value_Release(ContextPtr pContext, ValuePtr pValue) { - if (pValue == NULL || pContext == NULL) { + void v8_Value_Release(ContextPtr pContext, ValuePtr pValue) + { + if (pValue == NULL || pContext == NULL) + { return; } - ISOLATE_SCOPE(static_cast(pContext)->isolate); + ISOLATE_SCOPE(static_cast(pContext)->isolate); - Value* value = static_cast(pValue); + Value *value = static_cast(pValue); value->Reset(); delete value; } - String v8_Value_String(ContextPtr pContext, ValuePtr pValue) { + String v8_Value_String(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); return v8_String_Create(value); } - double v8_Value_Float64(ContextPtr pContext, ValuePtr pValue) { + double v8_Value_Float64(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); v8::Maybe maybe = value->NumberValue(context); - if (maybe.IsNothing()) { + if (maybe.IsNothing()) + { return 0; } return maybe.ToChecked(); } - int64_t v8_Value_Int64(ContextPtr pContext, ValuePtr pValue) { + int64_t v8_Value_Int64(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); v8::Maybe maybe = value->IntegerValue(context); - if (maybe.IsNothing()) { + if (maybe.IsNothing()) + { return 0; } return maybe.ToChecked(); } - int v8_Value_Bool(ContextPtr pContext, ValuePtr pValue) { + int v8_Value_Bool(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); v8::Maybe maybe = value->BooleanValue(context); - if (maybe.IsNothing()) { + if (maybe.IsNothing()) + { return 0; } return maybe.ToChecked() ? 1 : 0; } - ByteArray v8_Value_Bytes(ContextPtr pContext, ValuePtr pValue) { + ByteArray v8_Value_Bytes(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); v8::Local arrayBuffer; - if (value->IsTypedArray()) { + if (value->IsTypedArray()) + { arrayBuffer = v8::Local::Cast(value)->Buffer(); - } else if (value->IsArrayBuffer()) { + } + else if (value->IsArrayBuffer()) + { arrayBuffer = v8::Local::Cast(value); - } else { - return ByteArray{ NULL, 0 }; + } + else + { + return ByteArray{NULL, 0}; } - if (arrayBuffer.IsEmpty()) { - return ByteArray{ NULL, 0 }; + if (arrayBuffer.IsEmpty()) + { + return ByteArray{NULL, 0}; } return ByteArray{ - static_cast(arrayBuffer->GetContents().Data()), - static_cast(arrayBuffer->GetContents().ByteLength()) - }; + static_cast(arrayBuffer->GetContents().Data()), + static_cast(arrayBuffer->GetContents().ByteLength())}; } - ValueTuple v8_Value_PromiseInfo(ContextPtr pContext, ValuePtr pValue, int* promiseState) { + int v8_Value_ByteLength(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); - if (!value->IsPromise()) { + v8::Local value = static_cast(pValue)->Get(isolate); + + v8::Local arrayBuffer; + + if (value->IsTypedArray()) + { + arrayBuffer = v8::Local::Cast(value)->Buffer(); + } + else if (value->IsArrayBuffer()) + { + arrayBuffer = v8::Local::Cast(value); + } + else + { + return 0; + } + + if (arrayBuffer.IsEmpty()) + { + return 0; + } + + return static_cast(arrayBuffer->GetContents().ByteLength()); + } + + ValueTuple v8_Value_PromiseInfo(ContextPtr pContext, ValuePtr pValue, int *promiseState) + { + VALUE_SCOPE(pContext); + + v8::Local value = static_cast(pValue)->Get(isolate); + if (!value->IsPromise()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "Not a promise")); } v8::Local promise = v8::Local::Cast(value); *promiseState = promise->State(); - if (promise->State() == v8::Promise::PromiseState::kPending) { + if (promise->State() == v8::Promise::PromiseState::kPending) + { return v8_Value_ValueTuple(); } @@ -397,38 +502,42 @@ extern "C" { return v8_Value_ValueTuple(isolate, result); } - PrivatePtr v8_Private_New(IsolatePtr pIsolate, const char *name) { - ISOLATE_SCOPE(static_cast(pIsolate)); + PrivatePtr v8_Private_New(IsolatePtr pIsolate, const char *name) + { + ISOLATE_SCOPE(static_cast(pIsolate)); v8::HandleScope handleScope(isolate); v8::Local _private = v8::Private::New(isolate, v8::String::NewFromUtf8(isolate, name)); return static_cast(new Private(isolate, _private)); } - ValueTuple v8_JSON_Parse(ContextPtr pContext, const char* data) { + ValueTuple v8_JSON_Parse(ContextPtr pContext, const char *data) + { VALUE_SCOPE(pContext); v8::Local jsonString = v8_String_FromString(isolate, data); v8::MaybeLocal maybeValue = v8::JSON::Parse(context, jsonString); - if (maybeValue.IsEmpty()) { + if (maybeValue.IsEmpty()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "json parse gave an empty result")); } return v8_Value_ValueTuple(isolate, maybeValue.ToLocalChecked()); } - ValueTuple v8_JSON_Stringify(ContextPtr pContext, ValuePtr pValue) { + ValueTuple v8_JSON_Stringify(ContextPtr pContext, ValuePtr pValue) + { VALUE_SCOPE(pContext); - v8::Local value = static_cast(pValue)->Get(isolate); + v8::Local value = static_cast(pValue)->Get(isolate); v8::MaybeLocal maybeJson = v8::JSON::Stringify(context, value); - if (maybeJson.IsEmpty()) { + if (maybeJson.IsEmpty()) + { return v8_Value_ValueTuple_Error(v8_String_FromString(isolate, "json stringify gave an empty result")); } return v8_Value_ValueTuple(isolate, maybeJson.ToLocalChecked()); } - } diff --git a/v8_callback.go b/v8_callback.go index 54d145d..9565f83 100644 --- a/v8_callback.go +++ b/v8_callback.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -12,7 +12,7 @@ import ( "strings" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type callbackArgs struct { @@ -102,7 +102,7 @@ func callbackHandler(info *C.CallbackInfo) (r C.ValueTuple) { contextId, _ := strconv.Atoi(parts[1]) callbackId, _ := strconv.Atoi(parts[2]) - isolateRef := isolates.Get(refutils.ID(isolateId)) + isolateRef := isolateRefs.Get(refutils.ID(isolateId)) if isolateRef == nil { panic(fmt.Errorf("missing isolate pointer during callback for isolate #%d", isolateId)) } diff --git a/v8_context.go b/v8_context.go index 0de616b..347ec5c 100644 --- a/v8_context.go +++ b/v8_context.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -11,7 +11,7 @@ import ( "sync" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type Context struct { @@ -25,14 +25,16 @@ type Context struct { vfalse *Value vtrue *Value - functions *refutils.RefMap - accessors *refutils.RefMap - values *refutils.RefMap - refs *refutils.RefMap - objects map[uintptr]*Value + functions *refutils.RefMap + accessors *refutils.RefMap + values *refutils.RefMap + refs *refutils.RefMap + objects map[uintptr]*Value + objectsMutex sync.Mutex - baseConstructor *FunctionTemplate - constructors map[reflect.Type]*FunctionTemplate + baseConstructor *FunctionTemplate + constructors map[reflect.Type]*FunctionTemplate + constructorsMutex sync.Mutex weakCallbacks map[string]*weakCallbackInfo weakCallbackMutex sync.Mutex diff --git a/v8_create.go b/v8_create.go index 6b01f77..7d1f7ef 100644 --- a/v8_create.go +++ b/v8_create.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -15,7 +15,7 @@ import ( "unicode" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type Marshaler interface { @@ -78,6 +78,15 @@ func isZero(v reflect.Value) bool { } func (c *Context) Create(v interface{}) (*Value, error) { + // c.isolate.lock() + c.objectsMutex.Lock() + c.weakCallbackMutex.Lock() + c.constructorsMutex.Lock() + defer c.constructorsMutex.Unlock() + defer c.weakCallbackMutex.Unlock() + defer c.objectsMutex.Unlock() + // defer c.isolate.unlock() + rv := reflect.ValueOf(v) value, err := c.create(rv) return value, err diff --git a/v8_function.go b/v8_function.go index 3121039..bb9c94c 100644 --- a/v8_function.go +++ b/v8_function.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -11,7 +11,7 @@ import ( "runtime" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type CallerInfo struct { diff --git a/v8_inspector.go b/v8_inspector.go index 5fc2140..9393289 100644 --- a/v8_inspector.go +++ b/v8_inspector.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 diff --git a/v8_isolate.go b/v8_isolate.go index 57780df..48f7898 100644 --- a/v8_isolate.go +++ b/v8_isolate.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -12,7 +12,7 @@ import ( "runtime" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type Isolate struct { @@ -42,7 +42,7 @@ type HeapStatistics struct { DoesZapGarbage bool } -var isolates = refutils.NewWeakRefMap("i") +var isolateRefs = refutils.NewWeakRefMap("i") func NewIsolate() *Isolate { Initialize() @@ -81,11 +81,11 @@ func NewIsolateWithSnapshot(snapshot *Snapshot) *Isolate { } func (i *Isolate) ref() refutils.ID { - return isolates.Ref(i) + return isolateRefs.Ref(i) } func (i *Isolate) unref() { - isolates.Unref(i) + isolateRefs.Unref(i) } func (i *Isolate) lock() error { @@ -130,15 +130,61 @@ func (i *Isolate) RequestGarbageCollectionForTesting() { C.v8_Isolate_RequestGarbageCollectionForTesting(i.pointer) } +func (i *Isolate) Enter() { + if err := i.lock(); err != nil { + return + } else { + defer i.unlock() + } + + C.v8_Isolate_Enter(i.pointer) +} + +func (i *Isolate) Exit() { + if err := i.lock(); err != nil { + return + } else { + defer i.unlock() + } + + C.v8_Isolate_Exit(i.pointer) +} + +func (i *Isolate) RunMicrotasks() { + if err := i.lock(); err != nil { + return + } else { + defer i.unlock() + } + + C.v8_Isolate_RunMicrotasks(i.pointer) +} + +func (i *Isolate) EnqueueMicrotask(fn *Value) { + if err := i.lock(); err != nil { + return + } else { + defer i.unlock() + } + + fn.context.ref() + defer fn.context.unref() + + fn.Ref() + defer fn.Unref() + + C.v8_Isolate_EnqueueMicrotask(i.pointer, fn.context.pointer, fn.pointer) +} + func (i *Isolate) Terminate() { - runtime.SetFinalizer(i, nil) + // runtime.SetFinalizer(i, nil) i.mutex.Lock() if !i.running { i.mutex.Unlock() return } - isolates.Release(i) + isolateRefs.Release(i) C.v8_Isolate_Terminate(i.pointer) i.running = false @@ -160,7 +206,7 @@ func (i *Isolate) Terminate() { } tracer.Remove(i) - isolates.Release(i) + isolateRefs.Release(i) vi := reflect.ValueOf(i) for _, shutdownHook := range i.shutdownHooks { diff --git a/v8_isolate_test.go b/v8_isolate_test.go index c278305..14e7743 100644 --- a/v8_isolate_test.go +++ b/v8_isolate_test.go @@ -1,4 +1,4 @@ -package v8 +package isolates import ( "bufio" @@ -116,14 +116,14 @@ func BenchmarkIsolateCreate(b *testing.B) { FINISHED: close(finished) - for _, isolate := range isolates.Refs() { + for _, isolate := range isolateRefs.Refs() { isolate.(*Isolate).Terminate() } runtime.GC() - if isolates.Length() != 0 { - b.Errorf("%d isolates remaining after garbage collection", isolates.Length()) + if isolateRefs.Length() != 0 { + b.Errorf("%d isolates remaining after garbage collection", isolateRefs.Length()) } } diff --git a/v8_kind.go b/v8_kind.go index 42fc1c4..4bea075 100644 --- a/v8_kind.go +++ b/v8_kind.go @@ -1,4 +1,4 @@ -package v8 +package isolates import ( "fmt" diff --git a/v8_promise.go b/v8_promise.go index 07f061e..8fb57c4 100644 --- a/v8_promise.go +++ b/v8_promise.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -9,7 +9,7 @@ import ( "fmt" "runtime" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type Resolver struct { @@ -60,7 +60,8 @@ func (r *Resolver) Resolve(value interface{}) error { if v, err := r.context.Create(value); err != nil { return err } else { - return r.ResolveWithValue(v) + err := C.v8_Resolver_Resolve(r.context.pointer, r.pointer, v.pointer) + return r.context.isolate.newError(err) } } @@ -85,7 +86,8 @@ func (r *Resolver) Reject(value interface{}) error { if v, err := r.context.Create(value); err != nil { return err } else { - return r.RejectWithValue(v) + err := C.v8_Resolver_Reject(r.context.pointer, r.pointer, v.pointer) + return r.context.isolate.newError(err) } } @@ -105,7 +107,9 @@ func (r *Resolver) release() { tracer.Remove(r) runtime.SetFinalizer(r, nil) - if err := r.context.isolate.lock(); err == nil { + if err := r.context.isolate.lock(); err != nil { + return + } else { defer r.context.isolate.unlock() } diff --git a/v8_tracer.go b/v8_tracer.go index 8a4d668..42dc894 100644 --- a/v8_tracer.go +++ b/v8_tracer.go @@ -1,4 +1,4 @@ -package v8 +package isolates import ( "fmt" @@ -12,7 +12,7 @@ import ( "sync" "time" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type itracer interface { @@ -112,6 +112,15 @@ func newSimpleTracer() *simpleTracer { func (t *simpleTracer) Start() { go func() { + debug.SetPanicOnFault(true) + defer func() { + if p := recover(); p != nil { + err := fmt.Errorf("recover panic: sigseg") + log.Println(err) + return + } + }() + ch := t.channel for m := range ch { t.mutex.RLock() @@ -295,7 +304,7 @@ func (t *simpleTracer) Dump(w io.Writer, allocations bool) { stats["malloced memory"] = 0 stats["peak malloced memory"] = 0 - for _, isolate := range isolates.Refs() { + for _, isolate := range isolateRefs.Refs() { if hs, err := isolate.(*Isolate).GetHeapStatistics(); err != nil { continue } else { diff --git a/v8_unmarshal.go b/v8_unmarshal.go index b4b6b66..04b0f85 100644 --- a/v8_unmarshal.go +++ b/v8_unmarshal.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 diff --git a/v8_value.go b/v8_value.go index aca8d54..40636c1 100644 --- a/v8_value.go +++ b/v8_value.go @@ -1,4 +1,4 @@ -package v8 +package isolates // #include "v8_c_bridge.h" // #cgo CXXFLAGS: -I${SRCDIR} -I${SRCDIR}/include -g3 -fno-rtti -fpic -std=c++11 @@ -12,7 +12,7 @@ import ( "time" "unsafe" - refutils "github.com/behrsin/go-refutils" + refutils "github.com/grexie/refutils" ) type Value struct { @@ -59,11 +59,11 @@ func (c *Context) newValue(pointer C.ValuePtr, k C.Kinds) *Value { return v } -func (v *Value) ref() refutils.ID { +func (v *Value) Ref() refutils.ID { return v.context.refs.Ref(v) } -func (v *Value) unref() { +func (v *Value) Unref() { v.context.refs.Unref(v) } @@ -257,11 +257,40 @@ func (v *Value) Bytes() ([]byte, error) { if b.data == nil { return nil, nil } - buf := make([]byte, b.length) - copy(buf, ((*[1 << (maxArraySize - 13)]byte)(unsafe.Pointer(b.data)))[:b.length:b.length]) + + buf := C.GoBytes(unsafe.Pointer(b.data), b.length) + return buf, nil } +func (v *Value) SetBytes(bytes []byte) error { + if err := v.context.isolate.lock(); err != nil { + return err + } else { + defer v.context.isolate.unlock() + } + + b := C.v8_Value_Bytes(v.context.pointer, v.pointer) + if b.data == nil { + return nil + } + + copy(((*[1 << (maxArraySize - 13)]byte)(unsafe.Pointer(b.data)))[:len(bytes):len(bytes)], bytes) + return nil +} + +func (v *Value) GetByteLength() (int, error) { + if err := v.context.isolate.lock(); err != nil { + return 0, err + } else { + defer v.context.isolate.unlock() + } + + bytes := C.v8_Value_ByteLength(v.context.pointer, v.pointer) + + return int(bytes), nil +} + func (v *Value) Int64() (int64, error) { if err := v.context.isolate.lock(); err != nil { return 0, err