After some more digging I think I've got it. Using Persistent::MakeWeak you 
can set a callback for the objects destruction. Everything seems to be 
working ok now, so I'll attach my code for future users to find. If you see 
anything wrong with it please speak up.

Jake

--~--~---------~--~----~------------~-------~--~----~
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users
-~----------~----~----~----~------~----~------~--~---

#include <v8/v8.h>
#include <iostream>
#include <fstream>
#include <sstream>

using namespace v8;

class Point {
	public:
		Point(int px = 0, int py = 0) : x(px), y(py) {}
		int x, y;
};

Handle<Value> Point_GetX(Local<String> property, const AccessorInfo& info);
void Point_SetX(Local<String> property, Local<Value> value, const AccessorInfo& info);
Handle<Value> Point_GetY(Local<String> property, const AccessorInfo& info);
void Point_SetY(Local<String> property, Local<Value> value, const AccessorInfo& info);
Handle<Value> Point_Create(const Arguments& args);
void Point_Destroy(Persistent<Object> self, void* parameter);

Handle<String> ReadFile(const char* filename);
Handle<Value> Print(const Arguments& args);


int main()
{
	HandleScope handleScope;

	Handle<FunctionTemplate> pointFunctionTemplate = FunctionTemplate::New(Point_Create);
	pointFunctionTemplate->SetClassName(String::New("Point"));

	Handle<ObjectTemplate> pointInstanceTemplate = pointFunctionTemplate->InstanceTemplate();
	pointInstanceTemplate->SetInternalFieldCount(1);
	pointInstanceTemplate->SetAccessor(String::New("x"), Point_GetX, Point_SetX);
	pointInstanceTemplate->SetAccessor(String::New("y"), Point_GetY, Point_SetY);

	Handle<ObjectTemplate> globals = ObjectTemplate::New();
	globals->Set(String::New("print"), FunctionTemplate::New(Print));
	globals->Set(String::New("Point"), pointFunctionTemplate);

	Persistent<Context> context = Context::New(0, globals);
	Context::Scope contextScope(context);

	Handle<String> source = ReadFile("test.js");
	Handle<Script> script = Script::Compile(source);
	Handle<Value> result = script->Run();
	
	context.Dispose();
	return 0;
}

Handle<Value> Point_GetX(Local<String> property, const AccessorInfo& info)
{
	Local<Object> self = info.Holder();
	Local<External> external = Local<External>::Cast(self->GetInternalField(0));
	Point* p = static_cast<Point*>(external->Value());
	return Integer::New(p->x);
}

Handle<Value> Point_GetY(Local<String> property, const AccessorInfo& info)
{
	Local<Object> self = info.Holder();
	Local<External> external = Local<External>::Cast(self->GetInternalField(0));
	Point* p = static_cast<Point*>(external->Value());
	return Integer::New(p->y);
}

void Point_SetX(Local<String> property, Local<Value> value, const AccessorInfo& info)
{
	Local<Object> self = info.Holder();
	Local<External> external = Local<External>::Cast(self->GetInternalField(0));
	Point* p = static_cast<Point*>(external->Value());
	p->x = value->Int32Value();
}

void Point_SetY(Local<String> property, Local<Value> value, const AccessorInfo& info)
{
	Local<Object> self = info.Holder();
	Local<External> external = Local<External>::Cast(self->GetInternalField(0));
	Point* p = static_cast<Point*>(external->Value());
	p->y = value->Int32Value();
}

Handle<Value> Point_Create(const Arguments& args)
{
	HandleScope handleScope;

	if (!args.IsConstructCall()) 
		return ThrowException(String::New("Cannot call constructor as function"));

	if (args.Length() != 2)
		return ThrowException(String::New("Expected two integer arguments"));

	Point* p = new Point();
	p->x = args[0]->Int32Value();
	p->y = args[1]->Int32Value();

	// make a persistant handle for the instance and
	// make it weak so we get a callback on destruction
	Persistent<Object> self = Persistent<Object>::New(args.Holder());
	self.MakeWeak(0, Point_Destroy);

	self->SetInternalField(0, External::New(p));
	return self;
}

void Point_Destroy(Persistent<Object> self, void* parameter)
{
	Local<External> external = Local<External>::Cast(self->GetInternalField(0));
	delete static_cast<Point*>(external->Value());
}

Handle<String> ReadFile(const char* filename)
{
	std::ifstream fin(filename);
	if (!fin) {
		return Handle<String>();
	}

	std::ostringstream os;
	os << fin.rdbuf();

	return String::New(os.str().c_str());
}

Handle<Value> Print(const Arguments& args)
{
	bool first = true;
	for (int i = 0; i < args.Length(); ++i) {
		HandleScope handleScope;
		if (first) 
			first = false;
		else
			std::cout << ' ';
		std::cout << *String::AsciiValue(args[i]);
	}
	std::cout << std::endl;
	return Undefined();
}

Reply via email to