Google V8 programming (5) JS call C ++

Source: Internet
Author: User

Recently, due to busy solving the problem of individual Singles' Day, Chapter 5 was updated after so long.

The previous chapter focuses on the context concept of Google V8. In fact, the basic concepts of Google V8 include functiontemplate and objecttemplate, which will be infiltrated in subsequent chapters.

This chapter mainly describes how to use V8 to implement JS call C ++. JS calls C ++, which can be divided into JS calls C ++ functions (global) and c ++ calls.

JS calls C ++ Functions

JS calls the C ++ function, which is extended through functiontemplate and objecttemplate.

Functiontemplate, objecttemplate can be understood as the binding between JS function and C ++ function. Functiontemplate binds JS functions and C ++ functions. Of course, this binding is one-way, and only JavaScript calls C ++ functions. To put it bluntly, functiontemplate and objecttemplate are equivalent to JS functions and objects.

The basic principle is to bind the C ++ function through functiontemplate, and then register the functiontemplate to the JS global. In this way, JS can call the C ++ function.

The Code is as follows:

The above code calls the C ++ yell () function in Js.

The basic steps are as follows:

#include "v8.h"#include <string.h>#include <stdio.h>using namespace v8;using namespace std;Handle<Value> Yell(const Arguments& args) {HandleScope  handle_scope;char buffer[4096];memset(buffer, 0, sizeof(buffer));Handle<String> str = args[0]->ToString();str->WriteAscii(buffer);printf("Yell: %s\n", buffer);return Undefined();}int main(int argc, char** argv) {HandleScope handle_scope;//AHandle<FunctionTemplate> fun = FunctionTemplate::New(Yell);//BHandle<ObjectTemplate> global = ObjectTemplate::New();global->Set(String::New("yell"), fun);//CPersistent<Context> cxt = Context::New(NULL, global);Context::Scope context_scope(cxt);Handle<String> source = String::New("yell('Google V8!')");Handle<Script> script = Script::Compile(source);Handle<Value> result = script->Run();cxt.Dispose();}

Step 1: Define a functiontempte and bind it with the c ++ function:

Handle<FunctionTemplate> fun = FunctionTemplate::New(Yell);

The second part defines an obecttemplate and registers a functiontemplate to the object.

Handle<ObjectTemplate> global = ObjectTemplate::New();global->Set(String::New("yell"), fun);

Part 3: register the object to the JS Global:

Persistent<Context> cxt = Context::New(NULL, global);

JS calls C ++ class

In fact, JavaScript cannot directly use the C ++ class. When a new object is in JS, You need to manually bind the object generated by C ++ with the JS object. This leads to the illusion that JS uses the C ++ class:

var cloudapp = new CloudApp();cloudapp.xxInterface();

In this case, V8 is not powerful enough, and QT's qml (JS-like scripting language) can be automatically bound.

Internalfield

When JS new is an object, C ++ synchronizes the new object, stores the pointer inside C ++, and maintains the pointer list, this is the role of V8 internalfield. All the C ++ pointers to be bound to JS exist in the internalfield, which is actually a list. A V8 object can have any number of internalfields. If you need to use the C ++ pointer stored in interfield, you can get it directly:

Encapsulate the C ++ pointer in internalfield:

//....void* ptr = ...object->SetInternalField(0, External::New(ptr));

The above code saves a C ++ pointer PTR at index 0 of internalfield. In the future, if you need to obtain the pointer, you only need to use index 0 to obtain the pointer.

Obtain the C ++ pointer from internalfield:

Local<External> wrap = Local<External>::Cast(object->GetInternalField(0));void* ptr = wrap->Value();

Object-> getinternalfield (0) is to retrieve the C ++ pointer at Index = 0 from internalfield.

External

Now that we talk about the binding of the C ++ pointer, we have to talk about the external of V8. V8 external is specifically used to encapsulate (WRAP) and unwrap (unwrap) C ++ pointers. The external implementation of V8 is as follows:

Local<Value> External::Wrap(void* value) {  return External::New(value);}void* External::Unwrap(Handle<v8::Value> obj) {  return External::Cast(*obj)->Value();}

External is actually the carrier of the C ++ pointer. This explains why external: New and wrap-> value () was used when the C ++ pointer in internalfield was set and obtained. External: Value () returns the C ++ pointer.

The following code is used to check how JS calls the C ++ class:

// C ++ externtion # include "v8.h" # include "utils. H "# include <iostream >#include <string> using namespace STD; using namespace V8; Enum appstate {idel = 0, loaded, stop}; Class cloudapp {public: cloudapp (int id) {state = idel; appid = ID;} void start () {cout <"cloudapp been loaded id =" <appid <Endl; state = loaded ;}; int getstate () {return state;} int getappid () {return appid;} PRIVATE: appstate state; int Ppid ;}; // callback registered with makeweak. void cloudappweakreferencecallback (persistent <value> object, void * PARAM) {If (cloudapp * cloudapp = static_cast <cloudapp *> (PARAM) {Delete cloudapp ;}} // Save the C ++ pointer as a persistent object through external to avoid handle <external> makeweakcloudapp (void * parameter) {persistent <external> persistentcloudapp = persistent <external>: New (External: New (parameter); // makeweak is very important. When the JS world is new, a clouda After the PP object, // C ++ must also create a corresponding pointer. // After the JS object is parsed, you must find a way to parse the pointer of C ++, which can be achieved through makeweak, // The main purpose of makeweak is to detect the persistent handle except for the unique reference of the current persistent //. If there are no other references, you can analyze the persistent handle, // call the callback of makeweak at the same time. Here we can use the delete // C ++ pointer persistentcloudapp in this callback. makeweak (parameter, cloudappweakreferencecallback); Return persistentcloudapp;} // after parsing the parameters passed in by JS, create the C ++ object cloudapp * newcloudapp (const arguments & ARGs) {cloudapp * cloudapp = NULL; If (ARGs. length () = 1) {cloudapp = new cloudapp (ARGs [0]-> toint32 ()-> value ();} else {V8: throwexception (string :: new ("Too parameter parameters for newcloudapp");} return cloudapp ;}// It is equivalent to the JS constructor. When new cloudapp is used in JS, this callback will be automatically called handle <value> cloudappconstructcallback (const arguments & ARGs) {If (! Args. isconstructcall () return undefined (); cloudapp * cloudapp = newcloudapp (ARGs); handle <Object> Object = args. this (); object-> setinternalfield (0, makeweakcloudapp (cloudapp); Return undefined () ;}handle <value> getstate (const arguments & ARGs) {handle <Object> Self = args. holder (); Local <external> wrap = Local <external>: Cast (self-> getinternalfield (0); void * PTR = wrap-> value (); cloudapp * cloudapp = static _ Cast <cloudapp *> (PTR); Return INTEGER: New (cloudapp-> getstate ();} Handle <value> getappid (const arguments & ARGs) {handle <Object> Self = args. holder (); Local <external> wrap = Local <external>: Cast (self-> getinternalfield (0); void * PTR = wrap-> value (); cloudapp * cloudapp = static_cast <cloudapp *> (PTR); Return INTEGER: New (cloudapp-> getappid ();} Handle <value> Start (const arguments & ARGs) {handle <Object> Se LF = args. holder (); Local <external> wrap = Local <external>: Cast (self-> getinternalfield (0); void * PTR = wrap-> value (); cloudapp * cloudapp = static_cast <cloudapp *> (PTR); cloudapp-> Start (); Return undefined ();} void setupcloudappinterface (handle <objecttemplate> global) {handle <functiontemplate> cloudapp_template = functiontemplate: New (cloudappconstructcallback); cloudapp_template-> setclassname (string: ne W ("cloudapp"); handle <objecttemplate> cloudapp_proto = cloudapp_template-> prototypetemplate (); // In this step, you can use cloudapp_inst-> set (....) // use prototype to better adapt to JS programming: cloudapp_proto-> set (string: New ("START"), functiontemplate: New (start); cloudapp_proto-> set (string :: new ("state"), functiontemplate: New (getstate); cloudapp_proto-> set (string: New ("appid"), functiontemplate: New (getappid )); // ****** is very important !!! Handle <objecttemplate> cloudapp_inst = cloudapp_template-> instancetemplate (); cloudapp_inst-> setinternalfieldcount (1); // register a function from the JS world, the essence is to register a class with the global community of Js. // Therefore, the cloudapp class is also injected to global. Global-> set (string: New ("cloudapp"), cloudapp_template);} void initialnilizeinterface (handle <objecttemplate> global) {setupcloudappinterface (global);} void loadjsandrun () {handle <string> source = readjs ("script. JS "); handle <SCRIPT> script = Script: Compile (source); handle <value> result = script-> Run (); printvalue (result );} void regist2jscontext (handle <objecttemplate> & object, persistent <context> & context) {context = context: New (null, object);} int main (INT argc, char ** argv) {handlescope handle_scope; handle <objecttemplate> global = objecttemplate: New (); persistent <context> context; initialnilizeinterface (global); regist2jscontext (global, context ); context: Scope context_scope (context); loadjsandrun (); context. dispose (); Return 0 ;}

The JS Code is as follows:

//script.jsvar cloudapp = new CloudApp(24);cloudapp.start();var result;

The code above can be used to clarify the meaning of the function name and comment. Finally, let's talk about setinternalfieldcount:

Handle<ObjectTemplate> cloudapp_inst = cloudapp_template->InstanceTemplate();cloudapp_inst->SetInternalFieldCount(1);

Setinsternalfieldcount () is required after other operations are complete. This is to tell V8 that there are several internalfields, and there is only one. Otherwise, during interaction between JS and C ++ pointers, V8 will cross the border when searching for internalfield.

Copyright statement:
Reprinted articles please indicate the source of the original, any for commercial purposes, please contact me: hyman_tan@126.com

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.