Skip to content

Commit

Permalink
Add SnapshotCreator API
Browse files Browse the repository at this point in the history
Co-authored-by: Genevieve <genevieve.lesperance@shopify.com>
  • Loading branch information
2 people authored and GustavoCaso committed Jan 26, 2022
1 parent c0dbfd3 commit 6ddb67c
Show file tree
Hide file tree
Showing 7 changed files with 500 additions and 7 deletions.
22 changes: 22 additions & 0 deletions context.go
Expand Up @@ -8,6 +8,7 @@ package v8go
// #include "v8go.h"
import "C"
import (
"errors"
"runtime"
"sync"
"unsafe"
Expand Down Expand Up @@ -76,6 +77,27 @@ func NewContext(opt ...ContextOption) *Context {
return ctx
}

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("Must create an isolate from a snapshot blob")
}

ctx := &Context{
ref: ref,
ptr: C.NewContextFromSnapShot(iso.ptr, C.size_t(snapshot_index), C.int(ref)),
iso: iso,
}

ctx.register()
return ctx, nil
}

// Isolate gets the current context's parent isolate.An error is returned
// if the isolate has been terninated.
func (c *Context) Isolate() *Isolate {
Expand Down
16 changes: 16 additions & 0 deletions context_test.go
Expand Up @@ -39,6 +39,22 @@ func TestContextExec(t *testing.T) {
}
}

func TestNewContextFromSnapShotErrorWhenIsolateHasNoStartupData(t *testing.T) {
t.Parallel()

iso := v8.NewIsolate()
defer iso.Dispose()

ctx, err := v8.NewContextFromSnapShot(iso, 1)

if ctx != nil {
t.Errorf("error expected nil context got: %+v", ctx)
}
if err == nil {
t.Error("error expected but was <nil>")
}
}

func TestJSExceptions(t *testing.T) {
t.Parallel()

Expand Down
37 changes: 32 additions & 5 deletions isolate.go
Expand Up @@ -25,8 +25,9 @@ type Isolate struct {
cbSeq int
cbs map[int]FunctionCallback

null *Value
undefined *Value
null *Value
undefined *Value
createParams *CreateParams
}

// HeapStatistics represents V8 isolate heap statistics
Expand All @@ -44,20 +45,45 @@ type HeapStatistics struct {
NumberOfDetachedContexts uint64
}

type createOptions func(*CreateParams)

func WithStartupData(startupData *StartupData) createOptions {
return func(params *CreateParams) {
params.startupData = startupData
}
}

type CreateParams struct {
startupData *StartupData
}

// NewIsolate creates a new V8 isolate. Only one thread may access
// a given isolate at a time, but different threads may access
// different isolates simultaneously.
// When an isolate is no longer used its resources should be freed
// by calling iso.Dispose().
// An *Isolate can be used as a v8go.ContextOption to create a new
// Context, rather than creating a new default Isolate.
func NewIsolate() *Isolate {
func NewIsolate(opts ...createOptions) *Isolate {
v8once.Do(func() {
C.Init()
})
params := &CreateParams{}
for _, opt := range opts {
opt(params)
}

var cOptions C.IsolateOptions

if params.startupData != nil {
cOptions.snapshot_blob_data = (*C.char)(unsafe.Pointer(&params.startupData.data[0]))
cOptions.snapshot_blob_raw_size = params.startupData.raw_size
}

iso := &Isolate{
ptr: C.NewIsolate(),
cbs: make(map[int]FunctionCallback),
ptr: C.NewIsolate(cOptions),
cbs: make(map[int]FunctionCallback),
createParams: params,
}
iso.null = newValueNull(iso)
iso.undefined = newValueUndefined(iso)
Expand Down Expand Up @@ -146,6 +172,7 @@ func (i *Isolate) Dispose() {
return
}
C.IsolateDispose(i.ptr)
i.createParams = nil
i.ptr = nil
}

Expand Down
104 changes: 104 additions & 0 deletions snapshot_creator.go
@@ -0,0 +1,104 @@
// Copyright 2021 the v8go contributors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package v8go

// #include <stdlib.h>
// #include "v8go.h"
import "C"
import (
"errors"
"unsafe"
)

type FunctionCodeHandling int

const (
FunctionCodeHandlingKlear FunctionCodeHandling = iota
FunctionCodeHandlingKeep
)

type StartupData struct {
data []byte
raw_size C.int
}

type SnapshotCreator struct {
ptr C.SnapshotCreatorPtr
iso *Isolate
defaultContextAdded bool
}

func NewSnapshotCreator() *SnapshotCreator {
v8once.Do(func() {
C.Init()
})

rtn := C.NewSnapshotCreator()

return &SnapshotCreator{
ptr: rtn.creator,
iso: &Isolate{ptr: rtn.iso},
defaultContextAdded: false,
}
}

func (s *SnapshotCreator) GetIsolate() (*Isolate, error) {
if s.ptr == nil {
return nil, errors.New("v8go: Cannot get Isolate after creating the blob")
}

return s.iso, nil
}

func (s *SnapshotCreator) SetDeafultContext(ctx *Context) error {
if s.defaultContextAdded {
return errors.New("v8go: Cannot set multiple default context for snapshot creator")
}

C.SetDefaultContext(s.ptr, ctx.ptr)
s.defaultContextAdded = true
ctx.ptr = nil

return nil
}

func (s *SnapshotCreator) AddContext(ctx *Context) (int, error) {
if s.ptr == nil {
return 0, errors.New("v8go: Cannot add context to snapshot creator after creating the blob")
}

index := C.AddContext(s.ptr, ctx.ptr)
ctx.ptr = nil

return int(index), nil
}

func (s *SnapshotCreator) Create(functionCode FunctionCodeHandling) (*StartupData, error) {
if s.ptr == nil {
return nil, errors.New("v8go: Cannot use snapshot creator after creating the blob")
}

if !s.defaultContextAdded {
return nil, errors.New("v8go: Cannot create a snapshot without a default context")
}

rtn := C.CreateBlob(s.ptr, C.int(functionCode))

s.ptr = nil
s.iso.ptr = nil

raw_size := rtn.raw_size
data := C.GoBytes(unsafe.Pointer(rtn.data), raw_size)

C.SnapshotBlobDelete(rtn)

return &StartupData{data: data, raw_size: raw_size}, nil
}

func (s *SnapshotCreator) Dispose() {
if s.ptr != nil {
C.DeleteSnapshotCreator(s.ptr)
}
}

0 comments on commit 6ddb67c

Please sign in to comment.