Retrieving a context pointer in C++ function callback

954 views
Skip to first unread message

ericzundel

unread,
Feb 20, 2009, 6:37:43 AM2/20/09
to v8-users
(reposted from v8-dev to this group)

I'm working on a Chrome plugin that uses a separate context for V8
for
several entities. I've been using the sample shell.cc as an example
of how to bind a top level function to a C++ method and have read
through the embedder's guide. Here's what I have so far:

[CODE]
MyClass::init() {
v8::HandleScope handle_scope; // For allocation of local handles.
// Create a template for the global object.
v8::Handle<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New();
// Bind the global '__hLoad' function to the C++ Load callback.
global_template->Set(v8::String::New("__hLoad"),
v8::FunctionTemplate::New(&MyClass::Load));
...
}

// This method is declared static
v8::Handle<v8::Value> MyClass::Load(const v8::Arguments& args) {
...
return v8::Undefined();
}
[/CODE]


This works fine - My JavaScript methods can call __hLoad() and
MyClass::Load() is invoked. However, my question is, how do I get
the
instance pointer of type MyClass from init() into the MyClass::Load
static method? The examples in the docs don't seem to apply (I've
gotten many crashes trying to work it out.)
-Eric.

Ondrej Zara

unread,
Feb 20, 2009, 6:44:00 AM2/20/09
to v8-u...@googlegroups.com
Hi,

from what I know, it is not a good ideat to provide a _method_
callback. Use a function callback instead and set the reference to
your instance as an internal field of a JS class. In your callback
function, you then load the reference from internal field and do
whatever you want with it...


Ondrej

Eric Ayers

unread,
Feb 20, 2009, 8:08:51 AM2/20/09
to v8-u...@googlegroups.com
Sorry, I've been using the term method & function interchangeably and
I'm not sure what your point about the difference between 'method' and
'function' is.

There needs to be just one copy the function "__hLoad" and
"__hSendData" in this v8 context. I want to match up the function
calls with the C++ class instance associated with the v8 context so I
can route the data out of this v8 context to the correct destination.

My JS code looks like this:

myapi = {
prop1 : "value" // an example API property
};

/**
* Load external JavaScript from another file.
* path (String) - path relative to the config directory.
*/
myapi.load = function(path) {
// Instruct the plugin to load the specified file.
__hLoad(path);
}

/**
* Send a data string to the plugin, encoding the arguments as JSON.
*/
myapi.sendData = function(rule, tabId, timestamp, description, color,
refRecord) {
if (timestamp == null) {
throw new Error( rule + ": timestamp must be defined");
}
var value = {'rule' : rule,
'tabId' : tabId,
'timestamp' : timestamp,
'description' : description,
'color' : color,
'refRecord' : refRecord };
// Encode the object as JSON and send it to the plugin.
var jsonString = JSON.stringify(value);
__hSendData(jsonString);
}

Could you provide more details or a pointer on how to "set the
reference to your instance as an internal field of a JS class?" My
attempts to do this have resulted in crashes.

Alex Iskander

unread,
Feb 20, 2009, 8:20:09 AM2/20/09
to v8-u...@googlegroups.com
Difference between method and function:
class MyClass
{
public:
    void myMethod() { doSomething(); }
    static void MyFunction() { DoSomething(); }
}

void SomeFunction() { DoSomething(); }


Basically, methods belong to instances of a class. Functions do not. Methods are passed an invisible extra argument ("this"), functions are not.

What it looks like you want to do is actually create the "myapi" class in C++. In this case, myapi would be a FunctionTemplate that also has an InstanceTemplate, and perhaps a PrototypeTemplate.

Have you looked thoroughly through the Embedder's Guide, especially the part about using ObjectTemplates and internal fields?

Alex
Alex Iskander
Web and Marketing
TPSi



Eric Ayers

unread,
Feb 20, 2009, 10:51:24 AM2/20/09
to v8-u...@googlegroups.com
I appreciate the pointers thus far.

I re-cast my code to create an object template, then create an
instance of the object to add my C++ instance pointer too. I keep
getting a crash in the ObjectTemplate->NewInstance() method. I've
tried moving the NewInstance() call around to different places in the
code and re-ordering the steps of creating the templates and calling
Set(), but the crash always stays in the same place.

v8 version r1040:

[CODE]
// C++ Header
class MyClass {
public:
// Private constructor for singleton class.
MyClass();
~MyClass();

private:
// Initialize the singleton
void Init();

// Callbacks for functions registered as built-ins.
static v8::Handle<v8::Value> AddData(const v8::Arguments& args);
static v8::Handle<v8::Value> Load(const v8::Arguments& args);
static v8::Handle<v8::Value> Log(const v8::Arguments& args);

// Execution environment containing built-in functions.
v8::Persistent<v8::Context> execution_context_;
};



// C++ code for MyClass::Init
void MyClass::Init() {
v8::HandleScope handle_scope; // For allocation of local handles.

// Create a template for the global object.
v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();

v8::Handle<v8::ObjectTemplate> myApi_template = v8::ObjectTemplate::New();

// Bind C++ funtions as callbacks
myApi_template->SetInternalFieldCount(1);

// Bind the global '__hLog' function to the C++ Print callback.
myApi_template->Set(v8::String::New("__hLog"),
v8::FunctionTemplate::New(&apu::MyClass::Log));
// Bind the global '__hLoad' function to the C++ Load callback.
myApi_template->Set(v8::String::New("__hLoad"),
v8::FunctionTemplate::New(&apu::MyClass::Load));
// Bind the '__hAddData' function
myApi_template->Set(v8::String::New("__hAddData"),
v8::FunctionTemplate::New(&apu::MyClass::AddData));

// *** myApi_template->NewInstance crashes
v8::Local<v8::Object> myApi_instance = myApi_template->NewInstance();
myApi_instance->SetInternalField(0, v8::External::New(this));

// Create a new execution environment containing the built-in
// functions
v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);

execution_context_ = v8::Persistent<v8::Context>::New(context);

// Create a top level object named 'myApi' in the global object
context->Global()->Set(v8::String::New("myApi"), myApi_instance);

...
[/CODE]

Stack trace:
npmyplugin.dll!v8::internal::Array::length() Line 1375 + 0xa bytes C++
npmyplugin.dll!v8::internal::FixedArray::get(int index=0x00000004)
Line 1157 + 0xe bytes C++
npmyplugin.dll!v8::internal::Context::global() Line 238 + 0xa bytes C++
npmyplugin.dll!v8::internal::Context::builtins() Line 37 + 0x8 bytes C++
npmyplugin.dll!v8::internal::Top::builtins() Line 267 + 0xb bytes C++
npmyplugin.dll!v8::internal::Execution::InstantiateObject(v8::internal::Handle<v8::internal::ObjectTemplateInfo>
data={...}, bool * exc=0x05e4f3ff) Line 473 + 0x13 bytes C++
npmyplugin.dll!v8::ObjectTemplate::NewInstance() Line 2360 + 0x20 bytes C++
> npmyplugin.dll!apu::MyClass::Init() Line 96 C++
...

Alex Iskander

unread,
Feb 20, 2009, 10:57:12 AM2/20/09
to v8-u...@googlegroups.com
I believe you need to be in a Context Scope before you can call
NewInstance.

Try something like this instead:

// Create a new execution environment containing the built-in
// functions
v8::Handle<v8::Context> context = v8::Context::New(NULL,
global_template);

execution_context_ = v8::Persistent<v8::Context>::New(context);

// Create a top level object named 'myApi' in the global object
context->Global()->Set(v8::String::New("myApi"), myApi_instance);

/* ADD THIS LINE TO ENTER CONTEXT SCOPE: */
v8::Context::Scope context_scope(execution_context);

/* NOW CREATE THE INSTANCE */
// *** myApi_template->NewInstance crashes
v8::Local<v8::Object> myApi_instance = myApi_template->NewInstance();
myApi_instance->SetInternalField(0, v8::External::New(this));


Alex

Eric Ayers

unread,
Feb 20, 2009, 3:08:05 PM2/20/09
to v8-u...@googlegroups.com
Thank you Alex. That was the problem!

bmbsage

unread,
Aug 16, 2012, 4:42:09 PM8/16/12
to v8-u...@googlegroups.com
ericzundel  what was your final code?
I'm having the same issue..?
Reply all
Reply to author
Forward
0 new messages