• 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 "ecmascript/js_tagged_value-inl.h"
22 #include "ecmascript/mem/dyn_chunk.h"
23 #include "ecmascript/runtime.h"
24 #include "ecmascript/shared_mm/shared_mm.h"
25 #include "ecmascript/snapshot/mem/snapshot_env.h"
26 
27 namespace panda::ecmascript {
28 constexpr size_t INITIAL_CAPACITY = 64;
29 constexpr int CAPACITY_INCREASE_RATE = 2;
30 constexpr uint32_t RESERVED_INDEX = 0;
31 
32 typedef void* (*DetachFunc)(void *enginePointer, void *objPointer, void *hint, void *detachData);
33 typedef Local<JSValueRef> (*AttachFunc)(void *enginePointer, void *buffer, void *hint, void *attachData);
34 
35 enum class EncodeFlag : uint8_t {
36     // 0x00~0x06 represent new object to different space:
37     // 0x00: old space
38     // 0x01: non movable space
39     // 0x02: machine code space
40     // 0x03: huge space
41     // 0x04: shared old space
42     // 0x05: shared non movable space
43     // 0x06: shared huge space
44     NEW_OBJECT = 0x00,
45     REFERENCE = 0x07,
46     WEAK,
47     PRIMITIVE,
48     MULTI_RAW_DATA,
49     ROOT_OBJECT,
50     OBJECT_PROTO,
51     ARRAY_BUFFER,
52     TRANSFER_ARRAY_BUFFER,
53     SHARED_ARRAY_BUFFER,
54     SENDABLE_ARRAY_BUFFER,
55     NATIVE_BINDING_OBJECT,
56     JS_ERROR,
57     JS_REG_EXP,
58     SHARED_OBJECT,
59     LAST
60 };
61 
62 enum class SerializedObjectSpace : uint8_t {
63     OLD_SPACE = 0,
64     NON_MOVABLE_SPACE,
65     MACHINE_CODE_SPACE,
66     HUGE_SPACE,
67     SHARED_OLD_SPACE,
68     SHARED_NON_MOVABLE_SPACE,
69     SHARED_HUGE_SPACE
70 };
71 
72 enum class SerializeType : uint8_t {
73     VALUE_SERIALIZE,
74     PGO_SERIALIZE
75 };
76 
77 class SerializeData {
78 public:
SerializeData(JSThread * thread)79     explicit SerializeData(JSThread *thread) : thread_(thread) {}
~SerializeData()80     ~SerializeData()
81     {
82         regionRemainSizeVector_.clear();
83         // decrease sharedArrayBuffer reference
84         if (sharedArrayBufferSet_.size() > 0) {
85             DecreaseSharedArrayBufferReference();
86         }
87         free(buffer_);
88         if (!incompleteData_ && dataIndex_ != RESERVED_INDEX) {
89             Runtime::GetInstance()->RemoveSerializationRoot(thread_, dataIndex_);
90         }
91     }
92     NO_COPY_SEMANTIC(SerializeData);
93     NO_MOVE_SEMANTIC(SerializeData);
94 
EncodeNewObject(SerializedObjectSpace space)95     static uint8_t EncodeNewObject(SerializedObjectSpace space)
96     {
97         return static_cast<uint8_t>(space) | static_cast<uint8_t>(EncodeFlag::NEW_OBJECT);
98     }
99 
DecodeSpace(uint8_t type)100     static SerializedObjectSpace DecodeSpace(uint8_t type)
101     {
102         ASSERT(type < static_cast<uint8_t>(EncodeFlag::REFERENCE));
103         return static_cast<SerializedObjectSpace>(type);
104     }
105 
AlignUpRegionAvailableSize(size_t size)106     static size_t AlignUpRegionAvailableSize(size_t size)
107     {
108         if (size == 0) {
109             return Region::GetRegionAvailableSize();
110         }
111         size_t regionAvailableSize = Region::GetRegionAvailableSize();
112         return ((size - 1) / regionAvailableSize + 1) * regionAvailableSize; // 1: align up
113     }
114 
ExpandBuffer(size_t requestedSize)115     bool ExpandBuffer(size_t requestedSize)
116     {
117         size_t newCapacity = bufferCapacity_ * CAPACITY_INCREASE_RATE;
118         newCapacity = std::max(newCapacity, requestedSize);
119         if (newCapacity > sizeLimit_) {
120             return false;
121         }
122         uint8_t *newBuffer = reinterpret_cast<uint8_t *>(malloc(newCapacity));
123         if (newBuffer == nullptr) {
124             return false;
125         }
126         if (memcpy_s(newBuffer, newCapacity, buffer_, bufferSize_) != EOK) {
127             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
128             free(newBuffer);
129             return false;
130         }
131         free(buffer_);
132         buffer_ = newBuffer;
133         bufferCapacity_ = newCapacity;
134         return true;
135     }
136 
AllocateBuffer(size_t bytes)137     bool AllocateBuffer(size_t bytes)
138     {
139         // Get internal heap size
140         if (sizeLimit_ == 0) {
141             uint64_t heapSize = thread_->GetEcmaVM()->GetJSOptions().GetSerializerBufferSizeLimit();
142             sizeLimit_ = heapSize;
143         }
144         size_t oldSize = bufferSize_;
145         size_t newSize = oldSize + bytes;
146         if (newSize > sizeLimit_) {
147             return false;
148         }
149         if (bufferCapacity_ == 0) {
150             if (bytes < INITIAL_CAPACITY) {
151                 buffer_ = reinterpret_cast<uint8_t *>(malloc(INITIAL_CAPACITY));
152                 if (buffer_ != nullptr) {
153                     bufferCapacity_ = INITIAL_CAPACITY;
154                     return true;
155                 } else {
156                     return false;
157                 }
158             } else {
159                 buffer_ = reinterpret_cast<uint8_t *>(malloc(bytes));
160                 if (buffer_ != nullptr) {
161                     bufferCapacity_ = bytes;
162                     return true;
163                 } else {
164                     return false;
165                 }
166             }
167         }
168         if (newSize > bufferCapacity_) {
169             if (!ExpandBuffer(newSize)) {
170                 return false;
171             }
172         }
173         return true;
174     }
175 
RawDataEmit(const void * data,size_t length)176     ssize_t RawDataEmit(const void *data, size_t length)
177     {
178         return RawDataEmit(data, length, bufferSize_);
179     }
180 
RawDataEmit(const void * data,size_t length,size_t offset)181     ssize_t RawDataEmit(const void *data, size_t length, size_t offset)
182     {
183         if (length <= 0) {
184             return -1;
185         }
186         if ((offset + length) > bufferCapacity_) {
187             if (!AllocateBuffer(length)) {
188                 return -1;
189             }
190         }
191         if (memcpy_s(buffer_ + offset, bufferCapacity_ - offset, data, length) != EOK) {
192             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
193             return -1;
194         }
195         if (UNLIKELY(offset > std::numeric_limits<ssize_t>::max())) {
196             return -1;
197         }
198         ssize_t res = static_cast<ssize_t>(offset);
199         if (bufferSize_ == offset) {
200             bufferSize_ += length;
201         }
202         return res;
203     }
204 
EmitChar(uint8_t c)205     void EmitChar(uint8_t c)
206     {
207         RawDataEmit(&c, U8_SIZE);
208     }
209 
EmitU64(uint64_t c)210     ssize_t EmitU64(uint64_t c)
211     {
212         return RawDataEmit(reinterpret_cast<uint8_t *>(&c), U64_SIZE);
213     }
214 
EmitU64(uint64_t c,size_t offset)215     ssize_t EmitU64(uint64_t c, size_t offset)
216     {
217         return RawDataEmit(reinterpret_cast<uint8_t *>(&c), U64_SIZE, offset);
218     }
219 
WriteUint8(uint8_t data)220     void WriteUint8(uint8_t data)
221     {
222         RawDataEmit(&data, 1);
223     }
224 
ReadUint8(size_t & position)225     uint8_t ReadUint8(size_t &position)
226     {
227         ASSERT(position < Size());
228         return *(buffer_ + (position++));
229     }
230 
WriteEncodeFlag(EncodeFlag flag)231     void WriteEncodeFlag(EncodeFlag flag)
232     {
233         EmitChar(static_cast<uint8_t>(flag));
234     }
235 
WriteUint32(uint32_t data)236     void WriteUint32(uint32_t data)
237     {
238         RawDataEmit(reinterpret_cast<uint8_t *>(&data), U32_SIZE);
239     }
240 
ReadUint32(size_t & position)241     uint32_t ReadUint32(size_t &position)
242     {
243         ASSERT(position < Size());
244         uint32_t value = *reinterpret_cast<uint32_t *>(buffer_ + position);
245         position += sizeof(uint32_t);
246         return value;
247     }
248 
WriteRawData(uint8_t * data,size_t length)249     void WriteRawData(uint8_t *data, size_t length)
250     {
251         RawDataEmit(data, length);
252     }
253 
WriteJSTaggedValue(JSTaggedValue value)254     void WriteJSTaggedValue(JSTaggedValue value)
255     {
256         EmitU64(value.GetRawData());
257     }
258 
WriteJSTaggedType(JSTaggedType value)259     ssize_t WriteJSTaggedType(JSTaggedType value)
260     {
261         return EmitU64(value);
262     }
263 
ReadJSTaggedType(size_t & position)264     JSTaggedType ReadJSTaggedType(size_t &position)
265     {
266         ASSERT(position < Size());
267         JSTaggedType value = *reinterpret_cast<uint64_t *>(buffer_ + position);
268         position += sizeof(JSTaggedType);
269         return value;
270     }
271 
ReadRawData(uintptr_t addr,size_t len,size_t & position)272     void ReadRawData(uintptr_t addr, size_t len, size_t &position)
273     {
274         ASSERT(position + len <= Size());
275         if (memcpy_s(reinterpret_cast<void *>(addr), len, buffer_ + position, len) != EOK) {
276             LOG_ECMA(FATAL) << "this branch is unreachable";
277             UNREACHABLE();
278         }
279         position += len;
280     }
281 
Data()282     uint8_t* Data() const
283     {
284         return buffer_;
285     }
286 
Size()287     size_t Size() const
288     {
289         return bufferSize_;
290     }
291 
SetIncompleteData(bool incomplete)292     void SetIncompleteData(bool incomplete)
293     {
294         incompleteData_ = incomplete;
295     }
296 
IsIncompleteData()297     bool IsIncompleteData() const
298     {
299         return incompleteData_;
300     }
301 
GetRegionRemainSizeVector()302     const std::vector<size_t>& GetRegionRemainSizeVector() const
303     {
304         return regionRemainSizeVector_;
305     }
306 
GetOldSpaceSize()307     size_t GetOldSpaceSize() const
308     {
309         return oldSpaceSize_;
310     }
311 
GetNonMovableSpaceSize()312     size_t GetNonMovableSpaceSize() const
313     {
314         return nonMovableSpaceSize_;
315     }
316 
GetMachineCodeSpaceSize()317     size_t GetMachineCodeSpaceSize() const
318     {
319         return machineCodeSpaceSize_;
320     }
321 
GetSharedOldSpaceSize()322     size_t GetSharedOldSpaceSize() const
323     {
324         return sharedOldSpaceSize_;
325     }
326 
GetSharedNonMovableSpaceSize()327     size_t GetSharedNonMovableSpaceSize() const
328     {
329         return sharedNonMovableSpaceSize_;
330     }
331 
CalculateSerializedObjectSize(SerializedObjectSpace space,size_t objectSize)332     void CalculateSerializedObjectSize(SerializedObjectSpace space, size_t objectSize)
333     {
334         switch (space) {
335             case SerializedObjectSpace::OLD_SPACE:
336                 AlignSpaceObjectSize(oldSpaceSize_, objectSize);
337                 break;
338             case SerializedObjectSpace::NON_MOVABLE_SPACE:
339                 AlignSpaceObjectSize(nonMovableSpaceSize_, objectSize);
340                 break;
341             case SerializedObjectSpace::MACHINE_CODE_SPACE:
342                 AlignSpaceObjectSize(machineCodeSpaceSize_, objectSize);
343                 break;
344             case SerializedObjectSpace::SHARED_OLD_SPACE:
345                 AlignSpaceObjectSize(sharedOldSpaceSize_, objectSize);
346                 break;
347             case SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE:
348                 AlignSpaceObjectSize(sharedNonMovableSpaceSize_, objectSize);
349                 break;
350             default:
351                 break;
352         }
353     }
354 
AlignSpaceObjectSize(size_t & spaceSize,size_t objectSize)355     void AlignSpaceObjectSize(size_t &spaceSize, size_t objectSize)
356     {
357         size_t alignRegionSize = AlignUpRegionAvailableSize(spaceSize);
358         if (UNLIKELY(spaceSize + objectSize > alignRegionSize)) {
359             regionRemainSizeVector_.push_back(alignRegionSize - spaceSize);
360             spaceSize = alignRegionSize;
361         }
362         spaceSize += objectSize;
363         ASSERT(spaceSize <= SnapshotEnv::MAX_UINT_32);
364     }
365 
DecreaseSharedArrayBufferReference()366     void DecreaseSharedArrayBufferReference()
367     {
368         auto manager = JSSharedMemoryManager::GetInstance();
369         for (auto iter = sharedArrayBufferSet_.begin(); iter != sharedArrayBufferSet_.end(); iter++) {
370             JSSharedMemoryManager::RemoveSharedMemory(thread_->GetEnv(), reinterpret_cast<void *>(*iter), manager);
371         }
372         sharedArrayBufferSet_.clear();
373     }
374 
insertSharedArrayBuffer(uintptr_t ptr)375     void insertSharedArrayBuffer(uintptr_t ptr)
376     {
377         sharedArrayBufferSet_.insert(ptr);
378     }
379 
SetDataIndex(uint32_t dataIndex)380     void SetDataIndex(uint32_t dataIndex)
381     {
382         dataIndex_ = dataIndex;
383     }
384 
GetDataIndex()385     uint32_t GetDataIndex() const
386     {
387         return dataIndex_;
388     }
389 
390 private:
391     static constexpr size_t U8_SIZE = 1;
392     static constexpr size_t U16_SIZE = 2;
393     static constexpr size_t U32_SIZE = 4;
394     static constexpr size_t U64_SIZE = 8;
395     JSThread *thread_;
396     uint32_t dataIndex_ {RESERVED_INDEX};
397     uint8_t *buffer_ {nullptr};
398     uint64_t sizeLimit_ {0};
399     size_t bufferSize_ {0};
400     size_t bufferCapacity_ {0};
401     size_t oldSpaceSize_ {0};
402     size_t nonMovableSpaceSize_ {0};
403     size_t machineCodeSpaceSize_ {0};
404     size_t sharedOldSpaceSize_ {0};
405     size_t sharedNonMovableSpaceSize_ {0};
406     bool incompleteData_ {false};
407     std::vector<size_t> regionRemainSizeVector_;
408     std::set<uintptr_t> sharedArrayBufferSet_;
409 };
410 }
411 
412 #endif  // ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H