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