Hi, I posted these issues first to the Node mailing list as the errors I'm
seeing are coming from assertions in Node's API, but they appear to be a direct
result of how the v8 JavaScript <-> C++ bridge works, so I'm bringing them here
for further clarification. I'll include the full stripped-down C++ code I'm
testing with below.
So far I have two problems, both of which I think stem from the same underlying
issue. The first is that if I set up accessors on the prototype of my c++ proxy
I'm unable to unwrap the internal field object; switching from
t->PrototypeTemplate()->SetAccessor() to t->InstanceTemplate()->SetAccessor()
resolved the problem (see commented line in Initialize() in the code below.
Strangely, setting a method on the prototype seems to work just fine. So,
question: why does it not work to set an accessor on the prototype?
The second problem comes when I try to set up inheritance in JavaScript from an
object defined in c++. I think I understand why this one fails, but have no
idea how to fix it... I'm using test code like this, where Vector is defined in
c++ as show below:
function f() {}; f.prototype = Vector.prototype;
function g() { Vector.apply(this, arguments) }
var v = new g(1,2,3);
That emulates a common pattern for inheritance in JavaScript to avoid calling
the base type constructor when setting up the prototype of the inheriting
class. I think the problem is that, since there is no explicit 'new Vector'
anywhere, the c++ instantiation logic isn't fired at the right time. The result
is that Arguments::This() returns an object of an unexpected type (?) and
wrapping/unwrapping the proxied object fails. So, the question is how to adjust
my code to work when a constructor is called without the 'new' operator I think?
Here's the test code I'm working with:
*** Vector.h:
class Vector: public node::ObjectWrap {
public:
static Persistent<FunctionTemplate> ctor;
static void Initialize(Handle<Object> target);
static Handle<Value> GetX(Local<String> property, const AccessorInfo& info);
static void SetX(Local<String> property, Local<Value> value, const
AccessorInfo& info);
protected:
static Handle<Value> New(const Arguments &args);
Vector(btScalar &x, btScalar &y, btScalar &z);
private:
btVector3* m_btVector3;
};
*** Vector.cc:
Persistent<FunctionTemplate> Vector::ctor;
void
Vector::Initialize(Handle<Object> target) {
HandleScope scope;
ctor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(New));
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(String::NewSymbol("Vector"));
// ctor->PrototypeTemplate()->SetAccessor(String::NewSymbol("x"), GetX, SetX);
ctor->InstanceTemplate()->SetAccessor(String::NewSymbol("x"), GetX, SetX);
target->Set(String::NewSymbol("Vector"), ctor->GetFunction());
}
Handle<Value>
Vector::New(const Arguments &args) {
float x, y, z;
HandleScope scope;
if (args.Length() == 1 && args[0]->IsArray()) {
x = args[0]->ToObject()->Get(0)->NumberValue();
y = args[0]->ToObject()->Get(1)->NumberValue();
z = args[0]->ToObject()->Get(2)->NumberValue();
} else {
x = args[0]->IsNumber() ? args[0]->NumberValue() : 0;
y = args[1]->IsNumber() ? args[1]->NumberValue() : 0;
z = args[2]->IsNumber() ? args[2]->NumberValue() : 0;
}
Vector* obj = new Vector(x, y, z);
obj->Wrap(args.This());
return args.This();
}
Vector::Vector(btScalar &x, btScalar &y, btScalar &z) {
m_btVector3 = new btVector3(x, y, z);
}
Handle<Value>
Vector::GetX(Local<String> property, const AccessorInfo& info) {
HandleScope scope;
// Vector* v = ObjectWrap::Unwrap<Vector>(info.This()); // This vs. Holder?
Vector* v = ObjectWrap::Unwrap<Vector>(info.Holder()); // This vs. Holder?
Local<Number> result = Number::New(v->m_btVector3->getX());
return scope.Close(result);
}
void
Vector::SetX(Local<String> property, Local<Value> value, const AccessorInfo&
info) {
Vector* v = ObjectWrap::Unwrap<Vector>(info.Holder());
v->m_btVector3->setX(value->NumberValue());
}
--
Laurie Harper
http://laurie.holoweb.net/
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users