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 ERROR_MESSAGE_BEGIN, 95 ERROR_MESSAGE_END, 96 // Function begin 97 CONCURRENT_FUNCTION, 98 METHOD, 99 NATIVE_METHOD, 100 TAGGED_ARRAY, 101 // Function end 102 BYTE_ARRAY, 103 UID_END, 104 UNKNOWN 105 }; 106 107 class JSSerializer { 108 public: JSSerializer(JSThread * thread)109 explicit JSSerializer(JSThread *thread) : thread_(thread) {} 110 ~JSSerializer() = default; 111 bool SerializeJSTaggedValue(const JSHandle<JSTaggedValue> &value); 112 void InitTransferSet(CUnorderedSet<uintptr_t> transferDataSet); 113 void ClearTransferSet(); 114 115 // Return pointer to the buffer and its length, should not use this Serializer anymore after Release 116 std::pair<uint8_t *, size_t> ReleaseBuffer(); 117 118 private: 119 bool WriteJSFunction(const JSHandle<JSTaggedValue> &value); 120 bool WriteMethod(const JSHandle<JSTaggedValue> &value); 121 bool WriteConstantPool(const JSHandle<JSTaggedValue> &value); 122 bool WriteTaggedArray(const JSHandle<JSTaggedValue> &value); 123 bool WriteByteArray(const JSHandle<JSTaggedValue> &value, DataViewType viewType); 124 bool WriteTaggedObject(const JSHandle<JSTaggedValue> &value); 125 bool WritePrimitiveValue(const JSHandle<JSTaggedValue> &value); 126 bool WriteInt(int32_t value); 127 bool WriteDouble(double value); 128 bool WriteRawData(const void *data, size_t length); 129 bool WriteType(SerializationUID uId); 130 bool AllocateBuffer(size_t bytes); 131 bool ExpandBuffer(size_t requestedSize); 132 bool WriteBoolean(bool value); 133 bool WriteJSError(const JSHandle<JSTaggedValue> &value); 134 bool WriteJSErrorHeader(JSType type); 135 bool WriteJSDate(const JSHandle<JSTaggedValue> &value); 136 bool WriteJSArray(const JSHandle<JSTaggedValue> &value); 137 bool WriteJSMap(const JSHandle<JSTaggedValue> &value); 138 bool WriteJSSet(const JSHandle<JSTaggedValue> &value); 139 bool WriteJSRegExp(const JSHandle<JSTaggedValue> &value); 140 bool WriteEcmaString(const JSHandle<JSTaggedValue> &value); 141 bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId); 142 bool WritePlainObject(const JSHandle<JSTaggedValue> &value); 143 bool WriteNativeBindingObject(const JSHandle<JSTaggedValue> &value); 144 bool WriteJSNativePointer(const JSHandle<JSNativePointer> &value); 145 bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value); 146 bool WriteBigInt(const JSHandle<JSTaggedValue> &value); 147 bool WriteDesc(const PropertyDescriptor &desc); 148 bool IsNativeBindingObject(std::vector<JSTaggedValue> keyVector); 149 bool IsTargetSymbol(JSTaggedValue symbolVal); 150 bool IsSerialized(uintptr_t addr) const; 151 bool WriteIfSerialized(uintptr_t addr); 152 uint32_t GetDataViewTypeIndex(const DataViewType dataViewType); 153 bool WriteString(const CString &str); 154 155 NO_MOVE_SEMANTIC(JSSerializer); 156 NO_COPY_SEMANTIC(JSSerializer); 157 158 JSThread *thread_; 159 uint8_t *buffer_ = nullptr; 160 uint64_t sizeLimit_ = 0; 161 size_t bufferSize_ = 0; 162 size_t bufferCapacity_ = 0; 163 // The Reference map is used for check whether a tagged object has been serialized 164 // Reference map works only if no gc happens during serialization 165 CUnorderedMap<uintptr_t, uint64_t> referenceMap_; 166 CUnorderedSet<uintptr_t> transferDataSet_; 167 uint64_t objectId_ = 0; 168 }; 169 170 class JSDeserializer { 171 public: 172 // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 173 JSDeserializer(JSThread *thread, uint8_t *data, size_t size, void *hint = nullptr) thread_(thread)174 : thread_(thread), factory_(thread->GetEcmaVM()->GetFactory()), 175 begin_(data), position_(data), end_(data + size), engine_(hint) 176 { 177 } 178 ~JSDeserializer(); 179 JSHandle<JSTaggedValue> Deserialize(); 180 181 private: 182 bool ReadInt(int32_t *value); 183 bool ReadObjectId(uint64_t *objectId); 184 bool ReadDouble(double *value); 185 SerializationUID ReadType(); 186 JSHandle<JSTaggedValue> ReadJSFunctionBase(); 187 JSHandle<JSTaggedValue> ReadJSFunction(); 188 JSHandle<JSTaggedValue> ReadTaggedArray(); 189 JSHandle<JSTaggedValue> ReadByteArray(); 190 JSHandle<JSTaggedValue> ReadMethod(); 191 JSHandle<JSTaggedValue> ReadNativeMethod(); 192 JSHandle<JSTaggedValue> ReadJSError(SerializationUID uid); 193 JSHandle<JSTaggedValue> ReadJSDate(); 194 JSHandle<JSTaggedValue> ReadJSArray(); 195 JSHandle<JSTaggedValue> ReadPlainObject(); 196 JSHandle<JSTaggedValue> ReadEcmaString(); 197 JSHandle<JSTaggedValue> ReadJSMap(); 198 JSHandle<JSTaggedValue> ReadJSSet(); 199 JSHandle<JSTaggedValue> ReadJSRegExp(); 200 JSHandle<JSTaggedValue> ReadJSTypedArray(SerializationUID uid); 201 JSHandle<JSTaggedValue> ReadJSNativePointer(); 202 JSHandle<JSTaggedValue> ReadJSArrayBuffer(SerializationUID uid); 203 JSHandle<JSTaggedValue> ReadReference(); 204 JSHandle<JSTaggedValue> ReadNativeBindingObject(); 205 JSHandle<JSTaggedValue> ReadBigInt(); 206 JSHandle<JSTaggedValue> DeserializeJSTaggedValue(); 207 bool JudgeType(SerializationUID targetUid); 208 void *GetBuffer(uint32_t bufferSize); 209 bool ReadJSTaggedValue(JSTaggedValue *originalFlags); 210 bool ReadNativePointer(uintptr_t *pointer); 211 bool DefinePropertiesAndElements(const JSHandle<JSTaggedValue> &obj); 212 bool ReadDesc(PropertyDescriptor *desc); 213 bool ReadBoolean(bool *value); 214 bool ReadString(CString *value); 215 DataViewType GetDataViewTypeByIndex(uint32_t viewTypeIndex); 216 217 NO_MOVE_SEMANTIC(JSDeserializer); 218 NO_COPY_SEMANTIC(JSDeserializer); 219 220 JSThread *thread_ = nullptr; 221 ObjectFactory *factory_ = nullptr; 222 uint8_t *begin_ = nullptr; 223 const uint8_t *position_ = nullptr; 224 const uint8_t *end_ = nullptr; 225 uint64_t objectId_ = 0; 226 CUnorderedMap<uint64_t, JSHandle<JSTaggedValue>> referenceMap_; 227 void *engine_ = nullptr; 228 }; 229 230 class SerializationData { 231 public: SerializationData()232 SerializationData() : dataSize_(0), value_(nullptr) {} 233 ~SerializationData() = default; 234 GetData()235 uint8_t* GetData() const 236 { 237 return value_.get(); 238 } GetSize()239 size_t GetSize() const 240 { 241 return dataSize_; 242 } 243 244 private: 245 struct Deleter { operatorDeleter246 void operator()(uint8_t* ptr) const 247 { 248 free(ptr); 249 } 250 }; 251 252 size_t dataSize_; 253 std::unique_ptr<uint8_t, Deleter> value_; 254 255 private: 256 friend class Serializer; 257 258 NO_COPY_SEMANTIC(SerializationData); 259 }; 260 261 class Serializer { 262 public: Serializer(JSThread * thread)263 explicit Serializer(JSThread *thread) : valueSerializer_(thread) {} 264 ~Serializer() = default; 265 266 bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer); 267 std::unique_ptr<SerializationData> Release(); 268 269 private: 270 bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 271 272 private: 273 ecmascript::JSSerializer valueSerializer_; 274 std::unique_ptr<SerializationData> data_; 275 276 NO_COPY_SEMANTIC(Serializer); 277 }; 278 279 class Deserializer { 280 public: Deserializer(JSThread * thread,SerializationData * data,void * hint)281 Deserializer(JSThread *thread, SerializationData *data, void *hint) 282 : valueDeserializer_(thread, data->GetData(), data->GetSize(), hint), data_(data) {} ~Deserializer()283 ~Deserializer() 284 { 285 data_.reset(nullptr); 286 } 287 288 JSHandle<JSTaggedValue> ReadValue(); 289 290 private: 291 ecmascript::JSDeserializer valueDeserializer_; 292 std::unique_ptr<SerializationData> data_; 293 294 NO_COPY_SEMANTIC(Deserializer); 295 }; 296 } // namespace panda::ecmascript 297 298 #endif // ECMASCRIPT_JS_SERIALIZER_H 299