%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/d8/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/d8/async-hooks-wrapper.cc |
// Copyright 2018 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/d8/async-hooks-wrapper.h" #include "include/v8-function.h" #include "include/v8-local-handle.h" #include "include/v8-primitive.h" #include "include/v8-template.h" #include "src/api/api-inl.h" #include "src/api/api.h" #include "src/d8/d8.h" #include "src/execution/isolate-inl.h" #include "src/objects/managed-inl.h" namespace v8 { namespace { std::shared_ptr<AsyncHooksWrap> UnwrapHook( const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(i::ValidateCallbackInfo(info)); v8::Isolate* v8_isolate = info.GetIsolate(); HandleScope scope(v8_isolate); Local<Object> hook = info.This(); AsyncHooks* hooks = PerIsolateData::Get(v8_isolate)->GetAsyncHooks(); if (!hooks->async_hook_ctor.Get(v8_isolate)->HasInstance(hook)) { v8_isolate->ThrowError( "Invalid 'this' passed instead of AsyncHooks instance"); return nullptr; } i::Handle<i::Object> handle = Utils::OpenHandle(*hook->GetInternalField(0)); return i::Handle<i::Managed<AsyncHooksWrap>>::cast(handle)->get(); } void EnableHook(const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(i::ValidateCallbackInfo(info)); auto wrap = UnwrapHook(info); if (wrap) wrap->Enable(); } void DisableHook(const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(i::ValidateCallbackInfo(info)); auto wrap = UnwrapHook(info); if (wrap) wrap->Disable(); } } // namespace AsyncHooks::AsyncHooks(v8::Isolate* v8_isolate) : v8_isolate_(v8_isolate) { AsyncContext ctx; ctx.execution_async_id = 1; ctx.trigger_async_id = 0; asyncContexts.push(ctx); current_async_id = 1; HandleScope handle_scope(v8_isolate_); async_hook_ctor.Reset(v8_isolate_, FunctionTemplate::New(v8_isolate_)); async_hook_ctor.Get(v8_isolate_) ->SetClassName(String::NewFromUtf8Literal(v8_isolate_, "AsyncHook")); async_hooks_templ.Reset(v8_isolate_, async_hook_ctor.Get(v8_isolate_)->InstanceTemplate()); async_hooks_templ.Get(v8_isolate_)->SetInternalFieldCount(1); async_hooks_templ.Get(v8_isolate_) ->Set(v8_isolate_, "enable", FunctionTemplate::New(v8_isolate_, EnableHook)); async_hooks_templ.Get(v8_isolate_) ->Set(v8_isolate_, "disable", FunctionTemplate::New(v8_isolate_, DisableHook)); async_id_symbol.Reset(v8_isolate_, Private::New(v8_isolate_)); trigger_id_symbol.Reset(v8_isolate_, Private::New(v8_isolate_)); v8_isolate_->SetPromiseHook(ShellPromiseHook); } AsyncHooks::~AsyncHooks() { v8_isolate_->SetPromiseHook(nullptr); async_wraps_.clear(); } void AsyncHooksWrap::Enable() { enabled_ = true; } void AsyncHooksWrap::Disable() { enabled_ = false; } v8::Local<v8::Function> AsyncHooksWrap::init_function() const { return init_function_.Get(isolate_); } void AsyncHooksWrap::set_init_function(v8::Local<v8::Function> value) { init_function_.Reset(isolate_, value); } v8::Local<v8::Function> AsyncHooksWrap::before_function() const { return before_function_.Get(isolate_); } void AsyncHooksWrap::set_before_function(v8::Local<v8::Function> value) { before_function_.Reset(isolate_, value); } v8::Local<v8::Function> AsyncHooksWrap::after_function() const { return after_function_.Get(isolate_); } void AsyncHooksWrap::set_after_function(v8::Local<v8::Function> value) { after_function_.Reset(isolate_, value); } v8::Local<v8::Function> AsyncHooksWrap::promiseResolve_function() const { return promiseResolve_function_.Get(isolate_); } void AsyncHooksWrap::set_promiseResolve_function( v8::Local<v8::Function> value) { promiseResolve_function_.Reset(isolate_, value); } async_id_t AsyncHooks::GetExecutionAsyncId() const { return asyncContexts.top().execution_async_id; } async_id_t AsyncHooks::GetTriggerAsyncId() const { return asyncContexts.top().trigger_async_id; } Local<Object> AsyncHooks::CreateHook( const v8::FunctionCallbackInfo<v8::Value>& info) { DCHECK(i::ValidateCallbackInfo(info)); v8::Isolate* v8_isolate = info.GetIsolate(); EscapableHandleScope handle_scope(v8_isolate); if (v8_isolate->IsExecutionTerminating()) { return Local<Object>(); } Local<Context> currentContext = v8_isolate->GetCurrentContext(); if (info.Length() != 1 || !info[0]->IsObject()) { v8_isolate->ThrowError("Invalid arguments passed to createHook"); return Local<Object>(); } std::shared_ptr<AsyncHooksWrap> wrap = std::make_shared<AsyncHooksWrap>(v8_isolate); Local<Object> fn_obj = info[0].As<Object>(); #define SET_HOOK_FN(name) \ MaybeLocal<Value> name##_maybe_func = fn_obj->Get( \ currentContext, String::NewFromUtf8Literal(v8_isolate, #name)); \ Local<Value> name##_func; \ if (name##_maybe_func.ToLocal(&name##_func) && name##_func->IsFunction()) { \ wrap->set_##name##_function(name##_func.As<Function>()); \ } SET_HOOK_FN(init); SET_HOOK_FN(before); SET_HOOK_FN(after); SET_HOOK_FN(promiseResolve); #undef SET_HOOK_FN Local<Object> obj = async_hooks_templ.Get(v8_isolate) ->NewInstance(currentContext) .ToLocalChecked(); i::Handle<i::Object> managed = i::Managed<AsyncHooksWrap>::FromSharedPtr( reinterpret_cast<i::Isolate*>(v8_isolate), sizeof(AsyncHooksWrap), wrap); obj->SetInternalField(0, Utils::ToLocal(managed)); async_wraps_.push_back(std::move(wrap)); return handle_scope.Escape(obj); } void AsyncHooks::ShellPromiseHook(PromiseHookType type, Local<Promise> promise, Local<Value> parent) { v8::Isolate* v8_isolate = promise->GetIsolate(); AsyncHooks* hooks = PerIsolateData::Get(v8_isolate)->GetAsyncHooks(); if (v8_isolate->IsExecutionTerminating() || hooks->skip_after_termination_) { hooks->skip_after_termination_ = true; return; } i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate); HandleScope handle_scope(v8_isolate); // Temporarily clear any scheduled_exception to allow evaluating JS that can // throw. i::Handle<i::Object> scheduled_exception; if (i_isolate->has_scheduled_exception()) { scheduled_exception = handle(i_isolate->scheduled_exception(), i_isolate); i_isolate->clear_scheduled_exception(); } { TryCatch try_catch(v8_isolate); try_catch.SetVerbose(true); Local<Context> currentContext = v8_isolate->GetCurrentContext(); DCHECK(!currentContext.IsEmpty()); if (type == PromiseHookType::kInit) { ++hooks->current_async_id; Local<Integer> async_id = Integer::New(v8_isolate, hooks->current_async_id); CHECK(!promise ->HasPrivate(currentContext, hooks->async_id_symbol.Get(v8_isolate)) .ToChecked()); promise->SetPrivate(currentContext, hooks->async_id_symbol.Get(v8_isolate), async_id); if (parent->IsPromise()) { Local<Promise> parent_promise = parent.As<Promise>(); Local<Value> parent_async_id = parent_promise ->GetPrivate(currentContext, hooks->async_id_symbol.Get(v8_isolate)) .ToLocalChecked(); promise->SetPrivate(currentContext, hooks->trigger_id_symbol.Get(v8_isolate), parent_async_id); } else { CHECK(parent->IsUndefined()); promise->SetPrivate(currentContext, hooks->trigger_id_symbol.Get(v8_isolate), Integer::New(v8_isolate, 0)); } } else if (type == PromiseHookType::kBefore) { AsyncContext ctx; ctx.execution_async_id = promise ->GetPrivate(currentContext, hooks->async_id_symbol.Get(v8_isolate)) .ToLocalChecked() .As<Integer>() ->Value(); ctx.trigger_async_id = promise ->GetPrivate(currentContext, hooks->trigger_id_symbol.Get(v8_isolate)) .ToLocalChecked() .As<Integer>() ->Value(); hooks->asyncContexts.push(ctx); } else if (type == PromiseHookType::kAfter) { hooks->asyncContexts.pop(); } if (!i::StackLimitCheck{i_isolate}.HasOverflowed()) { for (size_t i = 0; i < hooks->async_wraps_.size(); ++i) { std::shared_ptr<AsyncHooksWrap> wrap = hooks->async_wraps_[i]; PromiseHookDispatch(type, promise, parent, *wrap, hooks); if (try_catch.HasCaught()) break; } if (try_catch.HasCaught()) Shell::ReportException(v8_isolate, &try_catch); } } if (!scheduled_exception.is_null()) { i_isolate->set_scheduled_exception(*scheduled_exception); } } void AsyncHooks::PromiseHookDispatch(PromiseHookType type, Local<Promise> promise, Local<Value> parent, const AsyncHooksWrap& wrap, AsyncHooks* hooks) { if (!wrap.IsEnabled()) return; v8::Isolate* v8_isolate = hooks->v8_isolate_; if (v8_isolate->IsExecutionTerminating()) return; HandleScope handle_scope(v8_isolate); Local<Value> rcv = Undefined(v8_isolate); Local<Context> context = v8_isolate->GetCurrentContext(); Local<Value> async_id = promise->GetPrivate(context, hooks->async_id_symbol.Get(v8_isolate)) .ToLocalChecked(); Local<Value> args[1] = {async_id}; switch (type) { case PromiseHookType::kInit: if (!wrap.init_function().IsEmpty()) { Local<Value> initArgs[4] = { async_id, String::NewFromUtf8Literal(v8_isolate, "PROMISE"), promise ->GetPrivate(context, hooks->trigger_id_symbol.Get(v8_isolate)) .ToLocalChecked(), promise}; USE(wrap.init_function()->Call(context, rcv, 4, initArgs)); } break; case PromiseHookType::kBefore: if (!wrap.before_function().IsEmpty()) { USE(wrap.before_function()->Call(context, rcv, 1, args)); } break; case PromiseHookType::kAfter: if (!wrap.after_function().IsEmpty()) { USE(wrap.after_function()->Call(context, rcv, 1, args)); } break; case PromiseHookType::kResolve: if (!wrap.promiseResolve_function().IsEmpty()) { USE(wrap.promiseResolve_function()->Call(context, rcv, 1, args)); } } } } // namespace v8