diff --git a/context.go b/context.go index 1ca4cbd4..b9b5cc33 100644 --- a/context.go +++ b/context.go @@ -8,7 +8,6 @@ package v8go // #include "v8go.h" import "C" import ( - "errors" "runtime" "sync" "unsafe" @@ -78,21 +77,22 @@ func NewContext(opt ...ContextOption) *Context { } // NewContextFromSnapshot creates a new JavaScript context from the Isolate startup data; -// If the Isolate has no startup data associated returns an error. +// error will be of type `JSError` if not nil. func NewContextFromSnapshot(iso *Isolate, snapshot_index int) (*Context, error) { ctxMutex.Lock() ctxSeq++ ref := ctxSeq ctxMutex.Unlock() - createParams := iso.createParams - if createParams == nil || createParams.startupData == nil { - return nil, errors.New("v8go: The isolate must have startupData associated with it") + rtn := C.NewContextFromSnapshot(iso.ptr, C.size_t(snapshot_index), C.int(ref)) + + if rtn.context == nil { + return nil, newJSError(rtn.error) } ctx := &Context{ ref: ref, - ptr: C.NewContextFromSnapshot(iso.ptr, C.size_t(snapshot_index), C.int(ref)), + ptr: rtn.context, iso: iso, } diff --git a/context_test.go b/context_test.go index acaca9db..989c0f22 100644 --- a/context_test.go +++ b/context_test.go @@ -55,6 +55,45 @@ func TestNewContextFromSnapshotErrorWhenIsolateHasNoStartupData(t *testing.T) { } } +func TestNewContextFromSnapshotErrorWhenIndexOutOfRange(t *testing.T) { + t.Parallel() + + snapshotCreator := v8.NewSnapshotCreator() + snapshotCreatorIso, err := snapshotCreator.GetIsolate() + fatalIf(t, err) + + snapshotCreatorCtx := v8.NewContext(snapshotCreatorIso) + defer snapshotCreatorCtx.Close() + + snapshotCreatorCtx.RunScript(`const add = (a, b) => a + b`, "add.js") + snapshotCreatorCtx.RunScript(`function run() { return add(3, 4); }`, "main.js") + err = snapshotCreator.SetDefaultContext(snapshotCreatorCtx) + fatalIf(t, err) + + snapshotCreatorCtx2 := v8.NewContext(snapshotCreatorIso) + defer snapshotCreatorCtx2.Close() + + snapshotCreatorCtx2.RunScript(`const multiply = (a, b) => a * b`, "add.js") + snapshotCreatorCtx2.RunScript(`function run() { return multiply(3, 4); }`, "main.js") + index, err := snapshotCreator.AddContext(snapshotCreatorCtx2) + fatalIf(t, err) + + data, err := snapshotCreator.Create(v8.FunctionCodeHandlingClear) + fatalIf(t, err) + + iso := v8.NewIsolate(v8.WithStartupData(data)) + defer iso.Dispose() + + ctx, err := v8.NewContextFromSnapshot(iso, index+1) + + if ctx != nil { + t.Errorf("expected nil context got: %+v", ctx) + } + if err == nil { + t.Error("error expected but was ") + } +} + func TestJSExceptions(t *testing.T) { t.Parallel() diff --git a/v8go.cc b/v8go.cc index 2bcb8e4b..a75743b9 100644 --- a/v8go.cc +++ b/v8go.cc @@ -668,28 +668,40 @@ ContextPtr NewContext(IsolatePtr iso, return ctx; } -ContextPtr NewContextFromSnapshot(IsolatePtr iso, +RtnContext NewContextFromSnapshot(IsolatePtr iso, size_t snapshot_blob_index, int ref) { Locker locker(iso); Isolate::Scope isolate_scope(iso); HandleScope handle_scope(iso); + RtnContext rtn = {}; + // For function callbacks we need a reference to the context, but because of // the complexities of C -> Go function pointers, we store a reference to the // context as a simple integer identifier; this can then be used on the Go // side to lookup the context in the context registry. We use slot 1 as slot 0 // has special meaning for the Chrome debugger. - Local local_ctx = - Context::FromSnapshot(iso, snapshot_blob_index).ToLocalChecked(); + Local local_ctx; + MaybeLocal maybe_local_ctx = + Context::FromSnapshot(iso, snapshot_blob_index); + + if (!maybe_local_ctx.ToLocal(&local_ctx)) { + RtnError error = {nullptr, nullptr, nullptr}; + error.msg = CopyString("Failed to create context from snapshot index: " + std::to_string(snapshot_blob_index)); + rtn.error = error; + return rtn; + } + local_ctx->SetEmbedderData(1, Integer::New(iso, ref)); m_ctx* ctx = new m_ctx; ctx->ptr.Reset(iso, local_ctx); ctx->iso = iso; ctx->startup_data = nullptr; - return ctx; + rtn.context = ctx; + return rtn; } void ContextFree(ContextPtr ctx) { diff --git a/v8go.h b/v8go.h index 5421f0a4..511d4a37 100644 --- a/v8go.h +++ b/v8go.h @@ -124,6 +124,11 @@ typedef struct { RtnError error; } RtnValue; +typedef struct { + ContextPtr context; + RtnError error; +} RtnContext; + typedef struct { const char* string; RtnError error; @@ -189,7 +194,7 @@ extern void CPUProfileDelete(CPUProfile* ptr); extern ContextPtr NewContext(IsolatePtr iso_ptr, TemplatePtr global_template_ptr, int ref); -extern ContextPtr NewContextFromSnapshot(IsolatePtr iso, +extern RtnContext NewContextFromSnapshot(IsolatePtr iso, size_t snapshot_blob_index, int ref); extern void ContextFree(ContextPtr ptr);