Introduce v8::Context::ScriptExecutionCallback
Bug: chromium:965916 Change-Id: I2cb28a8c569c88631bc835b55a04e8629f56cb6f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1630684 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#62034}
This commit is contained in:
parent
dfce0ae6af
commit
e77e65f159
@ -9469,6 +9469,15 @@ class V8_EXPORT Context {
|
||||
template <class T>
|
||||
V8_INLINE MaybeLocal<T> GetDataFromSnapshotOnce(size_t index);
|
||||
|
||||
/**
|
||||
* If callback is set, abort any attempt to execute JavaScript in this
|
||||
* context, call the specified callback, and throw an exception.
|
||||
* To unset abort, pass nullptr as callback.
|
||||
*/
|
||||
typedef void (*AbortScriptExecutionCallback)(Isolate* isolate,
|
||||
Local<Context> context);
|
||||
void SetAbortScriptExecution(AbortScriptExecutionCallback callback);
|
||||
|
||||
/**
|
||||
* Stack-allocated class which sets the execution context for all
|
||||
* operations executed within a local scope.
|
||||
|
@ -5920,6 +5920,19 @@ void Context::SetErrorMessageForCodeGenerationFromStrings(Local<String> error) {
|
||||
context->set_error_message_for_code_gen_from_strings(*error_handle);
|
||||
}
|
||||
|
||||
void Context::SetAbortScriptExecution(
|
||||
Context::AbortScriptExecutionCallback callback) {
|
||||
i::Handle<i::Context> context = Utils::OpenHandle(this);
|
||||
i::Isolate* isolate = context->GetIsolate();
|
||||
if (callback == nullptr) {
|
||||
context->set_script_execution_callback(
|
||||
i::ReadOnlyRoots(isolate).undefined_value());
|
||||
} else {
|
||||
SET_FIELD_WRAPPED(isolate, context, set_script_execution_callback,
|
||||
callback);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
i::Address* GetSerializedDataFromFixedArray(i::Isolate* isolate,
|
||||
i::FixedArray list, size_t index) {
|
||||
|
@ -235,6 +235,22 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
|
||||
return isolate->factory()->undefined_value();
|
||||
}
|
||||
|
||||
if (params.execution_target == Execution::Target::kCallable) {
|
||||
Handle<Context> context = isolate->native_context();
|
||||
if (!context->script_execution_callback().IsUndefined(isolate)) {
|
||||
v8::Context::AbortScriptExecutionCallback callback =
|
||||
v8::ToCData<v8::Context::AbortScriptExecutionCallback>(
|
||||
context->script_execution_callback());
|
||||
v8::Isolate* api_isolate = reinterpret_cast<v8::Isolate*>(isolate);
|
||||
v8::Local<v8::Context> api_context = v8::Utils::ToLocal(context);
|
||||
callback(api_isolate, api_context);
|
||||
DCHECK(!isolate->has_scheduled_exception());
|
||||
// Always throw an exception to abort execution, if callback exists.
|
||||
isolate->ThrowIllegalOperation();
|
||||
return MaybeHandle<Object>();
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder for return value.
|
||||
Object value;
|
||||
|
||||
|
@ -244,6 +244,7 @@ enum ContextLookupFlags {
|
||||
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map) \
|
||||
V(REGEXP_PROTOTYPE_INDEX, JSObject, regexp_prototype) \
|
||||
V(SCRIPT_CONTEXT_TABLE_INDEX, ScriptContextTable, script_context_table) \
|
||||
V(SCRIPT_EXECUTION_CALLBACK_INDEX, Object, script_execution_callback) \
|
||||
V(SECURITY_TOKEN_INDEX, Object, security_token) \
|
||||
V(SERIALIZED_OBJECTS, FixedArray, serialized_objects) \
|
||||
V(SET_VALUE_ITERATOR_MAP_INDEX, Map, set_value_iterator_map) \
|
||||
|
@ -10715,6 +10715,63 @@ static void GlobalObjectInstancePropertiesGet(
|
||||
ApiTestFuzzer::Fuzz();
|
||||
}
|
||||
|
||||
static int script_execution_count = 0;
|
||||
static void ScriptExecutionCallback(v8::Isolate* isolate,
|
||||
Local<Context> context) {
|
||||
script_execution_count++;
|
||||
}
|
||||
|
||||
THREADED_TEST(ContextScriptExecutionCallback) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
LocalContext context;
|
||||
|
||||
{
|
||||
v8::TryCatch try_catch(isolate);
|
||||
script_execution_count = 0;
|
||||
ExpectTrue("1 + 1 == 2");
|
||||
CHECK_EQ(0, script_execution_count);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
}
|
||||
|
||||
context->SetAbortScriptExecution(ScriptExecutionCallback);
|
||||
|
||||
{ // Function binding does not trigger callback.
|
||||
v8::Local<v8::FunctionTemplate> function_template =
|
||||
v8::FunctionTemplate::New(isolate, DummyCallHandler);
|
||||
v8::Local<v8::Function> function =
|
||||
function_template->GetFunction(context.local()).ToLocalChecked();
|
||||
|
||||
v8::TryCatch try_catch(isolate);
|
||||
script_execution_count = 0;
|
||||
|
||||
CHECK_EQ(13.4,
|
||||
function->Call(context.local(), v8::Undefined(isolate), 0, nullptr)
|
||||
.ToLocalChecked()
|
||||
->NumberValue(context.local())
|
||||
.FromJust());
|
||||
CHECK_EQ(0, script_execution_count);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
}
|
||||
|
||||
{ // Script execution triggers callback.
|
||||
v8::TryCatch try_catch(isolate);
|
||||
script_execution_count = 0;
|
||||
CHECK(CompileRun(context.local(), "2 + 2 == 4").IsEmpty());
|
||||
CHECK_EQ(1, script_execution_count);
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
|
||||
context->SetAbortScriptExecution(nullptr);
|
||||
|
||||
{ // Script execution no longer triggers callback.
|
||||
v8::TryCatch try_catch(isolate);
|
||||
script_execution_count = 0;
|
||||
ExpectTrue("2 + 2 == 4");
|
||||
CHECK_EQ(0, script_execution_count);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
}
|
||||
}
|
||||
|
||||
THREADED_TEST(GlobalObjectInstanceProperties) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
|
Loading…
Reference in New Issue
Block a user