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