-
-
Notifications
You must be signed in to change notification settings - Fork 210
/
function_template.go
109 lines (92 loc) · 3 KB
/
function_template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// Copyright 2021 Roger Chapman and 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 (
"runtime"
"unsafe"
)
// FunctionCallback is a callback that is executed in Go when a function is executed in JS.
type FunctionCallback func(info *FunctionCallbackInfo) *Value
// FunctionCallbackInfo is the argument that is passed to a FunctionCallback.
type FunctionCallbackInfo struct {
ctx *Context
args []*Value
this *Object
}
// Context is the current context that the callback is being executed in.
func (i *FunctionCallbackInfo) Context() *Context {
return i.ctx
}
// This returns the receiver object "this".
func (i *FunctionCallbackInfo) This() *Object {
return i.this
}
// Args returns a slice of the value arguments that are passed to the JS function.
func (i *FunctionCallbackInfo) Args() []*Value {
return i.args
}
func (i *FunctionCallbackInfo) Release() {
for _, arg := range i.args {
arg.Release()
}
i.this.Release()
}
// FunctionTemplate is used to create functions at runtime.
// There can only be one function created from a FunctionTemplate in a context.
// The lifetime of the created function is equal to the lifetime of the context.
type FunctionTemplate struct {
*template
}
// NewFunctionTemplate creates a FunctionTemplate for a given callback.
func NewFunctionTemplate(iso *Isolate, callback FunctionCallback) *FunctionTemplate {
if iso == nil {
panic("nil Isolate argument not supported")
}
if callback == nil {
panic("nil FunctionCallback argument not supported")
}
cbref := iso.registerCallback(callback)
tmpl := &template{
ptr: C.NewFunctionTemplate(iso.ptr, C.int(cbref)),
iso: iso,
}
runtime.SetFinalizer(tmpl, (*template).finalizer)
return &FunctionTemplate{tmpl}
}
// GetFunction returns an instance of this function template bound to the given context.
func (tmpl *FunctionTemplate) GetFunction(ctx *Context) *Function {
rtn := C.FunctionTemplateGetFunction(tmpl.ptr, ctx.ptr)
runtime.KeepAlive(tmpl)
val, err := valueResult(ctx, rtn)
if err != nil {
panic(err) // TODO: Consider returning the error
}
return &Function{val}
}
// 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)
this := *thisAndArgs
info := &FunctionCallbackInfo{
ctx: ctx,
this: &Object{&Value{ptr: this, ctx: ctx}},
args: make([]*Value, argsCount),
}
argv := (*[1 << 30]C.ValuePtr)(unsafe.Pointer(thisAndArgs))[1 : argsCount+1 : argsCount+1]
for i, v := range argv {
val := &Value{ptr: v, ctx: ctx}
info.args[i] = val
}
callbackFunc := ctx.iso.getCallback(cbref)
if val := callbackFunc(info); val != nil {
return val.ptr
}
return nil
}