1/*
2 * Copyright (c) 2023 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_BASE_DESERIALIZER_H
17#define ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H
18
19#include "ecmascript/serializer/serialize_data.h"
20
21namespace panda::ecmascript {
22class Heap;
23class JSThread;
24struct NativeBindingInfo {
25    AttachFunc af_ {nullptr};
26    void *bufferPointer_ {nullptr};
27    void *hint_ = {nullptr};
28    void *attachData_ = {nullptr};
29    uintptr_t objAddr_ {0U};
30    size_t offset_ {0U};
31    bool root_ {false};
32
33    NativeBindingInfo(AttachFunc af, void *bufferPointer, void *hint, void *attachData,
34                      uintptr_t objAddr, size_t offset, bool root) : af_(af), bufferPointer_(bufferPointer),
35        hint_(hint), attachData_(attachData), objAddr_(objAddr), offset_(offset), root_(root) {}
36
37    uintptr_t GetObjAddr() const
38    {
39        return objAddr_;
40    }
41
42    size_t GetFieldOffset() const
43    {
44        return offset_;
45    }
46
47    ObjectSlot GetSlot() const
48    {
49        return ObjectSlot(objAddr_ + offset_);
50    }
51};
52
53struct JSErrorInfo {
54    uint8_t errorType_ {0};
55    JSTaggedValue errorMsg_;
56    uintptr_t objAddr_ {0U};
57    size_t offset_ {0U};
58    bool root_ {false};
59
60    JSErrorInfo(uint8_t errorType, JSTaggedValue errorMsg, uintptr_t objAddr, size_t offset, bool root)
61        : errorType_(errorType), errorMsg_(errorMsg), objAddr_(objAddr), offset_(offset), root_(root) {}
62
63    uintptr_t GetObjAddr() const
64    {
65        return objAddr_;
66    }
67
68    size_t GetFieldOffset() const
69    {
70        return offset_;
71    }
72
73    ObjectSlot GetSlot() const
74    {
75        return ObjectSlot(objAddr_ + offset_);
76    }
77};
78
79class BaseDeserializer {
80public:
81    explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr);
82
83    ~BaseDeserializer()
84    {
85        objectVector_.clear();
86        regionVector_.clear();
87    }
88
89    NO_COPY_SEMANTIC(BaseDeserializer);
90    NO_MOVE_SEMANTIC(BaseDeserializer);
91
92    JSHandle<JSTaggedValue> ReadValue();
93
94private:
95    JSHandle<JSTaggedValue> DeserializeJSTaggedValue();
96    uintptr_t DeserializeTaggedObject(SerializedObjectSpace space);
97    void DeserializeNativeBindingObject(NativeBindingInfo *info);
98    void DeserializeJSError(JSErrorInfo *info);
99    uintptr_t RelocateObjectAddr(SerializedObjectSpace space, size_t objSize);
100    JSTaggedType RelocateObjectProtoAddr(uint8_t objectType);
101    void DeserializeObjectField(uintptr_t start, uintptr_t end);
102    size_t ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset, bool isRoot = false);
103    void HandleNewObjectEncodeFlag(SerializedObjectSpace space, uintptr_t objAddr, size_t fieldOffset, bool isRoot);
104
105    void TransferArrayBufferAttach(uintptr_t objAddr);
106    void IncreaseSharedArrayBufferReference(uintptr_t objAddr);
107    void ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer);
108
109    void AllocateToDifferentSpaces();
110    void AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t &regionIndex);
111    void AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t &regionIndex);
112    void AllocateToOldSpace(size_t oldSpaceSize);
113    void AllocateToNonMovableSpace(size_t nonMovableSpaceSize);
114    void AllocateToMachineCodeSpace(size_t machineCodeSpaceSize);
115    void AllocateToSharedOldSpace(size_t sOldSpaceSize);
116    void AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize);
117
118    bool GetAndResetWeak()
119    {
120        bool isWeak = isWeak_;
121        if (isWeak_) {
122            isWeak_ = false;
123        }
124        return isWeak;
125    }
126
127    bool GetAndResetTransferBuffer()
128    {
129        bool isTransferArrayBuffer = isTransferArrayBuffer_;
130        if (isTransferArrayBuffer_) {
131            isTransferArrayBuffer_ = false;
132        }
133        return isTransferArrayBuffer;
134    }
135
136    bool GetAndResetSharedArrayBuffer()
137    {
138        bool isSharedArrayBuffer = isSharedArrayBuffer_;
139        if (isSharedArrayBuffer_) {
140            isSharedArrayBuffer_ = false;
141        }
142        return isSharedArrayBuffer;
143    }
144
145    bool GetAndResetIsErrorMsg()
146    {
147        bool isErrorMsg = isErrorMsg_;
148        if (isErrorMsg_) {
149            isErrorMsg_ = false;
150        }
151        return isErrorMsg;
152    }
153
154    bool GetAndResetFunctionInShared()
155    {
156        bool functionInShared = functionInShared_;
157        if (functionInShared_) {
158            functionInShared_ = false;
159        }
160        return functionInShared;
161    }
162
163    void *GetAndResetBufferPointer()
164    {
165        if (bufferPointer_) {
166            void *buffer = bufferPointer_;
167            bufferPointer_ = nullptr;
168            return buffer;
169        }
170        return nullptr;
171    }
172
173    void DeserializeFatalOutOfMemory(size_t size, bool dump = true, bool isShared = false)
174    {
175        if (isShared) {
176            if (dump) {
177                sheap_->DumpHeapSnapshotBeforeOOM(true, thread_);
178            }
179            LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize shared obj size: " << size
180                << ", old space heap object size: "
181                << sheap_->GetOldSpace()->GetHeapObjectSize()
182                << ", old space committed size: "
183                << sheap_->GetOldSpace()->GetCommittedSize()
184                << ", non movable space heap object size: "
185                << sheap_->GetNonMovableSpace()->GetHeapObjectSize()
186                << ", non movable space committed size: "
187                << sheap_->GetNonMovableSpace()->GetCommittedSize()
188                << ", huge space committed size: "
189                << sheap_->GetHugeObjectSpace()->GetCommittedSize();
190        } else {
191            if (dump) {
192                heap_->StatisticHeapDetail();
193                heap_->DumpHeapSnapshotBeforeOOM();
194            }
195            LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize obj size: " << size
196                << ", old space heap object size: "
197                << heap_->GetOldSpace()->GetHeapObjectSize()
198                << ", old space committed size: "
199                << heap_->GetOldSpace()->GetCommittedSize()
200                << ", non movable space heap object size: "
201                << heap_->GetNonMovableSpace()->GetHeapObjectSize()
202                << ", non movable space committed size: "
203                << heap_->GetNonMovableSpace()->GetCommittedSize()
204                << ", huge space committed size: "
205                << heap_->GetHugeObjectSpace()->GetCommittedSize();
206        }
207    }
208
209    void UpdateMaybeWeak(ObjectSlot slot, uintptr_t addr, bool isWeak)
210    {
211        isWeak ? slot.UpdateWeak(addr) : slot.Update(addr);
212    }
213
214private:
215    JSThread *thread_;
216    Heap *heap_;
217    SharedHeap *sheap_;
218    SerializeData* data_;
219    void *engine_;
220    uintptr_t oldSpaceBeginAddr_ {0};
221    uintptr_t nonMovableSpaceBeginAddr_ {0};
222    uintptr_t machineCodeSpaceBeginAddr_ {0};
223    uintptr_t sOldSpaceBeginAddr_ {0};
224    uintptr_t sNonMovableSpaceBeginAddr_ {0};
225    // SerializationChunk store shared objects which have been serialized
226    SerializationChunk *sharedObjChunk_ {nullptr};
227    CVector<JSTaggedType> objectVector_;
228    CVector<Region *> regionVector_;
229    size_t oldRegionIndex_ {0};
230    size_t nonMovableRegionIndex_ {0};
231    size_t machineCodeRegionIndex_ {0};
232    size_t sOldRegionIndex_ {0};
233    size_t sNonMovableRegionIndex_ {0};
234    size_t regionRemainSizeIndex_ {0};
235    bool isWeak_ {false};
236    bool isTransferArrayBuffer_ {false};
237    bool isSharedArrayBuffer_ {false};
238    bool isErrorMsg_ {false};
239    void *bufferPointer_ {nullptr};
240    bool functionInShared_ {false};
241    CVector<NativeBindingInfo *> nativeBindingInfos_;
242    CVector<JSErrorInfo *> jsErrorInfos_;
243    CVector<JSHandle<JSFunction>> concurrentFunctions_;
244    size_t position_ {0};
245};
246}
247
248#endif  // ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H