diff options
author | Paul Gardiner <paul@glidos.net> | 2012-05-14 13:48:39 +0100 |
---|---|---|
committer | Paul Gardiner <paul@glidos.net> | 2012-05-15 13:20:28 +0100 |
commit | 0d8050285b4684ffcfe5472e85e5fce195e83988 (patch) | |
tree | 302ce07ea32f94cee922e54a8f8bdecb0600fb52 /pdf/pdf_jsimp_v8.cpp | |
parent | 407e39962d537d7c9cc38110cf37c0b93f329d0e (diff) | |
download | mupdf-0d8050285b4684ffcfe5472e85e5fce195e83988.tar.xz |
JavaScript: arrange for v8 gc to destroy native-side objects
Diffstat (limited to 'pdf/pdf_jsimp_v8.cpp')
-rw-r--r-- | pdf/pdf_jsimp_v8.cpp | 185 |
1 files changed, 142 insertions, 43 deletions
diff --git a/pdf/pdf_jsimp_v8.cpp b/pdf/pdf_jsimp_v8.cpp index 158fe63c..837a4919 100644 --- a/pdf/pdf_jsimp_v8.cpp +++ b/pdf/pdf_jsimp_v8.cpp @@ -9,35 +9,44 @@ extern "C" { #include "mupdf-internal.h" } +#include <vector> +#include <set> #include <v8.h> using namespace v8; +using namespace std; - -struct PDFJSImp +/* Object we pass to FunctionTemplate::New, which v8 passes back to us in + * callMethod, allowing us to call our client's, passed-in method. */ +struct PDFJSImpMethod { - fz_context *ctx; - void *jsctx; - Persistent<Context> context; + void *jsctx; + pdf_jsimp_method *meth; - PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx) - { - HandleScope scope; - context = Persistent<Context>::New(Context::New()); - } + PDFJSImpMethod(void *jsctx, pdf_jsimp_method *meth) : jsctx(jsctx), meth(meth) {} +}; - ~PDFJSImp() - { - context.Dispose(); - } +/* Object we pass to ObjectTemplate::SetAccessor, which v8 passes back to us in + * setProp and getProp, allowing us to call our client's, passed-in set/get methods. */ +struct PDFJSImpProperty +{ + void *jsctx; + pdf_jsimp_getter *get; + pdf_jsimp_setter *set; + + PDFJSImpProperty(void *jsctx, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : jsctx(jsctx), get(get), set(set) {} }; -/* We need only a couple of specific methods for calc.pdf */ +struct PDFJSImp; + +/* Internal representation of the pdf_jsimp_type object */ struct PDFJSImpType { PDFJSImp *imp; Persistent<ObjectTemplate> templ; pdf_jsimp_dtr *dtr; + vector<PDFJSImpMethod *> methods; + vector<PDFJSImpProperty *> properties; PDFJSImpType(PDFJSImp *imp, pdf_jsimp_dtr *dtr): imp(imp), dtr(dtr) { @@ -48,43 +57,89 @@ struct PDFJSImpType ~PDFJSImpType() { + vector<PDFJSImpMethod *>::iterator mit; + for (mit = methods.begin(); mit < methods.end(); mit++) + delete *mit; + + vector<PDFJSImpProperty *>::iterator pit; + for (pit = properties.begin(); pit < properties.end(); pit++) + delete *pit; + templ.Dispose(); } }; -struct PDFJSImpMethod +/* Info via which we destroy the client side part of objects that + * v8 garbage collects */ +struct PDFJSImpGCObj { - void *jsctx; - pdf_jsimp_method *meth; + Persistent<Object> pobj; + PDFJSImpType *type; - PDFJSImpMethod(void *jsctx, pdf_jsimp_method *meth) : jsctx(jsctx), meth(meth) {} + PDFJSImpGCObj(Handle<Object> obj, PDFJSImpType *type): type(type) + { + pobj = Persistent<Object>::New(obj); + } + + ~PDFJSImpGCObj() + { + pobj.Dispose(); + } }; -struct PDFJSImpProperty +/* Internal representation of the pdf_jsimp object */ +struct PDFJSImp { - void *jsctx; - pdf_jsimp_getter *get; - pdf_jsimp_setter *set; + fz_context *ctx; + void *jsctx; + Persistent<Context> context; + vector<PDFJSImpType *> types; + set<PDFJSImpGCObj *> gclist; - PDFJSImpProperty(void *jsctx, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : jsctx(jsctx), get(get), set(set) {} + PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx) + { + HandleScope scope; + context = Persistent<Context>::New(Context::New()); + } + + ~PDFJSImp() + { + HandleScope scope; + /* Tell v8 our context will not be used again */ + context.Dispose(); + + /* Unlink and destroy all the objects that v8 has yet to gc */ + set<PDFJSImpGCObj *>::iterator oit; + for (oit = gclist.begin(); oit != gclist.end(); oit++) + { + (*oit)->pobj.ClearWeak(); /* So that gcCallback wont get called */ + PDFJSImpType *vType = (*oit)->type; + Local<External> owrap = Local<External>::Cast((*oit)->pobj->GetInternalField(0)); + vType->dtr(vType->imp->jsctx, owrap->Value()); + delete *oit; + } + + vector<PDFJSImpType *>::iterator it; + for (it = types.begin(); it < types.end(); it++) + delete *it; + } }; +/* Internal representation of the pdf_jsimp_obj object */ class PDFJSImpObject { Persistent<Value> pobj; String::Utf8Value *utf8; public: - PDFJSImpObject(Handle<Value> obj) + PDFJSImpObject(Handle<Value> obj): utf8(NULL) { pobj = Persistent<Value>::New(obj); - utf8 = NULL; } - PDFJSImpObject(const char *str) + PDFJSImpObject(const char *str): utf8(NULL) { pobj = Persistent<Value>::New(String::New(str)); - utf8 = NULL; } ~PDFJSImpObject() @@ -119,31 +174,34 @@ extern "C" void pdf_drop_jsimp(pdf_jsimp *imp) extern "C" pdf_jsimp_type *pdf_jsimp_new_type(pdf_jsimp *imp, pdf_jsimp_dtr *dtr) { - return reinterpret_cast<pdf_jsimp_type *>(new PDFJSImpType((PDFJSImp *)imp, dtr)); + PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp); + PDFJSImpType *vType = new PDFJSImpType(vImp, dtr); + vImp->types.push_back(vType); + return reinterpret_cast<pdf_jsimp_type *>(vType); } extern "C" void pdf_jsimp_drop_type(pdf_jsimp *imp, pdf_jsimp_type *type) { - delete reinterpret_cast<PDFJSImpType *>(type); + /* Types are recorded and destroyed as part of PDFJSImp */ } static Handle<Value> callMethod(const Arguments &args) { HandleScope scope; - Local<Object> self = args.Holder(); - Local<External> owrap; - void *nself = NULL; Local<External> mwrap = Local<External>::Cast(args.Data()); PDFJSImpMethod *m = (PDFJSImpMethod *)mwrap->Value(); - int c = args.Length(); - PDFJSImpObject **native_args = new PDFJSImpObject*[c]; + Local<Object> self = args.Holder(); + Local<External> owrap; + void *nself = NULL; if (self->InternalFieldCount() > 0) { owrap = Local<External>::Cast(self->GetInternalField(0)); nself = owrap->Value(); } + int c = args.Length(); + PDFJSImpObject **native_args = new PDFJSImpObject*[c]; for (int i = 0; i < c; i++) native_args[i] = new PDFJSImpObject(args[i]); @@ -164,18 +222,27 @@ extern "C" void pdf_jsimp_addmethod(pdf_jsimp *imp, pdf_jsimp_type *type, char * PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type); HandleScope scope; - vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(new PDFJSImpMethod(vType->imp->jsctx, meth)))); + PDFJSImpMethod *pmeth = new PDFJSImpMethod(vType->imp->jsctx, meth); + vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(pmeth))); + vType->methods.push_back(pmeth); } static Handle<Value> getProp(Local<String> property, const AccessorInfo &info) { HandleScope scope; - Local<Object> self = info.Holder(); - Local<External> owrap = Local<External>::Cast(self->GetInternalField(0)); Local<External> pwrap = Local<External>::Cast(info.Data()); PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(pwrap->Value()); - PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(p->get(p->jsctx, owrap->Value())); + Local<Object> self = info.Holder(); + Local<External> owrap; + void *nself = NULL; + if (self->InternalFieldCount() > 0) + { + owrap = Local<External>::Cast(self->GetInternalField(0)); + nself = owrap->Value(); + } + + PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(p->get(p->jsctx, nself)); Handle<Value> val = obj->toValue(); delete obj; return scope.Close(val); @@ -184,13 +251,21 @@ static Handle<Value> getProp(Local<String> property, const AccessorInfo &info) static void setProp(Local<String> property, Local<Value> value, const AccessorInfo &info) { HandleScope scope; - Local<Object> self = info.Holder(); - Local<External> owrap = Local<External>::Cast(self->GetInternalField(0)); Local<External> wrap = Local<External>::Cast(info.Data()); PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(wrap->Value()); + + Local<Object> self = info.Holder(); + Local<External> owrap; + void *nself = NULL; + if (self->InternalFieldCount() > 0) + { + owrap = Local<External>::Cast(self->GetInternalField(0)); + nself = owrap->Value(); + } + PDFJSImpObject *obj = new PDFJSImpObject(value); - p->set(p->jsctx, owrap->Value(), reinterpret_cast<pdf_jsimp_obj *>(obj)); + p->set(p->jsctx, nself, reinterpret_cast<pdf_jsimp_obj *>(obj)); delete obj; } @@ -199,7 +274,9 @@ extern "C" void pdf_jsimp_addproperty(pdf_jsimp *imp, pdf_jsimp_type *type, char PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type); HandleScope scope; - vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(new PDFJSImpProperty(vType->imp->jsctx, get, set))); + PDFJSImpProperty *prop = new PDFJSImpProperty(vType->imp->jsctx, get, set); + vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(prop)); + vType->properties.push_back(prop); } extern "C" void pdf_jsimp_set_global_type(pdf_jsimp *imp, pdf_jsimp_type *type) @@ -211,6 +288,19 @@ extern "C" void pdf_jsimp_set_global_type(pdf_jsimp *imp, pdf_jsimp_type *type) vImp->context = Persistent<Context>::New(Context::New(NULL, vType->templ)); } +static void gcCallback(Persistent<Value> val, void *parm) +{ + PDFJSImpGCObj *gco = reinterpret_cast<PDFJSImpGCObj *>(parm); + PDFJSImpType *vType = gco->type; + HandleScope scope; + Persistent<Object> obj = Persistent<Object>::Cast(val); + + Local<External> owrap = Local<External>::Cast(obj->GetInternalField(0)); + vType->dtr(vType->imp->jsctx, owrap->Value()); + vType->imp->gclist.erase(gco); + delete gco; /* Disposes of the persistent handle */ +} + extern "C" pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj) { PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type); @@ -218,6 +308,15 @@ extern "C" pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type Local<Object> obj = vType->templ->NewInstance(); obj->SetInternalField(0, External::New(natobj)); + /* Arrange for destructor to be called on the client sire object + * when the v8 object is garbage collected */ + if (vType->dtr) + { + PDFJSImpGCObj *gco = new PDFJSImpGCObj(obj, vType); + vType->imp->gclist.insert(gco); + gco->pobj.MakeWeak(gco, gcCallback); + } + return reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(obj)); } |