1/*
2 * Copyright (c) 2024 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_SERIALIZER_SERIALIZATION_CHUNK_H
17#define ECMASCRIPT_SERIALIZER_SERIALIZATION_CHUNK_H
18
19#include "ecmascript/js_tagged_value-inl.h"
20#include "ecmascript/mem/mem.h"
21
22namespace panda::ecmascript {
23
24class SerializationChunk {
25public:
26    explicit SerializationChunk() {}
27    ~SerializationChunk()
28    {
29        if (begin_ != 0U) {
30            free(ToVoidPtr(begin_));
31        }
32    }
33    NO_COPY_SEMANTIC(SerializationChunk);
34    NO_MOVE_SEMANTIC(SerializationChunk);
35
36    void Emplace(JSTaggedType value)
37    {
38        if (top_ == end_) {
39            Expand();
40        }
41        ASSERT(top_ < end_);
42        *reinterpret_cast<JSTaggedType *>(top_) = value;
43        top_ += JSTaggedValue::TaggedTypeSize();
44    }
45
46    JSTaggedType Get(size_t index) const
47    {
48        ASSERT(begin_ + index * JSTaggedValue::TaggedTypeSize() < top_);
49        return *reinterpret_cast<JSTaggedType *>(begin_ + index * JSTaggedValue::TaggedTypeSize());
50    }
51
52    void Expand()
53    {
54        ASSERT(top_ == end_);
55        size_t oldCapacity = end_ - begin_;
56        size_t newCapacity = 0;
57        if (oldCapacity == 0U) {
58            newCapacity = INITIAL_CHUNK_CAPACITY;
59        } else {
60            newCapacity = (end_ - begin_) * CHUNK_CAPACITY_INCREASE_RATE;
61        }
62        void *newChunk = malloc(newCapacity);
63        if (newChunk == nullptr) {
64            LOG_ECMA_MEM(FATAL) << "malloc failed, current alloc size = " << newCapacity;
65            UNREACHABLE();
66        }
67
68        if (begin_ != 0U) {
69            if (memcpy_s(newChunk, newCapacity, ToVoidPtr(begin_), end_ - begin_) != EOK) {
70                LOG_FULL(FATAL) << "memcpy_s fail";
71            }
72            free(ToVoidPtr(begin_));
73        }
74        begin_ = ToUintPtr(newChunk);
75        top_ = begin_ + oldCapacity;
76        end_ = begin_ + newCapacity;
77    }
78
79    bool Empty() const
80    {
81        return top_ == begin_;
82    }
83
84    size_t Size() const
85    {
86        return (top_ - begin_) / JSTaggedValue::TaggedTypeSize();
87    }
88
89    void Iterate(const RootVisitor &v)
90    {
91        for (uintptr_t slot = begin_; slot < top_; slot += JSTaggedValue::TaggedTypeSize()) {
92            v(Root::ROOT_VM, ObjectSlot(slot));
93        }
94    }
95
96private:
97    static constexpr size_t INITIAL_CHUNK_CAPACITY = 1_KB;
98    static constexpr int CHUNK_CAPACITY_INCREASE_RATE = 2;
99    uintptr_t begin_ {0U};
100    uintptr_t end_ {0U};
101    uintptr_t top_ {0U};
102};
103}
104
105#endif  // ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
106