• 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 #ifndef ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
17 #define ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
18 
19 #include <limits>
20 
21 #include "common_components/heap/heap.h"
22 #include "common_components/serialize/serialize_utils.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/mem/dyn_chunk.h"
25 #include "ecmascript/runtime.h"
26 #include "ecmascript/shared_mm/shared_mm.h"
27 #include "ecmascript/snapshot/mem/snapshot_env.h"
28 
29 namespace panda::ecmascript {
30 constexpr size_t INITIAL_CAPACITY = 64;
31 constexpr int CAPACITY_INCREASE_RATE = 2;
32 constexpr uint32_t RESERVED_INDEX = 0;
33 static constexpr int SERIALIZE_SPACE_NUM = 12;
34 
35 typedef void* (*DetachFunc)(void *enginePointer, void *objPointer, void *hint, void *detachData);
36 typedef Local<JSValueRef> (*AttachFunc)(void *enginePointer, void *buffer, void *hint, void *attachData);
37 typedef Local<JSValueRef> (*AttachXRefFunc)(void *enginePointer, void *attachXRefData);
38 typedef void (*DetachFinalizer)(void *detachedObject, void *finalizerHint);
39 
40 struct NativeBindingDetachInfo {
41     DetachFinalizer detachedFinalizer = nullptr;
42     void *detachedObject = nullptr;
43     void *detachedHint = nullptr;
44 
NativeBindingDetachInfoNativeBindingDetachInfo45     NativeBindingDetachInfo(void *df, void *dObj, void *hint)
46         : detachedFinalizer(reinterpret_cast<DetachFinalizer>(df)), detachedObject(dObj), detachedHint(hint)
47     {
48     }
49 };
50 
51 enum class EncodeFlag : uint8_t {
52     // 0x00~0x06 represent new object to different space:
53     // 0x00: old space
54     // 0x01: non movable space
55     // 0x02: machine code space
56     // 0x03: huge space
57     // 0x04: shared old space
58     // 0x05: shared non movable space
59     // 0x06: shared huge space
60     NEW_OBJECT = 0x00,
61     REFERENCE = 0x10,
62     WEAK,
63     PRIMITIVE,
64     MULTI_RAW_DATA,
65     ROOT_OBJECT,
66     OBJECT_PROTO,
67     ARRAY_BUFFER,
68     TRANSFER_ARRAY_BUFFER,
69     SHARED_ARRAY_BUFFER,
70     SENDABLE_ARRAY_BUFFER,
71     NATIVE_BINDING_OBJECT,
72     XREF_BINDING_OBJECT,    // Only support in inter-op.
73     JS_ERROR,
74     JS_REG_EXP,
75     SHARED_OBJECT,
76     GLOBAL_ENV,
77     MODULE_FILE_NAME,
78     MODULE_RECORD_NAME,
79     MODULE_LAZY_ARRAY,
80     LAST
81 };
82 
83 enum class SerializedObjectSpace : uint8_t {
84     REGULAR_SPACE,
85     PIN_SPACE,
86     LARGE_SPACE,
87     READ_ONLY_SPACE,
88     OTHER,
89 
90     OLD_SPACE,
91     NON_MOVABLE_SPACE,
92     MACHINE_CODE_SPACE,
93     HUGE_SPACE,
94     SHARED_OLD_SPACE,
95     SHARED_NON_MOVABLE_SPACE,
96     SHARED_HUGE_SPACE,
97 };
98 using common::SerializedBaseObjectSpace;
99 
100 enum class SerializeType : uint8_t {
101     VALUE_SERIALIZE,
102     PGO_SERIALIZE
103 };
104 
105 class SerializeData {
106 public:
SerializeData(JSThread * thread)107     explicit SerializeData(JSThread *thread) : thread_(thread) {}
~SerializeData()108     ~SerializeData()
109     {
110         // decrease sharedArrayBuffer reference
111         if (sharedArrayBufferSet_.size() > 0) {
112             DecreaseSharedArrayBufferReference();
113         }
114         for (const auto &info: nativeBindingDetachInfos_) {
115             auto finalizer = reinterpret_cast<DetachFinalizer>(info->detachedFinalizer);
116             if (finalizer != nullptr) {
117                 finalizer(info->detachedObject, info->detachedHint);
118             }
119             delete info;
120         }
121         nativeBindingDetachInfos_.clear();
122         free(buffer_);
123         if (!incompleteData_ && dataIndex_ != RESERVED_INDEX) {
124             Runtime::GetInstance()->RemoveSerializationRoot(thread_, dataIndex_);
125         }
126     }
127     NO_COPY_SEMANTIC(SerializeData);
128     NO_MOVE_SEMANTIC(SerializeData);
129 
EncodeNewObject(SerializedObjectSpace space)130     static uint8_t EncodeNewObject(SerializedObjectSpace space)
131     {
132         return static_cast<uint8_t>(space) | static_cast<uint8_t>(EncodeFlag::NEW_OBJECT);
133     }
134 
DecodeSpace(uint8_t type)135     static SerializedObjectSpace DecodeSpace(uint8_t type)
136     {
137         ASSERT(type < static_cast<uint8_t>(EncodeFlag::REFERENCE));
138         return static_cast<SerializedObjectSpace>(type);
139     }
140 
AlignUpRegionAvailableSize(size_t size)141     static size_t AlignUpRegionAvailableSize(size_t size)
142     {
143         if (g_isEnableCMCGC) {
144             constexpr size_t REGION_SIZE = common::Heap::GetNormalRegionAvailableSize();
145             if (size == 0) {
146                 return REGION_SIZE;
147             }
148             ASSERT(REGION_SIZE != 0);
149             return ((size - 1) / REGION_SIZE + 1) * REGION_SIZE; // 1: align up
150         } else {
151             if (size == 0) {
152                 return Region::GetRegionAvailableSize();
153             }
154             size_t regionAvailableSize = Region::GetRegionAvailableSize();
155             return ((size - 1) / regionAvailableSize + 1) * regionAvailableSize; // 1: align up
156         }
157     }
158 
ExpandBuffer(size_t requestedSize)159     bool ExpandBuffer(size_t requestedSize)
160     {
161         size_t newCapacity = bufferCapacity_ * CAPACITY_INCREASE_RATE;
162         newCapacity = std::max(newCapacity, requestedSize);
163         if (newCapacity > sizeLimit_) {
164             return false;
165         }
166         uint8_t *newBuffer = reinterpret_cast<uint8_t *>(malloc(newCapacity));
167         if (newBuffer == nullptr) {
168             return false;
169         }
170         if (memcpy_s(newBuffer, newCapacity, buffer_, bufferSize_) != EOK) {
171             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
172             free(newBuffer);
173             return false;
174         }
175         free(buffer_);
176         buffer_ = newBuffer;
177         bufferCapacity_ = newCapacity;
178         return true;
179     }
180 
AllocateBuffer(size_t bytes)181     bool AllocateBuffer(size_t bytes)
182     {
183         // Get internal heap size
184         if (sizeLimit_ == 0) {
185             uint64_t heapSize = thread_->GetEcmaVM()->GetJSOptions().GetSerializerBufferSizeLimit();
186             sizeLimit_ = heapSize;
187         }
188         size_t oldSize = bufferSize_;
189         size_t newSize = oldSize + bytes;
190         if (newSize > sizeLimit_) {
191             return false;
192         }
193         if (bufferCapacity_ == 0) {
194             if (bytes < INITIAL_CAPACITY) {
195                 buffer_ = reinterpret_cast<uint8_t *>(malloc(INITIAL_CAPACITY));
196                 if (buffer_ != nullptr) {
197                     bufferCapacity_ = INITIAL_CAPACITY;
198                     return true;
199                 } else {
200                     return false;
201                 }
202             } else {
203                 buffer_ = reinterpret_cast<uint8_t *>(malloc(bytes));
204                 if (buffer_ != nullptr) {
205                     bufferCapacity_ = bytes;
206                     return true;
207                 } else {
208                     return false;
209                 }
210             }
211         }
212         if (newSize > bufferCapacity_) {
213             if (!ExpandBuffer(newSize)) {
214                 return false;
215             }
216         }
217         return true;
218     }
219 
RawDataEmit(const void * data,size_t length)220     ssize_t RawDataEmit(const void *data, size_t length)
221     {
222         return RawDataEmit(data, length, bufferSize_);
223     }
224 
RawDataEmit(const void * data,size_t length,size_t offset)225     ssize_t RawDataEmit(const void *data, size_t length, size_t offset)
226     {
227         if (length <= 0) {
228             return -1;
229         }
230         if ((offset + length) > bufferCapacity_) {
231             if (!AllocateBuffer(length)) {
232                 return -1;
233             }
234         }
235         if (memcpy_s(buffer_ + offset, bufferCapacity_ - offset, data, length) != EOK) {
236             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
237             return -1;
238         }
239         if (UNLIKELY(offset > std::numeric_limits<ssize_t>::max())) {
240             return -1;
241         }
242         ssize_t res = static_cast<ssize_t>(offset);
243         if (bufferSize_ == offset) {
244             bufferSize_ += length;
245         }
246         return res;
247     }
248 
EmitChar(uint8_t c)249     void EmitChar(uint8_t c)
250     {
251         RawDataEmit(&c, U8_SIZE);
252     }
253 
EmitU64(uint64_t c)254     ssize_t EmitU64(uint64_t c)
255     {
256         return RawDataEmit(reinterpret_cast<uint8_t *>(&c), U64_SIZE);
257     }
258 
EmitU64(uint64_t c,size_t offset)259     ssize_t EmitU64(uint64_t c, size_t offset)
260     {
261         return RawDataEmit(reinterpret_cast<uint8_t *>(&c), U64_SIZE, offset);
262     }
263 
WriteUint8(uint8_t data)264     void WriteUint8(uint8_t data)
265     {
266         RawDataEmit(&data, 1);
267     }
268 
ReadUint8(size_t & position)269     uint8_t ReadUint8(size_t &position)
270     {
271         ASSERT(position < Size());
272         return *(buffer_ + (position++));
273     }
274 
WriteEncodeFlag(EncodeFlag flag)275     void WriteEncodeFlag(EncodeFlag flag)
276     {
277         EmitChar(static_cast<uint8_t>(flag));
278     }
279 
WriteUint32(uint32_t data)280     void WriteUint32(uint32_t data)
281     {
282         RawDataEmit(reinterpret_cast<uint8_t *>(&data), U32_SIZE);
283     }
284 
ReadUint32(size_t & position)285     uint32_t ReadUint32(size_t &position)
286     {
287         ASSERT(position < Size());
288         uint32_t value = *reinterpret_cast<uint32_t *>(buffer_ + position);
289         position += sizeof(uint32_t);
290         return value;
291     }
292 
WriteRawData(uint8_t * data,size_t length)293     void WriteRawData(uint8_t *data, size_t length)
294     {
295         RawDataEmit(data, length);
296     }
297 
WriteJSTaggedValue(JSTaggedValue value)298     void WriteJSTaggedValue(JSTaggedValue value)
299     {
300         EmitU64(value.GetRawData());
301     }
302 
WriteJSTaggedType(JSTaggedType value)303     ssize_t WriteJSTaggedType(JSTaggedType value)
304     {
305         return EmitU64(value);
306     }
307 
ReadJSTaggedType(size_t & position)308     JSTaggedType ReadJSTaggedType(size_t &position)
309     {
310         ASSERT(position < Size());
311         JSTaggedType value = *reinterpret_cast<uint64_t *>(buffer_ + position);
312         position += sizeof(JSTaggedType);
313         return value;
314     }
315 
ReadRawData(uintptr_t addr,size_t len,size_t & position)316     void ReadRawData(uintptr_t addr, size_t len, size_t &position)
317     {
318         ASSERT(position + len <= Size());
319         if (memcpy_s(reinterpret_cast<void *>(addr), len, buffer_ + position, len) != EOK) {
320             LOG_ECMA(FATAL) << "this branch is unreachable";
321             UNREACHABLE();
322         }
323         position += len;
324     }
325 
Data()326     uint8_t* Data() const
327     {
328         return buffer_;
329     }
330 
Size()331     size_t Size() const
332     {
333         return bufferSize_;
334     }
335 
SetIncompleteData(bool incomplete)336     void SetIncompleteData(bool incomplete)
337     {
338         incompleteData_ = incomplete;
339     }
340 
IsIncompleteData()341     bool IsIncompleteData() const
342     {
343         return incompleteData_;
344     }
345 
GetRegularRemainSizeVector()346     const std::vector<size_t>& GetRegularRemainSizeVector() const
347     {
348         return regularRemainSizeVector_;
349     }
GetPinRemainSizeVector()350     const std::vector<size_t>& GetPinRemainSizeVector() const
351     {
352         return pinRemainSizeVector_;
353     }
GetRegionRemainSizeVectors()354     const std::array<std::vector<size_t>, SERIALIZE_SPACE_NUM>& GetRegionRemainSizeVectors() const
355     {
356         return regionRemainSizeVectors_;
357     }
358 
GetRegularSpaceSize()359     size_t GetRegularSpaceSize() const
360     {
361         return regularSpaceSize_;
362     }
363 
GetPinSpaceSize()364     size_t GetPinSpaceSize() const
365     {
366         return pinSpaceSize_;
367     }
368 
GetOldSpaceSize()369     size_t GetOldSpaceSize() const
370     {
371         return oldSpaceSize_;
372     }
373 
GetNonMovableSpaceSize()374     size_t GetNonMovableSpaceSize() const
375     {
376         return nonMovableSpaceSize_;
377     }
378 
GetMachineCodeSpaceSize()379     size_t GetMachineCodeSpaceSize() const
380     {
381         return machineCodeSpaceSize_;
382     }
383 
GetSharedOldSpaceSize()384     size_t GetSharedOldSpaceSize() const
385     {
386         return sharedOldSpaceSize_;
387     }
388 
GetSharedNonMovableSpaceSize()389     size_t GetSharedNonMovableSpaceSize() const
390     {
391         return sharedNonMovableSpaceSize_;
392     }
393 
CalculateSerializedObjectSize(SerializedObjectSpace space,size_t objectSize)394     void CalculateSerializedObjectSize(SerializedObjectSpace space, size_t objectSize)
395     {
396         if (g_isEnableCMCGC) {
397             switch (space) {
398                 case SerializedObjectSpace::REGULAR_SPACE:
399                     AlignSpaceObjectSize(regularRemainSizeVector_, regularSpaceSize_, objectSize);
400                     break;
401                 case SerializedObjectSpace::PIN_SPACE:
402                     AlignSpaceObjectSize(pinRemainSizeVector_, pinSpaceSize_, objectSize);
403                     break;
404                 default:
405                     break;
406             }
407         } else {
408             switch (space) {
409                 case SerializedObjectSpace::OLD_SPACE:
410                     AlignSpaceObjectSize(oldSpaceSize_, objectSize, SerializedObjectSpace::OLD_SPACE);
411                     break;
412                 case SerializedObjectSpace::NON_MOVABLE_SPACE:
413                     AlignSpaceObjectSize(nonMovableSpaceSize_, objectSize, SerializedObjectSpace::NON_MOVABLE_SPACE);
414                     break;
415                 case SerializedObjectSpace::MACHINE_CODE_SPACE:
416                     AlignSpaceObjectSize(machineCodeSpaceSize_, objectSize, SerializedObjectSpace::MACHINE_CODE_SPACE);
417                     break;
418                 case SerializedObjectSpace::SHARED_OLD_SPACE:
419                     AlignSpaceObjectSize(sharedOldSpaceSize_, objectSize, SerializedObjectSpace::SHARED_OLD_SPACE);
420                     break;
421                 case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE:
422                     AlignSpaceObjectSize(sharedNonMovableSpaceSize_, objectSize,
423                                          SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE);
424                     break;
425                 default:
426                     break;
427             }
428         }
429     }
430 
AlignSpaceObjectSize(size_t & spaceSize,size_t objectSize,SerializedObjectSpace spaceType)431     void AlignSpaceObjectSize(size_t &spaceSize, size_t objectSize, SerializedObjectSpace spaceType)
432     {
433         size_t alignRegionSize = AlignUpRegionAvailableSize(spaceSize);
434         if (UNLIKELY(spaceSize + objectSize > alignRegionSize)) {
435             regionRemainSizeVectors_.at(static_cast<uint8_t>(spaceType)).push_back(alignRegionSize - spaceSize);
436             spaceSize = alignRegionSize;
437         }
438         spaceSize += objectSize;
439         ASSERT(spaceSize <= SnapshotEnv::MAX_UINT_32);
440     }
441 
AlignSpaceObjectSize(std::vector<size_t> & remainSizeVec,size_t & spaceSize,size_t objectSize)442     void AlignSpaceObjectSize(std::vector<size_t> &remainSizeVec, size_t &spaceSize, size_t objectSize)
443     {
444         size_t alignRegionSize = AlignUpRegionAvailableSize(spaceSize);
445         if (UNLIKELY(spaceSize + objectSize > alignRegionSize)) {
446             remainSizeVec.push_back(alignRegionSize - spaceSize);
447             spaceSize = alignRegionSize;
448         }
449         spaceSize += objectSize;
450         ASSERT(spaceSize <= SnapshotEnv::MAX_UINT_32);
451     }
452 
DecreaseSharedArrayBufferReference()453     void DecreaseSharedArrayBufferReference()
454     {
455         auto manager = JSSharedMemoryManager::GetInstance();
456         for (auto iter = sharedArrayBufferSet_.begin(); iter != sharedArrayBufferSet_.end(); iter++) {
457             JSSharedMemoryManager::RemoveSharedMemory(thread_->GetEnv(), reinterpret_cast<void *>(*iter), manager);
458         }
459         sharedArrayBufferSet_.clear();
460     }
461 
insertSharedArrayBuffer(uintptr_t ptr)462     void insertSharedArrayBuffer(uintptr_t ptr)
463     {
464         sharedArrayBufferSet_.insert(ptr);
465     }
466 
SetDataIndex(uint32_t dataIndex)467     void SetDataIndex(uint32_t dataIndex)
468     {
469         dataIndex_ = dataIndex;
470     }
471 
GetDataIndex()472     uint32_t GetDataIndex() const
473     {
474         return dataIndex_;
475     }
476 
AddNativeBindingDetachInfo(panda::JSNApi::NativeBindingInfo * info,void * dObj)477     void AddNativeBindingDetachInfo(panda::JSNApi::NativeBindingInfo *info, void *dObj)
478     {
479         auto *detachInfo = new NativeBindingDetachInfo(info->detachedFinalizer, dObj, info->detachedHint);
480         nativeBindingDetachInfos_.insert(detachInfo);
481     }
482 
SetErrorMessage(const std::string & errorMessage)483     void SetErrorMessage(const std::string &errorMessage)
484     {
485         errorMessage_ = errorMessage;
486     }
487 
GetErrorMessage()488     const std::string &GetErrorMessage() const
489     {
490         return errorMessage_;
491     }
492 
493     // for ut
SetBuffer(uint8_t * buffer)494     void SetBuffer(uint8_t *buffer)
495     {
496         buffer_ = buffer;
497     }
498 
499 private:
500     static constexpr size_t U8_SIZE = 1;
501     static constexpr size_t U16_SIZE = 2;
502     static constexpr size_t U32_SIZE = 4;
503     static constexpr size_t U64_SIZE = 8;
504     JSThread *thread_;
505     uint32_t dataIndex_ {RESERVED_INDEX};
506     uint8_t *buffer_ {nullptr};
507     uint64_t sizeLimit_ {0};
508     size_t bufferSize_ {0};
509     size_t bufferCapacity_ {0};
510     size_t regularSpaceSize_ {0};
511     size_t pinSpaceSize_ {0};
512     size_t oldSpaceSize_ {0};
513     size_t nonMovableSpaceSize_ {0};
514     size_t machineCodeSpaceSize_ {0};
515     size_t sharedOldSpaceSize_ {0};
516     size_t sharedNonMovableSpaceSize_ {0};
517     bool incompleteData_ {false};
518     std::string errorMessage_;
519     std::vector<size_t> regularRemainSizeVector_ {};
520     std::vector<size_t> pinRemainSizeVector_ {};
521     std::array<std::vector<size_t>, SERIALIZE_SPACE_NUM> regionRemainSizeVectors_ {};
522     std::set<uintptr_t> sharedArrayBufferSet_ {};
523     std::set<NativeBindingDetachInfo *> nativeBindingDetachInfos_ {};
524     friend class ModuleSnapshot;
525 };
526 }
527 
528 #endif  // ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
529