• 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 "ecmascript/js_tagged_value-inl.h"
20 #include "ecmascript/mem/dyn_chunk.h"
21 #include "ecmascript/snapshot/mem/snapshot_env.h"
22 
23 namespace panda::ecmascript {
24 constexpr size_t INITIAL_CAPACITY = 64;
25 constexpr int CAPACITY_INCREASE_RATE = 2;
26 enum class EncodeFlag : uint8_t {
27     // 0x00~0x03 represent new object to different space:
28     // 0x00: old space
29     // 0x01: non movable space
30     // 0x02: machine code space
31     // 0x03: huge space
32     NEW_OBJECT = 0x00,
33     REFERENCE = 0x04,
34     WEAK,
35     PRIMITIVE,
36     MULTI_RAW_DATA,
37     ROOT_OBJECT,
38     OBJECT_PROTO,
39     ARRAY_BUFFER,
40     TRANSFER_ARRAY_BUFFER,
41     METHOD,
42     NATIVE_BINDING_OBJECT,
43     JS_ERROR,
44     JS_REG_EXP,
45     JS_FUNCTION_IN_SHARED,
46     LAST
47 };
48 
49 enum class SerializedObjectSpace : uint8_t {
50     OLD_SPACE = 0,
51     NON_MOVABLE_SPACE,
52     MACHINE_CODE_SPACE,
53     HUGE_SPACE
54 };
55 
56 enum class SerializeType : uint8_t {
57     VALUE_SERIALIZE,
58     PGO_SERIALIZE
59 };
60 
61 class SerializeData {
62 public:
SerializeData(JSThread * thread)63     explicit SerializeData(JSThread *thread) : thread_(thread) {}
~SerializeData()64     ~SerializeData()
65     {
66         regionRemainSizeVector_.clear();
67         free(buffer_);
68     }
69     NO_COPY_SEMANTIC(SerializeData);
70     NO_MOVE_SEMANTIC(SerializeData);
71 
EncodeNewObject(SerializedObjectSpace space)72     static uint8_t EncodeNewObject(SerializedObjectSpace space)
73     {
74         return static_cast<uint8_t>(space) | static_cast<uint8_t>(EncodeFlag::NEW_OBJECT);
75     }
76 
DecodeSpace(uint8_t type)77     static SerializedObjectSpace DecodeSpace(uint8_t type)
78     {
79         ASSERT(type < static_cast<uint8_t>(EncodeFlag::REFERENCE));
80         return static_cast<SerializedObjectSpace>(type);
81     }
82 
AlignUpRegionAvailableSize(size_t size)83     static size_t AlignUpRegionAvailableSize(size_t size)
84     {
85         if (size == 0) {
86             return Region::GetRegionAvailableSize();
87         }
88         size_t regionAvailableSize = Region::GetRegionAvailableSize();
89         return ((size - 1) / regionAvailableSize + 1) * regionAvailableSize; // 1: align up
90     }
91 
ExpandBuffer(size_t requestedSize)92     bool ExpandBuffer(size_t requestedSize)
93     {
94         size_t newCapacity = bufferCapacity_ * CAPACITY_INCREASE_RATE;
95         newCapacity = std::max(newCapacity, requestedSize);
96         if (newCapacity > sizeLimit_) {
97             return false;
98         }
99         uint8_t *newBuffer = reinterpret_cast<uint8_t *>(malloc(newCapacity));
100         if (newBuffer == nullptr) {
101             return false;
102         }
103         if (memcpy_s(newBuffer, newCapacity, buffer_, bufferSize_) != EOK) {
104             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
105             free(newBuffer);
106             return false;
107         }
108         free(buffer_);
109         buffer_ = newBuffer;
110         bufferCapacity_ = newCapacity;
111         return true;
112     }
113 
AllocateBuffer(size_t bytes)114     bool AllocateBuffer(size_t bytes)
115     {
116         // Get internal heap size
117         if (sizeLimit_ == 0) {
118             uint64_t heapSize = thread_->GetEcmaVM()->GetJSOptions().GetSerializerBufferSizeLimit();
119             sizeLimit_ = heapSize;
120         }
121         size_t oldSize = bufferSize_;
122         size_t newSize = oldSize + bytes;
123         if (newSize > sizeLimit_) {
124             return false;
125         }
126         if (bufferCapacity_ == 0) {
127             if (bytes < INITIAL_CAPACITY) {
128                 buffer_ = reinterpret_cast<uint8_t *>(malloc(INITIAL_CAPACITY));
129                 if (buffer_ != nullptr) {
130                     bufferCapacity_ = INITIAL_CAPACITY;
131                     return true;
132                 } else {
133                     return false;
134                 }
135             } else {
136                 buffer_ = reinterpret_cast<uint8_t *>(malloc(bytes));
137                 if (buffer_ != nullptr) {
138                     bufferCapacity_ = bytes;
139                     return true;
140                 } else {
141                     return false;
142                 }
143             }
144         }
145         if (newSize > bufferCapacity_) {
146             if (!ExpandBuffer(newSize)) {
147                 return false;
148             }
149         }
150         return true;
151     }
152 
RawDataEmit(const void * data,size_t length)153     bool RawDataEmit(const void *data, size_t length)
154     {
155         if (length <= 0) {
156             return false;
157         }
158         if ((bufferSize_ + length) > bufferCapacity_) {
159             if (!AllocateBuffer(length)) {
160                 return false;
161             }
162         }
163         if (memcpy_s(buffer_ + bufferSize_, bufferCapacity_ - bufferSize_, data, length) != EOK) {
164             LOG_FULL(ERROR) << "Failed to memcpy_s Data";
165             return false;
166         }
167         bufferSize_ += length;
168         return true;
169     }
170 
EmitChar(uint8_t c)171     void EmitChar(uint8_t c)
172     {
173         RawDataEmit(&c, U8_SIZE);
174     }
175 
EmitU64(uint64_t c)176     void EmitU64(uint64_t c)
177     {
178         RawDataEmit(reinterpret_cast<uint8_t *>(&c), U64_SIZE);
179     }
180 
WriteUint8(uint8_t data)181     void WriteUint8(uint8_t data)
182     {
183         RawDataEmit(&data, 1);
184     }
185 
ReadUint8()186     uint8_t ReadUint8()
187     {
188         ASSERT(position_ < Size());
189         return *(buffer_ + (position_++));
190     }
191 
WriteEncodeFlag(EncodeFlag flag)192     void WriteEncodeFlag(EncodeFlag flag)
193     {
194         EmitChar(static_cast<uint8_t>(flag));
195     }
196 
WriteUint32(uint32_t data)197     void WriteUint32(uint32_t data)
198     {
199         RawDataEmit(reinterpret_cast<uint8_t *>(&data), U32_SIZE);
200     }
201 
ReadUint32()202     uint32_t ReadUint32()
203     {
204         ASSERT(position_ < Size());
205         uint32_t value = *reinterpret_cast<uint32_t *>(buffer_ + position_);
206         position_ += sizeof(uint32_t);
207         return value;
208     }
209 
WriteRawData(uint8_t * data,size_t length)210     void WriteRawData(uint8_t *data, size_t length)
211     {
212         RawDataEmit(data, length);
213     }
214 
WriteJSTaggedValue(JSTaggedValue value)215     void WriteJSTaggedValue(JSTaggedValue value)
216     {
217         EmitU64(value.GetRawData());
218     }
219 
WriteJSTaggedType(JSTaggedType value)220     void WriteJSTaggedType(JSTaggedType value)
221     {
222         EmitU64(value);
223     }
224 
ReadJSTaggedType()225     JSTaggedType ReadJSTaggedType()
226     {
227         ASSERT(position_ < Size());
228         JSTaggedType value = *reinterpret_cast<uint64_t *>(buffer_ + position_);
229         position_ += sizeof(JSTaggedType);
230         return value;
231     }
232 
ReadRawData(uintptr_t addr,size_t len)233     void ReadRawData(uintptr_t addr, size_t len)
234     {
235         ASSERT(position_ + len <= Size());
236         if (memcpy_s(reinterpret_cast<void *>(addr), len, buffer_ + position_, len) != EOK) {
237             LOG_ECMA(FATAL) << "this branch is unreachable";
238             UNREACHABLE();
239         }
240         position_ += len;
241     }
242 
Data()243     uint8_t* Data() const
244     {
245         return buffer_;
246     }
247 
Size()248     size_t Size() const
249     {
250         return bufferSize_;
251     }
252 
GetPosition()253     size_t GetPosition() const
254     {
255         return position_;
256     }
257 
SetIncompleteData(bool incomplete)258     void SetIncompleteData(bool incomplete)
259     {
260         incompleteData_ = incomplete;
261     }
262 
IsIncompleteData()263     bool IsIncompleteData() const
264     {
265         return incompleteData_;
266     }
267 
GetRegionRemainSizeVector()268     const std::vector<size_t>& GetRegionRemainSizeVector() const
269     {
270         return regionRemainSizeVector_;
271     }
272 
GetOldSpaceSize()273     size_t GetOldSpaceSize() const
274     {
275         return oldSpaceSize_;
276     }
277 
GetNonMovableSpaceSize()278     size_t GetNonMovableSpaceSize() const
279     {
280         return nonMovableSpaceSize_;
281     }
282 
GetMachineCodeSpaceSize()283     size_t GetMachineCodeSpaceSize() const
284     {
285         return machineCodeSpaceSize_;
286     }
287 
CalculateSerializedObjectSize(SerializedObjectSpace space,size_t objectSize)288     void CalculateSerializedObjectSize(SerializedObjectSpace space, size_t objectSize)
289     {
290         switch (space) {
291             case SerializedObjectSpace::OLD_SPACE:
292                 AlignSpaceObjectSize(oldSpaceSize_, objectSize);
293                 break;
294             case SerializedObjectSpace::NON_MOVABLE_SPACE:
295                 AlignSpaceObjectSize(nonMovableSpaceSize_, objectSize);
296                 break;
297             case SerializedObjectSpace::MACHINE_CODE_SPACE:
298                 AlignSpaceObjectSize(machineCodeSpaceSize_, objectSize);
299                 break;
300             default:
301                 break;
302         }
303     }
304 
AlignSpaceObjectSize(size_t & spaceSize,size_t objectSize)305     void AlignSpaceObjectSize(size_t &spaceSize, size_t objectSize)
306     {
307         size_t alignRegionSize = AlignUpRegionAvailableSize(spaceSize);
308         if (UNLIKELY(spaceSize + objectSize > alignRegionSize)) {
309             regionRemainSizeVector_.push_back(alignRegionSize - spaceSize);
310             spaceSize = alignRegionSize;
311         }
312         spaceSize += objectSize;
313         ASSERT(spaceSize <= SnapshotEnv::MAX_UINT_32);
314     }
315 
ResetPosition()316     void ResetPosition()
317     {
318         position_ = 0;
319     }
320 
321 private:
322     static constexpr size_t U8_SIZE = 1;
323     static constexpr size_t U16_SIZE = 2;
324     static constexpr size_t U32_SIZE = 4;
325     static constexpr size_t U64_SIZE = 8;
326     JSThread *thread_;
327     uint8_t *buffer_ = nullptr;
328     uint64_t sizeLimit_ = 0;
329     size_t bufferSize_ = 0;
330     size_t bufferCapacity_ = 0;
331     size_t oldSpaceSize_ {0};
332     size_t nonMovableSpaceSize_ {0};
333     size_t machineCodeSpaceSize_ {0};
334     size_t position_ {0};
335     bool incompleteData_ {false};
336     std::vector<size_t> regionRemainSizeVector_;
337 };
338 }
339 
340 #endif  // ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H