1 /* 2 * Copyright (c) 2021-2022 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_JS_SERIALIZER_H 17 #define ECMASCRIPT_JS_SERIALIZER_H 18 19 #include "ecmascript/ecma_vm.h" 20 #include "ecmascript/js_date.h" 21 #include "ecmascript/js_map.h" 22 #include "ecmascript/js_native_pointer.h" 23 #include "ecmascript/js_object.h" 24 #include "ecmascript/js_thread.h" 25 #include "ecmascript/js_typed_array.h" 26 #include "ecmascript/jspandafile/js_pandafile.h" 27 #include "ecmascript/jspandafile/program_object.h" 28 #include "ecmascript/mem/dyn_chunk.h" 29 #include "ecmascript/napi/jsnapi_helper.h" 30 #include "ecmascript/napi/include/jsnapi.h" 31 32 using panda::JSValueRef; 33 namespace panda::ecmascript { 34 class JSPandaFile; 35 class ConstantPool; 36 37 typedef void* (*DetachFunc)(void *enginePointer, void *objPointer, void *hint, void *detachData); 38 typedef Local<JSValueRef> (*AttachFunc)(void *enginePointer, void *buffer, void *hint, void *attachData); 39 40 enum class SerializationUID : uint8_t { 41 UID_BEGIN = 0x01, 42 // JS special values 43 JS_NULL, 44 JS_UNDEFINED, 45 JS_TRUE, 46 JS_FALSE, 47 HOLE, 48 // Number types 49 INT32, 50 DOUBLE, 51 BIGINT, 52 ECMASTRING, 53 C_STRING, 54 // Boolean types 55 C_TRUE, 56 C_FALSE, 57 // Tagged object reference mark 58 TAGGED_OBJECT_REFERNCE, 59 // Support tagged object id reference begin 60 JS_DATE, 61 JS_REG_EXP, 62 JS_PLAIN_OBJECT, 63 NATIVE_BINDING_OBJECT, 64 JS_SET, 65 JS_MAP, 66 JS_ARRAY, 67 JS_ARRAY_BUFFER, 68 JS_SHARED_ARRAY_BUFFER, 69 JS_TRANSFER_ARRAY_BUFFER, 70 // TypedArray begin 71 JS_UINT8_ARRAY, 72 JS_UINT8_CLAMPED_ARRAY, 73 JS_UINT16_ARRAY, 74 JS_UINT32_ARRAY, 75 JS_INT8_ARRAY, 76 JS_INT16_ARRAY, 77 JS_INT32_ARRAY, 78 JS_FLOAT32_ARRAY, 79 JS_FLOAT64_ARRAY, 80 JS_BIGINT64_ARRAY, 81 JS_BIGUINT64_ARRAY, 82 // TypedArray end 83 // Support tagged object id reference end 84 // Error UIDs 85 JS_ERROR, 86 EVAL_ERROR, 87 RANGE_ERROR, 88 REFERENCE_ERROR, 89 TYPE_ERROR, 90 AGGREGATE_ERROR, 91 URI_ERROR, 92 SYNTAX_ERROR, 93 OOM_ERROR, 94 TERMINATION_ERROR, 95 ERROR_MESSAGE_BEGIN, 96 ERROR_MESSAGE_END, 97 // Function begin 98 CONCURRENT_FUNCTION, 99 METHOD, 100 NATIVE_METHOD, 101 TAGGED_ARRAY, 102 // Function end 103 BYTE_ARRAY, 104 UID_END, 105 UNKNOWN 106 }; 107 108 class JSSerializer { 109 public: JSSerializer(JSThread * thread)110 explicit JSSerializer(JSThread *thread) : thread_(thread) {} ~JSSerializer()111 ~JSSerializer() 112 { 113 // clear transfer obj set after serialization 114 transferDataSet_.clear(); 115 } 116 117 bool SerializeJSTaggedValue(const JSHandle<JSTaggedValue> &value); 118 void InitTransferSet(CUnorderedSet<uintptr_t> transferDataSet); 119 void ClearTransferSet(); 120 121 // Return pointer to the buffer and its length, should not use this Serializer anymore after Release 122 std::pair<uint8_t *, size_t> ReleaseBuffer(); 123 SetDefaultTransfer()124 void SetDefaultTransfer() 125 { 126 defaultTransfer_ = true; 127 } 128 129 private: 130 bool WriteJSFunction(const JSHandle<JSTaggedValue> &value); 131 bool WriteMethod(const JSHandle<JSTaggedValue> &value); 132 bool WriteConstantPool(const JSHandle<JSTaggedValue> &value); 133 bool WriteTaggedArray(const JSHandle<JSTaggedValue> &value); 134 bool WriteByteArray(const JSHandle<JSTaggedValue> &value, DataViewType viewType); 135 bool WriteTaggedObject(const JSHandle<JSTaggedValue> &value); 136 bool WritePrimitiveValue(const JSHandle<JSTaggedValue> &value); 137 bool WriteInt(int32_t value); 138 bool WriteDouble(double value); 139 bool WriteRawData(const void *data, size_t length); 140 bool WriteType(SerializationUID uId); 141 bool AllocateBuffer(size_t bytes); 142 bool ExpandBuffer(size_t requestedSize); 143 bool WriteBoolean(bool value); 144 bool WriteJSError(const JSHandle<JSTaggedValue> &value); 145 bool WriteJSErrorHeader(JSType type); 146 bool WriteJSDate(const JSHandle<JSTaggedValue> &value); 147 bool WriteJSArray(const JSHandle<JSTaggedValue> &value); 148 bool WriteJSMap(const JSHandle<JSTaggedValue> &value); 149 bool WriteJSSet(const JSHandle<JSTaggedValue> &value); 150 bool WriteJSRegExp(const JSHandle<JSTaggedValue> &value); 151 bool WriteEcmaString(const JSHandle<JSTaggedValue> &value); 152 bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId); 153 bool WritePlainObject(const JSHandle<JSTaggedValue> &value); 154 bool WriteNativeBindingObject(const JSHandle<JSTaggedValue> &value); 155 bool WriteJSNativePointer(const JSHandle<JSNativePointer> &value); 156 bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value); 157 bool WriteBigInt(const JSHandle<JSTaggedValue> &value); 158 bool WriteDesc(const PropertyDescriptor &desc); 159 bool IsNativeBindingObject(std::vector<JSTaggedValue> keyVector); 160 bool IsTargetSymbol(JSTaggedValue symbolVal); 161 bool IsSerialized(uintptr_t addr) const; 162 bool WriteIfSerialized(uintptr_t addr); 163 uint32_t GetDataViewTypeIndex(const DataViewType dataViewType); 164 bool WriteString(const CString &str); 165 166 NO_MOVE_SEMANTIC(JSSerializer); 167 NO_COPY_SEMANTIC(JSSerializer); 168 169 JSThread *thread_; 170 uint8_t *buffer_ = nullptr; 171 uint64_t sizeLimit_ = 0; 172 size_t bufferSize_ = 0; 173 size_t bufferCapacity_ = 0; 174 // The Reference map is used for check whether a tagged object has been serialized 175 // Reference map works only if no gc happens during serialization 176 CUnorderedMap<uintptr_t, uint64_t> referenceMap_; 177 CUnorderedSet<uintptr_t> transferDataSet_; 178 uint64_t objectId_ = 0; 179 bool defaultTransfer_ = false; 180 }; 181 182 class JSDeserializer { 183 public: 184 // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 185 JSDeserializer(JSThread *thread, uint8_t *data, size_t size, void *hint = nullptr) thread_(thread)186 : thread_(thread), factory_(thread->GetEcmaVM()->GetFactory()), 187 begin_(data), position_(data), end_(data + size), engine_(hint) 188 {} 189 ~JSDeserializer(); 190 JSHandle<JSTaggedValue> Deserialize(); 191 192 private: 193 bool ReadInt(int32_t *value); 194 bool ReadObjectId(uint64_t *objectId); 195 bool ReadDouble(double *value); 196 SerializationUID ReadType(); 197 JSHandle<JSTaggedValue> ReadJSFunctionBase(); 198 JSHandle<JSTaggedValue> ReadJSFunction(); 199 JSHandle<JSTaggedValue> ReadTaggedArray(); 200 JSHandle<JSTaggedValue> ReadByteArray(); 201 JSHandle<JSTaggedValue> ReadMethod(); 202 JSHandle<JSTaggedValue> ReadNativeMethod(); 203 JSHandle<JSTaggedValue> ReadJSError(SerializationUID uid); 204 JSHandle<JSTaggedValue> ReadJSDate(); 205 JSHandle<JSTaggedValue> ReadJSArray(); 206 JSHandle<JSTaggedValue> ReadPlainObject(); 207 JSHandle<JSTaggedValue> ReadEcmaString(); 208 JSHandle<JSTaggedValue> ReadJSMap(); 209 JSHandle<JSTaggedValue> ReadJSSet(); 210 JSHandle<JSTaggedValue> ReadJSRegExp(); 211 JSHandle<JSTaggedValue> ReadJSTypedArray(SerializationUID uid); 212 JSHandle<JSTaggedValue> ReadJSNativePointer(); 213 JSHandle<JSTaggedValue> ReadJSArrayBuffer(SerializationUID uid); 214 JSHandle<JSTaggedValue> ReadReference(); 215 JSHandle<JSTaggedValue> ReadNativeBindingObject(); 216 JSHandle<JSTaggedValue> ReadBigInt(); 217 JSHandle<JSTaggedValue> DeserializeJSTaggedValue(); 218 bool JudgeType(SerializationUID targetUid); 219 void *GetBuffer(uint32_t bufferSize); 220 bool ReadJSTaggedValue(JSTaggedValue *originalFlags); 221 bool ReadNativePointer(uintptr_t *pointer); 222 bool DefinePropertiesAndElements(const JSHandle<JSTaggedValue> &obj); 223 bool ReadDesc(PropertyDescriptor *desc); 224 bool ReadBoolean(bool *value); 225 bool ReadString(CString *value); 226 DataViewType GetDataViewTypeByIndex(uint32_t viewTypeIndex); 227 228 NO_MOVE_SEMANTIC(JSDeserializer); 229 NO_COPY_SEMANTIC(JSDeserializer); 230 231 JSThread *thread_ = nullptr; 232 ObjectFactory *factory_ = nullptr; 233 uint8_t *begin_ = nullptr; 234 const uint8_t *position_ = nullptr; 235 const uint8_t *end_ = nullptr; 236 uint64_t objectId_ = 0; 237 CUnorderedMap<uint64_t, JSHandle<JSTaggedValue>> referenceMap_; 238 void *engine_ = nullptr; 239 }; 240 241 class SerializationData { 242 public: SerializationData()243 SerializationData() : dataSize_(0), value_(nullptr) {} 244 ~SerializationData() = default; 245 GetData()246 uint8_t* GetData() const 247 { 248 return value_.get(); 249 } GetSize()250 size_t GetSize() const 251 { 252 return dataSize_; 253 } 254 255 private: 256 struct Deleter { operatorDeleter257 void operator()(uint8_t* ptr) const 258 { 259 free(ptr); 260 } 261 }; 262 263 size_t dataSize_; 264 std::unique_ptr<uint8_t, Deleter> value_; 265 266 private: 267 friend class Serializer; 268 269 NO_COPY_SEMANTIC(SerializationData); 270 }; 271 272 class Serializer { 273 public: Serializer(JSThread * thread)274 explicit Serializer(JSThread *thread) : valueSerializer_(thread) {} 275 ~Serializer() = default; 276 277 bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer); 278 std::unique_ptr<SerializationData> Release(); 279 280 private: 281 bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 282 283 private: 284 ecmascript::JSSerializer valueSerializer_; 285 std::unique_ptr<SerializationData> data_; 286 287 NO_COPY_SEMANTIC(Serializer); 288 }; 289 290 class Deserializer { 291 public: Deserializer(JSThread * thread,SerializationData * data,void * hint)292 Deserializer(JSThread *thread, SerializationData *data, void *hint) 293 : valueDeserializer_(thread, data->GetData(), data->GetSize(), hint) {} ~Deserializer()294 ~Deserializer() 295 {} 296 297 JSHandle<JSTaggedValue> ReadValue(); 298 299 private: 300 ecmascript::JSDeserializer valueDeserializer_; 301 302 NO_COPY_SEMANTIC(Deserializer); 303 }; 304 } // namespace panda::ecmascript 305 306 #endif // ECMASCRIPT_JS_SERIALIZER_H 307