#pragma once #include "environment.h" #include "util.h" #include #include #include namespace ivm { namespace detail { template class ExternalHolder { public: ExternalHolder(const ExternalHolder&) = delete; ~ExternalHolder() = default; auto operator=(const ExternalHolder&) = delete; template static auto New(Args&&... args) { // Allocate heap memory for ExternalHolder (don't construct) ExternalHolder* that = std::allocator{}.allocate(1); // Create a new v8::External referencing the unconstructed holder auto external = v8::External::New(v8::Isolate::GetCurrent(), &that->data); // Construct the holder in-place new(that) ExternalHolder(external, std::forward(args)...); // Setup weak callbacks (technically could throw) that->handle.SetWeak(reinterpret_cast(that), WeakCallbackV8, v8::WeakCallbackType::kParameter); IsolateEnvironment::GetCurrent().AddWeakCallback(&that->handle, WeakCallback, that); // Return local external handle return external; } private: template explicit ExternalHolder(v8::Local handle, Args&&... args) : handle{v8::Isolate::GetCurrent(), handle}, data{std::forward(args)...} {} static void WeakCallback(void* param) { auto* that = static_cast(param); auto& isolate = IsolateEnvironment::GetCurrent(); isolate.RemoveWeakCallback(&that->handle); that->handle.Reset(); delete that; } static void WeakCallbackV8(const v8::WeakCallbackInfo& info) { WeakCallback(info.GetParameter()); } v8::Persistent handle; Type data; }; } // namespace detail /** * Returns a v8::External with attached handle deletion */ template auto MakeExternal(Args&&... args) { return detail::ExternalHolder::New(std::forward(args)...); } }