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:
dgozman 2016-02-19 10:48:09 -08:00 committed by Commit bot
parent b62bf1e6fb
commit 0e9ea48c46
5 changed files with 123 additions and 10 deletions

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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_;

View File

@ -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';");
}