* 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.
*/
#include "ecmascript/serializer/base_deserializer.h"
#include "heap/heap_allocator.h"
#include "ecmascript/free_object.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_regexp.h"
#include "ecmascript/checkpoint/thread_state_transition.h"
#include "ecmascript/napi/jsnapi_helper.h"
#include "mem/mem.h"
namespace panda::ecmascript {
BaseDeserializer::BaseDeserializer(JSThread *thread, SerializeData *data, void *hint)
: thread_(thread), data_(data), engine_(hint), heap_(const_cast<Heap *>(thread->GetEcmaVM()->GetHeap()))
{
sheap_ = SharedHeap::GetInstance();
uint32_t index = data_->GetDataIndex();
if (index != 0) {
sharedObjChunk_ = Runtime::GetInstance()->GetSerializeRootMapValue(thread_, index);
if (sharedObjChunk_ == nullptr) {
LOG_ECMA(FATAL) << "Unknown serializer root index: " << index;
UNREACHABLE();
}
}
}
JSHandle<JSTaggedValue> BaseDeserializer::ReadValue()
{
ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK,
("Deserialize dataSize: " + std::to_string(data_->Size())).c_str(), "");
if (data_->IsIncompleteData()) {
LOG_ECMA(ERROR) << "The serialization data is incomplete";
return JSHandle<JSTaggedValue>();
}
JSHandle<JSTaggedValue> res = DeserializeJSTaggedValue();
return res;
}
JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
{
JSHandle<TaggedArray> resHolderHandle = heap_->GetEcmaVM()->GetFactory()->NewTaggedArray(1);
AllocateToDifferentSpaces();
heap_->SetOnSerializeEvent(true);
uint8_t encodeFlag = data_->ReadUint8(position_);
uintptr_t resHolderAddr = static_cast<uintptr_t>(resHolderHandle.GetTaggedType());
while (ReadSingleEncodeData(encodeFlag, resHolderAddr, TaggedArray::DATA_OFFSET) == 0) {
encodeFlag = data_->ReadUint8(position_);
}
for (auto func : concurrentFunctions_) {
JSFunction::InitializeForConcurrentFunction(thread_, func);
}
concurrentFunctions_.clear();
for (auto &nativeBindingInfo : nativeBindingAttachInfos_) {
DeserializeNativeBindingObject(&nativeBindingInfo);
}
nativeBindingAttachInfos_.clear();
for (auto &jsErrorInfo : jsErrorInfos_) {
DeserializeJSError(&jsErrorInfo);
}
jsErrorInfos_.clear();
DeserializeSpecialRecordedObjects();
heap_->SetOnSerializeEvent(false);
return JSHandle<JSTaggedValue>(thread_, resHolderHandle->Get(thread_, 0));
}
uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
{
size_t objSize = data_->ReadUint32(position_);
uintptr_t res = RelocateObjectAddr(space, objSize);
objectVector_.push_back(static_cast<JSTaggedType>(res));
DeserializeObjectField(res, res + objSize);
return res;
}
void BaseDeserializer::DeserializeObjectField(uintptr_t start, uintptr_t end)
{
size_t offset = 0;
while (start + offset < end) {
uint8_t encodeFlag = data_->ReadUint8(position_);
size_t result = ReadSingleEncodeData(encodeFlag, start, offset);
#if USE_STICKY_CMS_GC
if (offset == 0) {
TaggedObject *obj = JSTaggedValue(static_cast<JSTaggedType>(start)).GetTaggedObject();
Region *objRegion = Region::ObjectAddressToRange(obj);
if (!objRegion->InSharedHeap()) {
objRegion->AtomicMark(reinterpret_cast<void *>(obj));
obj->SetObjectState(ObjectState::OLD);
objRegion->IncreaseGCAliveSize(end - start);
}
}
#endif
offset += result;
}
}
void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingAttachInfo *info)
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
AttachFunc af = info->af_;
void *bufferPointer = info->bufferPointer_;
void *hint = info->hint_;
void *attachData = info->attachData_;
Local<JSValueRef> attachVal;
{
ThreadNativeScope nativeScope(thread_);
attachVal = af(engine_, bufferPointer, hint, attachData);
}
if (attachVal.IsEmpty()) {
LOG_ECMA(ERROR) << "NativeBindingObject is empty";
attachVal = JSValueRef::Undefined(thread_->GetEcmaVM());
}
JSTaggedType res = JSNApiHelper::ToJSHandle(attachVal).GetTaggedType();
ObjectSlot slot = info->GetSlot();
#ifdef USE_CMC_GC
slot.Update(res);
if (!JSTaggedValue(res).IsInvalidValue()) {
WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(), res);
}
#else
if (!JSTaggedValue(res).IsInvalidValue()) {
WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(), res);
}
slot.Update(res);
#endif
}
void BaseDeserializer::DeserializeJSError(JSErrorInfo *info)
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
uint8_t type = info->errorType_;
base::ErrorType errorType = base::ErrorType(type - static_cast<uint8_t>(JSType::JS_ERROR_FIRST));
JSHandle<JSTaggedValue> errorMsg = info->errorMsg_;
JSHandle<JSTaggedValue> errorStack = info->errorStack_;
ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
JSHandle<JSObject> errorTag;
if (!errorStack->IsUndefined()) {
errorTag = factory->NewJSError(errorType, JSHandle<EcmaString>(errorMsg),
JSHandle<EcmaString>(errorStack), StackCheck::NO);
} else {
errorTag = factory->NewJSError(errorType, JSHandle<EcmaString>(errorMsg), StackCheck::NO);
}
ObjectSlot slot = info->GetSlot();
#ifdef USE_CMC_GC
slot.Update(errorTag.GetTaggedType());
if (!errorTag.GetTaggedValue().IsInvalidValue()) {
WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(),
errorTag.GetTaggedType());
}
#else
if (!errorTag.GetTaggedValue().IsInvalidValue()) {
WriteBarrier(thread_, reinterpret_cast<void *>(info->GetObjAddr()), info->GetFieldOffset(),
errorTag.GetTaggedType());
}
slot.Update(errorTag.GetTaggedType());
#endif
}
void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, uintptr_t objAddr, size_t fieldOffset)
{
bool isWeak = GetAndResetWeak();
bool isTransferBuffer = GetAndResetTransferBuffer();
bool isSharedArrayBuffer = GetAndResetSharedArrayBuffer();
void *bufferPointer = GetAndResetBufferPointer();
bool* lazyArray = GetLazyArray();
CString moduleFileName = moduleFileName_;
moduleFileName_.clear();
CString moduleRecordName = moduleRecordName_;
moduleRecordName_.clear();
uintptr_t addr = DeserializeTaggedObject(space);
if (isTransferBuffer) {
TransferArrayBufferAttach(addr);
} else if (isSharedArrayBuffer) {
IncreaseSharedArrayBufferReference(addr);
} else if (bufferPointer != nullptr) {
ResetNativePointerBuffer(addr, bufferPointer);
}
TaggedObject *object = reinterpret_cast<TaggedObject *>(addr);
if (object->GetClass()->IsJSNativePointer()) {
JSNativePointer *nativePointer = reinterpret_cast<JSNativePointer *>(object);
if (nativePointer->GetDeleter() != nullptr) {
if (!object->GetClass()->IsJSShared()) {
thread_->GetEcmaVM()->PushToNativePointerList(nativePointer);
}
}
} else if (object->GetClass()->IsJSFunction()) {
JSFunction* func = reinterpret_cast<JSFunction *>(object);
FunctionKind funcKind = func->GetFunctionKind(thread_);
if (funcKind == FunctionKind::CONCURRENT_FUNCTION || object->GetClass()->IsJSSharedFunction()) {
JSHandle<JSFunction> funcHandle(thread_, func);
concurrentFunctions_.push_back(funcHandle);
}
if (!object->GetClass()->IsJSApiFunction()) {
func->SetRawProfileTypeInfo<SKIP_BARRIER>(thread_,
thread_->GlobalConstants()->GetEmptyProfileTypeInfoCell());
#if !ENABLE_MEMORY_OPTIMIZATION
func->SetWorkNodePointer(reinterpret_cast<uintptr_t>(nullptr));
#endif
}
} else if (object->GetClass()->IsSourceTextModule()) {
SourceTextModule* module = reinterpret_cast<SourceTextModule *>(object);
module->SetEcmaModuleFilenameStringForDeserialize(moduleFileName);
module->SetEcmaModuleRecordNameStringForDeserialize(moduleRecordName);
module->SetLazyImportArrayForDeserialize(lazyArray);
if (module->GetStatus() > ModuleStatus::INSTANTIATED) {
module->SetStatus(ModuleStatus::INSTANTIATED);
}
module->SetException(thread_, thread_->GlobalConstants()->GetHole());
module->SetCycleRoot(thread_, JSTaggedValue(module));
}
#ifdef USE_CMC_GC
UpdateMaybeWeak(ObjectSlot(objAddr + fieldOffset), addr, isWeak);
WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
static_cast<JSTaggedType>(addr));
#else
WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
static_cast<JSTaggedType>(addr));
UpdateMaybeWeak(ObjectSlot(objAddr + fieldOffset), addr, isWeak);
#endif
}
void BaseDeserializer::TransferArrayBufferAttach(uintptr_t objAddr)
{
ASSERT(JSTaggedValue(static_cast<JSTaggedType>(objAddr)).IsArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
bool withNativeAreaAllocator = arrayBuffer->GetWithNativeAreaAllocator();
JSNativePointer *np =
reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData(thread_).GetTaggedObject());
arrayBuffer->Attach(thread_, arrayLength, JSTaggedValue(np), withNativeAreaAllocator);
}
void BaseDeserializer::IncreaseSharedArrayBufferReference(uintptr_t objAddr)
{
ASSERT(JSTaggedValue(static_cast<JSTaggedType>(objAddr)).IsSharedArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
JSNativePointer *np =
reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData(thread_).GetTaggedObject());
void *buffer = np->GetExternalPointer();
if (JSSharedMemoryManager::GetInstance()->CreateOrLoad(&buffer, arrayLength)) {
LOG_ECMA(FATAL) << "BaseDeserializer::IncreaseSharedArrayBufferReference failed";
}
}
void BaseDeserializer::ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer)
{
JSTaggedValue obj = JSTaggedValue(static_cast<JSTaggedType>(objAddr));
ASSERT(obj.IsArrayBuffer() || obj.IsJSRegExp());
auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
JSNativePointer *np = nullptr;
if (obj.IsArrayBuffer()) {
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
arrayBuffer->SetWithNativeAreaAllocator(true);
np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData(thread_).GetTaggedObject());
nativeAreaAllocator->IncreaseNativeSizeStats(arrayBuffer->GetArrayBufferByteLength(), NativeFlag::ARRAY_BUFFER);
} else {
JSRegExp *jsRegExp = reinterpret_cast<JSRegExp *>(objAddr);
np = reinterpret_cast<JSNativePointer *>(jsRegExp->GetByteCodeBuffer(thread_).GetTaggedObject());
nativeAreaAllocator->IncreaseNativeSizeStats(jsRegExp->GetLength(), NativeFlag::REGEXP_BTYECODE);
}
np->SetExternalPointer(bufferPointer);
np->SetDeleter(NativeAreaAllocator::FreeBufferFunc);
np->SetData(thread_->GetEcmaVM()->GetNativeAreaAllocator());
}
void BaseDeserializer::SetErrorMsgAndStack(uint8_t flag, size_t &handledFieldSize)
{
switch (flag) {
case static_cast<uint8_t>(JSErrorInfo::ErrorInfo::IS_ERROR_MSG):
isErrorMsg_ = true;
isErrorStack_ = false;
handledFieldSize = 0;
break;
case static_cast<uint8_t>(JSErrorInfo::ErrorInfo::IS_ERROR_MSG_AND_STACK):
isErrorMsg_ = true;
isErrorStack_ = true;
handledFieldSize = 0;
break;
default:
isErrorMsg_ = false;
isErrorStack_ = false;
break;
}
}
size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset)
{
size_t handledFieldSize = sizeof(JSTaggedType);
ObjectSlot slot(objAddr + fieldOffset);
switch (encodeFlag) {
case (uint8_t)SerializedObjectSpace::REGULAR_SPACE:
case (uint8_t)SerializedObjectSpace::PIN_SPACE:
case (uint8_t)SerializedObjectSpace::LARGE_SPACE:
case (uint8_t)SerializedObjectSpace::OLD_SPACE:
case (uint8_t)SerializedObjectSpace::SLOT_SPACE:
case (uint8_t)SerializedObjectSpace::NON_MOVABLE_SPACE:
case (uint8_t)SerializedObjectSpace::MACHINE_CODE_SPACE:
case (uint8_t)SerializedObjectSpace::HUGE_SPACE:
case (uint8_t)SerializedObjectSpace::SHARED_OLD_SPACE:
case (uint8_t)SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE:
case (uint8_t)SerializedObjectSpace::SHARED_HUGE_SPACE: {
SerializedObjectSpace space = SerializeData::DecodeSpace(encodeFlag);
HandleNewObjectEncodeFlag(space, objAddr, fieldOffset);
break;
}
case (uint8_t)EncodeFlag::REFERENCE: {
uint32_t valueIndex = data_->ReadUint32(position_);
JSTaggedType valueAddr = objectVector_.at(valueIndex);
#ifdef USE_CMC_GC
UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak());
WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
valueAddr);
#else
WriteBarrier<WriteBarrierType::DESERIALIZE>(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
valueAddr);
UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak());
#endif
break;
}
case (uint8_t)EncodeFlag::WEAK: {
ASSERT(!isWeak_);
isWeak_ = true;
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::PRIMITIVE: {
JSTaggedType value = data_->ReadJSTaggedType(position_);
slot.Update(value);
break;
}
case (uint8_t)EncodeFlag::MULTI_RAW_DATA: {
uint32_t size = data_->ReadUint32(position_);
data_->ReadRawData(objAddr + fieldOffset, size, position_);
handledFieldSize = size;
break;
}
case (uint8_t)EncodeFlag::ROOT_OBJECT: {
uint32_t index = data_->ReadUint32(position_);
uintptr_t valueAddr = thread_->GetEcmaVM()->GetSnapshotEnv()->RelocateRootObjectAddr(index);
if (valueAddr > JSTaggedValue::INVALID_VALUE_LIMIT) {
WriteBarrier(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
static_cast<JSTaggedType>(valueAddr));
}
UpdateMaybeWeak(slot, valueAddr, GetAndResetWeak());
break;
}
case (uint8_t)EncodeFlag::OBJECT_PROTO: {
uint8_t type = data_->ReadUint8(position_);
uintptr_t protoAddr = RelocateObjectProtoAddr(type);
if (protoAddr > JSTaggedValue::INVALID_VALUE_LIMIT) {
WriteBarrier(thread_, reinterpret_cast<void *>(objAddr), fieldOffset,
static_cast<JSTaggedType>(protoAddr));
}
UpdateMaybeWeak(slot, protoAddr, GetAndResetWeak());
break;
}
case (uint8_t)EncodeFlag::TRANSFER_ARRAY_BUFFER: {
isTransferArrayBuffer_ = true;
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::SHARED_ARRAY_BUFFER: {
isSharedArrayBuffer_ = true;
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::ARRAY_BUFFER:
case (uint8_t)EncodeFlag::SENDABLE_ARRAY_BUFFER:
case (uint8_t)EncodeFlag::JS_REG_EXP: {
size_t bufferLength = data_->ReadUint32(position_);
auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
bufferPointer_ = nativeAreaAllocator->AllocateBuffer(bufferLength);
heap_->IncNativeSizeAfterLastGC(bufferLength);
data_->ReadRawData(ToUintPtr(bufferPointer_), bufferLength, position_);
heap_->IncreaseNativeBindingSize(bufferLength);
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::NATIVE_BINDING_OBJECT: {
slot.Update(JSTaggedValue::Undefined().GetRawData());
AttachFunc af = reinterpret_cast<AttachFunc>(data_->ReadJSTaggedType(position_));
void *bufferPointer = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
void *hint = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
void *attachData = reinterpret_cast<void *>(data_->ReadJSTaggedType(position_));
JSHandle<JSTaggedValue> obj(thread_, JSTaggedValue(static_cast<JSTaggedType>(objAddr)));
nativeBindingAttachInfos_.emplace_back(af, bufferPointer, hint, attachData, obj, fieldOffset);
break;
}
case (uint8_t)EncodeFlag::JS_ERROR: {
slot.Update(JSTaggedValue::Undefined().GetRawData());
uint8_t type = data_->ReadUint8(position_);
ASSERT(type >= static_cast<uint8_t>(JSType::JS_ERROR_FIRST)
&& type <= static_cast<uint8_t>(JSType::JS_ERROR_LAST));
JSHandle<JSTaggedValue> obj(thread_, JSTaggedValue(static_cast<JSTaggedType>(objAddr)));
jsErrorInfos_.emplace_back(type, JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()),
JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined()), obj,
fieldOffset);
uint8_t flag = data_->ReadUint8(position_);
SetErrorMsgAndStack(flag, handledFieldSize);
break;
}
case (uint8_t)EncodeFlag::SHARED_OBJECT: {
uint32_t index = data_->ReadUint32(position_);
if (UNLIKELY(index >= sharedObjChunk_->Size())) {
LOG_ECMA(FATAL) << "Shared object index invalid, index: " << index << " chunkSize: "
<< sharedObjChunk_->Size();
UNREACHABLE();
}
JSTaggedType value = sharedObjChunk_->Get(index);
objectVector_.push_back(value);
bool isErrorMsg = GetAndResetIsErrorMsg();
if (isErrorMsg) {
jsErrorInfos_.back().errorMsg_ = JSHandle<JSTaggedValue>(thread_, JSTaggedValue(value));
if (isErrorStack_) {
handledFieldSize = 0;
}
break;
}
bool isErrorStack = GetAndResetIsErrorStack();
if (isErrorStack) {
jsErrorInfos_.back().errorStack_ = JSHandle<JSTaggedValue>(thread_, JSTaggedValue(value));
break;
}
WriteBarrier(thread_, reinterpret_cast<void *>(objAddr), fieldOffset, value);
UpdateMaybeWeak(slot, value, GetAndResetWeak());
break;
}
case (uint8_t)EncodeFlag::GLOBAL_ENV: {
slot.Update(thread_->GetGlobalEnv().GetTaggedValue().GetTaggedObject());
break;
}
case (uint8_t)EncodeFlag::MODULE_FILE_NAME: {
uint32_t len = data_->ReadUint32(position_);
if (len > 0) {
moduleFileName_.resize(len);
data_->ReadRawData(ToUintPtr(moduleFileName_.data()), len, position_);
} else {
moduleFileName_ = "";
}
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::MODULE_RECORD_NAME: {
uint32_t len = data_->ReadUint32(position_);
if (len > 0) {
moduleRecordName_.resize(len);
data_->ReadRawData(ToUintPtr(moduleRecordName_.data()), len, position_);
} else {
moduleRecordName_ = "";
}
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::MODULE_LAZY_ARRAY: {
uint32_t len = data_->ReadUint32(position_);
if (len > 0) {
moduleLazyArray_ = new bool[len/sizeof(bool)];
data_->ReadRawData(ToUintPtr(moduleLazyArray_), len, position_);
} else {
moduleLazyArray_ = nullptr;
}
handledFieldSize = 0;
break;
}
case (uint8_t)EncodeFlag::SEQUENCE_HOLE: {
auto count = data_->ReadUint32(position_);
for (uint32_t i = 0; i < count; i++) {
slot.Update(JSTaggedValue::Hole().GetRawData());
slot++;
}
handledFieldSize *= count;
break;
}
default:
return DerivedExtraReadSingleEncodeData(encodeFlag, objAddr, fieldOffset);
}
return handledFieldSize;
}
size_t BaseDeserializer::DerivedExtraReadSingleEncodeData(uint8_t encodeFlag, uintptr_t objAddr, size_t fieldOffset)
{
LOG_ECMA(FATAL) << "this branch is unreachable " << static_cast<int>(encodeFlag);
UNREACHABLE();
}
uintptr_t BaseDeserializer::RelocateObjectAddr(SerializedObjectSpace space, size_t objSize)
{
uintptr_t res = 0U;
switch (space) {
case SerializedObjectSpace::REGULAR_SPACE: {
if (currentRegularObjectAddr_ + objSize >
currentRegularRegionBeginAddr_ + common::Heap::GetNormalRegionAvailableSize()) {
ASSERT(regularRegionIndex_ < regionVector_.size());
currentRegularObjectAddr_ = regionVector_[regularRegionIndex_++];
currentRegularRegionBeginAddr_ = currentRegularObjectAddr_;
}
res = currentRegularObjectAddr_;
currentRegularObjectAddr_ += objSize;
break;
}
case SerializedObjectSpace::PIN_SPACE: {
if (currentPinObjectAddr_ + objSize >
currentPinRegionBeginAddr_ + common::Heap::GetNormalRegionAvailableSize()) {
ASSERT(pinRegionIndex_ < regionVector_.size());
currentPinObjectAddr_ = regionVector_[pinRegionIndex_++];
currentPinRegionBeginAddr_ = currentPinObjectAddr_;
}
res = currentPinObjectAddr_;
currentPinObjectAddr_ += objSize;
break;
}
case SerializedObjectSpace::LARGE_SPACE: {
res = common::HeapAllocator::AllocateLargeRegion(objSize);
if (res == 0) {
DeserializeFatalOutOfMemory("", objSize, false, false);
}
break;
}
case SerializedObjectSpace::OLD_SPACE: {
if (oldSpaceBeginAddr_ + objSize > AlignUp(oldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(oldRegionIndex_ < regionVector_.size());
oldSpaceBeginAddr_ = regionVector_[oldRegionIndex_++];
}
res = oldSpaceBeginAddr_;
oldSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::SLOT_SPACE: {
res = heap_->GetSlotSpace()->Allocate<false>(objSize);
break;
}
case SerializedObjectSpace::NON_MOVABLE_SPACE: {
if (nonMovableSpaceBeginAddr_ + objSize > AlignUp(nonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(nonMovableRegionIndex_ < regionVector_.size());
nonMovableSpaceBeginAddr_ = regionVector_[nonMovableRegionIndex_++];
}
res = nonMovableSpaceBeginAddr_;
nonMovableSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::MACHINE_CODE_SPACE: {
if (machineCodeSpaceBeginAddr_ + objSize > AlignUp(machineCodeSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(machineCodeRegionIndex_ < regionVector_.size());
machineCodeSpaceBeginAddr_ = regionVector_[machineCodeRegionIndex_++];
}
res = machineCodeSpaceBeginAddr_;
machineCodeSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::HUGE_SPACE: {
res = heap_->GetHugeObjectSpace()->Allocate(objSize, thread_, AllocateEventType::DESERIALIZE);
if (res == 0) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(heap_->GetHugeObjectSpace()->GetSpaceType()),
objSize, false, false);
}
break;
}
case SerializedObjectSpace::SHARED_OLD_SPACE: {
if (sOldSpaceBeginAddr_ + objSize > AlignUp(sOldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(sOldRegionIndex_ < regionVector_.size());
sOldSpaceBeginAddr_ = regionVector_[sOldRegionIndex_++];
}
res = sOldSpaceBeginAddr_;
sOldSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE: {
if (sNonMovableSpaceBeginAddr_ + objSize > AlignUp(sNonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(sNonMovableRegionIndex_ < regionVector_.size());
sNonMovableSpaceBeginAddr_ = regionVector_[sNonMovableRegionIndex_++];
}
res = sNonMovableSpaceBeginAddr_;
sNonMovableSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::SHARED_HUGE_SPACE: {
res = sheap_->GetHugeObjectSpace()->Allocate(thread_, objSize, AllocateEventType::DESERIALIZE);
if (res == 0) {
DeserializeFatalOutOfMemory(
ToSpaceTypeName(sheap_->GetHugeObjectSpace()->GetSpaceType()), objSize, false, true);
}
break;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
return res;
}
JSTaggedType BaseDeserializer::RelocateObjectProtoAddr(uint8_t objectType)
{
auto env = thread_->GetEcmaVM()->GetGlobalEnv();
switch (objectType) {
case (uint8_t)JSType::JS_OBJECT:
return env->GetObjectFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_ERROR:
return JSHandle<JSFunction>(env->GetErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_EVAL_ERROR:
return JSHandle<JSFunction>(env->GetEvalErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_RANGE_ERROR:
return JSHandle<JSFunction>(env->GetRangeErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_REFERENCE_ERROR:
return JSHandle<JSFunction>(env->GetReferenceErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_TYPE_ERROR:
return JSHandle<JSFunction>(env->GetTypeErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_AGGREGATE_ERROR:
return JSHandle<JSFunction>(env->GetAggregateErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_URI_ERROR:
return JSHandle<JSFunction>(env->GetURIErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_SYNTAX_ERROR:
return JSHandle<JSFunction>(env->GetSyntaxErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_OOM_ERROR:
return JSHandle<JSFunction>(env->GetOOMErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_TERMINATION_ERROR:
return JSHandle<JSFunction>(env->GetTerminationErrorFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_DATE:
return env->GetDatePrototype().GetTaggedType();
case (uint8_t)JSType::JS_ARRAY:
return env->GetArrayPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_ARRAY:
return env->GetSharedArrayPrototype().GetTaggedType();
case (uint8_t)JSType::JS_API_BITVECTOR:
return env->GetBitVectorPrototype().GetTaggedType();
case (uint8_t)JSType::JS_MAP:
return env->GetMapPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_MAP:
return env->GetSharedMapPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SET:
return env->GetSetPrototype().GetTaggedType();
case (uint8_t)JSType::JS_API_TREE_SET:
return JSHandle<JSFunction>(env->GetTreeSetConstructor())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_SHARED_SET:
return env->GetSharedSetPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SENDABLE_ARRAY_BUFFER:
return env->GetSendableArrayBufferPrototype().GetTaggedType();
case (uint8_t)JSType::JS_REG_EXP:
return env->GetRegExpPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT8_ARRAY:
return env->GetInt8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT8_ARRAY:
return env->GetUint8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT8_CLAMPED_ARRAY:
return env->GetUint8ClampedArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT16_ARRAY:
return env->GetInt16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT16_ARRAY:
return env->GetUint16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT32_ARRAY:
return env->GetInt32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT32_ARRAY:
return env->GetUint32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_FLOAT32_ARRAY:
return env->GetFloat32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_FLOAT64_ARRAY:
return env->GetFloat64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_BIGINT64_ARRAY:
return env->GetBigInt64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_BIGUINT64_ARRAY:
return env->GetBigUint64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_INT8_ARRAY:
return env->GetSharedInt8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_UINT8_ARRAY:
return env->GetSharedUint8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_UINT8_CLAMPED_ARRAY:
return env->GetSharedUint8ClampedArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_INT16_ARRAY:
return env->GetSharedInt16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_UINT16_ARRAY:
return env->GetSharedUint16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_INT32_ARRAY:
return env->GetSharedInt32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_UINT32_ARRAY:
return env->GetSharedUint32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_FLOAT32_ARRAY:
return env->GetSharedFloat32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_FLOAT64_ARRAY:
return env->GetSharedFloat64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_BIGINT64_ARRAY:
return env->GetSharedBigInt64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_BIGUINT64_ARRAY:
return env->GetSharedBigUint64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_ARRAY_BUFFER:
return JSHandle<JSFunction>(env->GetArrayBufferFunction())->GetFunctionPrototype(thread_).GetRawData();
case (uint8_t)JSType::JS_SHARED_ARRAY_BUFFER:
return JSHandle<JSFunction>(env->GetSharedArrayBufferFunction())
->GetFunctionPrototype(thread_)
.GetRawData();
case (uint8_t)JSType::JS_ASYNC_FUNCTION:
return env->GetAsyncFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SHARED_ASYNC_FUNCTION:
return env->GetSAsyncFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::BIGINT:
return JSHandle<JSFunction>(env->GetBigIntFunction())->GetFunctionPrototype(thread_).GetRawData();
default:
LOG_ECMA(FATAL) << "Relocate unsupported JSType: " << JSHClass::DumpJSType(static_cast<JSType>(objectType));
UNREACHABLE();
break;
}
}
void BaseDeserializer::AllocateToDifferentSpaces()
{
if (g_isEnableCMCGC) {
AllocateToDifferentCMCSpaces();
} else {
size_t oldOrHugeSize = data_->GetOldSpaceSize() + data_->GetHugeSpaceSize();
if (heap_->OldSpaceExceedCapacity(oldOrHugeSize)) {
heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_FAILED);
}
if (!AllocateToDifferentLocalSpaces(true)) {
heap_->CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_FAILED);
AllocateToDifferentLocalSpaces(false);
}
AllocateToDifferentSharedSpaces();
}
}
bool BaseDeserializer::AllocateToDifferentLocalSpaces(bool isFirstAllocate)
{
size_t oldSpaceSize = data_->GetOldSpaceSize();
if (oldSpaceSize > 0) {
heap_->GetOldSpace()->IncreaseLiveObjectSize(oldSpaceSize);
if (!AllocateToOldSpace(oldSpaceSize, isFirstAllocate)) {
heap_->GetOldSpace()->DecreaseLiveObjectSize(oldSpaceSize);
return false;
}
}
size_t nonMovableSpaceSize = data_->GetNonMovableSpaceSize();
if (nonMovableSpaceSize > 0) {
if (!AllocateToNonMovableSpace(nonMovableSpaceSize, isFirstAllocate)) {
return false;
}
}
size_t machineCodeSpaceSize = data_->GetMachineCodeSpaceSize();
if (machineCodeSpaceSize > 0) {
if (!AllocateToMachineCodeSpace(machineCodeSpaceSize, isFirstAllocate)) {
return false;
}
}
return true;
}
void BaseDeserializer::AllocateToDifferentSharedSpaces()
{
size_t sOldSpaceSize = data_->GetSharedOldSpaceSize();
if (sOldSpaceSize > 0) {
sheap_->GetOldSpace()->IncreaseLiveObjectSize(sOldSpaceSize);
AllocateToSharedOldSpace(sOldSpaceSize);
}
size_t sNonMovableSpaceSize = data_->GetSharedNonMovableSpaceSize();
if (sNonMovableSpaceSize > 0) {
sheap_->GetNonMovableSpace()->IncreaseLiveObjectSize(sNonMovableSpaceSize);
AllocateToSharedNonMovableSpace(sNonMovableSpaceSize);
}
}
void BaseDeserializer::AllocateToDifferentCMCSpaces()
{
size_t regularSpaceSize = data_->GetRegularSpaceSize();
if (regularSpaceSize > 0) {
AllocateToRegularSpace(regularSpaceSize);
}
size_t pinSpaceSize = data_->GetPinSpaceSize();
if (pinSpaceSize > 0) {
AllocateToPinSpace(pinSpaceSize);
}
}
void BaseDeserializer::AllocateToRegularSpace(size_t regularSpaceSize)
{
if (regularSpaceSize <= common::Heap::GetNormalRegionAvailableSize()) {
currentRegularObjectAddr_ = common::HeapAllocator::AllocateNoGC(regularSpaceSize);
} else {
currentRegularObjectAddr_ = AllocateMultiCMCRegion(regularSpaceSize, regularRegionIndex_,
RegionType::RegularRegion);
}
currentRegularRegionBeginAddr_ = currentRegularObjectAddr_;
if (currentRegularObjectAddr_ == 0U) {
LOG_ECMA(FATAL) << "Deserialize oom error";
}
}
void BaseDeserializer::AllocateToPinSpace(size_t pinSpaceSize)
{
if (pinSpaceSize <= common::Heap::GetNormalRegionAvailableSize()) {
currentPinObjectAddr_ = common::HeapAllocator::AllocateNonmoveNoGC(pinSpaceSize);
} else {
currentPinObjectAddr_ = AllocateMultiCMCRegion(pinSpaceSize, pinRegionIndex_, RegionType::PinRegion);
}
currentPinRegionBeginAddr_ = currentPinObjectAddr_;
if (currentPinObjectAddr_ == 0U) {
LOG_ECMA(FATAL) << "Deserialize oom error";
}
}
uintptr_t BaseDeserializer::AllocateMultiCMCRegion(size_t spaceObjSize, size_t ®ionIndex, RegionType regionType)
{
constexpr size_t REGION_SIZE = common::Heap::GetNormalRegionAvailableSize();
ASSERT(REGION_SIZE != 0);
ASSERT(spaceObjSize > REGION_SIZE);
regionIndex = regionVector_.size();
size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
ASSERT(regionAlignedSize % REGION_SIZE == 0);
size_t regionNum = regionAlignedSize / REGION_SIZE;
uintptr_t firstRegionAddr = 0U;
std::vector<size_t> regionRemainSizeVector;
size_t regionRemainSizeIndex = 0;
if (regionType == RegionType::RegularRegion) {
regionRemainSizeVector = data_->GetRegularRemainSizeVector();
} else {
regionRemainSizeVector = data_->GetPinRemainSizeVector();
}
while (regionNum > 0) {
uintptr_t regionAddr = 0U;
if (regionType == RegionType::RegularRegion) {
regionAddr = common::HeapAllocator::AllocateOldRegion();
} else {
regionAddr = common::HeapAllocator::AllocateNonMovableRegion();
}
if (regionAddr == 0U) {
LOG_ECMA(FATAL) << "Deserialize allocate multi cmc region fail";
}
if (firstRegionAddr == 0U) {
firstRegionAddr = regionAddr;
} else {
regionVector_.push_back(regionAddr);
}
if (regionNum == 1) {
size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
FreeObject::FillFreeObject(heap_, regionAddr + REGION_SIZE - lastRegionRemainSize,
lastRegionRemainSize);
} else {
auto regionAliveObjSize = REGION_SIZE - regionRemainSizeVector[regionRemainSizeIndex++];
FreeObject::FillFreeObject(heap_, regionAddr + regionAliveObjSize, REGION_SIZE - regionAliveObjSize);
}
regionNum--;
}
return firstRegionAddr;
}
bool BaseDeserializer::AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
SerializedObjectSpace spaceType, bool isFirstAllocate)
{
ASSERT(spaceType != SerializedObjectSpace::NON_MOVABLE_SPACE);
regionIndex = regionVector_.size();
size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
size_t regionNum = regionAlignedSize / DefaultRegion::GetRegionAvailableSize();
size_t index = 0;
while (regionNum > 1) {
auto regionRemainSizeVector = data_->GetRegionRemainSizeVectors().at(static_cast<uint8_t>(spaceType));
auto regionAliveObjSize = DefaultRegion::GetRegionAvailableSize() - regionRemainSizeVector[index++];
space->GetCurrentRegion()->IncreaseAliveObject(regionAliveObjSize);
space->ResetTopPointer(space->GetCurrentRegion()->GetBegin() + regionAliveObjSize);
if (!space->Expand()) {
if (!isFirstAllocate) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(space->GetSpaceType()), spaceObjSize);
}
regionVector_.clear();
return false;
}
Region *currentRegion = space->GetCurrentRegion();
FreeObject::FillFreeObject(heap_, currentRegion->GetBegin(), currentRegion->GetSize());
regionVector_.push_back(currentRegion->GetBegin());
regionNum--;
}
size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
space->GetCurrentRegion()->IncreaseAliveObject(DefaultRegion::GetRegionAvailableSize() - lastRegionRemainSize);
space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - lastRegionRemainSize);
return true;
}
bool BaseDeserializer::AllocateMultiNonmovableRegion(SparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
[[maybe_unused]] SerializedObjectSpace spaceType,
bool isFirstAllocate)
{
ASSERT(spaceType == SerializedObjectSpace::NON_MOVABLE_SPACE);
regionIndex = regionVector_.size();
size_t allocatedSize = 0;
const std::vector<size_t> &remainSize = data_->GetRegionRemainSizeVectors().at(static_cast<int>(spaceType));
size_t numRegion = 0;
size_t totalRegion = remainSize.size();
while (allocatedSize < spaceObjSize) {
size_t leftSize = spaceObjSize - allocatedSize;
size_t size = std::min(leftSize, DefaultRegion::GetRegionAvailableSize());
uintptr_t obj = space->Allocate(size, false);
if (obj == 0) {
if (!isFirstAllocate) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(space->GetSpaceType()), spaceObjSize);
}
regionVector_.clear();
return false;
}
if (allocatedSize == 0) {
nonMovableSpaceBeginAddr_ = obj;
} else {
regionVector_.push_back(obj);
}
allocatedSize += size;
if (numRegion < totalRegion) {
size_t wastedSize = remainSize[numRegion++];
FreeObject::FillFreeObject(heap_, obj, size - wastedSize);
FreeObject::FillFreeObject(heap_, obj + size - wastedSize, wastedSize);
} else {
FreeObject::FillFreeObject(heap_, obj, size);
}
}
return true;
}
void BaseDeserializer::AllocateMultiSharedRegion(SharedSparseSpace *space, size_t spaceObjSize, size_t ®ionIndex,
SerializedObjectSpace spaceType)
{
regionIndex = regionVector_.size();
size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
size_t regionNum = regionAlignedSize / DefaultRegion::GetRegionAvailableSize();
auto regionRemainSizeVector = data_->GetRegionRemainSizeVectors().at(static_cast<uint8_t>(spaceType));
std::vector<Region *> allocateRegions;
size_t index = 0;
while (regionNum > 0) {
if (space->CommittedSizeExceed()) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(space->GetSpaceType()), spaceObjSize, true, true);
}
Region *region = space->AllocateDeserializeRegion(thread_);
FreeObject::FillFreeObject(sheap_, region->GetBegin(), region->GetSize());
if (regionNum == 1) {
size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
region->SetHighWaterMark(region->GetEnd() - lastRegionRemainSize);
} else {
region->SetHighWaterMark(region->GetEnd() - regionRemainSizeVector[index++]);
}
region->IncreaseAliveObject(region->GetAllocatedBytes());
regionVector_.push_back(region->GetBegin());
allocateRegions.push_back(region);
regionNum--;
}
space->MergeDeserializeAllocateRegions(allocateRegions);
}
bool BaseDeserializer::AllocateToOldSpace(size_t oldSpaceSize, bool isFirstAllocate)
{
OldSpace *space = heap_->GetOldSpace();
uintptr_t object = space->AllocateSlow(oldSpaceSize, true);
if (UNLIKELY(object == 0U)) {
if (space->CommittedSizeExceed()) {
if (!isFirstAllocate) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(space->GetSpaceType()), oldSpaceSize);
}
return false;
}
oldSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
FreeObject::FillFreeObject(heap_, oldSpaceBeginAddr_, space->GetCurrentRegion()->GetSize());
return AllocateMultiRegion(space, oldSpaceSize, oldRegionIndex_,
SerializedObjectSpace::OLD_SPACE, isFirstAllocate);
}
FreeObject::FillFreeObject(heap_, object, oldSpaceSize);
oldSpaceBeginAddr_ = object;
return true;
}
bool BaseDeserializer::AllocateToNonMovableSpace(size_t nonMovableSpaceSize, bool isFirstAllocate)
{
SparseSpace *space = heap_->GetNonMovableSpace();
uintptr_t object = space->Allocate(nonMovableSpaceSize, false);
if (UNLIKELY(object == 0U)) {
return AllocateMultiNonmovableRegion(space, nonMovableSpaceSize, nonMovableRegionIndex_,
SerializedObjectSpace::NON_MOVABLE_SPACE, isFirstAllocate);
}
FreeObject::FillFreeObject(heap_, object, nonMovableSpaceSize);
nonMovableSpaceBeginAddr_ = object;
return true;
}
bool BaseDeserializer::AllocateToMachineCodeSpace(size_t machineCodeSpaceSize, bool isFirstAllocate)
{
SparseSpace *space = heap_->GetMachineCodeSpace();
uintptr_t object = space->Allocate(machineCodeSpaceSize, false);
if (UNLIKELY(object == 0U)) {
if (space->CommittedSizeExceed()) {
if (!isFirstAllocate) {
DeserializeFatalOutOfMemory(ToSpaceTypeName(space->GetSpaceType()), machineCodeSpaceSize);
}
return false;
}
machineCodeSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
FreeObject::FillFreeObject(heap_, machineCodeSpaceBeginAddr_, space->GetCurrentRegion()->GetSize());
return AllocateMultiRegion(space, machineCodeSpaceSize, machineCodeRegionIndex_,
SerializedObjectSpace::MACHINE_CODE_SPACE, isFirstAllocate);
}
FreeObject::FillFreeObject(heap_, object, machineCodeSpaceSize);
machineCodeSpaceBeginAddr_ = object;
return true;
}
void BaseDeserializer::AllocateToSharedOldSpace(size_t sOldSpaceSize)
{
SharedSparseSpace *space = sheap_->GetOldSpace();
uintptr_t object = space->AllocateNoGCAndExpand(thread_, sOldSpaceSize);
if (UNLIKELY(object == 0U)) {
AllocateMultiSharedRegion(space, sOldSpaceSize, sOldRegionIndex_, SerializedObjectSpace::SHARED_OLD_SPACE);
sOldSpaceBeginAddr_ = regionVector_[sOldRegionIndex_++];
} else {
if (thread_->IsSharedConcurrentMarkingOrFinished()) {
Region *region = Region::ObjectAddressToRange(object);
region->IncreaseAliveObject(sOldSpaceSize);
}
FreeObject::FillFreeObject(sheap_, object, sOldSpaceSize);
sOldSpaceBeginAddr_ = object;
}
}
void BaseDeserializer::AllocateToSharedNonMovableSpace(size_t sNonMovableSpaceSize)
{
SharedNonMovableSpace *space = sheap_->GetNonMovableSpace();
uintptr_t object = space->AllocateNoGCAndExpand(thread_, sNonMovableSpaceSize);
if (UNLIKELY(object == 0U)) {
AllocateMultiSharedRegion(space, sNonMovableSpaceSize, sNonMovableRegionIndex_,
SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE);
sNonMovableSpaceBeginAddr_ = regionVector_[sNonMovableRegionIndex_++];
} else {
if (thread_->IsSharedConcurrentMarkingOrFinished()) {
Region *region = Region::ObjectAddressToRange(object);
region->IncreaseAliveObject(sNonMovableSpaceSize);
}
FreeObject::FillFreeObject(sheap_, object, sNonMovableSpaceSize);
sNonMovableSpaceBeginAddr_ = object;
}
}
}