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 <map> 20 21 #include "ecmascript/ecma_vm.h" 22 #include "ecmascript/js_date.h" 23 #include "ecmascript/js_map.h" 24 #include "ecmascript/js_native_pointer.h" 25 #include "ecmascript/js_object.h" 26 #include "ecmascript/js_thread.h" 27 #include "ecmascript/js_typed_array.h" 28 #include "ecmascript/jspandafile/js_pandafile.h" 29 #include "ecmascript/jspandafile/program_object.h" 30 #include "ecmascript/mem/dyn_chunk.h" 31 #include "ecmascript/napi/jsnapi_helper.h" 32 #include "ecmascript/napi/include/jsnapi.h" 33 34 using panda::JSValueRef; 35 namespace panda::ecmascript { 36 class JSPandaFile; 37 class ConstantPool; 38 39 typedef void* (*DetachFunc)(void *enginePointer, void *objPointer, void *hint, void *detachData); 40 typedef Local<JSValueRef> (*AttachFunc)(void *enginePointer, void *buffer, void *hint, void *attachData); 41 42 enum class SerializationUID : uint8_t { 43 // JS special values 44 JS_NULL = 0x01, 45 JS_UNDEFINED, 46 JS_TRUE, 47 JS_FALSE, 48 HOLE, 49 // Number types 50 INT32, 51 DOUBLE, 52 // Not support yet, BigInt type has not been implemented in ark engine 53 BIGINT, 54 ECMASTRING, 55 // Boolean types 56 C_TRUE, 57 C_FALSE, 58 // Tagged object reference mark 59 TAGGED_OBJECT_REFERNCE, 60 // Support tagged object id reference begin 61 JS_DATE, 62 JS_REG_EXP, 63 JS_PLAIN_OBJECT, 64 NATIVE_BINDING_OBJECT, 65 JS_SET, 66 JS_MAP, 67 JS_ARRAY, 68 JS_ARRAY_BUFFER, 69 JS_SHARED_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 JS_METHOD, 99 NATIVE_METHOD, 100 CONSTANT_POOL, 101 TAGGED_ARRAY, 102 // Function end 103 BYTE_ARRAY, 104 NATIVE_POINTER, 105 UNKNOWN 106 }; 107 108 class JSSerializer { 109 public: JSSerializer(JSThread * thread)110 explicit JSSerializer(JSThread *thread) : thread_(thread) {} 111 ~JSSerializer() = default; 112 bool SerializeJSTaggedValue(const JSHandle<JSTaggedValue> &value); 113 114 // Return pointer to the buffer and its length, should not use this Serializer anymore after Release 115 std::pair<uint8_t *, size_t> ReleaseBuffer(); 116 117 private: 118 bool WriteJSFunction(const JSHandle<JSTaggedValue> &value); 119 bool WriteMethod(const JSHandle<JSTaggedValue> &value); 120 bool WriteConstantPool(const JSHandle<JSTaggedValue> &value); 121 bool WriteTaggedArray(const JSHandle<JSTaggedValue> &value); 122 bool WriteByteArray(const JSHandle<JSTaggedValue> &value, DataViewType viewType); 123 bool WriteTaggedObject(const JSHandle<JSTaggedValue> &value); 124 bool WritePrimitiveValue(const JSHandle<JSTaggedValue> &value); 125 bool WriteInt(int32_t value); 126 bool WriteDouble(double value); 127 bool WriteRawData(const void *data, size_t length); 128 bool WriteType(SerializationUID uId); 129 bool AllocateBuffer(size_t bytes); 130 bool ExpandBuffer(size_t requestedSize); 131 bool WriteBoolean(bool value); 132 bool WriteJSError(const JSHandle<JSTaggedValue> &value); 133 bool WriteJSErrorHeader(JSType type); 134 bool WriteJSDate(const JSHandle<JSTaggedValue> &value); 135 bool WriteJSArray(const JSHandle<JSTaggedValue> &value); 136 bool WriteJSMap(const JSHandle<JSTaggedValue> &value); 137 bool WriteJSSet(const JSHandle<JSTaggedValue> &value); 138 bool WriteJSRegExp(const JSHandle<JSTaggedValue> &value); 139 bool WriteEcmaString(const JSHandle<JSTaggedValue> &value); 140 bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId); 141 bool WritePlainObject(const JSHandle<JSTaggedValue> &value); 142 bool WriteNativeBindingObject(const JSHandle<JSTaggedValue> &value); 143 bool WriteNativePointer(const JSHandle<JSTaggedValue> &value); 144 bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value); 145 bool WriteDesc(const PropertyDescriptor &desc); 146 bool IsNativeBindingObject(std::vector<JSTaggedValue> keyVector); 147 bool IsTargetSymbol(JSTaggedValue symbolVal); 148 bool IsSerialized(uintptr_t addr) const; 149 bool WriteIfSerialized(uintptr_t addr); 150 uint32_t GetDataViewTypeIndex(const DataViewType dataViewType); 151 152 NO_MOVE_SEMANTIC(JSSerializer); 153 NO_COPY_SEMANTIC(JSSerializer); 154 155 JSThread *thread_; 156 uint8_t *buffer_ = nullptr; 157 uint64_t sizeLimit_ = 0; 158 size_t bufferSize_ = 0; 159 size_t bufferCapacity_ = 0; 160 // The Reference map is used for check whether a tagged object has been serialized 161 // Reference map works only if no gc happens during serialization 162 std::map<uintptr_t, uint64_t> referenceMap_; 163 uint64_t objectId_ = 0; 164 }; 165 166 class JSDeserializer { 167 public: 168 // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 169 JSDeserializer(JSThread *thread, uint8_t *data, size_t size, void *hint = nullptr) thread_(thread)170 : thread_(thread), factory_(thread->GetEcmaVM()->GetFactory()), 171 begin_(data), position_(data), end_(data + size), engine_(hint) 172 { 173 } 174 ~JSDeserializer(); 175 JSHandle<JSTaggedValue> DeserializeJSTaggedValue(); 176 177 private: 178 bool ReadInt(int32_t *value); 179 bool ReadObjectId(uint64_t *objectId); 180 bool ReadDouble(double *value); 181 SerializationUID ReadType(); 182 JSHandle<JSTaggedValue> ReadJSFunctionBase(); 183 JSHandle<JSTaggedValue> ReadJSFunction(); 184 JSHandle<JSTaggedValue> ReadTaggedArray(); 185 JSHandle<JSTaggedValue> ReadByteArray(); 186 JSHandle<JSTaggedValue> ReadJSMethod(); 187 JSHandle<JSTaggedValue> ReadNativeMethod(); 188 JSHandle<JSTaggedValue> ReadConstantPool(); 189 JSHandle<JSTaggedValue> ReadJSError(SerializationUID uid); 190 JSHandle<JSTaggedValue> ReadJSDate(); 191 JSHandle<JSTaggedValue> ReadJSArray(); 192 JSHandle<JSTaggedValue> ReadPlainObject(); 193 JSHandle<JSTaggedValue> ReadEcmaString(); 194 JSHandle<JSTaggedValue> ReadJSMap(); 195 JSHandle<JSTaggedValue> ReadJSSet(); 196 JSHandle<JSTaggedValue> ReadJSRegExp(); 197 JSHandle<JSTaggedValue> ReadJSTypedArray(SerializationUID uid); 198 JSHandle<JSTaggedValue> ReadNativePointer(); 199 JSHandle<JSTaggedValue> ReadJSArrayBuffer(); 200 JSHandle<JSTaggedValue> ReadReference(); 201 JSHandle<JSTaggedValue> ReadNativeBindingObject(); 202 bool JudgeType(SerializationUID targetUid); 203 void *GetBuffer(uint32_t bufferSize); 204 bool ReadJSTaggedValue(JSTaggedValue *originalFlags); 205 bool ReadNativePointer(uintptr_t *pointer); 206 bool DefinePropertiesAndElements(const JSHandle<JSTaggedValue> &obj); 207 bool ReadDesc(PropertyDescriptor *desc); 208 bool ReadBoolean(bool *value); 209 DataViewType GetDataViewTypeByIndex(uint32_t viewTypeIndex); 210 211 NO_MOVE_SEMANTIC(JSDeserializer); 212 NO_COPY_SEMANTIC(JSDeserializer); 213 214 JSThread *thread_ = nullptr; 215 ObjectFactory *factory_ = nullptr; 216 uint8_t *begin_ = nullptr; 217 const uint8_t *position_ = nullptr; 218 const uint8_t * const end_ = nullptr; 219 uint64_t objectId_ = 0; 220 std::map<uint64_t, JSHandle<JSTaggedValue>> referenceMap_; 221 void *engine_ = nullptr; 222 }; 223 224 class SerializationData { 225 public: SerializationData()226 SerializationData() : dataSize_(0), value_(nullptr) {} 227 ~SerializationData() = default; 228 GetData()229 uint8_t* GetData() const 230 { 231 return value_.get(); 232 } GetSize()233 size_t GetSize() const 234 { 235 return dataSize_; 236 } 237 238 private: 239 struct Deleter { operatorDeleter240 void operator()(uint8_t* ptr) const 241 { 242 free(ptr); 243 } 244 }; 245 246 size_t dataSize_; 247 std::unique_ptr<uint8_t, Deleter> value_; 248 249 private: 250 friend class Serializer; 251 252 NO_COPY_SEMANTIC(SerializationData); 253 }; 254 255 class Serializer { 256 public: Serializer(JSThread * thread)257 explicit Serializer(JSThread *thread) : valueSerializer_(thread) {} 258 ~Serializer() = default; 259 260 bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer); 261 std::unique_ptr<SerializationData> Release(); 262 263 private: 264 bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 265 bool FinalizeTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 266 267 private: 268 ecmascript::JSSerializer valueSerializer_; 269 std::unique_ptr<SerializationData> data_; 270 CVector<int> arrayBufferIdxs_; 271 272 NO_COPY_SEMANTIC(Serializer); 273 }; 274 275 class Deserializer { 276 public: Deserializer(JSThread * thread,SerializationData * data,void * hint)277 explicit Deserializer(JSThread *thread, SerializationData *data, void *hint) 278 : valueDeserializer_(thread, data->GetData(), data->GetSize(), hint) {} 279 ~Deserializer() = default; 280 281 JSHandle<JSTaggedValue> ReadValue(); 282 283 private: 284 ecmascript::JSDeserializer valueDeserializer_; 285 286 NO_COPY_SEMANTIC(Deserializer); 287 }; 288 } // namespace panda::ecmascript 289 290 #endif // ECMASCRIPT_JS_SERIALIZER_H