Hi, all!
After having bound hundreds of C-like functions i'm ready to bind my
first class in v8. i've got it working so far except that my Weak
Pointer callback isn't being triggered, and i have been unable to
figure out why. i'm pasting the code here - it's a bit long, but i
would really appreciate any insights on this, as i can't do ANY class-
level wrapping until i figure out how to get the objects deleted
properly.
Most of the code below was based on suggestions from:
http://create.tpsitulsa.com/blog/2009/01/31/persistent-handles/
http://create.tpsitulsa.com/blog/2009/01/29/v8-objects/
It's worth noting that the v8 sample code doesn't have any examples of
weak pointers :(.
The class i'm wrapping, PathFinder, can be considered opaque for our
purposes - the binding to the object appears to work, it's just that
my dtor (pf_dtor()) is never called.
The functions listed below are:
- SetupPathFinderClass() sets up the class for JS-side access.
Installs the ctor and class instance prototype
- pf_ctor() - the instance constructor
- pf_dtor() - the weak pointer callback
- pf_wrap() - associates a PathFinder JS object with a C++ object
and does the Persistent/Weak voodoo.
i've tried with and without HandleScopes, but the results are the same
- pf_dtor() is never being called.
The C++ code (JS code follows):
#include <v8/PathFinder.h>
#include <v8.h>
#include <v8/v8-convert.h>
#include <v8/v8-plugin.h>
#include <iostream> /* only for debuggering */
#ifndef CERR
#define CERR std::cerr << __FILE__ << ":" << std::dec << __LINE__ <<
" : "
#endif
namespace v8 { namespace p3 {
using namespace ::v8::bind;
using namespace ::v8::convert;
//static const void * pf_bind_cx() { static const int x=7;return
&x;}
static void pf_dtor(Persistent< Value > object, void *parameter)
{
CERR << "pf_dtor() PathFinder @"<<parameter<<'\n';
PathFinder * pf = static_cast<PathFinder*>( parameter );
//UnbindNative( pf_bind_cx(), parameter, pf );
if( pf != &::v8::p3::plugin::PluginPath() )
{
delete pf;
}
object.Dispose();
object.Clear();
}
static Persistent<Object> pf_wrap( Handle<Object> _self,
PathFinder * value )
{
//HandleScope scope;
//BindNative( pf_bind_cx(), value, value );
Persistent<Object> self( Persistent<Object>::New(_self) );
self.MakeWeak( value, pf_dtor );
self->SetInternalField(0,External::New(value));
self->Set(String::New("bogo"),String::New("bogo was here"));
CERR << "Wrapped PathFinder @"<<value<<" in a Persistent<Object>.\n";
//return scope.Close(self);
return self;
}
static Handle<Value> pf_ctor(const Arguments& argv)
{
if (!argv.IsConstructCall())
return ThrowException(String::New("Cannot call constructor as
function"));
const int argc = argv.Length();
if( (1 == argc) && argv[0]->IsExternal() )
{
External * ex = External::Cast( *argv[0] );
if( ex )
{
return pf_wrap( argv.This(), static_cast<PathFinder*>(ex->Value
()) );
}
else
{
return ThrowException(String::New("First argument to ctor failed
External::Cast()"));
}
}
//HandleScope hscope;
std::string a0 = (argc>0) ? JSToStdString(argv[0]) : "";
std::string a1 = (argc>1) ? JSToStdString(argv[1]) : "";
std::string a2 = (argc>2) ? JSToStdString(argv[2]) : "";
CERR << "PathFinder(["<<a0<<"], ["<<a1<<"], ["<<a2<<"])\n";
PathFinder * pf = new PathFinder( a0, a1, a2 );
//return hscope.Close( pf_wrap( argv.This(), pf ) );
return pf_wrap( argv.This(), pf );
//return hscope.Close( pf_wrap( argv.This(), pf ) );
}
Handle<Value> SetupPathFinderClass(const Handle<Object> target )
{
// Set up prototype:
Handle<FunctionTemplate> ctor = FunctionTemplate::New(pf_ctor);
Local<ObjectTemplate> objt = ctor->InstanceTemplate();
objt->SetInternalFieldCount(1);
// Install ctor:
Handle<Function> pffunc( ctor->GetFunction() );
target->Set(String::New("PathFinder"), pffunc );
// Install instance wrapping PluginPath() shared object:
Handle<Value> pfex( External::New( &::v8::p3::plugin::PluginPath
() ) );
Handle<Object> pfobj = pffunc->NewInstance( 1, &pfex );
pffunc->Set(String::New("plugins"), pfobj );
return pfobj;
}
}} // namespaces
i've created hundreds of PathFinder objects in small scopes to try to
force GC, but my debugging message in pf_dtor() never gets output:
var my = {p:null};
{
for( var i = 0; i < 5; ++i )
{
var p = ['/usr/bin','/bin','~/bin'];
my.p = new PathFinder(p.join(''+i),"",""+i);
//delete my.p;
}
print('my.p=',my.p,typeof my.p,my.p.bogo);
delete my.p;
print('my.p=',my.p);
}
print('my.p=',my.p);
print
('PathFinder.plugins=',PathFinder.plugins,PathFinder.plugins.bogo);
print("Bye!");
The output is:
stephan@jareth:~/cvs/fossil/v8-addons/addons$ m && ./shell js/pf.js
make: Nothing to be done for `default'.
PathFinder-js.cc:43 : Wrapped PathFinder @0xb7c940a0 in a
Persistent<Object>.
PathFinder-js.cc:69 : PathFinder([/usr/bin0/bin0~/bin], [], [0])
PathFinder-js.cc:43 : Wrapped PathFinder @0x88cda78 in a
Persistent<Object>.
PathFinder-js.cc:69 : PathFinder([/usr/bin1/bin1~/bin], [], [1])
PathFinder-js.cc:43 : Wrapped PathFinder @0x88cda40 in a
Persistent<Object>.
PathFinder-js.cc:69 : PathFinder([/usr/bin2/bin2~/bin], [], [2])
PathFinder-js.cc:43 : Wrapped PathFinder @0x88cdc10 in a
Persistent<Object>.
PathFinder-js.cc:69 : PathFinder([/usr/bin3/bin3~/bin], [], [3])
PathFinder-js.cc:43 : Wrapped PathFinder @0x88cdd00 in a
Persistent<Object>.
PathFinder-js.cc:69 : PathFinder([/usr/bin4/bin4~/bin], [], [4])
PathFinder-js.cc:43 : Wrapped PathFinder @0x88cddf0 in a
Persistent<Object>.
my.p= [object Object] object bogo was here
my.p= undefined
my.p= undefined
PathFinder.plugins= [object Object] bogo was here
Bye!
---------------------------------------
(end demo)
:-?