Commit e77e65f1 authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

Introduce v8::Context::ScriptExecutionCallback

Bug: chromium:965916
Change-Id: I2cb28a8c569c88631bc835b55a04e8629f56cb6f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1630684Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62034}
parent dfce0ae6
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment