arkcompiler_ets_runtime/ecmascript/js_serializer.h

245 lines
7.4 KiB
C
Raw Normal View History

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_JS_SERIALIZER_H
#define ECMASCRIPT_JS_SERIALIZER_H
#include <map>
#include "ecmascript/ecma_vm.h"
#include "ecmascript/js_date.h"
#include "ecmascript/js_map.h"
#include "ecmascript/js_native_pointer.h"
#include "ecmascript/js_object.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/regexp/dyn_chunk.h"
namespace panda::ecmascript {
enum class SerializationUID : uint8_t {
// JS special values
JS_NULL = 0x01,
JS_UNDEFINED,
JS_TRUE,
JS_FALSE,
HOLE,
// Number types
INT32,
DOUBLE,
// Not support yet, BigInt type has not been implemented in ark engine
BIGINT,
ECMASTRING,
// Boolean types
C_TRUE,
C_FALSE,
// Tagged object reference mark
TAGGED_OBJECT_REFERNCE,
// Support tagged object id reference begin
JS_DATE,
JS_REG_EXP,
JS_PLAIN_OBJECT,
JS_SET,
JS_MAP,
JS_ARRAY,
JS_ARRAY_BUFFER,
// TypedArray begin
JS_UINT8_ARRAY,
JS_UINT8_CLAMPED_ARRAY,
JS_UINT16_ARRAY,
JS_UINT32_ARRAY,
JS_INT8_ARRAY,
JS_INT16_ARRAY,
JS_INT32_ARRAY,
JS_FLOAT32_ARRAY,
JS_FLOAT64_ARRAY,
// TypedArray end
// Support tagged object id reference end
// Error UIDs
JS_ERROR,
EVAL_ERROR,
RANGE_ERROR,
REFERENCE_ERROR,
TYPE_ERROR,
URI_ERROR,
SYNTAX_ERROR,
ERROR_MESSAGE_BEGIN,
ERROR_MESSAGE_END,
// NativeFunctionPointer
NATIVE_FUNCTION_POINTER,
UNKNOWN
};
class JSSerializer {
public:
explicit JSSerializer(JSThread *thread) : thread_(thread) {}
~JSSerializer() = default;
bool SerializeJSTaggedValue(const JSHandle<JSTaggedValue> &value);
// Return pointer to the buffer and its length, should not use this Serializer anymore after Release
std::pair<uint8_t *, size_t> ReleaseBuffer();
private:
bool WriteTaggedObject(const JSHandle<JSTaggedValue> &value);
bool WritePrimitiveValue(const JSHandle<JSTaggedValue> &value);
bool WriteInt(int32_t value);
bool WriteDouble(double value);
bool WriteRawData(const void *data, size_t length);
bool WriteType(SerializationUID uId);
bool AllocateBuffer(size_t bytes);
bool ExpandBuffer(size_t requestedSize);
bool WriteBoolean(bool value);
bool WriteJSError(const JSHandle<JSTaggedValue> &value);
bool WriteJSErrorHeader(JSType type);
bool WriteJSDate(const JSHandle<JSTaggedValue> &value);
bool WriteJSArray(const JSHandle<JSTaggedValue> &value);
bool WriteJSMap(const JSHandle<JSTaggedValue> &value);
bool WriteJSSet(const JSHandle<JSTaggedValue> &value);
bool WriteJSRegExp(const JSHandle<JSTaggedValue> &value);
bool WriteEcmaString(const JSHandle<JSTaggedValue> &value);
bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId);
bool WritePlainObject(const JSHandle<JSTaggedValue> &value);
bool WriteNativeFunctionPointer(const JSHandle<JSTaggedValue> &value);
bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value);
bool WriteDesc(const PropertyDescriptor &desc);
bool IsSerialized(uintptr_t addr) const;
bool WriteIfSerialized(uintptr_t addr);
NO_MOVE_SEMANTIC(JSSerializer);
NO_COPY_SEMANTIC(JSSerializer);
JSThread *thread_;
uint8_t *buffer_ = nullptr;
uint64_t sizeLimit_ = 0;
size_t bufferSize_ = 0;
size_t bufferCapacity_ = 0;
// The Reference map is used for check whether a tagged object has been serialized
// Reference map works only if no gc happens during serialization
std::map<uintptr_t, uint64_t> referenceMap_;
uint64_t objectId_ = 0;
};
class JSDeserializer {
public:
// NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
JSDeserializer(JSThread *thread, uint8_t *data, size_t size)
: thread_(thread), begin_(data), position_(data), end_(data + size)
{
}
~JSDeserializer();
JSHandle<JSTaggedValue> DeserializeJSTaggedValue();
private:
bool ReadInt(int32_t *value);
bool ReadObjectId(uint64_t *objectId);
bool ReadDouble(double *value);
SerializationUID ReadType();
JSHandle<JSTaggedValue> ReadJSError(SerializationUID uid);
JSHandle<JSTaggedValue> ReadJSDate();
JSHandle<JSTaggedValue> ReadJSArray();
JSHandle<JSTaggedValue> ReadPlainObject();
JSHandle<JSTaggedValue> ReadEcmaString();
JSHandle<JSTaggedValue> ReadJSMap();
JSHandle<JSTaggedValue> ReadJSSet();
JSHandle<JSTaggedValue> ReadJSRegExp();
JSHandle<JSTaggedValue> ReadJSTypedArray(SerializationUID uid);
JSHandle<JSTaggedValue> ReadNativeFunctionPointer();
JSHandle<JSTaggedValue> ReadJSArrayBuffer();
JSHandle<JSTaggedValue> ReadReference();
bool JudgeType(SerializationUID targetUid);
void *GetBuffer(uint32_t bufferSize);
bool ReadJSTaggedValue(JSTaggedValue *originalFlags);
bool DefinePropertiesAndElements(const JSHandle<JSTaggedValue> &obj);
bool ReadDesc(PropertyDescriptor *desc);
bool ReadBoolean(bool *value);
NO_MOVE_SEMANTIC(JSDeserializer);
NO_COPY_SEMANTIC(JSDeserializer);
JSThread *thread_ = nullptr;
uint8_t *begin_ = nullptr;
const uint8_t *position_ = nullptr;
const uint8_t * const end_ = nullptr;
uint64_t objectId_ = 0;
std::map<uint64_t, JSHandle<JSTaggedValue>> referenceMap_;
};
class SerializationData {
public:
SerializationData() : dataSize_(0), value_(nullptr) {}
~SerializationData() = default;
uint8_t* GetData() const
{
return value_.get();
}
size_t GetSize() const
{
return dataSize_;
}
private:
struct Deleter {
void operator()(uint8_t* ptr) const
{
free(ptr);
}
};
size_t dataSize_;
std::unique_ptr<uint8_t, Deleter> value_;
private:
friend class Serializer;
NO_COPY_SEMANTIC(SerializationData);
};
class Serializer {
public:
explicit Serializer(JSThread *thread) : valueSerializer_(thread) {}
~Serializer() = default;
bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer);
std::unique_ptr<SerializationData> Release();
private:
bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer);
bool FinalizeTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer);
private:
ecmascript::JSSerializer valueSerializer_;
std::unique_ptr<SerializationData> data_;
CVector<int> arrayBufferIdxs_;
NO_COPY_SEMANTIC(Serializer);
};
class Deserializer {
public:
explicit Deserializer(JSThread *thread, SerializationData* data)
: valueDeserializer_(thread, data->GetData(), data->GetSize()) {}
~Deserializer() = default;
JSHandle<JSTaggedValue> ReadValue();
private:
ecmascript::JSDeserializer valueDeserializer_;
NO_COPY_SEMANTIC(Deserializer);
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JS_SERIALIZER_H