Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement set, get internal fields, & set internal field count #145

Merged
merged 6 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Undefined, Null functions to get these constant values for the isolate
- Support for calling a method on an object.
- Support for calling `IsExecutionTerminating` on isolate to check if execution is still terminating.
- Support for setting and getting internal fields for template object instances

### Changed
- Removed error return value from NewIsolate which never fails
Expand Down
8 changes: 8 additions & 0 deletions helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ func fatalIf(t *testing.T, err error) {
t.Fatal(err)
}
}

func recoverPanic(f func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
f()
return nil
}
37 changes: 37 additions & 0 deletions object.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,34 @@ func (o *Object) SetIdx(idx uint32, val interface{}) error {
}

C.ObjectSetIdx(o.ptr, C.uint32_t(idx), value.ptr)

return nil
}

// SetInternalField sets the value of an internal field for an ObjectTemplate instance.
// Panics if the index isn't in the range set by (*ObjectTemplate).SetInternalFieldCount.
func (o *Object) SetInternalField(idx uint32, val interface{}) error {
value, err := coerceValue(o.ctx.iso, val)

if err != nil {
return err
}

inserted := C.ObjectSetInternalField(o.ptr, C.uint32_t(idx), value.ptr)

if inserted == 0 {
panic(fmt.Errorf("index out of range [%v] with length %v", idx, o.InternalFieldCount()))
}

return nil
}

// InternalFieldCount returns the number of internal fields this Object has.
func (o *Object) InternalFieldCount() uint32 {
count := C.ObjectInternalFieldCount(o.ptr)
return uint32(count)
}

// Get tries to get a Value for a given Object property key.
func (o *Object) Get(key string) (*Value, error) {
ckey := C.CString(key)
Expand All @@ -92,6 +117,18 @@ func (o *Object) Get(key string) (*Value, error) {
return valueResult(o.ctx, rtn)
}

// GetInternalField gets the Value set by SetInternalField for the given index
// or the JS undefined value if the index hadn't been set.
// Panics if given an out of range index.
func (o *Object) GetInternalField(idx uint32) *Value {
rtn := C.ObjectGetInternalField(o.ptr, C.uint32_t(idx))
if rtn == nil {
panic(fmt.Errorf("index out of range [%v] with length %v", idx, o.InternalFieldCount()))
}
return &Value{rtn, o.ctx}

}

// GetIdx tries to get a Value at a give Object index.
func (o *Object) GetIdx(idx uint32) (*Value, error) {
rtn := C.ObjectGetIdx(o.ptr, C.uint32_t(idx))
Expand Down
12 changes: 12 additions & 0 deletions object_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ func (o *ObjectTemplate) NewInstance(ctx *Context) (*Object, error) {
return objectResult(ctx, rtn)
}

// SetInternalFieldCount sets the number of internal fields that instances of this
// template will have.
func (o *ObjectTemplate) SetInternalFieldCount(fieldCount uint32) {
C.ObjectTemplateSetInternalFieldCount(o.ptr, C.uint32_t(fieldCount))
}

// InternalFieldCount returns the number of internal fields that instances of this
// template will have.
func (o *ObjectTemplate) InternalFieldCount() uint32 {
return uint32(C.ObjectTemplateInternalFieldCount(o.ptr))
}

func (o *ObjectTemplate) apply(opts *contextOptions) {
opts.gTmpl = o
}
47 changes: 47 additions & 0 deletions object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,53 @@ func TestObjectSet(t *testing.T) {
}
}

func TestObjectInternalFields(t *testing.T) {
iso := v8.NewIsolate()
defer iso.Dispose()
ctx := v8.NewContext(iso)
defer ctx.Close()

tmpl := v8.NewObjectTemplate(iso)
obj, err := tmpl.NewInstance(ctx)
fatalIf(t, err)
if count := obj.InternalFieldCount(); count != 0 {
t.Errorf("expected 0 got %v", count)
}
if recoverPanic(func() { obj.GetInternalField(0) }) == nil {
t.Error("expected panic")
}

tmpl = v8.NewObjectTemplate(iso)
tmpl.SetInternalFieldCount(1)
if count := tmpl.InternalFieldCount(); count != 1 {
t.Errorf("expected 1 got %v", count)
}

obj, err = tmpl.NewInstance(ctx)
fatalIf(t, err)
if count := obj.InternalFieldCount(); count != 1 {
t.Errorf("expected 1 got %v", count)
}

if v := obj.GetInternalField(0); !v.SameValue(v8.Undefined(iso)) {
t.Errorf("unexpected value: %q", v)
}

if err := obj.SetInternalField(0, t); err == nil {
t.Error("expected unsupported value error")
}

err = obj.SetInternalField(0, "baz")
fatalIf(t, err)
if v := obj.GetInternalField(0); v.String() != "baz" {
t.Errorf("unexpected value: %q", v)
}

if recoverPanic(func() { obj.SetInternalField(1, "baz") }) == nil {
t.Error("expected panic from index out of bounds")
}
}

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

Expand Down
50 changes: 50 additions & 0 deletions v8go.cc
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,20 @@ RtnValue ObjectTemplateNewInstance(TemplatePtr ptr, ContextPtr ctx) {
return rtn;
}

void ObjectTemplateSetInternalFieldCount(TemplatePtr ptr, uint32_t field_count) {
LOCAL_TEMPLATE(ptr);

Local<ObjectTemplate> obj_tmpl = tmpl.As<ObjectTemplate>();
obj_tmpl->SetInternalFieldCount(field_count);
}

int ObjectTemplateInternalFieldCount(TemplatePtr ptr) {
LOCAL_TEMPLATE(ptr);

Local<ObjectTemplate> obj_tmpl = tmpl.As<ObjectTemplate>();
return obj_tmpl->InternalFieldCount();
}

/********** FunctionTemplate **********/

static void FunctionTemplateCallback(const FunctionCallbackInfo<Value>& info) {
Expand Down Expand Up @@ -1048,6 +1062,24 @@ void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr prop_val) {
obj->Set(local_ctx, idx, prop_val->ptr.Get(iso)).Check();
}

int ObjectSetInternalField(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr) {
LOCAL_OBJECT(ptr);
m_value* prop_val = static_cast<m_value*>(val_ptr);

if (idx >= obj->InternalFieldCount()) {
return 0;
}

obj->SetInternalField(idx, prop_val->ptr.Get(iso));

return 1;
}

int ObjectInternalFieldCount(ValuePtr ptr) {
LOCAL_OBJECT(ptr);
return obj->InternalFieldCount();
}

RtnValue ObjectGet(ValuePtr ptr, const char* key) {
LOCAL_OBJECT(ptr);
RtnValue rtn = {nullptr, nullptr};
Expand All @@ -1073,6 +1105,24 @@ RtnValue ObjectGet(ValuePtr ptr, const char* key) {
return rtn;
}

ValuePtr ObjectGetInternalField(ValuePtr ptr, uint32_t idx) {
LOCAL_OBJECT(ptr);

if (idx >= obj->InternalFieldCount()) {
return nullptr;
}

Local<Value> result = obj->GetInternalField(idx);

m_value* new_val = new m_value;
new_val->iso = iso;
new_val->ctx = ctx;
new_val->ptr = Persistent<Value, CopyablePersistentTraits<Value>>(
iso, result);

return tracked_value(ctx, new_val);
}

RtnValue ObjectGetIdx(ValuePtr ptr, uint32_t idx) {
LOCAL_OBJECT(ptr);
RtnValue rtn = {nullptr, nullptr};
Expand Down
5 changes: 5 additions & 0 deletions v8go.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ extern void TemplateSetTemplate(TemplatePtr ptr,

extern TemplatePtr NewObjectTemplate(IsolatePtr iso_ptr);
extern RtnValue ObjectTemplateNewInstance(TemplatePtr ptr, ContextPtr ctx_ptr);
extern void ObjectTemplateSetInternalFieldCount(TemplatePtr ptr, uint32_t field_count);
extern int ObjectTemplateInternalFieldCount(TemplatePtr ptr);

extern TemplatePtr NewFunctionTemplate(IsolatePtr iso_ptr, int callback_ref);
extern RtnValue FunctionTemplateGetFunction(TemplatePtr ptr,
Expand Down Expand Up @@ -183,8 +185,11 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr);

extern void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr);
extern void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr);
extern int ObjectSetInternalField(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr);
extern int ObjectInternalFieldCount(ValuePtr ptr);
extern RtnValue ObjectGet(ValuePtr ptr, const char* key);
extern RtnValue ObjectGetIdx(ValuePtr ptr, uint32_t idx);
extern ValuePtr ObjectGetInternalField(ValuePtr ptr, uint32_t idx);
int ObjectHas(ValuePtr ptr, const char* key);
int ObjectHasIdx(ValuePtr ptr, uint32_t idx);
int ObjectDelete(ValuePtr ptr, const char* key);
Expand Down