I put all the code into a gist which can be downloaded, built and tested
locally:
$ git clone git://gist.github.com/982157.git
$ cd 982157
$ node-waf configure build
$ node VectorTests.js
Vector is function Vector() { [native code] }
Vector.proto is [object Object]
v is { x: 1 }
v.x is 1
v is { x: 9 }
v.x is 9
Assertion failed: (handle->InternalFieldCount() > 0), function Wrap, file
/Users/laurie/.nvm/v0.4.5/include/node/node_object_wrap.h, line 61.
Abort trap
L.
On 2011-05-19, at 8:22 PM, Laurie Harper wrote:
> Oops, there's a line missing from the JavaScript inheritance setup code; it
> should read:
>
> function f() {}; f.prototype = Vector.prototype;
> function g() { Vector.apply(this, arguments) }
> g.prototype = new f();
> var v = new g(1,2,3);
>
> It's correct in my test suite, so my questions still stand...
>
> On 2011-05-19, at 4:31 PM, Laurie Harper wrote:
>
>> 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
>
> --
> Laurie Harper
> http://laurie.holoweb.net/
>
> --
> v8-users mailing list
> [email protected]
> http://groups.google.com/group/v8-users
--
Laurie Harper
http://laurie.holoweb.net/
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users