• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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