I'm trying to create a node.js module which invokes a JS callback from a
system routine (Event Tracing for Windows ProcessTrace).
I'd like to avoid the cost of fully instantiating the event objects passed
to the callback, so I've created an ObjectTemplate with Accessors for the
various underlying C structure members.
How do I go about creating nested ObjectTemplates? What I'd like is to have
an object like:
{
outer: <accessor1>
sub: {
inner: <accessor2>
}
}
Just using template->Set(...) with a nested ObjectTemplate seems to work,
but I see no way to get SetInternalField() set correctly for the nested
template.
I've tried using sub: Accessor functions which lazy-instantantiate the
sub-object, which does let me call SetInternalField(), but unfortunately
there doesn't seem to be a way to override the accessor behavior (accessors
for sub: always fire so I end up creating a new instance each access).
What's the right way to do what I want (have a nested structure with
accessors for all of the leaf properties)? Failing that what's the right
way to override a template accessor from an object instance?
here's a more verbose sample of what I've tried to do with the
lazy-instantiation:
//
// TestAccessor - test accessor functionality
//
static Persistent<ObjectTemplate> static_templ;
static Persistent<ObjectTemplate> static_sub_templ;
static int *UnwrapRequest(Handle<Object> obj) {
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
void *p = field->Value();
return reinterpret_cast<int *>(p);
}
//
// this horrible hack lazy-instantiates accessor sub-structures so you can
have { foo: <magic()>, bar: { baz: <magic()> } }
// the advantage is that none of this is paid for until you actually access
it.
// we start out with a root ObjectTemplate getting instantiated with bar:
accessors which instantiate the sub-structure.
//
static Handle<Value> GetSubVal(Local<String> property, const AccessorInfo
&info)
{
int *p = UnwrapRequest(info.Holder());
printf("GetSubVal %p\n", p);
return Int32::New(*p);
}
static void SetSubVal(Local<String> property, Local<Value> value, const
AccessorInfo &info)
{
int *p = UnwrapRequest(info.Holder());
int newValue = value->Int32Value();
printf("SetSubVal <- %d\n", newValue);
*p = newValue;
}
Handle<Object> MakeSubInstance(const AccessorInfo &info)
{
HandleScope scope;
Handle<ObjectTemplate> templ = static_sub_templ;
Handle<Object> result = templ->NewInstance();
int *p = UnwrapRequest(info.Holder());
Handle<External> c_ptr = External::New(p);
result->SetInternalField(0, c_ptr);
return scope.Close(result);
}
static Handle<Value> GetSub(Local<String> property, const AccessorInfo
&info)
{
int *p = UnwrapRequest(info.Holder());
String::Utf8Value name(property->ToString());
printf("GetSub %p %d prop %s\n", p, *p, *name);
Handle<Object> th = info.This();
Handle<Object> sub = MakeSubInstance(info);
th->Set(property, sub);
return sub;
}
static void SetSub(Local<String> property, Local<Value> value, const
AccessorInfo &info)
{
int *p = UnwrapRequest(info.Holder());
printf("SetSub %d <- %d\n", *p, value->IsObject());
}
static Handle<Value> GetTest(Local<String> property, const AccessorInfo
&info)
{
int *p = UnwrapRequest(info.Holder());
printf("GetTest %p %d\n", p, *p);
return Int32::New(*p);
}
static void SetTest(Local<String> property, Local<Value> value, const
AccessorInfo &info)
{
int *p = UnwrapRequest(info.Holder());
int newValue = value->Int32Value();
printf("SetTest %d <- %d\n", *p, newValue);
*p = newValue;
}
static Handle<ObjectTemplate> MakeSubTemplate() {
HandleScope handle_scope;
Handle<ObjectTemplate> sub = ObjectTemplate::New();
sub->SetAccessor(String::NewSymbol("val"), GetSubVal, SetSubVal);
sub->SetInternalFieldCount(1);
return handle_scope.Close(sub);
}
static Handle<ObjectTemplate> MakeTemplate() {
HandleScope handle_scope;
Handle<ObjectTemplate> result = ObjectTemplate::New();
result->SetInternalFieldCount(1);
result->SetAccessor(String::NewSymbol("test"), GetTest, SetTest);
result->SetAccessor(String::NewSymbol("sub"), GetSub, SetSub);
return handle_scope.Close(result);
}
Handle<Value> api::TestAccessor(const Arguments &args)
{
HandleScope scope;
if (static_templ.IsEmpty()) {
static_templ = Persistent<ObjectTemplate>::New(MakeTemplate());
static_sub_templ =
Persistent<ObjectTemplate>::New(MakeSubTemplate());
}
// XXX why do you need this? worked without it but maybe leaks? - Ed
Handle<ObjectTemplate> templ = static_templ;
// Create an empty map wrapper.
Handle<Object> result = templ->NewInstance();
// dummy C++ object (just an int *)
static int calls = 0;
int *c_obj = new int(calls++);
Handle<External> c_ptr = External::New(c_obj);
// Store the map pointer in the JavaScript wrapper.
result->SetInternalField(0, c_ptr);
return scope.Close(result);
}
--
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.