1/*
2 * Copyright (c) 2021 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 ECMASCRIPT_ACCESSOR_DATA_H
17#define ECMASCRIPT_ACCESSOR_DATA_H
18
19#include "ecmascript/ecma_macros.h"
20#include "ecmascript/js_hclass.h"
21#include "ecmascript/js_native_pointer.h"
22#include "ecmascript/js_object.h"
23#include "ecmascript/js_tagged_value.h"
24#include "ecmascript/mem/slots.h"
25#include "ecmascript/mem/visitor.h"
26#include "ecmascript/record.h"
27
28namespace panda::ecmascript {
29class InternalAccessor final : public Record {
30public:
31    using InternalGetFunc = JSTaggedValue (*)(JSThread *, const JSHandle<JSObject> &);
32    using InternalSetFunc = bool (*)(JSThread *, const JSHandle<JSObject> &, const JSHandle<JSTaggedValue> &, bool);
33
34    CAST_CHECK(InternalAccessor, IsInternalAccessor);
35
36    inline bool HasSetter() const
37    {
38        return GetSetter() != nullptr;
39    }
40
41    static constexpr size_t GETTER_OFFSET = Record::SIZE;
42    ACCESSORS_FIXED_SIZE_FIELD(Getter, InternalGetFunc, JSTaggedType, GETTER_OFFSET, SETTER_OFFSET)
43    ACCESSORS_FIXED_SIZE_FIELD(Setter, InternalSetFunc, JSTaggedType, SETTER_OFFSET, SIZE)
44
45    DECL_VISIT_NATIVE_FIELD(GETTER_OFFSET, SIZE)
46};
47
48class AccessorData final : public Record {
49public:
50    static AccessorData *Cast(TaggedObject *object)
51    {
52        ASSERT(JSTaggedValue(object).IsAccessorData() || JSTaggedValue(object).IsInternalAccessor());
53        return static_cast<AccessorData *>(object);
54    }
55
56    inline bool IsInternal() const
57    {
58        return GetClass()->IsInternalAccessor();
59    }
60
61    inline bool HasSetter() const
62    {
63        auto setter = GetSetter();
64        // When the raw data is 0, means the InternalAccessor's setter is nullptr.
65        return !(setter.IsUndefined() || setter.GetRawData() == 0U);
66    }
67
68    JSTaggedValue CallInternalGet(JSThread *thread, const JSHandle<JSObject> &obj) const
69    {
70        ASSERT(IsInternal());
71        auto getFunc = InternalAccessor::ConstCast(this)->GetGetter();
72        return getFunc(thread, obj);
73    }
74
75    bool CallInternalSet(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &value,
76                         bool mayThrow = false) const
77    {
78        ASSERT(IsInternal());
79        auto setFunc = InternalAccessor::ConstCast(this)->GetSetter();
80        return setFunc(thread, obj, value, mayThrow);
81    }
82
83    static constexpr size_t GETTER_OFFSET = Record::SIZE;
84    ACCESSORS(Getter, GETTER_OFFSET, SETTER_OFFSET);
85    ACCESSORS(Setter, SETTER_OFFSET, SIZE);
86
87    DECL_DUMP()
88    DECL_VISIT_OBJECT(GETTER_OFFSET, SIZE)
89};
90
91static_assert(AccessorData::SIZE == InternalAccessor::SIZE &&
92              AccessorData::GETTER_OFFSET == InternalAccessor::GETTER_OFFSET &&
93              AccessorData::SETTER_OFFSET == InternalAccessor::SETTER_OFFSET);
94
95enum class CompletionRecordType : uint8_t {
96    NORMAL = 0U,
97    BREAK,
98    CONTINUE,
99    RETURN,
100    THROW
101};
102
103class CompletionRecord final : public Record {
104public:
105    static CompletionRecord *Cast(TaggedObject *object)
106    {
107        ASSERT(JSTaggedValue(object).IsCompletionRecord());
108        return static_cast<CompletionRecord *>(object);
109    }
110
111    bool IsThrow() const
112    {
113        return GetType() == CompletionRecordType::THROW;
114    }
115
116    static constexpr size_t VALUE_OFFSET = Record::SIZE;
117    ACCESSORS(Value, VALUE_OFFSET, BIT_FIELD_OFFSET)
118    ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
119    DEFINE_ALIGN_SIZE(LAST_OFFSET);
120
121    // define BitField
122    static constexpr size_t TYPE_BITS = 3;
123    FIRST_BIT_FIELD(BitField, Type, CompletionRecordType, TYPE_BITS)
124
125    DECL_DUMP()
126
127    DECL_VISIT_OBJECT(VALUE_OFFSET, BIT_FIELD_OFFSET)
128};
129}  // namespace panda::ecmascript
130#endif  // ECMASCRIPT_ACCESSOR_DATA_H
131