Reusing object templates in individual contexts

687 views
Skip to first unread message

developerdr

unread,
Mar 28, 2011, 12:32:50 PM3/28/11
to v8-users
Hallo,

I just tried to port my wrapper code from v8 2.0 to the v8 3.2. Now
I'm facing with a problem I cannot fix on my own and I cannot find any
examples or details descriptions in this group.

Here my detailed problem:
We developed a JavaScript API for our framework using v8 2.0.
We added several object templates and function templates to wrap
several of our C++ classes (device classes etc.)
Our software allows to load several JavaScript files concurrently each
allowing (independently) access to our framework. Different C++
threads can invoke functions inside the individual JavaScript files to
change the behavior of our applications. (Locks avoid that v8 is
called concurrently by different threads)

Therefore, we created one (static) global object template holding
several function templates of the individual wrapper objects like
this:

v8::Handle<FunctionTemplate>
templateHandle(FunctionTemplate::New(cppConstructorOfObjectToBeWrapped));
templateHandle->SetClassName(v8::String::New("javascriptClassName));

Handle<ObjectTemplate> objectTemplate(templateHandle-
>InstanceTemplate());
objectTemplate->SetInternalFieldCount(1);
objectTemplate->Set(v8::String::New("doanything"),
FunctionTemplate::New(cppDoAnythingFunction));

Local<ObjectTemplate> globalTemplateObject =
Local<ObjectTemplate>(ObjectTemplate::New());
globalTemplateObject->Set(String::New("javascriptClassName"),
templateHandle);

And created a context using the global object template:

...
v8::Locker locker;
v8::HandleScope handleScope;
v8::Persistent<v8::Context> contextObject = Context::New(NULL,
globalTemplateObject);
Context::Scope contextScope(contextObject);
...

For the first time everything goes fine.
Now we would like to reuse the global object for further context
objects (e.g. each time a new scriptfile has to be loaded).
Everything was fine using v8 2.0.
However, now v8 3.2 crashes with an "Access violation ..." at objects-
inl.h, line 2926: ACCESSORS(TemplateInfo, property_list, Object,
kPropertyListOffset)

I guess that I'm not allowed to reuse the static global object
template again in different context objects. Or that I do have to
defined them in a different way - I also tried a
Persistent<ObjectTemplate> object but this also crashes...

I also tried to create a new template object for each new context
(only for testing), but I need a static template object of the
individual wrapper objects to create new instances of the JavaScript
objects for e.g. return values of the wrapped functions
(objectTemplate()->NewInstance();)...

Do you have any hint what I can do to fix the problem?
Some more descriptions about contexts and multi threading would be
very helpful...

Thanks,
Jan

developerdr

unread,
Mar 31, 2011, 8:19:43 PM3/31/11
to v8-users
Is there nobody have the same problem?
No one having any hint for my problem?

Cheers,
Jan

Mads Sig Ager

unread,
Apr 1, 2011, 1:59:30 AM4/1/11
to v8-u...@googlegroups.com
Hi Jan,

if you store and reuse your global object template you definitely have
to put it in a persistent handle. Otherwise it will be garbage
collected when you exit the handle scope in which the handle to it was
created and further uses of it will lead to crashes.

If you could create a simple reproduction that we can compile and run
to experience the problem that would make it much easier to help. We
have not noticed any such problems.

Thanks, -- Mads

> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
>

Stephan Beal

unread,
Apr 1, 2011, 4:41:40 AM4/1/11
to v8-u...@googlegroups.com
On Fri, Apr 1, 2011 at 7:59 AM, Mads Sig Ager <ag...@chromium.org> wrote:
if you store and reuse your global object template you definitely have
to put it in a persistent handle. Otherwise it will be garbage
collected when you exit the handle scope in which the handle to it was
created and further uses of it will lead to crashes.


Minor clarification: that should say "MAY be garbage collected" or ""will be made available for garbage collection," rather than "WILL be garbage collected." For bound native types which require destructor calls for proper cleanup, this distinction is significant.

--
----- stephan beal
http://wanderinghorse.net/home/stephan/

Mads Sig Ager

unread,
Apr 1, 2011, 4:44:55 AM4/1/11
to v8-u...@googlegroups.com

No, not if you do not allocate a persistent handle and register a weak
callback. The JS memory will be free for allocation as soon as the
handle exits its handle scope. We are talking about an ObjectTemplate
which is in the V8 heap with no associated C++ allocated data.

-- Mads

developerdr

unread,
Apr 3, 2011, 12:29:40 AM4/3/11
to v8-users
Dear Mads,

thank you very much for your answer. Please find the simple example
below (it took me some time to make it that small).
The problem occurs even without the usage of additional threads.
I think it's obviously that my code must have a logical mistake -
because it's that simple.
However, according to all the explanations provided in this mailing
list and provided by the tutorials on the developer side I'm not able
to find the problem...

The example is written for windows and you should be able to test it
using a simple console application.
You will see that the crash occurs during the second context creation
using the one and only static but persistent object template.
As I understand the documentation of persistent objects: they are not
influenced by the handle scope and thus the example should work fine.
If you replace the usage of the static object template by two
independent objects template the example does not crash...

Thanks for you support,
Jan

#include <tchar.h>
#include <cstdlib>
#include <iostream>
#include <cassert>
#include <v8.h>
#include <windows.h>

/**
* Simple singleton implementation.
*/
class Singleton
{
public:

/**
* Returns the unique singleton object.
*/
static Singleton& get()
{
static Singleton singleton;
return singleton;
}

/**
* Returns the unique object template.
*/
v8::Persistent<v8::ObjectTemplate> objectTemplate()
{
if (uniqueObjectTemplate.IsEmpty())
{
uniqueObjectTemplate =
v8::Persistent<v8::ObjectTemplate>(v8::ObjectTemplate::New());

// normally here function templates would be added
//uniqueObjectTemplate->Set(String::New("functionName"),
createSpecificFunctionTemplate())
}

return uniqueObjectTemplate;
}

private:

v8::Persistent<v8::ObjectTemplate> uniqueObjectTemplate;
};

int _tmain(int argc, _TCHAR* argv[])
{
{
v8::HandleScope handleScope;

{
v8::Persistent<v8::Context> anyContext = v8::Context::New(NULL,
Singleton::get().objectTemplate());

// do something with this context

anyContext.Dispose();
}
}

{
v8::HandleScope handleScope;

{
// ** CRASH ->
v8::Persistent<v8::Context> anyContext = v8::Context::New(NULL,
Singleton::get().objectTemplate());
// <-- CRASH **

// do something with this context

anyContext.Dispose();
}
}

std::cout << "Press a key to exit" << std::endl;
getchar();

return 0;
}

Matthias Ernst

unread,
Apr 3, 2011, 3:30:36 AM4/3/11
to v8-u...@googlegroups.com

Here's your problem. You're missing a "::New" and instead you're
casting a local to a persistent handle:

/**
* "Casts" a plain handle which is known to be a persistent handle
* to a persistent handle.
*/
template <class S> explicit inline Persistent(Handle<S> that)
: Handle<T>(*that) { }

Maybe V8 team could add an overload Persistent(Local) that triggers a
compile-time error, or at least a useful runtime error.

Matthias


>
>                                // normally here function templates would be added
>                                //uniqueObjectTemplate->Set(String::New("functionName"),
> createSpecificFunctionTemplate())
>                        }
>
>                        return uniqueObjectTemplate;
>                }
>
>        private:
>
>                v8::Persistent<v8::ObjectTemplate> uniqueObjectTemplate;
> };
>
> int _tmain(int argc, _TCHAR* argv[])
> {
>        {
>                v8::HandleScope handleScope;
>
>                {
>                        v8::Persistent<v8::Context> anyContext = v8::Context::New(NULL,
> Singleton::get().objectTemplate());
>
>                        // do something with this context
>
>                        anyContext.Dispose();
>                }
>        }
>
>        {
>                v8::HandleScope handleScope;
>
>                {
>                        // ** CRASH ->
>                        v8::Persistent<v8::Context> anyContext = v8::Context::New(NULL,
> Singleton::get().objectTemplate());
>                        // <-- CRASH **
>
>                        // do something with this context
>
>                        anyContext.Dispose();
>                }
>        }
>
>        std::cout << "Press a key to exit" << std::endl;
>        getchar();
>
>        return 0;
> }
>

developerdr

unread,
Apr 4, 2011, 5:10:09 AM4/4/11
to v8-users
Dear Matthias,

thanks! Exactly that was my problem.
I strongly would agree that such a cast must be permitted by an
error...

Jan

On 3 Apr., 09:30, Matthias Ernst <matth...@mernst.org> wrote:
Reply all
Reply to author
Forward
0 new messages