Accessing global object in javascript function call

101 views
Skip to first unread message

Bryan Grim

unread,
Jul 21, 2016, 5:58:49 PM7/21/16
to v8-users
I have a need to execute functions in completely isolated contexts.  I'm not having much luck, though.  My context's global object does not seem accessible to a call to my javascript function. 

Using the shell.cc example, I added these callbacks:

void SetupContext(const v8::FunctionCallbackInfo<v8::Value>& args);
void CallInContext(const v8::FunctionCallbackInfo<v8::Value>& args);
void PrintGlobalContext(const v8::FunctionCallbackInfo<v8::Value>& args);


Implemented like so:

void SetupContext(const v8::FunctionCallbackInfo<v8::Value>& args)
{
   
//Get the default isolate
    v8
::Isolate* pIsolate = args.GetIsolate();
   
//create a stack allocated handle scope
    v8
::HandleScope handle_scope(pIsolate);
   
//Create the global template

   
if (args.Length() < 2)
   
{
        args
.GetIsolate()->ThrowException(
            v8
::String::NewFromUtf8(args.GetIsolate(), "Not enough parameters for call.  Correct format: ([ontext name], [script to run])",
                v8
::NewStringType::kNormal).ToLocalChecked());
       
return;
   
}
    v8
::String::Utf8Value argContextName(args[0]);
    v8
::String::Utf8Value argContextGlobals(args[1]);
    std
::string strScriptName = ToCString(argContextName);
   
if (!sContextMap[strScriptName].IsEmpty())
   
{
       
// assume it's not an error for, as we should be able to continue on no problem.
       
return;
   
}

    v8
::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
   
//Create the context
    v8
::Local<v8::Context> context = v8::Context::New(pIsolate, NULL, global_template);
    v8
::Context::Scope context_scope(context);

    v8
::Local<v8::String> scriptName = v8::String::NewFromUtf8(pIsolate, *argContextName, v8::NewStringType::kNormal).ToLocalChecked();
    v8
::Local<v8::String> source     = v8::String::NewFromUtf8(pIsolate, *argContextGlobals, v8::NewStringType::kNormal).ToLocalChecked();

   
bool success = ExecuteString(pIsolate, source, scriptName, false, true);

   
if (success)
   
{
       
if (sContextMap[strScriptName].IsEmpty())
       
{
            v8
::Local<v8::Value> security = v8::String::NewFromUtf8(pIsolate, "Security!", v8::NewStringType::kNormal).ToLocalChecked();
            context
->SetSecurityToken(security);
            sContextMap
[strScriptName].Reset(pIsolate, context);
       
}
        args
.GetReturnValue().Set(
                    v8
::String::NewFromUtf8(args.GetIsolate(), "Awesome!!",
                    v8
::NewStringType::kNormal).ToLocalChecked());
   
}
   
else
   
{
        args
.GetReturnValue().Set(
            v8
::String::NewFromUtf8(args.GetIsolate(), "Totally Not Awesome...",
                v8
::NewStringType::kNormal).ToLocalChecked());

   
}
}

As you can see, I keep the newly created contexts in a map:  static std::map<std::string, v8::Persistent<v8::Context>> sContextMap;  They are created when this script runs:
setupContext("one","var number1 = 4;");

I want to be able to call a function within this new context, by running this:
var num3 = 0;
var num4 = 0;
callInContext("one", function (outerNum1, outerNum2) { var num2 = 3; outerNum1 = number1; outerNum2 = outerNum1 + num2; }, num3, num4);

The CallinContext function looks like this:

void CallInContext(const v8::FunctionCallbackInfo<v8::Value>& args)
{
   
//Get the default isolate
    v8
::Isolate* pIsolate = args.GetIsolate();
   
//create a stack allocated handle scope
    v8
::HandleScope handle_scope(pIsolate);

   
if (args.Length() < 4)
   
{
        args
.GetIsolate()->ThrowException(
            v8
::String::NewFromUtf8(args.GetIsolate(), "Not enough parameters for call.",
                v8
::NewStringType::kNormal).ToLocalChecked());
       
return;
   
}

   
int argIndex = 0;
    std
::string ruleContext = ToCString(v8::String::Utf8Value(args[argIndex]));
    v8
::String::Utf8Value argContext(args[argIndex]);
   
auto context = sContextMap[ruleContext].Get(pIsolate);

   
if (!context.IsEmpty())
   
{
        v8
::Context::Scope cs(context);

       
auto scriptFun = v8::Local<v8::Function>::Cast(args[1]);
       
const int argc = 2;
        v8
::Local<v8::Value> argv[argc];
        argv
[0] = args[2];
        argv
[1] = args[3];

       
auto result = scriptFun->Call(context->Global(), argc, argv);


   
}
}

When I run it all, though, I get a complaint that "number1 is not defined."

If I run this script, though
printGlobalContext("one");

and trigger this function:
void PrintGlobalContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
   
bool first = true;
   
for (int i = 0; i < args.Length(); i++)
   
{
        v8
::HandleScope handle_scope(args.GetIsolate());
       
if (first) {
            first
= false;
       
}
       
else {
            printf
(" ");
       
}
        v8
::String::Utf8Value str(args[i]);
       
const char* cstr = ToCString(str);

       
auto context = sContextMap[cstr].Get(args.GetIsolate());
       
if (!context.IsEmpty())
       
{
            v8
::Context::Scope cs(context);
           
auto global = context->Global();
            v8
::Local<v8::Array> keys = global->GetOwnPropertyNames();
            uint32_t length
= keys->Length();
           
for (uint32_t i = 0; i < length; ++i) {
                v8
::Local<v8::Value> key = keys->Get(i);
                v8
::Local<v8::String> key_str(key->ToString());
                v8
::String::Utf8Value tag(key_str);
                v8
::String::Utf8Value val(global->Get(key_str));

                printf
("%s: %s\n", ToCString(tag), ToCString(val));
           
}
       
}
   
}
    printf
("\n");
    fflush
(stdout);
}

It prints:
number1: 4

Jochen Eisinger

unread,
Jul 22, 2016, 3:39:56 AM7/22/16
to v8-users
Function::Call only allows you to set the receiver, not rebind the function to a different context.

You should be able to access number1 using this.number1.

You could pass the script in as a string and compile it for the target context for example.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages