1 /* 2 * Copyright (c) 2021 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/regexp/dyn_chunk.h" 29 30 namespace panda::ecmascript { 31 enum class SerializationUID : uint8_t { 32 // JS special values 33 JS_NULL = 0x01, 34 JS_UNDEFINED, 35 JS_TRUE, 36 JS_FALSE, 37 HOLE, 38 // Number types 39 INT32, 40 DOUBLE, 41 // Not support yet, BigInt type has not been implemented in ark engine 42 BIGINT, 43 ECMASTRING, 44 // Boolean types 45 C_TRUE, 46 C_FALSE, 47 // Tagged object reference mark 48 TAGGED_OBJECT_REFERNCE, 49 // Support tagged objct id reference begin 50 JS_DATE, 51 JS_REG_EXP, 52 JS_PLAIN_OBJECT, 53 JS_SET, 54 JS_MAP, 55 JS_ARRAY, 56 JS_ARRAY_BUFFER, 57 // TypedArray begin 58 JS_UINT8_ARRAY, 59 JS_UINT8_CLAMPED_ARRAY, 60 JS_UINT16_ARRAY, 61 JS_UINT32_ARRAY, 62 JS_INT8_ARRAY, 63 JS_INT16_ARRAY, 64 JS_INT32_ARRAY, 65 JS_FLOAT32_ARRAY, 66 JS_FLOAT64_ARRAY, 67 // TypedArray end 68 // Support tagged objct id reference end 69 // Error UIDs 70 JS_ERROR, 71 EVAL_ERROR, 72 RANGE_ERROR, 73 REFERENCE_ERROR, 74 TYPE_ERROR, 75 URI_ERROR, 76 SYNTAX_ERROR, 77 ERROR_MESSAGE_BEGIN, 78 ERROR_MESSAGE_END, 79 // NativeFunctionPointer 80 NATIVE_FUNCTION_POINTER, 81 UNKNOWN 82 }; 83 84 class JSSerializer { 85 public: JSSerializer(JSThread * thread)86 explicit JSSerializer(JSThread *thread) : thread_(thread) {} 87 ~JSSerializer() = default; 88 bool SerializeJSTaggedValue(const JSHandle<JSTaggedValue> &value); 89 90 // Return pointer to the buffer and its length, should not use this Serializer anymore after Release 91 std::pair<uint8_t *, size_t> ReleaseBuffer(); 92 93 private: 94 bool WriteTaggedObject(const JSHandle<JSTaggedValue> &value); 95 bool WritePrimitiveValue(const JSHandle<JSTaggedValue> &value); 96 bool WriteInt(int32_t value); 97 bool WriteDouble(double value); 98 bool WriteRawData(const void *data, size_t length); 99 bool WriteType(SerializationUID uId); 100 bool AllocateBuffer(size_t bytes); 101 bool ExpandBuffer(size_t requestedSize); 102 bool WriteBoolean(bool value); 103 bool WriteJSError(const JSHandle<JSTaggedValue> &value); 104 bool WriteJSErrorHeader(JSType type); 105 bool WriteJSDate(const JSHandle<JSTaggedValue> &value); 106 bool WriteJSArray(const JSHandle<JSTaggedValue> &value); 107 bool WriteJSMap(const JSHandle<JSTaggedValue> &value); 108 bool WriteJSSet(const JSHandle<JSTaggedValue> &value); 109 bool WriteJSRegExp(const JSHandle<JSTaggedValue> &value); 110 bool WriteEcmaString(const JSHandle<JSTaggedValue> &value); 111 bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId); 112 bool WritePlainObject(const JSHandle<JSTaggedValue> &value); 113 bool WriteNativeFunctionPointer(const JSHandle<JSTaggedValue> &value); 114 bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value); 115 bool WriteDesc(const PropertyDescriptor &desc); 116 bool IsSerialized(uintptr_t addr) const; 117 bool WriteIfSerialized(uintptr_t addr); 118 119 NO_MOVE_SEMANTIC(JSSerializer); 120 NO_COPY_SEMANTIC(JSSerializer); 121 122 JSThread *thread_; 123 uint8_t *buffer_ = nullptr; 124 uint64_t sizeLimit_ = 0; 125 size_t bufferSize_ = 0; 126 size_t bufferCapacity_ = 0; 127 // The Reference map is used for check whether a tagged object has been serialized 128 // Reference map works only if no gc happens during serialization 129 std::map<uintptr_t, uint64_t> referenceMap_; 130 uint64_t objectId_ = 0; 131 }; 132 133 class JSDeserializer { 134 public: 135 // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) JSDeserializer(JSThread * thread,uint8_t * data,size_t size)136 JSDeserializer(JSThread *thread, uint8_t *data, size_t size) 137 : thread_(thread), begin_(data), position_(data), end_(data + size) 138 { 139 } 140 ~JSDeserializer(); 141 JSHandle<JSTaggedValue> DeserializeJSTaggedValue(); 142 143 private: 144 bool ReadInt(int32_t *value); 145 bool ReadObjectId(uint64_t *objectId); 146 bool ReadDouble(double *value); 147 SerializationUID ReadType(); 148 JSHandle<JSTaggedValue> ReadJSError(SerializationUID uid); 149 JSHandle<JSTaggedValue> ReadJSDate(); 150 JSHandle<JSTaggedValue> ReadJSArray(); 151 JSHandle<JSTaggedValue> ReadPlainObject(); 152 JSHandle<JSTaggedValue> ReadEcmaString(); 153 JSHandle<JSTaggedValue> ReadJSMap(); 154 JSHandle<JSTaggedValue> ReadJSSet(); 155 JSHandle<JSTaggedValue> ReadJSRegExp(); 156 JSHandle<JSTaggedValue> ReadJSTypedArray(SerializationUID uid); 157 JSHandle<JSTaggedValue> ReadNativeFunctionPointer(); 158 JSHandle<JSTaggedValue> ReadJSArrayBuffer(); 159 JSHandle<JSTaggedValue> ReadReference(); 160 bool JudgeType(SerializationUID targetUid); 161 void *GetBuffer(uint32_t bufferSize); 162 bool ReadJSTaggedValue(JSTaggedValue *originalFlags); 163 bool DefinePropertiesAndElements(const JSHandle<JSTaggedValue> &obj); 164 bool ReadDesc(PropertyDescriptor *desc); 165 bool ReadBoolean(bool *value); 166 167 NO_MOVE_SEMANTIC(JSDeserializer); 168 NO_COPY_SEMANTIC(JSDeserializer); 169 170 JSThread *thread_ = nullptr; 171 uint8_t *begin_ = nullptr; 172 const uint8_t *position_ = nullptr; 173 const uint8_t * const end_ = nullptr; 174 uint64_t objectId_ = 0; 175 std::map<uint64_t, JSHandle<JSTaggedValue>> referenceMap_; 176 }; 177 178 class SerializationData { 179 public: SerializationData()180 SerializationData() : dataSize_(0), value_(nullptr) {} 181 ~SerializationData() = default; 182 GetData()183 uint8_t* GetData() const 184 { 185 return value_.get(); 186 } GetSize()187 size_t GetSize() const 188 { 189 return dataSize_; 190 } 191 192 private: 193 struct Deleter { operatorDeleter194 void operator()(uint8_t* ptr) const 195 { 196 free(ptr); 197 } 198 }; 199 200 size_t dataSize_; 201 std::unique_ptr<uint8_t, Deleter> value_; 202 203 private: 204 friend class Serializer; 205 206 NO_COPY_SEMANTIC(SerializationData); 207 }; 208 209 class Serializer { 210 public: Serializer(JSThread * thread)211 explicit Serializer(JSThread *thread) : valueSerializer_(thread) {} 212 ~Serializer() = default; 213 214 bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer); 215 std::unique_ptr<SerializationData> Release(); 216 217 private: 218 bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 219 bool FinalizeTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer); 220 221 private: 222 ecmascript::JSSerializer valueSerializer_; 223 std::unique_ptr<SerializationData> data_; 224 CVector<int> arrayBufferIdxs_; 225 226 NO_COPY_SEMANTIC(Serializer); 227 }; 228 229 class Deserializer { 230 public: Deserializer(JSThread * thread,SerializationData * data)231 explicit Deserializer(JSThread *thread, SerializationData* data) 232 : valueDeserializer_(thread, data->GetData(), data->GetSize()) {} 233 ~Deserializer() = default; 234 235 JSHandle<JSTaggedValue> ReadValue(); 236 237 private: 238 ecmascript::JSDeserializer valueDeserializer_; 239 240 NO_COPY_SEMANTIC(Deserializer); 241 }; 242 } // namespace panda::ecmascript 243 244 #endif // ECMASCRIPT_JS_SERIALIZER_H 245