* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H
#define ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H
#include "ecmascript/serializer/serialize_data.h"
namespace panda::ecmascript {
class Heap;
class JSThread;
struct NativeBindingAttachInfo {
AttachFunc af_ {nullptr};
void *bufferPointer_ {nullptr};
void *hint_ = {nullptr};
void *attachData_ = {nullptr};
JSHandle<JSTaggedValue> obj_;
size_t offset_ {0U};
NativeBindingAttachInfo(AttachFunc af, void *bufferPointer, void *hint, void *attachData,
JSHandle<JSTaggedValue> obj, size_t offset) : af_(af), bufferPointer_(bufferPointer),
hint_(hint), attachData_(attachData), obj_(obj), offset_(offset) {}
uintptr_t GetObjAddr() const
{
return static_cast<uintptr_t>(obj_.GetTaggedType());
}
size_t GetFieldOffset() const
{
return offset_;
}
ObjectSlot GetSlot() const
{
return ObjectSlot(GetObjAddr() + offset_);
}
};
struct JSErrorInfo {
uint8_t errorType_ {0};
JSHandle<JSTaggedValue> errorMsg_;
JSHandle<JSTaggedValue> errorStack_;
JSHandle<JSTaggedValue> obj_;
size_t offset_ {0U};
enum class ErrorInfo: uint8_t {
IS_ERROR_MSG = 1,
IS_ERROR_MSG_AND_STACK = 2,
};
JSErrorInfo(uint8_t errorType, JSHandle<JSTaggedValue> errorMsg, JSHandle<JSTaggedValue> errorStack,
JSHandle<JSTaggedValue> obj, size_t offset)
: errorType_(errorType), errorMsg_(errorMsg), errorStack_(errorStack), obj_(obj), offset_(offset) {}
uintptr_t GetObjAddr() const
{
return static_cast<uintptr_t>(obj_.GetTaggedType());
}
size_t GetFieldOffset() const
{
return offset_;
}
ObjectSlot GetSlot() const
{
return ObjectSlot(GetObjAddr() + offset_);
}
};
class BaseDeserializer {
public:
explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr);
virtual ~BaseDeserializer()
{
objectVector_.clear();
regionVector_.clear();
}
NO_COPY_SEMANTIC(BaseDeserializer);
NO_MOVE_SEMANTIC(BaseDeserializer);
JSHandle<JSTaggedValue> ReadValue();
protected:
virtual uintptr_t DeserializeTaggedObject(SerializedObjectSpace space);
private:
JSHandle<JSTaggedValue> DeserializeJSTaggedValue();
void DeserializeNativeBindingObject(NativeBindingAttachInfo *info);
void DeserializeJSError(JSErrorInfo *info);
uintptr_t RelocateObjectAddr(SerializedObjectSpace space, size_t objSize);
JSTaggedType RelocateObjectProtoAddr(uint8_t objectType);
void DeserializeObjectField(uintptr_t start, uintptr_t end);
void SetErrorMsgAndStack(uint8_t flag, size_t &handledFieldSize);
size_t ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset);
virtual size_t DerivedExtraReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset);
void HandleNewObjectEncodeFlag(SerializedObjectSpace space, uintptr_t objAddr, size_t fieldOffset);
void TransferArrayBufferAttach(uintptr_t objAddr);
void IncreaseSharedArrayBufferReference(uintptr_t objAddr);
void ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer);
void AllocateToDifferentSpaces();
bool AllocateToDifferentLocalSpaces(bool isFirstAllocate);
void AllocateToDifferentSharedSpaces();
void AllocateToDifferentCMCSpaces();
enum class RegionType : uint8_t {
RegularRegion,
PinRegion,
};
void AllocateToRegularSpace(size_t regularSpaceSize);
void AllocateToPinSpace(size_t pinSpaceSize);
uintptr_t AllocateMultiCMCRegion(size_t spaceObjSize, size_t ®ionIndex, RegionType regionType);
bool AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
SerializedObjectSpace spaceType, bool isFirstAllocate);
bool AllocateMultiNonmovableRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
SerializedObjectSpace spaceType, bool isFirstAllocate);
void AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
SerializedObjectSpace spaceType);
bool AllocateToOldSpace(size_t oldSpaceSize, bool isFirstAllocate);
bool AllocateToNonMovableSpace(size_t nonMovableSpaceSize, bool isFirstAllocate);
bool AllocateToMachineCodeSpace(size_t machineCodeSpaceSize, bool isFirstAllocate);
void AllocateToSharedOldSpace(size_t sOldSpaceSize);
void AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize);
bool GetAndResetWeak()
{
bool isWeak = isWeak_;
if (isWeak_) {
isWeak_ = false;
}
return isWeak;
}
bool GetAndResetTransferBuffer()
{
bool isTransferArrayBuffer = isTransferArrayBuffer_;
if (isTransferArrayBuffer_) {
isTransferArrayBuffer_ = false;
}
return isTransferArrayBuffer;
}
bool GetAndResetSharedArrayBuffer()
{
bool isSharedArrayBuffer = isSharedArrayBuffer_;
if (isSharedArrayBuffer_) {
isSharedArrayBuffer_ = false;
}
return isSharedArrayBuffer;
}
bool GetAndResetIsErrorMsg()
{
bool isErrorMsg = isErrorMsg_;
if (isErrorMsg_) {
isErrorMsg_ = false;
}
return isErrorMsg;
}
bool GetAndResetIsErrorStack()
{
bool isErrorStack = isErrorStack_;
if (isErrorStack_) {
isErrorStack_ = false;
}
return isErrorStack;
}
bool GetAndResetFunctionInShared()
{
bool functionInShared = functionInShared_;
if (functionInShared_) {
functionInShared_ = false;
}
return functionInShared;
}
void *GetAndResetBufferPointer()
{
if (bufferPointer_) {
void *buffer = bufferPointer_;
bufferPointer_ = nullptr;
return buffer;
}
return nullptr;
}
void DeserializeFatalOutOfMemory(const std::string &spaceTypeName,
size_t size, bool dump = true, bool isShared = false)
{
if (isShared) {
if (dump) {
sheap_->DumpHeapSnapshotBeforeOOM(thread_, SharedHeapOOMSource::DESERIALIZE,
spaceTypeName, size, SHARED_HEAP_STR);
}
LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize shared obj size: " << size
<< ", old space heap object size: "
<< sheap_->GetOldSpace()->GetHeapObjectSize()
<< ", old space committed size: "
<< sheap_->GetOldSpace()->GetCommittedSize()
<< ", non movable space heap object size: "
<< sheap_->GetNonMovableSpace()->GetHeapObjectSize()
<< ", non movable space committed size: "
<< sheap_->GetNonMovableSpace()->GetCommittedSize()
<< ", huge space committed size: "
<< sheap_->GetHugeObjectSpace()->GetCommittedSize();
} else {
if (dump) {
heap_->StatisticHeapDetail();
heap_->DumpHeapSnapshotBeforeOOM(false, spaceTypeName, size, LOCAL_HEAP_STR);
}
LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize obj size: " << size
<< ", old space heap object size: "
<< heap_->GetOldSpace()->GetHeapObjectSize()
<< ", old space committed size: "
<< heap_->GetOldSpace()->GetCommittedSize()
<< ", non movable space heap object size: "
<< heap_->GetNonMovableSpace()->GetHeapObjectSize()
<< ", non movable space committed size: "
<< heap_->GetNonMovableSpace()->GetCommittedSize()
<< ", huge space committed size: "
<< heap_->GetHugeObjectSpace()->GetCommittedSize();
}
}
void UpdateMaybeWeak(ObjectSlot slot, uintptr_t addr, bool isWeak)
{
isWeak ? slot.UpdateWeak(addr) : slot.Update(addr);
}
bool *GetLazyArray()
{
if (moduleLazyArray_) {
bool *buffer = moduleLazyArray_;
moduleLazyArray_ = nullptr;
return buffer;
}
return nullptr;
}
protected:
JSThread *thread_;
SerializeData *data_;
void *engine_;
size_t position_ {0};
CVector<JSTaggedType> objectVector_ {};
virtual void DeserializeSpecialRecordedObjects() {}
private:
Heap *heap_;
SharedHeap *sheap_;
uintptr_t currentRegularObjectAddr_ {0};
uintptr_t currentRegularRegionBeginAddr_ {0};
uintptr_t currentPinObjectAddr_ {0};
uintptr_t currentPinRegionBeginAddr_ {0};
size_t regularRegionIndex_ {0};
size_t pinRegionIndex_ {0};
CVector<uintptr_t> regionVector_;
uintptr_t oldSpaceBeginAddr_ {0};
uintptr_t nonMovableSpaceBeginAddr_ {0};
uintptr_t machineCodeSpaceBeginAddr_ {0};
uintptr_t sOldSpaceBeginAddr_ {0};
uintptr_t sNonMovableSpaceBeginAddr_ {0};
size_t oldRegionIndex_ {0};
size_t nonMovableRegionIndex_ {0};
size_t machineCodeRegionIndex_ {0};
size_t sOldRegionIndex_ {0};
size_t sNonMovableRegionIndex_ {0};
SerializationChunk *sharedObjChunk_ {nullptr};
bool isWeak_ {false};
bool isTransferArrayBuffer_ {false};
bool isSharedArrayBuffer_ {false};
bool isErrorMsg_ {false};
bool isErrorStack_ {false};
void *bufferPointer_ {nullptr};
bool functionInShared_ {false};
CVector<NativeBindingAttachInfo> nativeBindingAttachInfos_;
CVector<JSErrorInfo> jsErrorInfos_;
CVector<JSHandle<JSFunction>> concurrentFunctions_;
CString moduleFileName_ {};
CString moduleRecordName_ {};
bool* moduleLazyArray_ {nullptr};
};
}
#endif