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