• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_FLAGS_H
17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_FLAGS_H
18 
19 #include "plugins/ets/runtime/types/ets_object.h"
20 
21 namespace ark::ets::interop::js::ets_proxy {
22 
23 // |------------------------------------------------------------|
24 // |          SharedReference flag bits represenatation:32      |
25 // |------------------------------------------------------------|
26 // |     NextIndex:28|12 | ... | MarkBit:1 | JSbit:1 | ETSbit:1 |
27 // |------------------------------------------------------------|
28 class SharedReferenceFlags {
29 public:
30     using ValueType = ObjectPointerType;
31     using IndexType = decltype(std::declval<EtsObject>().GetInteropIndex());
32     static_assert(sizeof(IndexType) <= sizeof(ValueType));
33 
34     enum class Bit : ValueType {
35         ETS = 1U << 0U,
36         JS = 1U << 1U,
37         MARK = 1U << 2U,
38     };
39 
IsEmpty()40     bool IsEmpty() const
41     {
42         return GetRawFlags() == EMPTY_FLAGS;
43     }
44 
ClearFlags()45     void ClearFlags()
46     {
47         SetRawFlags(EMPTY_FLAGS);
48     }
49 
50     template <SharedReferenceFlags::Bit BIT>
SetBit()51     bool SetBit()
52     {
53         static constexpr auto BIT_VALUE = static_cast<ValueType>(BIT);
54         return SetFlagCAS<BIT_VALUE>();
55     }
56 
57     template <SharedReferenceFlags::Bit BIT>
HasBit()58     bool HasBit() const
59     {
60         static constexpr auto BIT_VALUE = static_cast<ValueType>(BIT);
61         return (GetRawFlags() & BIT_VALUE) != 0U;
62     }
63 
Unmark()64     void Unmark()
65     {
66         UnsetFlagCAS<static_cast<ValueType>(Bit::MARK)>();
67     }
68 
SetNextIndex(IndexType index)69     void SetNextIndex(IndexType index)
70     {
71         static constexpr ValueType NO_NEXT_INDEX_MASK = (1U << NEXT_INDEX_SHIFT) - 1U;
72         ValueType indexMask = index << NEXT_INDEX_SHIFT;
73         ValueType oldFlags = GetRawFlags();
74         while (!flags_.compare_exchange_weak(oldFlags, (oldFlags & NO_NEXT_INDEX_MASK) | indexMask,
75                                              std::memory_order_seq_cst)) {
76         }
77     }
78 
GetNextIndex()79     IndexType GetNextIndex() const
80     {
81         return static_cast<IndexType>(GetRawFlags() >> NEXT_INDEX_SHIFT);
82     }
83 
84     friend std::ostream &operator<<(std::ostream &out, const SharedReferenceFlags &flags)
85     {
86         out << "idx:" << flags.GetNextIndex() << " mark:" << flags.HasBit<SharedReferenceFlags::Bit::MARK>()
87             << " JS:" << flags.HasBit<SharedReferenceFlags::Bit::JS>()
88             << " ETS:" << flags.HasBit<SharedReferenceFlags::Bit::ETS>();
89         return out;
90     }
91 
92 private:
93     static constexpr ValueType EMPTY_FLAGS = 0U;
94     static constexpr ValueType NEXT_INDEX_SHIFT =
95         sizeof(ValueType) * BITS_PER_BYTE - MarkWord::MarkWordRepresentation::HASH_SIZE;
96     static_assert(static_cast<ValueType>(Bit::MARK) < (1U << NEXT_INDEX_SHIFT));
97 
GetRawFlags()98     ALWAYS_INLINE ValueType GetRawFlags() const
99     {
100         // Atomic with acquire order reason: data race with flags_ with dependecies on reads after the load which
101         // should become visible
102         return flags_.load(std::memory_order_acquire);
103     }
104 
SetRawFlags(ValueType flags)105     ALWAYS_INLINE void SetRawFlags(ValueType flags)
106     {
107         // Atomic with release order reason: other thread should see last value of flags
108         flags_.store(flags, std::memory_order_release);
109     }
110 
111     template <ValueType FLAG>
SetFlagCAS()112     ALWAYS_INLINE bool SetFlagCAS()
113     {
114         static_assert(Popcount(FLAG) == 1);
115         ValueType oldFlags;
116         do {
117             oldFlags = GetRawFlags();
118             if ((oldFlags & FLAG) != 0) {
119                 return false;
120             }
121         } while (!flags_.compare_exchange_weak(oldFlags, oldFlags | FLAG, std::memory_order_seq_cst));
122         return true;
123     }
124 
125     template <ValueType FLAG>
UnsetFlagCAS()126     ALWAYS_INLINE void UnsetFlagCAS()
127     {
128         static_assert(Popcount(FLAG) == 1);
129         static constexpr ValueType MASK = ~FLAG;
130         ValueType oldFlags;
131         do {
132             oldFlags = GetRawFlags();
133             if ((oldFlags & FLAG) == 0) {
134                 return;
135             }
136         } while (!flags_.compare_exchange_weak(oldFlags, oldFlags & MASK, std::memory_order_seq_cst));
137     }
138 
139     std::atomic<ValueType> flags_ {};
140 };
141 
142 }  // namespace ark::ets::interop::js::ets_proxy
143 
144 #endif  // PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ETS_PROXY_SHARED_REFERENCE_FLAGS_H
145