From 6706c0c833a7ce98287c771f3e808f33ee7b29d4 Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Mon, 3 Apr 2023 09:06:31 -0600 Subject: [PATCH 1/7] Initial (rough) support for SharedArrayBuffer --- go.mod | 2 +- v8go.cc | 41 +++++++++++++++++++++++++++++++++++++++++ v8go.h | 9 +++++++++ value.go | 32 +++++++++++++++++++++++++------- value_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 0bacfa29..4a8709c8 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module rogchap.com/v8go -go 1.16 +go 1.17 diff --git a/v8go.cc b/v8go.cc index 86cdc874..f32e3bd0 100644 --- a/v8go.cc +++ b/v8go.cc @@ -1670,4 +1670,45 @@ const char* Version() { void SetFlags(const char* flags) { V8::SetFlagsFromString(flags); } + +/********** SharedArrayBuffer & BackingStore ***********/ + +struct v8BackingStore { + v8BackingStore(std::shared_ptr<v8::BackingStore>&& ptr) + : backing_store{ptr} + {} + std::shared_ptr<v8::BackingStore> backing_store; +}; + +BackingStorePtr SharedArrayBufferGetBackingStore(ValuePtr ptr) { + LOCAL_VALUE(ptr); + auto buffer = Local<SharedArrayBuffer>::Cast(value); + auto backing_store = buffer->GetBackingStore(); + auto proxy = new v8BackingStore(std::move(backing_store)); + return proxy; +} + +void BackingStoreRelease(BackingStorePtr ptr) { + if (ptr == nullptr){ + return; + } + ptr->backing_store.reset(); + delete ptr; +} + +void* BackingStoreData(BackingStorePtr ptr) { + if (ptr == nullptr){ + return nullptr; + } + + return ptr->backing_store->Data(); +} + +size_t BackingStoreByteLength(BackingStorePtr ptr) { + if (ptr == nullptr){ + return 0; + } + return ptr->backing_store->ByteLength(); +} + } diff --git a/v8go.h b/v8go.h index b20daca4..57e20cfa 100644 --- a/v8go.h +++ b/v8go.h @@ -35,6 +35,10 @@ typedef struct v8ScriptCompilerCachedData v8ScriptCompilerCachedData; typedef const v8ScriptCompilerCachedData* ScriptCompilerCachedDataPtr; #endif +// Opaque to both C and C++ +typedef struct v8BackingStore v8BackingStore; +typedef v8BackingStore* BackingStorePtr; + #include <stddef.h> #include <stdint.h> @@ -307,6 +311,11 @@ ValuePtr FunctionSourceMapUrl(ValuePtr ptr); const char* Version(); extern void SetFlags(const char* flags); +extern BackingStorePtr SharedArrayBufferGetBackingStore(ValuePtr ptr); +extern void BackingStoreRelease(BackingStorePtr ptr); +extern void* BackingStoreData(BackingStorePtr ptr); +extern size_t BackingStoreByteLength(BackingStorePtr ptr); + #ifdef __cplusplus } // extern "C" #endif diff --git a/value.go b/value.go index 61d4deec..7ded7f20 100644 --- a/value.go +++ b/value.go @@ -54,13 +54,14 @@ func Null(iso *Isolate) *Value { } // NewValue will create a primitive value. Supported values types to create are: -// string -> V8::String -// int32 -> V8::Integer -// uint32 -> V8::Integer -// int64 -> V8::BigInt -// uint64 -> V8::BigInt -// bool -> V8::Boolean -// *big.Int -> V8::BigInt +// +// string -> V8::String +// int32 -> V8::Integer +// uint32 -> V8::Integer +// int64 -> V8::BigInt +// uint64 -> V8::BigInt +// bool -> V8::Boolean +// *big.Int -> V8::BigInt func NewValue(iso *Isolate, val interface{}) (*Value, error) { if iso == nil { return nil, errors.New("v8go: failed to create new Value: Isolate cannot be <nil>") @@ -580,3 +581,20 @@ func (v *Value) MarshalJSON() ([]byte, error) { } return []byte(jsonStr), nil } + +func (v *Value) SharedArrayBufferGetContents() ([]byte, func(), error) { + if !v.IsSharedArrayBuffer() { + return nil, nil, errors.New("v8go: value is not a SharedArrayBuffer") + } + + backingStore := C.SharedArrayBufferGetBackingStore(v.ptr) + release := func() { + C.BackingStoreRelease(backingStore) + } + + byte_ptr := (*byte)(unsafe.Pointer(C.BackingStoreData(backingStore))) + byte_size := C.BackingStoreByteLength(backingStore) + byte_slice := unsafe.Slice(byte_ptr, byte_size) + + return byte_slice, release, nil +} diff --git a/value_test.go b/value_test.go index d386a589..04403df5 100644 --- a/value_test.go +++ b/value_test.go @@ -7,6 +7,7 @@ package v8go_test import ( "bytes" "fmt" + "log" "math" "math/big" "reflect" @@ -711,3 +712,50 @@ func TestValueMarshalJSON(t *testing.T) { }) } } + +func TestValueArrayBufferContents(t *testing.T) { + t.Parallel() + log.Printf("v8.Version(): %#v\n", v8.Version()) + iso := v8.NewIsolate() + defer iso.Dispose() + + ctx := v8.NewContext(iso) + defer ctx.Close() + + val, err := ctx.RunScript(` + (()=>{ + let buf = new SharedArrayBuffer(1024); + let arr = new Int8Array(buf); + arr[0] = 42; + arr[1] = 52; + return buf; + })(); + `, "test.js") + + if err != nil { + t.Fatalf("failed to run script: %v", err) + } + + if !val.IsSharedArrayBuffer() { + t.Fatalf("expected SharedArrayBuffer value") + } + + buf, cleanup, err := val.SharedArrayBufferGetContents() + defer cleanup() + + if len(buf) != 1024 { + t.Fatalf("expected len(buf) to be 1024") + } + + if buf[0] != 42 { + t.Fatalf("expected buf[0] to be 42") + } + + if buf[1] != 52 { + t.Fatalf("expected buf[1] to be 52") + } + + if buf[3] != 0 { + t.Fatalf("expected buf[1] to be 0") + } +} From ed7e8bbac43bc0f52e1a075e80eba953d9d54f9f Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Mon, 3 Apr 2023 11:35:22 -0600 Subject: [PATCH 2/7] Handle error in test --- value_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/value_test.go b/value_test.go index 04403df5..665531a3 100644 --- a/value_test.go +++ b/value_test.go @@ -741,6 +741,9 @@ func TestValueArrayBufferContents(t *testing.T) { } buf, cleanup, err := val.SharedArrayBufferGetContents() + if err != nil { + t.Fatalf("error getting array buffer contents: %#v", err) + } defer cleanup() if len(buf) != 1024 { From 5df1f4a1174383c57d4127ea95cdfaf45970fe0b Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Tue, 4 Apr 2023 08:41:03 -0600 Subject: [PATCH 3/7] Remove unneeded log --- value_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/value_test.go b/value_test.go index 665531a3..236a8cd3 100644 --- a/value_test.go +++ b/value_test.go @@ -7,7 +7,6 @@ package v8go_test import ( "bytes" "fmt" - "log" "math" "math/big" "reflect" @@ -715,7 +714,6 @@ func TestValueMarshalJSON(t *testing.T) { func TestValueArrayBufferContents(t *testing.T) { t.Parallel() - log.Printf("v8.Version(): %#v\n", v8.Version()) iso := v8.NewIsolate() defer iso.Dispose() From 02c9ec07d1f06a9b301675bfc362dda803241363 Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Wed, 5 Apr 2023 12:06:07 -0600 Subject: [PATCH 4/7] Fix lint errors --- v8go.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/v8go.cc b/v8go.cc index f32e3bd0..836bf204 100644 --- a/v8go.cc +++ b/v8go.cc @@ -1675,8 +1675,7 @@ void SetFlags(const char* flags) { struct v8BackingStore { v8BackingStore(std::shared_ptr<v8::BackingStore>&& ptr) - : backing_store{ptr} - {} + : backing_store{ptr} {} std::shared_ptr<v8::BackingStore> backing_store; }; @@ -1689,7 +1688,7 @@ BackingStorePtr SharedArrayBufferGetBackingStore(ValuePtr ptr) { } void BackingStoreRelease(BackingStorePtr ptr) { - if (ptr == nullptr){ + if (ptr == nullptr) { return; } ptr->backing_store.reset(); @@ -1697,7 +1696,7 @@ void BackingStoreRelease(BackingStorePtr ptr) { } void* BackingStoreData(BackingStorePtr ptr) { - if (ptr == nullptr){ + if (ptr == nullptr) { return nullptr; } @@ -1705,10 +1704,9 @@ void* BackingStoreData(BackingStorePtr ptr) { } size_t BackingStoreByteLength(BackingStorePtr ptr) { - if (ptr == nullptr){ + if (ptr == nullptr) { return 0; } return ptr->backing_store->ByteLength(); } - } From 17a6ab1f6f09229643c570d22a6c484022217354 Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Mon, 10 Apr 2023 09:37:06 -0600 Subject: [PATCH 5/7] Fix lint? --- function_template.go | 1 + 1 file changed, 1 insertion(+) diff --git a/function_template.go b/function_template.go index 66f1b8ce..42ff0058 100644 --- a/function_template.go +++ b/function_template.go @@ -83,6 +83,7 @@ func (tmpl *FunctionTemplate) GetFunction(ctx *Context) *Function { // Note that ideally `thisAndArgs` would be split into two separate arguments, but they were combined // to workaround an ERROR_COMMITMENT_LIMIT error on windows that was detected in CI. +// //export goFunctionCallback func goFunctionCallback(ctxref int, cbref int, thisAndArgs *C.ValuePtr, argsCount int) C.ValuePtr { ctx := getContext(ctxref) From 8b555ac69af14d8d36ef004cd2ab5aa9c47bb85c Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Mon, 10 Apr 2023 09:56:02 -0600 Subject: [PATCH 6/7] Add another check so code cov doesn't slip --- value_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/value_test.go b/value_test.go index 236a8cd3..5bd439d7 100644 --- a/value_test.go +++ b/value_test.go @@ -759,4 +759,14 @@ func TestValueArrayBufferContents(t *testing.T) { if buf[3] != 0 { t.Fatalf("expected buf[1] to be 0") } + + // ensure there's an error if we call the method on something that isn't a SharedArrayBuffer + val, err = ctx.RunScript("7", "test2.js") + if err != nil { + t.Fatalf("error running trivial script") + } + _, _, err = val.SharedArrayBufferGetContents() + if err == nil { + t.Fatalf("Expected an error trying call SharedArrayBufferGetContents on value of incorrect type") + } } From 06d9d9639d8f017a0ed951967884716405c5c9be Mon Sep 17 00:00:00 2001 From: Jonathan Geddes <jonathan.geddes@reddit.com> Date: Mon, 10 Apr 2023 10:01:00 -0600 Subject: [PATCH 7/7] Update Changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7ba1668..1a366da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v0.10.0] - 2023-04-10 + +### Changed +- Required Go version changed to 1.17 (needed for SharedArrayBuffer support) + +### Added +- Support for getting the underlying data (as a `[]byte`) from a SharedArrayBuffer + +### Fixed +- Upgrade to V8 11.1.277.13 + + ## [v0.9.0] - 2023-03-30 ### Fixed