/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SRC_JSVM_REFERENCE_ #define SRC_JSVM_REFERENCE_ #include #include "jsvm_types.h" #include "jsvm_util.h" namespace v8impl { class RefTracker; using RefList = RefTracker; class RefTracker { public: RefTracker() : next(nullptr), prev(nullptr) {} virtual ~RefTracker() = default; static void FinalizeAll(RefList* list); protected: virtual void Finalize(); inline void Link(RefList* list); inline void Unlink(); private: RefList* next; RefList* prev; }; class UserReference final : public RefTracker { public: static UserReference* New(JSVM_Env env, v8::Local value, uint32_t initialRefcount); static UserReference* NewData(JSVM_Env env, v8::Local data, uint32_t initialRefcount); ~UserReference() override; // Increase and decrease reference uint32_t Ref(); uint32_t Unref(); uint32_t RefCount(); // Get v8::Local value inline v8::Local Get(); inline v8::Local GetData(); bool IsValue() { return isValue; } protected: UserReference(JSVM_Env env, v8::Local value, bool isValue, uint32_t initialRefcount); void Finalize() override; private: void SetWeak(); private: v8impl::Persistent persistent; JSVM_Env env; uint32_t refcount; bool isValue; bool canBeWeak; }; class FinalizerTracker : public RefTracker { protected: FinalizerTracker(JSVM_Env env, JSVM_Finalize cb, void* data, void* hint); public: static FinalizerTracker* New(JSVM_Env env, JSVM_Finalize cb, void* finalizeData, void* finalizeHint); ~FinalizerTracker() override; void* GetData() { return data; } protected: void ResetFinalizer(); void CallFinalizer(); void Finalize() override; void ResetEnv() { env = nullptr; } private: JSVM_Env env; JSVM_Finalize cb; void* data; void* hint; }; class RuntimeReference : public FinalizerTracker { protected: RuntimeReference(JSVM_Env env, v8::Local value, JSVM_Finalize cb, void* data, void* hint); public: static RuntimeReference* New(JSVM_Env env, v8::Local value, void* data); static RuntimeReference* New(JSVM_Env env, v8::Local value, JSVM_Finalize cb, void* data, void* hint); static void DeleteReference(RuntimeReference* ref); private: inline void SetWeak(bool needSecondPass); static void FirstPassCallback(const v8::WeakCallbackInfo& data); static void SecondPassCallback(const v8::WeakCallbackInfo& data); static void FirstPassCallbackWithoutFinalizer(const v8::WeakCallbackInfo& data); private: v8impl::Persistent persistent; }; class TrackedStringResource : public FinalizerTracker { public: TrackedStringResource(JSVM_Env env, JSVM_Finalize finalizeCallback, void* data, void* finalizeHint) : FinalizerTracker(env, finalizeCallback, data, finalizeHint) {} protected: // The only time Finalize() gets called before Dispose() is if the // environment is dying. Finalize() expects that the item will be unlinked, // so we do it here. V8 will still call Dispose() on us later, so we don't do // any deleting here. We just null out env_ to avoid passing a stale pointer // to the user's finalizer when V8 does finally call Dispose(). void Finalize() override { Unlink(); ResetEnv(); } ~TrackedStringResource() override { CallFinalizer(); } }; class ExternalOneByteStringResource : public v8::String::ExternalOneByteStringResource, TrackedStringResource { public: ExternalOneByteStringResource(JSVM_Env env, char* string, const size_t length, JSVM_Finalize finalizeCallback, void* finalizeHint) : TrackedStringResource(env, finalizeCallback, string, finalizeHint), string_(string), length_(length) {} const char* data() const override { return string_; } size_t length() const override { return length_; } private: const char* string_; const size_t length_; }; class ExternalStringResource : public v8::String::ExternalStringResource, TrackedStringResource { public: ExternalStringResource(JSVM_Env env, char16_t* string, const size_t length, JSVM_Finalize finalizeCallback, void* finalizeHint) : TrackedStringResource(env, finalizeCallback, string, finalizeHint), string_(reinterpret_cast(string)), length_(length) {} const uint16_t* data() const override { return string_; } size_t length() const override { return length_; } private: const uint16_t* string_; const size_t length_; }; } // namespace v8impl #endif