14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JSHANDLE_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_JSHANDLE_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <type_traits>
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_ci#include "ecmascript/ecma_handle_scope.h"
224514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h"
234514f5e3Sopenharmony_ci#include "ecmascript/mem/assert_scope.h"
244514f5e3Sopenharmony_ci
254514f5e3Sopenharmony_ci/*
264514f5e3Sopenharmony_ci * JSHandle: A JSHandle provides a reference to an object that survives relocation by the garbage collector.
274514f5e3Sopenharmony_ci *
284514f5e3Sopenharmony_ci * HandleStorage: Handles are only valid within a HandleScope. When a JSHandle is created for an object a cell is
294514f5e3Sopenharmony_ci * allocated in the current HandleScope.
304514f5e3Sopenharmony_ci *
314514f5e3Sopenharmony_ci * HandleStorage: HandleStorage is the storage structure of the object pointer. GC will use the stored pointer as root
324514f5e3Sopenharmony_ci * and update the stored value after the object is moved
334514f5e3Sopenharmony_ci *
344514f5e3Sopenharmony_ci *  JSHandle ---- HandleStorage -----  heap
354514f5e3Sopenharmony_ci *    |               |               |
364514f5e3Sopenharmony_ci * address-----> store: T*  ------> object
374514f5e3Sopenharmony_ci *
384514f5e3Sopenharmony_ci *    {
394514f5e3Sopenharmony_ci *      EcmaHandleScope scope2(thread);
404514f5e3Sopenharmony_ci *      JSHandle<T> jhandle(thread, obj4);
414514f5e3Sopenharmony_ci *      JSHandle<T> jhandle(thread, obj5);
424514f5e3Sopenharmony_ci *      JSHandle<T> jhandle(thread, obj6);
434514f5e3Sopenharmony_ci *      JSHandle<T> jhandle(thread, obj7);
444514f5e3Sopenharmony_ci *    }
454514f5e3Sopenharmony_ci *
464514f5e3Sopenharmony_ci *  // out of scope, The obj pointer in node will be free (obj7, obj6, obj5, obj4) and PopTopNode(top_node = prev_node)
474514f5e3Sopenharmony_ci *
484514f5e3Sopenharmony_ci *      |        |          |  obj5   |
494514f5e3Sopenharmony_ci *      |        | scope2-> |  obj4   |
504514f5e3Sopenharmony_ci *      |        |          |  obj3   |
514514f5e3Sopenharmony_ci *      |  obj7  |          |  obj2   |
524514f5e3Sopenharmony_ci *      |__obj6__| scope1-> |__obj1___|
534514f5e3Sopenharmony_ci *       top_node --------->  prev_node------>nullptr
544514f5e3Sopenharmony_ci *
554514f5e3Sopenharmony_ci *  example:
564514f5e3Sopenharmony_ci *      JSHandle<T> handle;
574514f5e3Sopenharmony_ci *      {
584514f5e3Sopenharmony_ci *          EcmaHandleScope(thread);
594514f5e3Sopenharmony_ci *          JSHandle<T> jshandle(thread, T*);
604514f5e3Sopenharmony_ci *          jshandle->method();  // to invoke method of T
614514f5e3Sopenharmony_ci *          handle = jshandle;
624514f5e3Sopenharmony_ci *      }
634514f5e3Sopenharmony_ci *      handle->method(); // error! do not used handle out of scope
644514f5e3Sopenharmony_ci */
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_cinamespace panda::test {
674514f5e3Sopenharmony_ciclass JSHandleTest;
684514f5e3Sopenharmony_ci}  // namespace panda::test
694514f5e3Sopenharmony_ci
704514f5e3Sopenharmony_cinamespace panda::ecmascript {
714514f5e3Sopenharmony_ciclass TaggedArray;
724514f5e3Sopenharmony_ciclass LinkedHashMap;
734514f5e3Sopenharmony_ciclass LinkedHashSet;
744514f5e3Sopenharmony_ciclass NameDictionary;
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_citemplate <typename T>
774514f5e3Sopenharmony_ciclass JSHandle {
784514f5e3Sopenharmony_cipublic:
794514f5e3Sopenharmony_ci    inline JSHandle() : address_(reinterpret_cast<uintptr_t>(nullptr)) {}
804514f5e3Sopenharmony_ci    ~JSHandle() = default;
814514f5e3Sopenharmony_ci    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSHandle);
824514f5e3Sopenharmony_ci    DEFAULT_COPY_SEMANTIC(JSHandle);
834514f5e3Sopenharmony_ci
844514f5e3Sopenharmony_ci    JSHandle(const JSThread *thread, JSTaggedValue value)
854514f5e3Sopenharmony_ci    {
864514f5e3Sopenharmony_ci        address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), value.GetRawData());
874514f5e3Sopenharmony_ci    }
884514f5e3Sopenharmony_ci
894514f5e3Sopenharmony_ci    JSHandle(const JSThread *thread, JSTaggedValue value, bool isPrimitive)
904514f5e3Sopenharmony_ci    {
914514f5e3Sopenharmony_ci        if (LIKELY(isPrimitive)) {
924514f5e3Sopenharmony_ci            address_ = EcmaHandleScope::NewPrimitiveHandle(
934514f5e3Sopenharmony_ci                const_cast<JSThread *>(thread), value.GetRawData());
944514f5e3Sopenharmony_ci            return;
954514f5e3Sopenharmony_ci        }
964514f5e3Sopenharmony_ci        address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), value.GetRawData());
974514f5e3Sopenharmony_ci    }
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_ci    JSHandle(const JSThread *thread, const TaggedObject *value)
1004514f5e3Sopenharmony_ci    {
1014514f5e3Sopenharmony_ci        address_ = EcmaHandleScope::NewHandle(const_cast<JSThread *>(thread), JSTaggedValue(value).GetRawData());
1024514f5e3Sopenharmony_ci    }
1034514f5e3Sopenharmony_ci
1044514f5e3Sopenharmony_ci    inline uintptr_t GetAddress() const
1054514f5e3Sopenharmony_ci    {
1064514f5e3Sopenharmony_ci        return address_;
1074514f5e3Sopenharmony_ci    }
1084514f5e3Sopenharmony_ci
1094514f5e3Sopenharmony_ci    template <typename S>
1104514f5e3Sopenharmony_ci    explicit JSHandle(const JSHandle<S> &handle) : address_(handle.GetAddress()) {}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_ci    template <typename S>
1134514f5e3Sopenharmony_ci    inline static JSHandle<T> Cast(const JSHandle<S> &handle)
1144514f5e3Sopenharmony_ci    {
1154514f5e3Sopenharmony_ci        T::Cast(handle.GetTaggedValue().GetTaggedObject());
1164514f5e3Sopenharmony_ci        return JSHandle<T>(handle.GetAddress());
1174514f5e3Sopenharmony_ci    }
1184514f5e3Sopenharmony_ci
1194514f5e3Sopenharmony_ci    inline JSTaggedValue GetTaggedValue() const
1204514f5e3Sopenharmony_ci    {
1214514f5e3Sopenharmony_ci        CHECK_NO_DEREF_HANDLE;
1224514f5e3Sopenharmony_ci        if (GetAddress() == 0U) {
1234514f5e3Sopenharmony_ci            return JSTaggedValue::Undefined();
1244514f5e3Sopenharmony_ci        }
1254514f5e3Sopenharmony_ci        return *(reinterpret_cast<JSTaggedValue *>(GetAddress()));  // NOLINT(clang-analyzer-core.NullDereference)
1264514f5e3Sopenharmony_ci    }
1274514f5e3Sopenharmony_ci
1284514f5e3Sopenharmony_ci    inline JSTaggedType GetTaggedType() const
1294514f5e3Sopenharmony_ci    {
1304514f5e3Sopenharmony_ci        CHECK_NO_DEREF_HANDLE;
1314514f5e3Sopenharmony_ci        if (GetAddress() == 0U) {
1324514f5e3Sopenharmony_ci            return JSTaggedValue::Undefined().GetRawData();
1334514f5e3Sopenharmony_ci        }
1344514f5e3Sopenharmony_ci        return *reinterpret_cast<JSTaggedType *>(GetAddress());  // NOLINT(clang-analyzer-core.NullDereference)
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci
1374514f5e3Sopenharmony_ci    inline T *operator*() const
1384514f5e3Sopenharmony_ci    {
1394514f5e3Sopenharmony_ci        return T::Cast(GetTaggedValue().GetTaggedObject());
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    inline T *operator->() const
1434514f5e3Sopenharmony_ci    {
1444514f5e3Sopenharmony_ci        return T::Cast(GetTaggedValue().GetTaggedObject());
1454514f5e3Sopenharmony_ci    }
1464514f5e3Sopenharmony_ci
1474514f5e3Sopenharmony_ci    inline bool operator==(const JSHandle<T> &other) const
1484514f5e3Sopenharmony_ci    {
1494514f5e3Sopenharmony_ci        return GetTaggedType() == other.GetTaggedType();
1504514f5e3Sopenharmony_ci    }
1514514f5e3Sopenharmony_ci
1524514f5e3Sopenharmony_ci    inline bool operator!=(const JSHandle<T> &other) const
1534514f5e3Sopenharmony_ci    {
1544514f5e3Sopenharmony_ci        return GetTaggedType() != other.GetTaggedType();
1554514f5e3Sopenharmony_ci    }
1564514f5e3Sopenharmony_ci
1574514f5e3Sopenharmony_ci    inline bool IsEmpty() const
1584514f5e3Sopenharmony_ci    {
1594514f5e3Sopenharmony_ci        return GetAddress() == 0U;
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ci    template <typename R>
1634514f5e3Sopenharmony_ci    R *GetObject() const
1644514f5e3Sopenharmony_ci    {
1654514f5e3Sopenharmony_ci        return reinterpret_cast<R *>(GetTaggedValue().GetTaggedObject());
1664514f5e3Sopenharmony_ci    }
1674514f5e3Sopenharmony_ci
1684514f5e3Sopenharmony_ci    inline explicit JSHandle(uintptr_t slot) : address_(slot)
1694514f5e3Sopenharmony_ci    {
1704514f5e3Sopenharmony_ci        if (!std::is_convertible<T *, JSTaggedValue *>::value) {
1714514f5e3Sopenharmony_ci            ASSERT(slot != 0);
1724514f5e3Sopenharmony_ci            if ((*reinterpret_cast<JSTaggedValue *>(slot)).IsHeapObject()) {
1734514f5e3Sopenharmony_ci                T::Cast((*reinterpret_cast<JSTaggedValue *>(slot)).GetTaggedObject());
1744514f5e3Sopenharmony_ci            }
1754514f5e3Sopenharmony_ci        }
1764514f5e3Sopenharmony_ci    }
1774514f5e3Sopenharmony_ci
1784514f5e3Sopenharmony_ci    void Dump() const DUMP_API_ATTR
1794514f5e3Sopenharmony_ci    {
1804514f5e3Sopenharmony_ci        GetTaggedValue().D();
1814514f5e3Sopenharmony_ci    }
1824514f5e3Sopenharmony_ci
1834514f5e3Sopenharmony_ciprivate:
1844514f5e3Sopenharmony_ci    inline explicit JSHandle(const JSTaggedType *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {}
1854514f5e3Sopenharmony_ci    inline explicit JSHandle(const T *const *slot) : address_(reinterpret_cast<uintptr_t>(slot)) {}
1864514f5e3Sopenharmony_ci
1874514f5e3Sopenharmony_ci    uintptr_t address_;  // NOLINT(misc-non-private-member-variables-in-classes)
1884514f5e3Sopenharmony_ci    friend class EcmaVM;
1894514f5e3Sopenharmony_ci    friend class GlobalEnv;
1904514f5e3Sopenharmony_ci    friend class JSHandleTest;
1914514f5e3Sopenharmony_ci    friend class GlobalHandleCollection;
1924514f5e3Sopenharmony_ci    friend class RuntimeStubs;
1934514f5e3Sopenharmony_ci};
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_citemplate <>
1964514f5e3Sopenharmony_ciinline JSTaggedValue *JSHandle<JSTaggedValue>::operator->() const
1974514f5e3Sopenharmony_ci{
1984514f5e3Sopenharmony_ci    return reinterpret_cast<JSTaggedValue *>(GetAddress());
1994514f5e3Sopenharmony_ci}
2004514f5e3Sopenharmony_ci
2014514f5e3Sopenharmony_citemplate <>
2024514f5e3Sopenharmony_ciinline JSTaggedValue *JSHandle<JSTaggedValue>::operator*() const
2034514f5e3Sopenharmony_ci{
2044514f5e3Sopenharmony_ci    return reinterpret_cast<JSTaggedValue *>(GetAddress());
2054514f5e3Sopenharmony_ci}
2064514f5e3Sopenharmony_ci
2074514f5e3Sopenharmony_citemplate <typename T>
2084514f5e3Sopenharmony_ciclass JSMutableHandle : public JSHandle<T> {
2094514f5e3Sopenharmony_cipublic:
2104514f5e3Sopenharmony_ci    JSMutableHandle() = default;
2114514f5e3Sopenharmony_ci    ~JSMutableHandle() = default;
2124514f5e3Sopenharmony_ci    DEFAULT_NOEXCEPT_MOVE_SEMANTIC(JSMutableHandle);
2134514f5e3Sopenharmony_ci    DEFAULT_COPY_SEMANTIC(JSMutableHandle);
2144514f5e3Sopenharmony_ci
2154514f5e3Sopenharmony_ci    JSMutableHandle(const JSThread *thread, JSTaggedValue value) : JSHandle<T>(thread, value) {}
2164514f5e3Sopenharmony_ci    JSMutableHandle(const JSThread *thread, const TaggedArray *value) : JSHandle<T>(thread, value) {}
2174514f5e3Sopenharmony_ci    template <typename S>
2184514f5e3Sopenharmony_ci    JSMutableHandle(const JSThread *thread, const JSHandle<S> &handle)
2194514f5e3Sopenharmony_ci        : JSHandle<T>(thread, handle.GetTaggedValue())
2204514f5e3Sopenharmony_ci    {
2214514f5e3Sopenharmony_ci    }
2224514f5e3Sopenharmony_ci    inline explicit JSMutableHandle(uintptr_t slot) : JSHandle<T>(slot)
2234514f5e3Sopenharmony_ci    {
2244514f5e3Sopenharmony_ci    }
2254514f5e3Sopenharmony_ci
2264514f5e3Sopenharmony_ci    template <typename S>
2274514f5e3Sopenharmony_ci    inline static JSMutableHandle<T> Cast(const JSMutableHandle<S> &handle)
2284514f5e3Sopenharmony_ci    {
2294514f5e3Sopenharmony_ci        JSHandle<T>::Cast(handle);
2304514f5e3Sopenharmony_ci        return JSMutableHandle<T>(handle.GetAddress());
2314514f5e3Sopenharmony_ci    }
2324514f5e3Sopenharmony_ci
2334514f5e3Sopenharmony_ci    void Update(JSTaggedValue value)
2344514f5e3Sopenharmony_ci    {
2354514f5e3Sopenharmony_ci        auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress());
2364514f5e3Sopenharmony_ci        ASSERT(addr != nullptr);
2374514f5e3Sopenharmony_ci        *addr = value;
2384514f5e3Sopenharmony_ci    }
2394514f5e3Sopenharmony_ci
2404514f5e3Sopenharmony_ci    template <typename S>
2414514f5e3Sopenharmony_ci    void Update(const JSHandle<S> &handle)
2424514f5e3Sopenharmony_ci    {
2434514f5e3Sopenharmony_ci        auto addr = reinterpret_cast<JSTaggedValue *>(this->GetAddress());
2444514f5e3Sopenharmony_ci        *addr = handle.GetTaggedValue();
2454514f5e3Sopenharmony_ci    }
2464514f5e3Sopenharmony_ci};
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_citemplate<typename>
2494514f5e3Sopenharmony_cistruct IsJSHandle : std::false_type {};
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_citemplate<typename Value>
2524514f5e3Sopenharmony_cistruct IsJSHandle<JSHandle<Value>> : std::true_type {};
2534514f5e3Sopenharmony_ci
2544514f5e3Sopenharmony_citemplate<typename Value>
2554514f5e3Sopenharmony_cistruct IsJSHandle<JSMutableHandle<Value>> : std::true_type {};
2564514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
2574514f5e3Sopenharmony_ci
2584514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_JSHANDLE_H
259