Introduce BeforeCallEnteredCallback.
This new callback is similar to CallCompletedCallback, but is executed before the call has been made. Added Isolate* parameter to CallCompletedCallback, marking previous one as deprecated. BUG=chromium:585949 LOG=Y Review URL: https://codereview.chromium.org/1689863002 Cr-Commit-Position: refs/heads/master@{#34167}
This commit is contained in:
parent
b62bf1e6fb
commit
0e9ea48c46
27
include/v8.h
27
include/v8.h
@ -5009,8 +5009,10 @@ typedef void (*MemoryAllocationCallback)(ObjectSpace space,
|
||||
AllocationAction action,
|
||||
int size);
|
||||
|
||||
// --- Leave Script Callback ---
|
||||
typedef void (*CallCompletedCallback)();
|
||||
// --- Enter/Leave Script Callback ---
|
||||
typedef void (*BeforeCallEnteredCallback)(Isolate*);
|
||||
typedef void (*CallCompletedCallback)(Isolate*);
|
||||
typedef void (*DeprecatedCallCompletedCallback)();
|
||||
|
||||
// --- Promise Reject Callback ---
|
||||
enum PromiseRejectEvent {
|
||||
@ -5812,6 +5814,19 @@ class V8_EXPORT Isolate {
|
||||
*/
|
||||
void SetEventLogger(LogEventCallback that);
|
||||
|
||||
/**
|
||||
* Adds a callback to notify the host application right before a script
|
||||
* is about to run. If a script re-enters the runtime during executing, the
|
||||
* BeforeCallEnteredCallback is invoked for each re-entrance.
|
||||
* Executing scripts inside the callback will re-trigger the callback.
|
||||
*/
|
||||
void AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
|
||||
|
||||
/**
|
||||
* Removes callback that was installed by AddBeforeCallEnteredCallback.
|
||||
*/
|
||||
void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
|
||||
|
||||
/**
|
||||
* Adds a callback to notify the host application when a script finished
|
||||
* running. If a script re-enters the runtime during executing, the
|
||||
@ -5820,12 +5835,18 @@ class V8_EXPORT Isolate {
|
||||
* further callbacks.
|
||||
*/
|
||||
void AddCallCompletedCallback(CallCompletedCallback callback);
|
||||
V8_DEPRECATE_SOON(
|
||||
"Use callback with parameter",
|
||||
void AddCallCompletedCallback(DeprecatedCallCompletedCallback callback));
|
||||
|
||||
/**
|
||||
* Removes callback that was installed by AddCallCompletedCallback.
|
||||
*/
|
||||
void RemoveCallCompletedCallback(CallCompletedCallback callback);
|
||||
|
||||
V8_DEPRECATE_SOON(
|
||||
"Use callback with parameter",
|
||||
void RemoveCallCompletedCallback(
|
||||
DeprecatedCallCompletedCallback callback));
|
||||
|
||||
/**
|
||||
* Set callback to notify about promise reject with no handler, or
|
||||
|
28
src/api.cc
28
src/api.cc
@ -168,6 +168,7 @@ class CallDepthScope {
|
||||
isolate_->IncrementJsCallsFromApiCounter();
|
||||
isolate_->handle_scope_implementer()->IncrementCallDepth();
|
||||
if (!context_.IsEmpty()) context_->Enter();
|
||||
if (do_callback_) isolate_->FireBeforeCallEnteredCallback();
|
||||
}
|
||||
~CallDepthScope() {
|
||||
if (!context_.IsEmpty()) context_->Exit();
|
||||
@ -7372,6 +7373,20 @@ void Isolate::SetEventLogger(LogEventCallback that) {
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback) {
|
||||
if (callback == NULL) return;
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->AddBeforeCallEnteredCallback(callback);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveBeforeCallEnteredCallback(
|
||||
BeforeCallEnteredCallback callback) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->RemoveBeforeCallEnteredCallback(callback);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddCallCompletedCallback(CallCompletedCallback callback) {
|
||||
if (callback == NULL) return;
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
@ -7385,6 +7400,19 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddCallCompletedCallback(
|
||||
DeprecatedCallCompletedCallback callback) {
|
||||
AddCallCompletedCallback(reinterpret_cast<CallCompletedCallback>(callback));
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveCallCompletedCallback(
|
||||
DeprecatedCallCompletedCallback callback) {
|
||||
RemoveCallCompletedCallback(
|
||||
reinterpret_cast<CallCompletedCallback>(callback));
|
||||
}
|
||||
|
||||
|
||||
void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
|
||||
if (callback == NULL) return;
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
|
@ -2608,6 +2608,31 @@ Handle<JSObject> Isolate::GetSymbolRegistry() {
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback) {
|
||||
for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
|
||||
if (callback == before_call_entered_callbacks_.at(i)) return;
|
||||
}
|
||||
before_call_entered_callbacks_.Add(callback);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveBeforeCallEnteredCallback(
|
||||
BeforeCallEnteredCallback callback) {
|
||||
for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
|
||||
if (callback == before_call_entered_callbacks_.at(i)) {
|
||||
before_call_entered_callbacks_.Remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::FireBeforeCallEnteredCallback() {
|
||||
for (int i = 0; i < before_call_entered_callbacks_.length(); i++) {
|
||||
before_call_entered_callbacks_.at(i)(reinterpret_cast<v8::Isolate*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddCallCompletedCallback(CallCompletedCallback callback) {
|
||||
for (int i = 0; i < call_completed_callbacks_.length(); i++) {
|
||||
if (callback == call_completed_callbacks_.at(i)) return;
|
||||
@ -2633,10 +2658,10 @@ void Isolate::FireCallCompletedCallback() {
|
||||
if (!handle_scope_implementer()->CallDepthIsZero()) return;
|
||||
if (run_microtasks) RunMicrotasks();
|
||||
// Fire callbacks. Increase call depth to prevent recursive callbacks.
|
||||
v8::Isolate::SuppressMicrotaskExecutionScope suppress(
|
||||
reinterpret_cast<v8::Isolate*>(this));
|
||||
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this);
|
||||
v8::Isolate::SuppressMicrotaskExecutionScope suppress(isolate);
|
||||
for (int i = 0; i < call_completed_callbacks_.length(); i++) {
|
||||
call_completed_callbacks_.at(i)();
|
||||
call_completed_callbacks_.at(i)(isolate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1055,6 +1055,10 @@ class Isolate {
|
||||
void RemoveCallCompletedCallback(CallCompletedCallback callback);
|
||||
void FireCallCompletedCallback();
|
||||
|
||||
void AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
|
||||
void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
|
||||
void FireBeforeCallEnteredCallback();
|
||||
|
||||
void SetPromiseRejectCallback(PromiseRejectCallback callback);
|
||||
void ReportPromiseReject(Handle<JSObject> promise, Handle<Object> value,
|
||||
v8::PromiseRejectEvent event);
|
||||
@ -1318,6 +1322,9 @@ class Isolate {
|
||||
int next_unique_sfi_id_;
|
||||
#endif
|
||||
|
||||
// List of callbacks before a Call starts execution.
|
||||
List<BeforeCallEnteredCallback> before_call_entered_callbacks_;
|
||||
|
||||
// List of callbacks when a Call completes.
|
||||
List<CallCompletedCallback> call_completed_callbacks_;
|
||||
|
||||
|
@ -20790,20 +20790,34 @@ THREADED_TEST(ForeignFunctionReceiver) {
|
||||
|
||||
|
||||
uint8_t callback_fired = 0;
|
||||
uint8_t before_call_entered_callback_count1 = 0;
|
||||
uint8_t before_call_entered_callback_count2 = 0;
|
||||
|
||||
|
||||
void CallCompletedCallback1() {
|
||||
void CallCompletedCallback1(v8::Isolate*) {
|
||||
v8::base::OS::Print("Firing callback 1.\n");
|
||||
callback_fired ^= 1; // Toggle first bit.
|
||||
}
|
||||
|
||||
|
||||
void CallCompletedCallback2() {
|
||||
void CallCompletedCallback2(v8::Isolate*) {
|
||||
v8::base::OS::Print("Firing callback 2.\n");
|
||||
callback_fired ^= 2; // Toggle second bit.
|
||||
}
|
||||
|
||||
|
||||
void BeforeCallEnteredCallback1(v8::Isolate*) {
|
||||
v8::base::OS::Print("Firing before call entered callback 1.\n");
|
||||
before_call_entered_callback_count1++;
|
||||
}
|
||||
|
||||
|
||||
void BeforeCallEnteredCallback2(v8::Isolate*) {
|
||||
v8::base::OS::Print("Firing before call entered callback 2.\n");
|
||||
before_call_entered_callback_count2++;
|
||||
}
|
||||
|
||||
|
||||
void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
int32_t level =
|
||||
args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust();
|
||||
@ -20836,36 +20850,54 @@ TEST(CallCompletedCallback) {
|
||||
env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
|
||||
env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
|
||||
env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
|
||||
env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
|
||||
env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback2);
|
||||
env->GetIsolate()->AddBeforeCallEnteredCallback(BeforeCallEnteredCallback1);
|
||||
v8::base::OS::Print("--- Script (1) ---\n");
|
||||
callback_fired = 0;
|
||||
before_call_entered_callback_count1 = 0;
|
||||
before_call_entered_callback_count2 = 0;
|
||||
Local<Script> script =
|
||||
v8::Script::Compile(env.local(), v8_str("recursion(0)")).ToLocalChecked();
|
||||
script->Run(env.local()).ToLocalChecked();
|
||||
CHECK_EQ(3, callback_fired);
|
||||
CHECK_EQ(4, before_call_entered_callback_count1);
|
||||
CHECK_EQ(4, before_call_entered_callback_count2);
|
||||
|
||||
v8::base::OS::Print("\n--- Script (2) ---\n");
|
||||
callback_fired = 0;
|
||||
before_call_entered_callback_count1 = 0;
|
||||
before_call_entered_callback_count2 = 0;
|
||||
env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
|
||||
env->GetIsolate()->RemoveBeforeCallEnteredCallback(
|
||||
BeforeCallEnteredCallback1);
|
||||
script->Run(env.local()).ToLocalChecked();
|
||||
CHECK_EQ(2, callback_fired);
|
||||
CHECK_EQ(0, before_call_entered_callback_count1);
|
||||
CHECK_EQ(4, before_call_entered_callback_count2);
|
||||
|
||||
v8::base::OS::Print("\n--- Function ---\n");
|
||||
callback_fired = 0;
|
||||
before_call_entered_callback_count1 = 0;
|
||||
before_call_entered_callback_count2 = 0;
|
||||
Local<Function> recursive_function = Local<Function>::Cast(
|
||||
env->Global()->Get(env.local(), v8_str("recursion")).ToLocalChecked());
|
||||
v8::Local<Value> args[] = {v8_num(0)};
|
||||
recursive_function->Call(env.local(), env->Global(), 1, args)
|
||||
.ToLocalChecked();
|
||||
CHECK_EQ(2, callback_fired);
|
||||
CHECK_EQ(0, before_call_entered_callback_count1);
|
||||
CHECK_EQ(4, before_call_entered_callback_count2);
|
||||
}
|
||||
|
||||
|
||||
void CallCompletedCallbackNoException() {
|
||||
void CallCompletedCallbackNoException(v8::Isolate*) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
CompileRun("1+1;");
|
||||
}
|
||||
|
||||
|
||||
void CallCompletedCallbackException() {
|
||||
void CallCompletedCallbackException(v8::Isolate*) {
|
||||
v8::HandleScope scope(CcTest::isolate());
|
||||
CompileRun("throw 'second exception';");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user