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