Skip to content

Commit

Permalink
Implement set, get internal fields, & set internal field count (#145)
Browse files Browse the repository at this point in the history
Co-authored-by: Dylan Thacker-Smith <Dylan.Smith@shopify.com>
  • Loading branch information
wisepythagoras and dylanahsmith authored Oct 18, 2021
1 parent f75f288 commit 19ec71c
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 0 deletions.
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

0 comments on commit 19ec71c

Please sign in to comment.