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#include "ecmascript/serializer/base_deserializer.h"
17
18
19#include "ecmascript/free_object.h"
20#include "ecmascript/global_env.h"
21#include "ecmascript/js_arraybuffer.h"
22#include "ecmascript/js_function.h"
23#include "ecmascript/js_regexp.h"
24#include "ecmascript/checkpoint/thread_state_transition.h"
25
26namespace panda::ecmascript {
27
28#define NEW_OBJECT_ALL_SPACES()                                           \
29    (uint8_t)SerializedObjectSpace::OLD_SPACE:                            \
30    case (uint8_t)SerializedObjectSpace::NON_MOVABLE_SPACE:               \
31    case (uint8_t)SerializedObjectSpace::MACHINE_CODE_SPACE:              \
32    case (uint8_t)SerializedObjectSpace::HUGE_SPACE:                      \
33    case (uint8_t)SerializedObjectSpace::SHARED_OLD_SPACE:                \
34    case (uint8_t)SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE:        \
35    case (uint8_t)SerializedObjectSpace::SHARED_HUGE_SPACE
36
37BaseDeserializer::BaseDeserializer(JSThread *thread, SerializeData *data, void *hint)
38    : thread_(thread), heap_(const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())), data_(data), engine_(hint)
39{
40    sheap_ = SharedHeap::GetInstance();
41    uint32_t index = data_->GetDataIndex();
42    if (index != 0) {
43        sharedObjChunk_ = Runtime::GetInstance()->GetSerializeRootMapValue(thread_, index);
44        if (sharedObjChunk_ == nullptr) {
45            LOG_ECMA(FATAL) << "Unknown serializer root index: " << index;
46            UNREACHABLE();
47        }
48    }
49}
50
51JSHandle<JSTaggedValue> BaseDeserializer::ReadValue()
52{
53    ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Deserialize dataSize: " + std::to_string(data_->Size()));
54    AllocateToDifferentSpaces();
55    JSHandle<JSTaggedValue> res = DeserializeJSTaggedValue();
56    return res;
57}
58
59JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
60{
61    if (data_->IsIncompleteData()) {
62        LOG_ECMA(ERROR) << "The serialization data is incomplete";
63        return JSHandle<JSTaggedValue>();
64    }
65
66    // stop gc during deserialize
67    heap_->SetOnSerializeEvent(true);
68
69    uint8_t encodeFlag = data_->ReadUint8(position_);
70    JSHandle<JSTaggedValue> resHandle(thread_, JSTaggedValue::Undefined());
71    while (ReadSingleEncodeData(encodeFlag, resHandle.GetAddress(), 0, true) == 0) { // 0: root object offset
72        encodeFlag = data_->ReadUint8(position_);
73    }
74
75    // initialize concurrent func here
76    for (auto func : concurrentFunctions_) {
77        JSFunction::InitializeForConcurrentFunction(thread_, func);
78    }
79    concurrentFunctions_.clear();
80
81    // new native binding object here
82    for (auto nativeBindingInfo : nativeBindingInfos_) {
83        DeserializeNativeBindingObject(nativeBindingInfo);
84        delete nativeBindingInfo;
85    }
86    nativeBindingInfos_.clear();
87
88    // new js error here
89    for (auto jsErrorInfo : jsErrorInfos_) {
90        DeserializeJSError(jsErrorInfo);
91        delete jsErrorInfo;
92    }
93    jsErrorInfos_.clear();
94
95    // recovery gc after serialize
96    heap_->SetOnSerializeEvent(false);
97
98    return resHandle;
99}
100
101uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
102{
103    size_t objSize = data_->ReadUint32(position_);
104    uintptr_t res = RelocateObjectAddr(space, objSize);
105    objectVector_.push_back(static_cast<JSTaggedType>(res));
106    DeserializeObjectField(res, res + objSize);
107    return res;
108}
109
110void BaseDeserializer::DeserializeObjectField(uintptr_t start, uintptr_t end)
111{
112    size_t offset = 0; // 0: initial offset
113    while (start + offset < end) {
114        uint8_t encodeFlag = data_->ReadUint8(position_);
115        offset += ReadSingleEncodeData(encodeFlag, start, offset);
116    }
117}
118
119void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingInfo *info)
120{
121    [[maybe_unused]] EcmaHandleScope scope(thread_);
122    AttachFunc af = info->af_;
123    void *bufferPointer = info->bufferPointer_;
124    void *hint = info->hint_;
125    void *attachData = info->attachData_;
126    bool root = info->root_;
127    Local<JSValueRef> attachVal;
128    {
129        ThreadNativeScope nativeScope(thread_);
130        attachVal = af(engine_, bufferPointer, hint, attachData);
131    }
132    if (attachVal.IsEmpty()) {
133        LOG_ECMA(ERROR) << "NativeBindingObject is empty";
134        attachVal = JSValueRef::Undefined(thread_->GetEcmaVM());
135    }
136    JSTaggedType res = JSNApiHelper::ToJSHandle(attachVal).GetTaggedType();
137    ObjectSlot slot = info->GetSlot();
138    slot.Update(res);
139    if (!root && !JSTaggedValue(res).IsInvalidValue()) {
140        WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(), res);
141    }
142}
143
144void BaseDeserializer::DeserializeJSError(JSErrorInfo *info)
145{
146    [[maybe_unused]] EcmaHandleScope scope(thread_);
147    uint8_t type = info->errorType_;
148    base::ErrorType errorType = base::ErrorType(type - static_cast<uint8_t>(JSType::JS_ERROR_FIRST));
149    JSTaggedValue errorMsg = info->errorMsg_;
150    bool root = info->root_;
151    ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
152    JSHandle<JSObject> errorTag = factory->NewJSError(errorType, JSHandle<EcmaString>(thread_, errorMsg),
153                                                      StackCheck::NO);
154    ObjectSlot slot = info->GetSlot();
155    slot.Update(errorTag.GetTaggedType());
156    if (!root && !errorTag.GetTaggedValue().IsInvalidValue()) {
157        WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(),
158                     errorTag.GetTaggedType());
159    }
160}
161
162void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space,  uintptr_t objAddr, size_t fieldOffset,
163                                                 bool isRoot)
164{
165    // deserialize object prologue
166    bool isWeak = GetAndResetWeak();
167    bool isTransferBuffer = GetAndResetTransferBuffer();
168    bool isSharedArrayBuffer = GetAndResetSharedArrayBuffer();
169    void *bufferPointer = GetAndResetBufferPointer();
170    // deserialize object here
171    uintptr_t addr = DeserializeTaggedObject(space);
172
173    // deserialize object epilogue
174    if (isTransferBuffer) {
175        TransferArrayBufferAttach(addr);
176    } else if (isSharedArrayBuffer) {
177        IncreaseSharedArrayBufferReference(addr);
178    } else if (bufferPointer != nullptr) {
179        ResetNativePointerBuffer(addr, bufferPointer);
180    }
181    TaggedObject *object = reinterpret_cast<TaggedObject *>(addr);
182    if (object->GetClass()->IsJSNativePointer()) {
183        JSNativePointer *nativePointer = reinterpret_cast<JSNativePointer *>(object);
184        if (nativePointer->GetDeleter() != nullptr) {
185            thread_->GetEcmaVM()->PushToNativePointerList(nativePointer);
186        }
187    } else if (object->GetClass()->IsJSFunction()) {
188        JSFunction* func = reinterpret_cast<JSFunction *>(object);
189        FunctionKind funcKind = func->GetFunctionKind();
190        if (funcKind == FunctionKind::CONCURRENT_FUNCTION || object->GetClass()->IsJSSharedFunction()) {
191            // defer initialize concurrent function
192            JSHandle<JSFunction> funcHandle(thread_, func);
193            concurrentFunctions_.push_back(funcHandle);
194        }
195        func->SetRawProfileTypeInfo(thread_, thread_->GlobalConstants()->GetEmptyProfileTypeInfoCell(), SKIP_BARRIER);
196        func->SetWorkNodePointer(reinterpret_cast<uintptr_t>(nullptr));
197    }
198    UpdateMaybeWeak(ObjectSlot(objAddr + fieldOffset), addr, isWeak);
199    if (!isRoot) {
200        WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
201                                                    static_cast<JSTaggedType>(addr));
202    }
203}
204
205void BaseDeserializer::TransferArrayBufferAttach(uintptr_t objAddr)
206{
207    ASSERT(JSTaggedValue(static_cast<JSTaggedType>(objAddr)).IsArrayBuffer());
208    JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
209    size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
210    bool withNativeAreaAllocator = arrayBuffer->GetWithNativeAreaAllocator();
211    JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
212    arrayBuffer->Attach(thread_, arrayLength, JSTaggedValue(np), withNativeAreaAllocator);
213}
214
215void BaseDeserializer::IncreaseSharedArrayBufferReference(uintptr_t objAddr)
216{
217    ASSERT(JSTaggedValue(static_cast<JSTaggedType>(objAddr)).IsSharedArrayBuffer());
218    JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
219    size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
220    JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
221    void *buffer = np->GetExternalPointer();
222    if (JSSharedMemoryManager::GetInstance()->CreateOrLoad(&buffer, arrayLength)) {
223        LOG_ECMA(FATAL) << "BaseDeserializer::IncreaseSharedArrayBufferReference failed";
224    }
225}
226
227void BaseDeserializer::ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer)
228{
229    JSTaggedValue obj = JSTaggedValue(static_cast<JSTaggedType>(objAddr));
230    ASSERT(obj.IsArrayBuffer() || obj.IsJSRegExp());
231    auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
232    JSNativePointer *np = nullptr;
233    if (obj.IsArrayBuffer()) {
234        JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
235        arrayBuffer->SetWithNativeAreaAllocator(true);
236        np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
237        nativeAreaAllocator->IncreaseNativeSizeStats(arrayBuffer->GetArrayBufferByteLength(), NativeFlag::ARRAY_BUFFER);
238    } else {
239        JSRegExp *jsRegExp = reinterpret_cast<JSRegExp *>(objAddr);
240        np = reinterpret_cast<JSNativePointer *>(jsRegExp->GetByteCodeBuffer().GetTaggedObject());
241        nativeAreaAllocator->IncreaseNativeSizeStats(jsRegExp->GetLength(), NativeFlag::REGEXP_BTYECODE);
242    }
243
244    np->SetExternalPointer(bufferPointer);
245    np->SetDeleter(NativeAreaAllocator::FreeBufferFunc);
246    np->SetData(thread_->GetEcmaVM()->GetNativeAreaAllocator());
247}
248
249size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset, bool isRoot)
250{
251    size_t handledFieldSize = sizeof(JSTaggedType);
252    ObjectSlot slot(objAddr + fieldOffset);
253    switch (encodeFlag) {
254        case NEW_OBJECT_ALL_SPACES(): {
255            SerializedObjectSpace space = SerializeData::DecodeSpace(encodeFlag);
256            HandleNewObjectEncodeFlag(space, objAddr, fieldOffset, isRoot);
257            break;
258        }
259        case (uint8_t)EncodeFlag::REFERENCE: {
260            uint32_t valueIndex = data_->ReadUint32(position_);
261            JSTaggedType valueAddr = objectVector_[valueIndex];
262            UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak());
263            WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
264                                                        valueAddr);
265            break;
266        }
267        case (uint8_t)EncodeFlag::WEAK: {
268            ASSERT(!isWeak_);
269            isWeak_ = true;
270            handledFieldSize = 0;
271            break;
272        }
273        case (uint8_t)EncodeFlag::PRIMITIVE: {
274            JSTaggedType value = data_->ReadJSTaggedType(position_);
275            slot.Update(value);
276            break;
277        }
278        case (uint8_t)EncodeFlag::MULTI_RAW_DATA: {
279            uint32_t size = data_->ReadUint32(position_);
280            data_->ReadRawData(objAddr + fieldOffset, size, position_);
281            handledFieldSize = size;
282            break;
283        }
284        case (uint8_t)EncodeFlag::ROOT_OBJECT: {
285            uint32_t index = data_->ReadUint32(position_);
286            uintptr_t valueAddr = thread_->GetEcmaVM()->GetSnapshotEnv()->RelocateRootObjectAddr(index);
287            if (!isRoot && valueAddr > JSTaggedValue::INVALID_VALUE_LIMIT) {
288                WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
289                                                            static_cast<JSTaggedType>(valueAddr));
290            }
291            UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak());
292            break;
293        }
294        case (uint8_t)EncodeFlag::OBJECT_PROTO: {
295            uint8_t type = data_->ReadUint8(position_);
296            uintptr_t protoAddr = RelocateObjectProtoAddr(type);
297            if (!isRoot && protoAddr > JSTaggedValue::INVALID_VALUE_LIMIT) {
298                WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
299                                                            static_cast<JSTaggedType>(protoAddr));
300            }
301            UpdateMaybeWeak(slot, protoAddr, GetAndResetWeak());
302            break;
303        }
304        case (uint8_t)EncodeFlag::TRANSFER_ARRAY_BUFFER: {
305            isTransferArrayBuffer_ = true;
306            handledFieldSize = 0;
307            break;
308        }
309        case (uint8_t)EncodeFlag::SHARED_ARRAY_BUFFER: {
310            isSharedArrayBuffer_ = true;
311            handledFieldSize = 0;
312            break;
313        }
314        case (uint8_t)EncodeFlag::ARRAY_BUFFER:
315        case (uint8_t)EncodeFlag::SENDABLE_ARRAY_BUFFER:
316        case (uint8_t)EncodeFlag::JS_REG_EXP: {
317            size_t bufferLength = data_->ReadUint32(position_);
318            auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
319            bufferPointer_ = nativeAreaAllocator->AllocateBuffer(bufferLength);
320            heap_->IncNativeSizeAfterLastGC(bufferLength);
321            data_->ReadRawData(ToUintPtr(bufferPointer_), bufferLength, position_);
322            heap_->IncreaseNativeBindingSize(bufferLength);
323            handledFieldSize = 0;
324            break;
325        }
326        case (uint8_t)EncodeFlag::NATIVE_BINDING_OBJECT: {
327            slot.Update(JSTaggedValue::Undefined().GetRawData());
328            AttachFunc af = reinterpret_cast<AttachFunc>(data_->ReadJSTaggedType(position_));
329            void *bufferPointer = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
330            void *hint = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
331            void *attachData = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
332            // defer new native binding object until deserialize finish
333            nativeBindingInfos_.push_back(new NativeBindingInfo(af, bufferPointer, hint, attachData,
334                                                                objAddr, fieldOffset, isRoot));
335            break;
336        }
337        case (uint8_t)EncodeFlag::JS_ERROR: {
338            slot.Update(JSTaggedValue::Undefined().GetRawData());
339            uint8_t type = data_->ReadUint8(position_);
340            ASSERT(type >= static_cast<uint8_t>(JSType::JS_ERROR_FIRST)
341                && type <= static_cast<uint8_t>(JSType::JS_ERROR_LAST));
342            jsErrorInfos_.push_back(new JSErrorInfo(type, JSTaggedValue::Undefined(), objAddr, fieldOffset, isRoot));
343            uint8_t flag = data_->ReadUint8(position_);
344            if (flag == 1) { // error msg is string
345                isErrorMsg_ = true;
346                handledFieldSize = 0;
347            }
348            break;
349        }
350        case (uint8_t)EncodeFlag::SHARED_OBJECT: {
351            uint32_t index = data_->ReadUint32(position_);
352            if (UNLIKELY(index >= sharedObjChunk_->Size())) {
353                LOG_ECMA(FATAL) << "Shared object index invalid, index: " << index << " chunkSize: "
354                    << sharedObjChunk_->Size();
355                UNREACHABLE();
356            }
357            JSTaggedType value = sharedObjChunk_->Get(index);
358            objectVector_.push_back(value);
359            bool isErrorMsg = GetAndResetIsErrorMsg();
360            if (isErrorMsg) {
361                // defer new js error
362                jsErrorInfos_.back()->errorMsg_ = JSTaggedValue(value);
363                break;
364            }
365            if (!isRoot) {
366                WriteBarrier(thread_, reinterpret_cast<void *>(objAddr), fieldOffset, value);
367            }
368            UpdateMaybeWeak(slot, value, GetAndResetWeak());
369            break;
370        }
371        default:
372            LOG_ECMA(FATAL) << "this branch is unreachable";
373            UNREACHABLE();
374            break;
375    }
376    return handledFieldSize;
377}
378
379uintptr_t BaseDeserializer::RelocateObjectAddr(SerializedObjectSpace space, size_t objSize)
380{
381    uintptr_t res = 0U;
382    switch (space) {
383        case SerializedObjectSpace::OLD_SPACE: {
384            if (oldSpaceBeginAddr_ + objSize > AlignUp(oldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
385                ASSERT(oldRegionIndex_ < regionVector_.size());
386                oldSpaceBeginAddr_ = regionVector_[oldRegionIndex_++]->GetBegin();
387            }
388            res = oldSpaceBeginAddr_;
389            oldSpaceBeginAddr_ += objSize;
390            break;
391        }
392        case SerializedObjectSpace::NON_MOVABLE_SPACE: {
393            if (nonMovableSpaceBeginAddr_ + objSize > AlignUp(nonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
394                ASSERT(nonMovableRegionIndex_ < regionVector_.size());
395                nonMovableSpaceBeginAddr_ = regionVector_[nonMovableRegionIndex_++]->GetBegin();
396            }
397            res = nonMovableSpaceBeginAddr_;
398            nonMovableSpaceBeginAddr_ += objSize;
399            break;
400        }
401        case SerializedObjectSpace::MACHINE_CODE_SPACE: {
402            if (machineCodeSpaceBeginAddr_ + objSize > AlignUp(machineCodeSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
403                ASSERT(machineCodeRegionIndex_ < regionVector_.size());
404                machineCodeSpaceBeginAddr_ = regionVector_[machineCodeRegionIndex_++]->GetBegin();
405            }
406            res = machineCodeSpaceBeginAddr_;
407            machineCodeSpaceBeginAddr_ += objSize;
408            break;
409        }
410        case SerializedObjectSpace::HUGE_SPACE: {
411            // no gc for this allocate
412            res = heap_->GetHugeObjectSpace()->Allocate(objSize, thread_, AllocateEventType::DESERIALIZE);
413            if (res == 0) {
414                DeserializeFatalOutOfMemory(objSize, false, false);
415            }
416            break;
417        }
418        case SerializedObjectSpace::SHARED_OLD_SPACE: {
419            if (sOldSpaceBeginAddr_ + objSize > AlignUp(sOldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
420                ASSERT(sOldRegionIndex_ < regionVector_.size());
421                sOldSpaceBeginAddr_ = regionVector_[sOldRegionIndex_++]->GetBegin();
422            }
423            res = sOldSpaceBeginAddr_;
424            sOldSpaceBeginAddr_ += objSize;
425            break;
426        }
427        case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: {
428            if (sNonMovableSpaceBeginAddr_ + objSize > AlignUp(sNonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
429                ASSERT(sNonMovableRegionIndex_ < regionVector_.size());
430                sNonMovableSpaceBeginAddr_ = regionVector_[sNonMovableRegionIndex_++]->GetBegin();
431            }
432            res = sNonMovableSpaceBeginAddr_;
433            sNonMovableSpaceBeginAddr_ += objSize;
434            break;
435        }
436        case SerializedObjectSpace::SHARED_HUGE_SPACE: {
437            // no gc for this allocate
438            res = sheap_->GetHugeObjectSpace()->Allocate(thread_, objSize, AllocateEventType::DESERIALIZE);
439            if (res == 0) {
440                DeserializeFatalOutOfMemory(objSize, false, true);
441            }
442            break;
443        }
444        default:
445            LOG_ECMA(FATAL) << "this branch is unreachable";
446            UNREACHABLE();
447    }
448    return res;
449}
450
451JSTaggedType BaseDeserializer::RelocateObjectProtoAddr(uint8_t objectType)
452{
453    auto env = thread_->GetEcmaVM()->GetGlobalEnv();
454    switch (objectType) {
455        case (uint8_t)JSType::JS_OBJECT:
456            return env->GetObjectFunctionPrototype().GetTaggedType();
457        case (uint8_t)JSType::JS_ERROR:
458            return JSHandle<JSFunction>(env->GetErrorFunction())->GetFunctionPrototype().GetRawData();
459        case (uint8_t)JSType::JS_EVAL_ERROR:
460            return JSHandle<JSFunction>(env->GetEvalErrorFunction())->GetFunctionPrototype().GetRawData();
461        case (uint8_t)JSType::JS_RANGE_ERROR:
462            return JSHandle<JSFunction>(env->GetRangeErrorFunction())->GetFunctionPrototype().GetRawData();
463        case (uint8_t)JSType::JS_REFERENCE_ERROR:
464            return JSHandle<JSFunction>(env->GetReferenceErrorFunction())->GetFunctionPrototype().GetRawData();
465        case (uint8_t)JSType::JS_TYPE_ERROR:
466            return JSHandle<JSFunction>(env->GetTypeErrorFunction())->GetFunctionPrototype().GetRawData();
467        case (uint8_t)JSType::JS_AGGREGATE_ERROR:
468            return JSHandle<JSFunction>(env->GetAggregateErrorFunction())->GetFunctionPrototype().GetRawData();
469        case (uint8_t)JSType::JS_URI_ERROR:
470            return JSHandle<JSFunction>(env->GetURIErrorFunction())->GetFunctionPrototype().GetRawData();
471        case (uint8_t)JSType::JS_SYNTAX_ERROR:
472            return JSHandle<JSFunction>(env->GetSyntaxErrorFunction())->GetFunctionPrototype().GetRawData();
473        case (uint8_t)JSType::JS_OOM_ERROR:
474            return JSHandle<JSFunction>(env->GetOOMErrorFunction())->GetFunctionPrototype().GetRawData();
475        case (uint8_t)JSType::JS_TERMINATION_ERROR:
476            return JSHandle<JSFunction>(env->GetTerminationErrorFunction())->GetFunctionPrototype().GetRawData();
477        case (uint8_t)JSType::JS_DATE:
478            return env->GetDatePrototype().GetTaggedType();
479        case (uint8_t)JSType::JS_ARRAY:
480            return env->GetArrayPrototype().GetTaggedType();
481        case (uint8_t)JSType::JS_SHARED_ARRAY:
482            return env->GetSharedArrayPrototype().GetTaggedType();
483        case (uint8_t)JSType::JS_MAP:
484            return env->GetMapPrototype().GetTaggedType();
485        case (uint8_t)JSType::JS_SHARED_MAP:
486            return env->GetSharedMapPrototype().GetTaggedType();
487        case (uint8_t)JSType::JS_SET:
488            return env->GetSetPrototype().GetTaggedType();
489        case (uint8_t)JSType::JS_SHARED_SET:
490            return env->GetSharedSetPrototype().GetTaggedType();
491        case (uint8_t)JSType::JS_SENDABLE_ARRAY_BUFFER:
492            return env->GetSendableArrayBufferPrototype().GetTaggedType();
493        case (uint8_t)JSType::JS_REG_EXP:
494            return env->GetRegExpPrototype().GetTaggedType();
495        case (uint8_t)JSType::JS_INT8_ARRAY:
496            return env->GetInt8ArrayFunctionPrototype().GetTaggedType();
497        case (uint8_t)JSType::JS_UINT8_ARRAY:
498            return env->GetUint8ArrayFunctionPrototype().GetTaggedType();
499        case (uint8_t)JSType::JS_UINT8_CLAMPED_ARRAY:
500            return env->GetUint8ClampedArrayFunctionPrototype().GetTaggedType();
501        case (uint8_t)JSType::JS_INT16_ARRAY:
502            return env->GetInt16ArrayFunctionPrototype().GetTaggedType();
503        case (uint8_t)JSType::JS_UINT16_ARRAY:
504            return env->GetUint16ArrayFunctionPrototype().GetTaggedType();
505        case (uint8_t)JSType::JS_INT32_ARRAY:
506            return env->GetInt32ArrayFunctionPrototype().GetTaggedType();
507        case (uint8_t)JSType::JS_UINT32_ARRAY:
508            return env->GetUint32ArrayFunctionPrototype().GetTaggedType();
509        case (uint8_t)JSType::JS_FLOAT32_ARRAY:
510            return env->GetFloat32ArrayFunctionPrototype().GetTaggedType();
511        case (uint8_t)JSType::JS_FLOAT64_ARRAY:
512            return env->GetFloat64ArrayFunctionPrototype().GetTaggedType();
513        case (uint8_t)JSType::JS_BIGINT64_ARRAY:
514            return env->GetBigInt64ArrayFunctionPrototype().GetTaggedType();
515        case (uint8_t)JSType::JS_BIGUINT64_ARRAY:
516            return env->GetBigUint64ArrayFunctionPrototype().GetTaggedType();
517        case (uint8_t)JSType::JS_SHARED_INT8_ARRAY:
518            return env->GetSharedInt8ArrayFunctionPrototype().GetTaggedType();
519        case (uint8_t)JSType::JS_SHARED_UINT8_ARRAY:
520            return env->GetSharedUint8ArrayFunctionPrototype().GetTaggedType();
521        case (uint8_t)JSType::JS_SHARED_UINT8_CLAMPED_ARRAY:
522            return env->GetSharedUint8ClampedArrayFunctionPrototype().GetTaggedType();
523        case (uint8_t)JSType::JS_SHARED_INT16_ARRAY:
524            return env->GetSharedInt16ArrayFunctionPrototype().GetTaggedType();
525        case (uint8_t)JSType::JS_SHARED_UINT16_ARRAY:
526            return env->GetSharedUint16ArrayFunctionPrototype().GetTaggedType();
527        case (uint8_t)JSType::JS_SHARED_INT32_ARRAY:
528            return env->GetSharedInt32ArrayFunctionPrototype().GetTaggedType();
529        case (uint8_t)JSType::JS_SHARED_UINT32_ARRAY:
530            return env->GetSharedUint32ArrayFunctionPrototype().GetTaggedType();
531        case (uint8_t)JSType::JS_SHARED_FLOAT32_ARRAY:
532            return env->GetSharedFloat32ArrayFunctionPrototype().GetTaggedType();
533        case (uint8_t)JSType::JS_SHARED_FLOAT64_ARRAY:
534            return env->GetSharedFloat64ArrayFunctionPrototype().GetTaggedType();
535        case (uint8_t)JSType::JS_SHARED_BIGINT64_ARRAY:
536            return env->GetSharedBigInt64ArrayFunctionPrototype().GetTaggedType();
537        case (uint8_t)JSType::JS_SHARED_BIGUINT64_ARRAY:
538            return env->GetSharedBigUint64ArrayFunctionPrototype().GetTaggedType();
539        case (uint8_t)JSType::JS_ARRAY_BUFFER:
540            return JSHandle<JSFunction>(env->GetArrayBufferFunction())->GetFunctionPrototype().GetRawData();
541        case (uint8_t)JSType::JS_SHARED_ARRAY_BUFFER:
542            return JSHandle<JSFunction>(env->GetSharedArrayBufferFunction())->GetFunctionPrototype().GetRawData();
543        case (uint8_t)JSType::JS_ASYNC_FUNCTION:
544            return env->GetAsyncFunctionPrototype().GetTaggedType();
545        case (uint8_t)JSType::JS_SHARED_ASYNC_FUNCTION:
546            return env->GetSAsyncFunctionPrototype().GetTaggedType();
547        case (uint8_t)JSType::BIGINT:
548            return JSHandle<JSFunction>(env->GetBigIntFunction())->GetFunctionPrototype().GetRawData();
549        default:
550            LOG_ECMA(ERROR) << "Relocate unsupported JSType: " << JSHClass::DumpJSType(static_cast<JSType>(objectType));
551            LOG_ECMA(FATAL) << "this branch is unreachable";
552            UNREACHABLE();
553            break;
554    }
555}
556
557void BaseDeserializer::AllocateToDifferentSpaces()
558{
559    size_t oldSpaceSize = data_->GetOldSpaceSize();
560    if (oldSpaceSize > 0) {
561        heap_->GetOldSpace()->IncreaseLiveObjectSize(oldSpaceSize);
562        AllocateToOldSpace(oldSpaceSize);
563    }
564    size_t nonMovableSpaceSize = data_->GetNonMovableSpaceSize();
565    if (nonMovableSpaceSize > 0) {
566        heap_->GetNonMovableSpace()->IncreaseLiveObjectSize(nonMovableSpaceSize);
567        AllocateToNonMovableSpace(nonMovableSpaceSize);
568    }
569    size_t machineCodeSpaceSize = data_->GetMachineCodeSpaceSize();
570    if (machineCodeSpaceSize > 0) {
571        heap_->GetMachineCodeSpace()->IncreaseLiveObjectSize(machineCodeSpaceSize);
572        AllocateToMachineCodeSpace(machineCodeSpaceSize);
573    }
574    size_t sOldSpaceSize = data_->GetSharedOldSpaceSize();
575    if (sOldSpaceSize > 0) {
576        sheap_->GetOldSpace()->IncreaseLiveObjectSize(sOldSpaceSize);
577        AllocateToSharedOldSpace(sOldSpaceSize);
578    }
579    size_t sNonMovableSpaceSize = data_->GetSharedNonMovableSpaceSize();
580    if (sNonMovableSpaceSize > 0) {
581        sheap_->GetNonMovableSpace()->IncreaseLiveObjectSize(sNonMovableSpaceSize);
582        AllocateToSharedNonMovableSpace(sNonMovableSpaceSize);
583    }
584}
585
586void BaseDeserializer::AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t &regionIndex)
587{
588    regionIndex = regionVector_.size();
589    size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
590    size_t regionNum = regionAlignedSize / Region::GetRegionAvailableSize();
591    while (regionNum > 1) { // 1: one region have allocated before
592        std::vector<size_t> regionRemainSizeVector = data_->GetRegionRemainSizeVector();
593        space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - regionRemainSizeVector[regionRemainSizeIndex_++]);
594        if (!space->Expand()) {
595            DeserializeFatalOutOfMemory(spaceObjSize);
596        }
597        Region *currentRegion = space->GetCurrentRegion();
598        FreeObject::FillFreeObject(heap_, currentRegion->GetBegin(), currentRegion->GetSize());
599        regionVector_.push_back(currentRegion);
600        regionNum--;
601    }
602    size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
603    space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - lastRegionRemainSize);
604}
605
606void BaseDeserializer::AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t &regionIndex)
607{
608    regionIndex = regionVector_.size();
609    size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
610    size_t regionNum = regionAlignedSize / Region::GetRegionAvailableSize();
611    std::vector<size_t> regionRemainSizeVector = data_->GetRegionRemainSizeVector();
612    std::vector<Region *> allocateRegions;
613    while (regionNum > 0) {
614        if (space->CommittedSizeExceed()) {
615            DeserializeFatalOutOfMemory(spaceObjSize, true, true);
616        }
617        Region *region = space->AllocateDeserializeRegion(thread_);
618        FreeObject::FillFreeObject(sheap_, region->GetBegin(), region->GetSize());
619        if (regionNum == 1) { // 1: Last allocate region
620            size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
621            region->SetHighWaterMark(region->GetEnd() - lastRegionRemainSize);
622        } else {
623            region->SetHighWaterMark(region->GetEnd() - regionRemainSizeVector[regionRemainSizeIndex_++]);
624        }
625        region->IncreaseAliveObject(region->GetAllocatedBytes());
626        regionVector_.push_back(region);
627        allocateRegions.push_back(region);
628        regionNum--;
629    }
630    space->MergeDeserializeAllocateRegions(allocateRegions);
631}
632
633void BaseDeserializer::AllocateToOldSpace(size_t oldSpaceSize)
634{
635    SparseSpace *space = heap_->GetOldSpace();
636    uintptr_t object = space->Allocate(oldSpaceSize, false);
637    if (UNLIKELY(object == 0U)) {
638        if (space->CommittedSizeExceed()) {
639            DeserializeFatalOutOfMemory(oldSpaceSize);
640        }
641        oldSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
642        FreeObject::FillFreeObject(heap_, oldSpaceBeginAddr_, space->GetCurrentRegion()->GetSize());
643        AllocateMultiRegion(space, oldSpaceSize, oldRegionIndex_);
644    } else {
645        FreeObject::FillFreeObject(heap_, object, oldSpaceSize);
646        oldSpaceBeginAddr_ = object;
647    }
648}
649
650void BaseDeserializer::AllocateToNonMovableSpace(size_t nonMovableSpaceSize)
651{
652    SparseSpace *space = heap_->GetNonMovableSpace();
653    uintptr_t object = space->Allocate(nonMovableSpaceSize, false);
654    if (UNLIKELY(object == 0U)) {
655        if (space->CommittedSizeExceed()) {
656            DeserializeFatalOutOfMemory(nonMovableSpaceSize);
657        }
658        nonMovableSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
659        FreeObject::FillFreeObject(heap_, nonMovableSpaceBeginAddr_, space->GetCurrentRegion()->GetSize());
660        AllocateMultiRegion(space, nonMovableSpaceSize, nonMovableRegionIndex_);
661    } else {
662        FreeObject::FillFreeObject(heap_, object, nonMovableSpaceSize);
663        nonMovableSpaceBeginAddr_ = object;
664    }
665}
666
667void BaseDeserializer::AllocateToMachineCodeSpace(size_t machineCodeSpaceSize)
668{
669    SparseSpace *space = heap_->GetMachineCodeSpace();
670    uintptr_t object = space->Allocate(machineCodeSpaceSize, false);
671    if (UNLIKELY(object == 0U)) {
672        if (space->CommittedSizeExceed()) {
673            DeserializeFatalOutOfMemory(machineCodeSpaceSize);
674        }
675        machineCodeSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
676        FreeObject::FillFreeObject(heap_, machineCodeSpaceBeginAddr_, space->GetCurrentRegion()->GetSize());
677        AllocateMultiRegion(space, machineCodeSpaceSize, machineCodeRegionIndex_);
678    } else {
679        FreeObject::FillFreeObject(heap_, object, machineCodeSpaceSize);
680        machineCodeSpaceBeginAddr_ = object;
681    }
682}
683
684void BaseDeserializer::AllocateToSharedOldSpace(size_t sOldSpaceSize)
685{
686    SharedSparseSpace *space = sheap_->GetOldSpace();
687    uintptr_t object = space->AllocateNoGCAndExpand(thread_, sOldSpaceSize);
688    if (UNLIKELY(object == 0U)) {
689        AllocateMultiSharedRegion(space, sOldSpaceSize, sOldRegionIndex_);
690        sOldSpaceBeginAddr_ = regionVector_[sOldRegionIndex_++]->GetBegin();
691    } else {
692        if (thread_->IsSharedConcurrentMarkingOrFinished()) {
693            Region *region = Region::ObjectAddressToRange(object);
694            region->IncreaseAliveObject(sOldSpaceSize);
695        }
696        FreeObject::FillFreeObject(sheap_, object, sOldSpaceSize);
697        sOldSpaceBeginAddr_ = object;
698    }
699}
700
701void BaseDeserializer::AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize)
702{
703    SharedNonMovableSpace *space = sheap_->GetNonMovableSpace();
704    uintptr_t object = space->AllocateNoGCAndExpand(thread_, sNonMovableSpaceSize);
705    if (UNLIKELY(object == 0U)) {
706        AllocateMultiSharedRegion(space, sNonMovableSpaceSize, sNonMovableRegionIndex_);
707        sNonMovableSpaceBeginAddr_ = regionVector_[sNonMovableRegionIndex_++]->GetBegin();
708    } else {
709        if (thread_->IsSharedConcurrentMarkingOrFinished()) {
710            Region *region = Region::ObjectAddressToRange(object);
711            region->IncreaseAliveObject(sNonMovableSpaceSize);
712        }
713        FreeObject::FillFreeObject(sheap_, object, sNonMovableSpaceSize);
714        sNonMovableSpaceBeginAddr_ = object;
715    }
716}
717
718}  // namespace panda::ecmascript
719
720