#include "timers.h" #include "env-inl.h" #include "node_external_reference.h" #include "util-inl.h" #include "v8.h" #include namespace node { namespace timers { using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::Number; using v8::Object; using v8::ObjectTemplate; using v8::Value; void BindingData::SetupTimers(const FunctionCallbackInfo& args) { CHECK(args[0]->IsFunction()); CHECK(args[1]->IsFunction()); auto env = Environment::GetCurrent(args); env->set_immediate_callback_function(args[0].As()); env->set_timers_callback_function(args[1].As()); } void BindingData::SlowGetLibuvNow(const FunctionCallbackInfo& args) { double now = GetLibuvNowImpl(Realm::GetBindingData(args)); args.GetReturnValue().Set(Number::New(args.GetIsolate(), now)); } double BindingData::FastGetLibuvNow(Local receiver) { return GetLibuvNowImpl(FromJSObject(receiver)); } double BindingData::GetLibuvNowImpl(BindingData* data) { return static_cast(data->env()->GetNowUint64()); } void BindingData::SlowScheduleTimer(const FunctionCallbackInfo& args) { int64_t duration = args[0]->IntegerValue(args.GetIsolate()->GetCurrentContext()).FromJust(); ScheduleTimerImpl(Realm::GetBindingData(args), duration); } void BindingData::FastScheduleTimer(Local receiver, int64_t duration) { ScheduleTimerImpl(FromJSObject(receiver), duration); } void BindingData::ScheduleTimerImpl(BindingData* data, int64_t duration) { data->env()->ScheduleTimer(duration); } void BindingData::SlowToggleTimerRef( const v8::FunctionCallbackInfo& args) { ToggleTimerRefImpl(Realm::GetBindingData(args), args[0]->IsTrue()); } void BindingData::FastToggleTimerRef(Local receiver, bool ref) { ToggleTimerRefImpl(FromJSObject(receiver), ref); } void BindingData::ToggleTimerRefImpl(BindingData* data, bool ref) { data->env()->ToggleTimerRef(ref); } void BindingData::SlowToggleImmediateRef( const v8::FunctionCallbackInfo& args) { ToggleImmediateRefImpl(Realm::GetBindingData(args), args[0]->IsTrue()); } void BindingData::FastToggleImmediateRef(Local receiver, bool ref) { ToggleImmediateRefImpl(FromJSObject(receiver), ref); } void BindingData::ToggleImmediateRefImpl(BindingData* data, bool ref) { data->env()->ToggleImmediateRef(ref); } BindingData::BindingData(Realm* realm, Local object) : SnapshotableObject(realm, object, type_int) {} bool BindingData::PrepareForSerialization(Local context, v8::SnapshotCreator* creator) { // Return true because we need to maintain the reference to the binding from // JS land. return true; } InternalFieldInfoBase* BindingData::Serialize(int index) { DCHECK_EQ(index, BaseObject::kEmbedderType); InternalFieldInfo* info = InternalFieldInfoBase::New(type()); return info; } void BindingData::Deserialize(Local context, Local holder, int index, InternalFieldInfoBase* info) { DCHECK_EQ(index, BaseObject::kEmbedderType); v8::HandleScope scope(context->GetIsolate()); Realm* realm = Realm::GetCurrent(context); // Recreate the buffer in the constructor. BindingData* binding = realm->AddBindingData(context, holder); CHECK_NOT_NULL(binding); } v8::CFunction BindingData::fast_get_libuv_now_( v8::CFunction::Make(FastGetLibuvNow)); v8::CFunction BindingData::fast_schedule_timers_( v8::CFunction::Make(FastScheduleTimer)); v8::CFunction BindingData::fast_toggle_timer_ref_( v8::CFunction::Make(FastToggleTimerRef)); v8::CFunction BindingData::fast_toggle_immediate_ref_( v8::CFunction::Make(FastToggleImmediateRef)); void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, Local ctor) { Isolate* isolate = isolate_data->isolate(); Local target = ctor->InstanceTemplate(); SetMethod(isolate, target, "setupTimers", SetupTimers); SetFastMethod( isolate, target, "getLibuvNow", SlowGetLibuvNow, &fast_get_libuv_now_); SetFastMethod(isolate, target, "scheduleTimer", SlowScheduleTimer, &fast_schedule_timers_); SetFastMethod(isolate, target, "toggleTimerRef", SlowToggleTimerRef, &fast_toggle_timer_ref_); SetFastMethod(isolate, target, "toggleImmediateRef", SlowToggleImmediateRef, &fast_toggle_immediate_ref_); } void BindingData::CreatePerContextProperties(Local target, Local unused, Local context, void* priv) { Realm* realm = Realm::GetCurrent(context); Environment* env = realm->env(); BindingData* const binding_data = realm->AddBindingData(context, target); if (binding_data == nullptr) return; // TODO(joyeecheung): move these into BindingData. target ->Set(context, FIXED_ONE_BYTE_STRING(realm->isolate(), "immediateInfo"), env->immediate_info()->fields().GetJSArray()) .Check(); target ->Set(context, FIXED_ONE_BYTE_STRING(realm->isolate(), "timeoutInfo"), env->timeout_info().GetJSArray()) .Check(); } void BindingData::RegisterTimerExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(SetupTimers); registry->Register(SlowGetLibuvNow); registry->Register(FastGetLibuvNow); registry->Register(fast_get_libuv_now_.GetTypeInfo()); registry->Register(SlowScheduleTimer); registry->Register(FastScheduleTimer); registry->Register(fast_schedule_timers_.GetTypeInfo()); registry->Register(SlowToggleTimerRef); registry->Register(FastToggleTimerRef); registry->Register(fast_toggle_timer_ref_.GetTypeInfo()); registry->Register(SlowToggleImmediateRef); registry->Register(FastToggleImmediateRef); registry->Register(fast_toggle_immediate_ref_.GetTypeInfo()); } } // namespace timers } // namespace node NODE_BINDING_CONTEXT_AWARE_INTERNAL( timers, node::timers::BindingData::CreatePerContextProperties) NODE_BINDING_PER_ISOLATE_INIT( timers, node::timers::BindingData::CreatePerIsolateProperties) NODE_BINDING_EXTERNAL_REFERENCE( timers, node::timers::BindingData::RegisterTimerExternalReferences)