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